Waveform filter programs
tidofi.cc
Go to the documentation of this file.
1 
45 #define TIDOFI_VERSION \
46  "TIDOFI V1.6 time domain filter"
47 
48 #include <iostream>
49 #include <fstream>
50 #include <string>
51 #include <tfxx/commandline.h>
52 #include <tfxx/xcmdline.h>
53 #include <tfxx/error.h>
54 #include <tfxx/stringfunc.h>
55 #include <tfxx/rangestring.h>
56 #include <tfxx/rangelist.h>
57 #include <tfxx/misc.h>
58 #include <tfxx/seitosh.h>
59 #include <tsxx/anyfilter.h>
60 #include <datrwxx/readany.h>
61 #include <datrwxx/writeany.h>
62 #include <sffxx.h>
63 #include <sffostream.h>
64 #include <aff/dump.h>
65 #include <tsxx/ovtaper.h>
66 
67 using std::cout;
68 using std::cerr;
69 using std::endl;
70 
73 
74 /*----------------------------------------------------------------------*/
75 
76 struct Options {
78  bool overwrite;
80  std::string commandfile;
81  bool readstdin;
82  std::string inputformat, outputformat;
83 }; // struct Options
84 
85 /*======================================================================*/
86 
87 int main(int iargc, char* argv[])
88 {
89 
90  // define usage information
91  char usage_text[]=
92  {
93  TIDOFI_VERSION "\n"
94  "usage: tidofi [-v] [-o] [-cf file] [-cs] [-type type] [-Type type]" "\n"
95  " outfile infile [t:T|a:T] [f:F] [prft:file] [poft:file]\n"
96  " [infile [t:T|a:T] [f:F] [prft:file] [poft:file] ... ]" "\n"
97  " or: tidofi --help|-h" "\n"
98  " or: tidofi --xhelp" "\n"
99  };
100 
101  // define full help text
102  char help_text[]=
103  {
104  "outfile name of file to contain results" "\n"
105  "infile input file" "\n"
106  " t:T select traces T, where T may be any range" "\n"
107  " specification like \'3-4\' or \'5,6,7-12,20\'" "\n"
108  " f:F specifies an input file format differing from" "\n"
109  " the format selected by \"-type\"" "\n"
110  " a:T apply filter to traces T, where T may be any range" "\n"
111  " specification like \'3-4\' or \'5,6,7-12,20\'" "\n"
112  " all other traces are passed to the output unchanged\n"
113  " prft:file\n"
114  " pre-filter taper from file to be applied before\n"
115  " filtering traces\n"
116  " poft:file\n"
117  " post-filter taper from file to be applied before\n"
118  " filtering traces\n"
119  " file mofifiers t and a are mutually exclusive, where a\n"
120  " has higher precendence\n"
121  " prft and poft taper parameters are read from \"file\"\n"
122  " taper parameter file is expected in format produced\n"
123  " by refract\n"
124  "\n"
125  "-xhelp print detailed information regarding file formats" "\n"
126  "-v be verbose" "\n"
127  "-DEBUG produce debug output" "\n"
128  "-DUMP produce debug dumps" "\n"
129  "-o overwrite output" "\n"
130  "-cf file read filter commands from \"file\"" "\n"
131  "-cs read filter commands from stdin" "\n"
132  "-type type choose input file format (default: sff)" "\n"
133  "-Type type choose output file format (default: sff)" "\n"
134  "\n"
135  "In command files comment lines may either commence with \"rem\" like" "\n"
136  "in seife command files or with \'#\'. The seife command \"end\" is" "\n"
137  "simply ignored (like a comment line)."
138  };
139 
140  // define commandline options
141  using namespace tfxx::cmdline;
142  static Declare options[]=
143  {
144  // 0: print help
145  {"help",arg_no,"-"},
146  // 1: verbose mode
147  {"v",arg_no,"-"},
148  // 2: overwrite mode
149  {"o",arg_no,"-"},
150  // 3: command file
151  {"cf",arg_yes,"-"},
152  // 4: stdin mode
153  {"cs",arg_no,"-"},
154  // 5: input file format
155  {"type",arg_yes,"sff"},
156  // 6: generate debug output
157  {"DEBUG",arg_no,"-"},
158  // 7: generate debug dumps
159  {"DUMP",arg_no,"-"},
160  // 8: output file format
161  {"Type",arg_yes,"sff"},
162  // 9: output file format
163  {"xhelp",arg_no,"-"},
164  {NULL}
165  };
166 
167  static const char tracekey[]="t";
168  static const char applykey[]="a";
169  static const char formatkey[]="f";
170  static const char prefiltertaperkey[]="prft";
171  static const char postfiltertaperkey[]="poft";
172 
173  // define commandline argument modifier keys
174  static const char* cmdlinekeys[]
175  ={tracekey, formatkey, applykey, prefiltertaperkey, postfiltertaperkey, 0};
176 
177  // no arguments? print usage...
178  if (iargc<2)
179  {
180  cerr << usage_text << endl;
181  cerr << tfxx::seitosh::repository_reference << endl;
182  exit(0);
183  }
184 
185  // collect options from commandline
186  Commandline cmdline(iargc, argv, options);
187 
188  // help requested? print full help text...
189  if (cmdline.optset(0))
190  {
191  cerr << usage_text << endl;
192  cerr << help_text << endl;
193  datrw::supported_data_types(cerr);
194  cerr << endl;
195  ts::filter::print_any_help(cerr);
196  cerr << endl << tfxx::seitosh::repository_reference << endl;
197  exit(0);
198  }
199 
200  // help on file format details requested?
201  if (cmdline.optset(9))
202  {
203  cerr << usage_text << endl;
204  cerr << endl;
205  datrw::online_help(cerr);
206  cerr << endl << tfxx::seitosh::repository_reference << endl;
207  exit(0);
208  }
209 
210  // extract commandline options
211  Options opt;
212  opt.verbose=cmdline.optset(1);
213  opt.overwrite=cmdline.optset(2);
214  opt.readcommandfile=cmdline.optset(3);
215  opt.commandfile=cmdline.string_arg(3);
216  opt.readstdin=cmdline.optset(4);
217  opt.inputformat=cmdline.string_arg(5);
218  opt.debug=cmdline.optset(6);
219  opt.debugdump=cmdline.optset(7);
220  opt.outputformat=cmdline.string_arg(8);
221  // 9 is --xhelp
222 
223  if (opt.verbose)
224  { cout << TIDOFI_VERSION << endl; }
225 
226  // extract commandline arguments
227  TFXX_assert(cmdline.extra(), "missing output file");
228  std::string outfile=cmdline.next();
229  TFXX_assert(cmdline.extra(), "missing input file");
230  tfxx::cmdline::Tparsed arguments=parse_cmdline(cmdline, cmdlinekeys);
231  if ((arguments.size()>1) && opt.verbose)
232  {
233  cout << "NOTICE: file specific information (SRCE line and file FREE)" <<
234  endl
235  << " will be taken from first file only!" << endl;
236  }
237 
238  /*----------------------------------------------------------------------*/
239  // first of all read the filter commands
240  // we use an sff FREE block to store the lines - its so easy
241  sff::FREE filtercommands;
242  if (opt.readcommandfile)
243  {
244  if (opt.verbose)
245  {
246  cout << "read filter commands from file \""
247  << opt.commandfile << "\"" << endl;
248  }
249  std::ifstream ifs(opt.commandfile.c_str());
250  while (ifs.good())
251  {
252  std::string line;
253  getline(ifs, line);
254  line=tfxx::string::trimws(line);
255  if (line.size() > 0)
256  {
257  filtercommands.append(line);
258  if (opt.verbose)
259  { cout << ">> " << line << endl; }
260  }
261  }
262  }
263  // read commands from stdin
264  if (opt.readstdin)
265  {
266  if (opt.verbose)
267  {
268  cout << "read filter commands from stdin (terminate with ctrl-D)"
269  << endl;
270  }
271  while (std::cin.good())
272  {
273  std::string line;
274  getline(std::cin, line);
275  line=tfxx::string::trimws(line);
276  if (line.size() > 0)
277  {
278  filtercommands.append(line);
279  if (opt.verbose)
280  { cout << ">> " << line << endl; }
281  }
282  }
283  }
284 
285  /*----------------------------------------------------------------------*/
286  // strip comments etc from filter commands
287  // and create filter object
288  sff::FREE commands;
289  ts::filter::FilterCollection filter;
290  {
291  sff::FREE::Tlines::const_iterator line=filtercommands.lines.begin();
292  while (line != filtercommands.lines.end())
293  {
294  // skip comments
295  bool skip=false;
296  TFXX_debug(opt.debug, "main",
297  "skip " + *line + " if irrelevant" );
298  skip |= (line->substr(0,1)=="#");
299  skip |= (line->substr(0,3)=="rem");
300  skip |= (line->substr(0,3)=="end");
301  if (!skip) {
302  std::string command=(*line);
303  // replace comma by space
304  std::string::size_type i=command.find(",",i);
305  while (i!=std::string::npos)
306  {
307  command.replace(i,1," ");
308  i=command.find(",",i+1);
309  }
310  commands.append(command);
311  filter.push_back(ts::filter::make_any_filter(command, opt.debug));
312  }
313  else
314  {
315  TFXX_debug(opt.debug, "main",
316  "skip " + *line + "!" );
317  }
318  ++line;
319  }
320  }
321  // TFXX_debug(opt.debug, "main", "STOP" ); exit(0);
322 
323  /*----------------------------------------------------------------------*/
324  // prepare file FREE block
325  sff::FREE filefree;
326  {
327  filefree.append(TIDOFI_VERSION);
328  std::string line;
329  if (opt.readcommandfile || opt.readstdin)
330  {
331  line="commands are read from";
332  if (opt.readstdin)
333  {
334  line += " stdin";
335  if (opt.readcommandfile)
336  {
337  line += " (first) and";
338  }
339  else
340  {
341  line += ":";
342  }
343  }
344  filefree.append(line);
345  line.clear();
346  if (opt.readcommandfile)
347  {
348  line += "file \"" + opt.commandfile + "\":";
349  filefree.append(line);
350  }
351  if (filtercommands.lines.size() > 0)
352  {
353  filefree.append(filtercommands);
354  }
355  else
356  {
357  filefree.append(" command list is empty!");
358  }
359  }
360  else
361  {
362  filefree.append("no filtercommands were read");
363  }
364  filefree.append("output file name:");
365  filefree.append(" " + outfile);
366  filefree.append("input file selection:");
367  tfxx::cmdline::Tparsed::const_iterator file=arguments.begin();
368  while (file != arguments.end())
369  {
370  filefree.append(" " + file->name);
371  line=" ";
372  tfxx::cmdline::Toptionmap::const_iterator option=file->options.begin();
373  while (option != file->options.end())
374  {
375  line += " " + option->first + ":" + option->second;
376  ++option;
377  }
378  if (line.size()>2) { filefree.append(line); }
379  ++file;
380  }
381  if (arguments.size()>1)
382  {
383  filefree.append("In cases where more than one input file is read,");
384  filefree.append("the SRCE line is taken from the first file only (if");
385  filefree.append("present there).");
386  }
387  }
388 
389  /*======================================================================*/
390  // start processing
391 
392  // open output file
393  // ----------------
394  if (opt.verbose) { cout << "open output file " << outfile << endl; }
395  // check if output file exists and open
396  if (!opt.overwrite)
397  {
398  std::ifstream file(outfile.c_str(),std::ios_base::in);
399  TFXX_assert((!file.good()),"ERROR: output file exists!");
400  }
401  std::ios_base::openmode oopenmode
402  =datrw::oanystream::openmode(opt.outputformat);
403  std::ofstream ofs(outfile.c_str(), oopenmode);
404  datrw::oanystream os(ofs, opt.outputformat, opt.debug);
405 
406  // set flag to process header of first input file
407  bool firstfile=true;
408  // cycle through all input files
409  // -----------------------------
410  tfxx::cmdline::Tparsed::const_iterator infile=arguments.begin();
411  while (infile != arguments.end())
412  {
413  // open input file
414  if (opt.verbose) { cout << "open input file " << infile->name << endl; }
415  std::string inputformat=opt.inputformat;
416  if (infile->haskey(formatkey))
417  {
418  inputformat=infile->value(formatkey);
419  }
420  std::ios_base::openmode iopenmode
421  =datrw::ianystream::openmode(inputformat);
422  std::ifstream ifs(infile->name.c_str(), iopenmode);
423  datrw::ianystream is(ifs, inputformat);
424 
425  // read tapers
426  // -----------
427  bool applyprefiltertaper=infile->haskey(prefiltertaperkey);
428  bool applypostfiltertaper=infile->haskey(postfiltertaperkey);
429 
430  // create taper objects here
431  ts::tapers::OffsetVariableTaper prefiltertaper;
432  ts::tapers::OffsetVariableTaper postfiltertaper;
433 
434  // read taper parameters here
435  if (applyprefiltertaper)
436  {
437  std::string taperfilename
438  =infile->value(prefiltertaperkey);
439  prefiltertaper.read(taperfilename);
440  }
441  if (applypostfiltertaper)
442  {
443  std::string taperfilename
444  =infile->value(postfiltertaperkey);
445  postfiltertaper.read(taperfilename);
446  }
447 
448  // handle file header
449  // ------------------
450  sff::SRCE insrceline;
451  bool srceavailable=false;
452  if (firstfile)
453  {
454  if (is.hasfree())
455  {
456  sff::FREE infilefree;
457  is >> infilefree;
458  filefree.append("block read from first input file:");
459  filefree.append(infilefree);
460  }
461  if (os.handlesfilefree()) { os << filefree; }
462  if (is.hassrce())
463  {
464  is >> insrceline;
465  srceavailable=true;
466  if (os.handlessrce()) { os << insrceline; }
467  }
468  }
469 
470  // cycle through traces of input file
471  // ----------------------------------
472  // setup trace selection
473  typedef tfxx::RangeList<int> Trangelist;
474  bool doselect=infile->haskey(tracekey);
475  bool doapply=infile->haskey(applykey);
476  Trangelist traceranges=
477  tfxx::string::rangelist<Trangelist::Tvalue>(infile->value(tracekey));
478  // apply has precedence
479  if (doapply)
480  {
481  if (opt.verbose && doselect)
482  {
483  std::cout << " trace \"apply\" modifier has precedence "
484  << "over trace \"selection\" modifier."
485  << std::endl;
486  }
487  doselect=false;
488  traceranges
489  =tfxx::string::rangelist<Trangelist::Tvalue>(infile->value(applykey));
490  }
491  int itrace=0;
492  while (is.good())
493  {
494  ++itrace;
495  if ((!doselect) || traceranges.contains(itrace))
496  {
497  TFXX_debug(opt.debug, "main", "process trace #" << itrace );
498  if (opt.verbose)
499  { std::cout << " process trace #" << itrace << ":"; }
500  Tseries series;
501  is >> series;
502  if (opt.debugdump)
503  {
504  TFXX_debug(opt.debugdump, "main",
505  " input series:");
506  DUMP(series);
507  }
508  sff::WID2 wid2;
509  is >> wid2;
510  TFXX_debug(opt.debug, "main",
511  " series and WID2 are read");
512  sff::INFO info;
513  if (is.hasinfo())
514  {
515  is >> info;
516  }
517  // apply filter only if requested
518  // ------------------------------
519  if ((!doapply) || traceranges.contains(itrace))
520  {
521  double offset, t0, T;
522  if (applyprefiltertaper || applypostfiltertaper)
523  {
524  TFXX_assert(is.hasinfo() && srceavailable,
525  "Offset variable taper requires source and receiver "
526  "coordinates");
527  offset=::sff::offset(insrceline, info);
528  t0=libtime::time2double(insrceline.date-wid2.date);
529  T=wid2.dt*wid2.nsamples;
530  }
531  if (applyprefiltertaper)
532  {
533  // apply pre-filter taper
534  ts::tapers::FourPoint taper
535  =prefiltertaper.taper(offset, t0, T);
536  taper.apply(series);
537  }
538  Ttimeseries filterseries(series, wid2.dt);
539  TFXX_debug(opt.debug, "main",
540  TFXX_value(filterseries.header.dt)
541  << " " <<
542  TFXX_value(filterseries.f())
543  << " " <<
544  TFXX_value(filterseries.l())
545  << " " <<
546  TFXX_value(filterseries.size())
547  );
548  filterseries=filter(filterseries, opt.debug);
549  wid2.dt=filterseries.header.dt;
550  series=filterseries;
551  wid2.nsamples=series.size();
552  TFXX_debug(opt.debug, "main",
553  TFXX_value(filterseries.header.dt)
554  << " " <<
555  TFXX_value(filterseries.f())
556  << " " <<
557  TFXX_value(filterseries.l())
558  << " " <<
559  TFXX_value(filterseries.size())
560  );
561  if (applypostfiltertaper)
562  {
563  // apply post-filter taper
564  ts::tapers::FourPoint taper
565  =postfiltertaper.taper(offset, t0, T);
566  taper.apply(series);
567  }
568  TFXX_debug(opt.debug, "main",
569  " series is filtered");
570  if (opt.debugdump)
571  {
572  TFXX_debug(opt.debugdump, "main",
573  " output series:");
574  DUMP(series);
575  }
576  if (opt.verbose) { std::cout << " filtered" << std::endl; }
577  // ------------------------------
578  }
579  else
580  {
581  if (opt.verbose) { std::cout << " passed unchanged" << std::endl; }
582  }
583  os << wid2;
584  TFXX_debug(opt.debug, "main",
585  " series and WID are written");
586  if (is.hasinfo())
587  {
588  if (os.handlesinfo()) { os << info; }
589  }
590  if (is.hasfree() || true)
591  {
592  sff::FREE tracefree;
593  is >> tracefree;
594  tracefree.append(TIDOFI_VERSION);
595  tracefree.append("read from file " + infile->name);
596  if ((!doapply) || traceranges.contains(itrace))
597  {
598  tracefree.append(commands);
599  }
600  else
601  {
602  tracefree.append("passed unchanged");
603  }
604  if (os.handlestracefree()) { os << tracefree; }
605  }
606  TFXX_debug(opt.debug, "main",
607  "trace #" << itrace << " successfully processed");
608  os << series;
609  }
610  else
611  {
612  TFXX_debug(opt.debug, "main", "skip trace #" << itrace );
613  if (opt.verbose)
614  { std::cout << " skip trace #" << itrace << std::endl; }
615  is.skipseries();
616  }
617  }
618 
619  // go to next file
620  firstfile=false;
621  ++infile;
622  }
623 
624 }
625 
626 /* ----- END OF tidofi.cc ----- */
ts::sff::SFFTimeSeries< Tseries > Ttimeseries
Definition: deconv.cc:62
bool readstdin
Definition: tidofi.cc:81
std::string inputformat
Definition: cross.cc:75
ts::filter::Ttimeseries Ttimeseries
Definition: tidofi.cc:71
int main(int iargc, char *argv[])
Definition: tidofi.cc:87
static const char * cmdlinekeys[]
Definition: fidasexx.cc:131
std::string commandfile
Definition: tidofi.cc:80
static const char formatkey[]
Definition: fidasexx.cc:128
bool overwrite
Definition: autocorr.cc:61
std::string outputformat
Definition: cross.cc:75
bool debug
Definition: autocorr.cc:61
bool verbose
Definition: autocorr.cc:61
bool debugdump
Definition: tidofi.cc:77
Ttimeseries::Tseries Tseries
Definition: tidofi.cc:72
const char *const tracekey
key to select traces
Definition: deconv.cc:68
bool readcommandfile
Definition: tidofi.cc:79
aff::Series< double > Tseries
Definition: cross.cc:69
#define TIDOFI_VERSION
Definition: tidofi.cc:45