next up previous contents
Next: Obtaining and Installing SU Up: How to Write an Previous: A template SU program   Contents

Writing a new program: suvlength

A user asked about SU processing for variable length traces. At his institute, data are collected from time of excitation to a variable termination time. The difficulty is that SU processing is based on the SEG-Y standard which mandates that all traces in the data set be of the same length. Rather than contemplating changing all of SU, it seems to us that the solution is to provide a program that converts the variable length data to fixed length data by padding with zeroes where necessary at the end of the traces--let's name this new program suvlength. We can make the length of the output traces a user parameter. If there is a reasonable choice, it makes sense to provide a default value for parameters. Here, using the length of the first trace seems the best choice since that value can be ascertained before the main processing loop starts.

So far, so good. But now our plan runs into a serious snag: the fundamental trace getting facility, gettr, itself assumes fixed length traces (or perhaps we should say that gettr deliberately enforces the fixed length trace standard). But, if you think about it, you'll realize that gettr itself has to take special measures with the first trace to figure out its length. All we have to do is make a new trace getting routine that employs that first trace logic for every trace. Here, we'll suppress the details of writing the ``fvgettr'' subroutine and turn to converting the template above into the new suvlength code:

/* SUVLENGTH: $Revision: 1.20 $ ; $Date: 2002/08/22 20:19:54 $   */

#include "su.h"
#include "segy.h"

/*********************** self documentation **********************/
char *sdoc[] = {
"                                                                ",
" SUVLENGTH - Adjust variable length traces to common length     ",
"                                                                ",
" suvlength <variable_length_traces >fixed_length_traces         ",
"                                                                ",
" Required parameters:                                           ",
"         none                                                   ",
"                                                                ",
" Optional parameters:                                           ",
"        ns      output number of samples (default: 1st trace ns)",
NULL};
/**************** end self doc ***********************************/

/* Credits:
 *        CWP: Jack Cohen, John Stockwell
 */

/* prototype */
int fvgettr(FILE *fp, segy *tp);

segy tr;

main(int argc, char **argv)
{
        int ns;        /* number of samples on output traces  */


        /* Initialize */                 
        initargs(argc, argv);
        requestdoc(1);
 
        /* Get parameters */
        ...
        
        /* Get info from first trace */
        ...

        ...

        return EXIT_SUCCESS;                                          [16]
}

/* fvgettr code goes here */
        ...
Now we run into a small difficulty. Our only parameter has a default value that is obtained only after we read in the first trace. The obvious solution is to reverse the parameter getting and the trace getting in the template. Thus we resume:
        /* Get info from first trace and set ns */ 
        if (!fvgettr(stdin, &tr))  err("can't get first trace"); 
        if (!getparint("ns", &ns))    ns = tr.ns;

        /* Loop over the traces */
        do {
                int nt = tr.ns;
Now comes the actual seismic algorithm--which is rather trivial in the present case: add zeroes to the end of the input trace if the output length is specified greater than the input length. We could write a simple loop to do the job, but the task is done most succinctly by using the ANSI-C routine memset. However, we confess that unless we've used it recently, we usually forget how to use this routine. One solution is to cd to the su/main directory and use grep to find other uses of memset. When we did this, we found that sumute had usage closest to what we needed and that is why we started from a copy of that code. Here is the complete main for suvlength:
/* SUVLENGTH: $Revision: 1.20 $ ; $Date: 2002/08/22 20:19:54 $        */

#include "su.h"
#include "segy.h"

/*********************** self documentation **********************/
char *sdoc[] = {
"                                                                 ",
" SUVLENGTH - Adjust variable length traces to common length      ",
"                                                                 ",
" suvlength <vdata >stdout                                        ",
"                                                                 ",
" Required parameters:                                            ",
"         none                                                    ",
"                                                                 ",
" Optional parameters:                                            ",
"          ns     output number of samples (default: 1st trace ns)",
NULL};
/**************** end self doc ***********************************/

/* Credits:
 *        CWP: Jack Cohen, John Stockwell
 *
 * Trace header fields accessed:  ns
 * Trace header fields modified:  ns
 */

/* prototype */
int fvgettr(FILE *fp, segy *tp);

segy tr;

main(int argc, char **argv)
{
        int ns;                /* samples on output traces        */


        /* Initialize */
        initargs(argc, argv);
        requestdoc(1);


        /* Get info from first trace */ 
        if (!fvgettr(stdin, &tr))  err("can't get first trace"); 
        if (!getparint("ns", &ns))    ns = tr.ns;


        /* Loop over the traces */
        do {
                int nt = tr.ns;
                                
                if (nt < ns) /* pad with zeros */
                        memset((void *)(tr.data + nt), '\0', (ns-nt)*FSIZE);
                tr.ns = ns;
                puttr(&tr);
        } while (fvgettr(stdin, &tr));
        
        return EXIT_SUCCESS;
}


#include "header.h"

/* fvgettr - get a segy trace from a file by file pointer (nt can vary)
 *
 * Returns:
 *        int: number of bytes read on current trace (0 after last trace)
 *
 * Synopsis:
 *        int fvgettr(FILE *fp, segy *tp)
 *
 * Credits:
 *        Cloned from .../su/lib/fgettr.c
 */

int fvgettr(FILE *fp, segy *tp)
   ...
Remark: In the actual SU, the subroutine fvgettr has been extracted as a library function and we also made a convenience macro vgettr for the case of standard input. But these are secondary considerations that don't arise for most applications.

For any new SU code, one should provide an example shell program to show how the new code is to be used. Here is such a program for X Windows graphics:

#! /bin/sh
# Trivial test of suvlength with X Windows graphics

WIDTH=700
HEIGHT=900
WIDTHOFF=50
HEIGHTOFF=20

>tempdata
>vdata
suplane >tempdata  # default is 32 traces with 64 samples per trace
suplane nt=72 >>tempdata
suvlength <tempdata ns=84 |
sushw key=tracl a=1 b=1 >vdata

# Plot the data 
suxwigb <vdata \
        perc=99 title="suvlength test"\
        label1="Time (sec)" label2="Traces" \
        wbox=$WIDTH hbox=$HEIGHT xbox=$WIDTHOFF ybox=$HEIGHTOFF &

# Remove #comment sign on next line to test the header
#sugethw <vdata tracl ns | more


next up previous contents
Next: Obtaining and Installing SU Up: How to Write an Previous: A template SU program   Contents
John Stockwell 2007-04-10