July 2, 2013 Seismic Data Preprocessing Workshop
Total Page:16
File Type:pdf, Size:1020Kb
August 13, 2013 Seismic Data Preprocessing Workshop http://sepwww.stanford.edu/oldsep/stew/Summer2013Workshop/
In this session you tackled the last of three hands-on projects—writing your own custom tool. For this exercise I provided a Fortran code for calculating the Burg Maximum Entropy deconvolution trace-by-trace filters and the short section of the OpenCPS manual describing how to build and install a custom tool.
Building a Custom Tool
OpenCPS provides a set of examples for custom tools under $OPENCPS_HOME/src/bluefin/example. Tools may be written in C++, Fortran 90, Java or even Python, however the manual focuses only on C++ as will my example.
A C++ tool consists of three parts: a user interface description, help documentation, and C++ source code, typically all packaged into one file. For the Burg tool, my user interface description consists of
/* OpenCPS_tool_v1 * * Copyright (c) 2010 Open Geophysical, Inc. * ===begin_json_info=== { "name" : "BurgDecon", "purpose" : "To perform Burg maximum entropy deconvolution", "categories" : ["Filters"], "guiwidgets" : { "flen" : { "widget" : "float", "label" : "Burg filter length:", "tooltip" : "Length of Burg filter (ms)." }, "waveout" : { "widget" : "combo", "label" : "Select output:", "options" : ["Deconvolved traces", "Estimated filters"], "values" : ["traces", "filters"], "tooltip" : "Choose whether to output the filter estimates instead of deconvolving the input data." } } }
The only extension beyond the examples in the bluefin subdirectory is that I employed a combo widget to add an option to output the filter estimates instead of the deconvolved traces. Following the user interface description, I provide a small help section:
===begin_html_help=== This tool performs Burg maximum entropy deconvolution
Description
Filter length, default 60 msec.
Select output, choose whether to output filters instead of deconvolved traces.
Usage
This tool runs well interactively. ===end_html_help=== */The keen-eyed reader will have noted that these two initial sections are embedded in a C++ comment beginning with /* and ending with */ . The C++ source code begins immediately after the close of that comment block. The initial portion of the C++ is the declaration of the boilerplate structure of an OpenCPS C++ tool, subclassed from the master Tool class:
#include
#include "tools/tool.hpp" using namespace ogi; using std::string; using std::endl; class BurgDecon : public Tool { public: BurgDecon(); void update(); void startExecution(); void finishExecution(); int execute(int ntr, const char*const*hdsIn, const float*const*trsIn, char*const*hdsOut, float*const*trsOut); private: /* menu parameters */ Parameter
I close out this class declaration with a list of private variables that define the parameters and work buffers for the deconvolution:
/* internal resources */ int lc; /* number of samples in Burg filter */ double *ep; double *em; double *a; double *c; double *s; bool bwaveout; double tcvt; /* used to sort out msec vs. sec */ }; where the first 6 correspond to the variables in the Fortran subroutine in the handout. After this class declaration, each of the functions is defined and the variables initialized. First is the class constructor:
/* public constructor */ BurgDecon::BurgDecon() : Tool(), flen("flen", locals(), 60.0f ), waveout("waveout", locals(), "traces" ) { lc = 0; ep = (double *) 0; em = (double *) 0; a = (double *) 0; c = (double *) 0; s = (double *) 0; bwaveout = false; tcvt = 1.0; /* assume sample rate is going to be msec */ }
Note that the work arrays are not allocated at this point. That comes later. Next I define the update() method used to interact with the user menu selections: void BurgDecon::update() {
if(d1In < 1.0) tcvt = 1000.0; else tcvt = 1.0; /* Check for invalid parameters. */ if (flen <= d1In*tcvt) errors.append("Burg filter length must be greater than sample rate."); bwaveout = (waveout.get() == "filters"); lc = (int) ((flen+0.5*d1In*tcvt)/(d1In*tcvt));
if(bwaveout) { o1Out = 0.0f; n1Out = lc; }
toolType = SIMPLE; twosets = true; }
As you can see, the input data sample interval is used to convert the filter length, which is expected to be defined in units of msec, into a number of samples. The update() method finished by letting OpenCPS know how it intends to operate, in this case a simple gather in/gather out mode. The real work happens in the next, execute(), method: int BurgDecon::execute(int ntr, const char*const*hdsIn, const float*const*trsIn, char*const*hdsOut, float*const*trsOut) { int ismp, itr, ic; int i, j; double top, bot, epi;
/* Loop over traces */ for (itr = 0; itr < ntr; itr++) {
/* copy next input trace to work buffers */ for (ismp = 0; ismp < n1In; ismp++) ep[ismp] = trsIn[itr][ismp]; for (ismp = 0; ismp < n1In; ismp++) em[ismp] = ep[ismp];
/* run Burg recursion */ a[0] = 1.0; for(j=1; j /* copy filter to output trace */ for (ismp = 0; ismp < lc; ismp++) trsOut[itr][ismp] = a[ismp]; } else { /* Apply Burg inverse decon filter */ /* copy next input trace to output buffer */ for (ismp = 0; ismp < n1In; ismp++) trsOut[itr][ismp] = trsIn[itr][ismp]; /* apply by the filter */ for(ic = 1; ic return ntr; } The Burg recursion differs from the Fortran only in the respect that C++ array indices begin at 0 instead of 1. The filter application here is in the time domain. A production code might switch to Fourier domain application for long filter lengths. Finally, I implement the runtime setup and cleanup methods: void BurgDecon::startExecution() { /* Allocate memory, files, and other resources here */ if(ep == 0) ep = (double *)malloc(n1In*sizeof(double)); if(em == 0) em = (double *)malloc(n1In*sizeof(double)); if(a == 0) a = (double *) malloc(lc * sizeof(double)); if(c == 0) c = (double *) malloc(lc * sizeof(double)); if(s == 0) s = (double *) malloc(lc * sizeof(double)); } void BurgDecon::finishExecution() { /* Release resources */ if(s) free(s); s = 0; if(c) free(c); c = 0; if(a) free(a); a = 0; if(em) free(em); em = 0; if(ep) free(ep); ep = 0; lc = 0; } In an interactive setting, the update(), startExecution() and finishExecution() may be called repeatedly, hence the care to both free memory and reset pointers to zero. Having now written our tool, we have to compile it and inform OpenCPS where to find it. The Makefile in the bluefin example should be copied to the same directory where the tool source file has been created. There is one line, the one flagged by (YOU MUST SET THIS), that has to be edited to point to the directory where OpenCPS has been installed. After that simply type “make” to build a small tool shared library ./bin/linux64/lib/libmytools.so . Once you have successfully built your tool library, select Window>Preferences in the OpenCPS user interface. This pops up the option list from which you select the Custom Tools option: Enter the directory where your tool source file resides into the top box. In the middle box enter the directory where your libmytools.so was built. If you happen to be using other local libraries in your tool, in this example an FFT package, those also go in the middle box. Hitting OK will then make your new tool appear under the Custom Tools list: If it doesn’t appear try hitting the Refresh button at the top of the Tools list. If that doesn’t work, you probably have a mistake, perhaps a missing or an extra comma or brace in your json user interface section.