Ejemplo n.º 1
1
int
main (int argc, char **argv)
{

    int             c,
                    errflg = 0;

    char           *in,
                   *out;
    int             orbin,
                    orbout;
    double          maxpkts = VERY_LARGE_NUMBER ;
    int             quit;
    char           *pktmatch = strdup(".*/pf/evtinfo"),
                   *reject = 0;
    int             nmatch;
    int             specified_after = 0;
    double          after = 0.0,
                    until = VERY_LARGE_NUMBER ;
    double          start_time,
                    end_time,
                    delta_t ;
    double          totpkts = 0,
                    totbytes = 0;
    Flags           flags;
    static int      last_pktid = -1;
    static double   last_pkttime = 0.0;
    char           *statefile = 0;
    double          last_burial = 0.0;
    double          decent_interval = 300.0;
    int             mode = PKT_NOSAMPLES;
    int             rcode;
    char            srcname[ORBSRCNAME_SIZE];
    double          pkttime = 0.0 ;
    int             pktid;
    int             nbytes;
    char           *packet = 0;
    int             packetsz = 0;
    Packet         *unstuffed = 0;
	Pf				*pf;
	Tbl				*tbl;
	Arr				*arr;
	char			*arrkey;
	char			*pffilename;

	Tbl				*channels;
	char			*net;
	char			*sta;
	char			*chan;
	char			netstachan[ORBSRCNAME_SIZE];
	Srcname			parts;
	double			maxtime,mintime,starttime,triggertime,duration,min_g,max_g,snr;
	char			*datalogger;
	int				evtfilesize,channelno,maxcts,mincts;
	char			*errors,*evtfilename,*ft,*filter,*srcid;
	char			*line;
	int				i;
	Pf				*pfnew;
	Dbptr			db;
	int 			put_tests=0;
	char 			*chanmatch=0;
	Hook			*hook=0;
	char			*tdummy=0;
	char 			*match=malloc(100);

	


    memset (&flags, 0, sizeof (flags));
    elog_init (argc, argv);
    elog_notify (0, "%s $Revision: 1.5 $ $Date: 2005/05/10 07:34:43 $\n",
		 Program_Name);

    while ((c = getopt (argc, argv, "m:n:r:S:c:tvV")) != -1) {
	switch (c) {
	  case 'm':
	    match = optarg;
		sprintf(pktmatch,"%s/pf/evtinfo",match);
	    break;
	  case 'c':
	 	chanmatch = optarg;
		break;
	  case 't':
	  	put_tests = 1;
		break;
	  case 'n':
	    maxpkts = atoi (optarg);
	    break;

	  case 'r':
	    reject = optarg;
	    break;

	  case 'S':
	    statefile = optarg;
	    break;

	  case 'v':
	    flags.verbose++;
	    break;

	  case 'V':
		flags.verbose++;
		flags.verbose++;
	    break;

	  case '?':
	    errflg++;
	}
    }

    if (errflg || argc - optind < 2 || argc - optind > 4)
	usage ();

    in = argv[optind++];
    out = argv[optind++];

    if (argc > optind) {
	after = str2epoch (argv[optind++]);
	specified_after = 1;
	if (argc > optind) {
	    until = str2epoch (argv[optind++]);
	    if (until < after) {
		until += after ;
	    }
	}
    }
    if ((orbin = orbopen (in, "r&")) < 0)
	die (0, "Can't open input '%s'\n", in);

    if (statefile != 0) {
		char           *s;
		if (exhume (statefile, &quit, RT_MAX_DIE_SECS, 0) != 0) {
	    elog_notify (0, "read old state file\n");
		}
		if (orbresurrect (orbin, &last_pktid, &last_pkttime) == 0) {
	    	elog_notify (0, "resurrection successful: repositioned to pktid #%d @ %s\n",
			 last_pktid, s = strtime (last_pkttime));
	    	free (s);
		} else {
	    	complain (0, "resurrection unsuccessful\n");
		}
    }
    if ((orbout = orbopen (out, "w&")) < 0) {
	die (0, "Can't open output '%s'\n", out);
    }
    if (pktmatch) {
	nmatch = orbselect (orbin, pktmatch);
    }
    if (nmatch < 0) {
	die (1, "select '%s' returned %d\n", pktmatch, nmatch);
    }
    if (reject) {
	nmatch = orbreject (orbin, reject);
    }
    if (nmatch < 0) {
		elog_die (1, "reject '%s' returned %d\n", reject, nmatch);
    } else {
		if (flags.verbose) {
			elog_notify (1,"%d sources selected\n", nmatch);
		}	
    }

    if (specified_after) {
	pktid = orbafter (orbin, after);
	if (pktid < 0) {
	    char           *s;
	    elog_complain (1, "seek to %s failed\n", s = strtime (after));
	    free (s);
	    pktid = forbtell (orbin);
	    elog_complain (1,"pktid is still #%d\n", pktid);
	} else {
	    if (flags.verbose) elog_notify (1,"new starting pktid is #%d\n", pktid);
	}
    }
    start_time = now ();

	db = dbtmp("rt1.0");

    while (!quit && pkttime < until && totpkts < maxpkts) {
	rcode = orbreap (orbin,
		    &pktid, srcname, &pkttime, &packet, &nbytes, &packetsz);

	switch (rcode) {
	  case 0:
	    totpkts++;
	    totbytes += nbytes;

	    if (flags.verbose>2) {
		showPkt (pktid, srcname, pkttime, packet, nbytes, stdout, mode);
	    }
	    if (statefile != 0
		    && last_pkttime - last_burial > decent_interval) {
		bury ();
		last_burial = pkttime;
	    }
	    if ((unstuffPkt (srcname, pkttime, packet, nbytes, &unstuffed))==Pkt_pf) {
		  	pf = 			unstuffed->pf;
			tbl=			pfkeys(pf);
			arrkey=			gettbl(tbl,0);
			pfget(pf,arrkey,&pfnew);
			datalogger=		pfget_string(pfnew,"datalogger");
			duration=		pfget_double(pfnew,"duration");
			errors=			pfget_string(pfnew,"errors");
			evtfilename=	pfget_string(pfnew,"evtfilename");
			evtfilesize=	pfget_int(pfnew,"evtfilesize");
			ft=				pfget_string(pfnew,"ft");
			starttime=		pfget_double(pfnew,"time");
			triggertime=	pfget_double(pfnew,"triggertime");

			channels=pfget_tbl(pfnew,"channels");
			if (strcasecmp(ft,"no")==0 || put_tests == 1) {
				for (i=0; i<maxtbl(channels);i++) {
					line=gettbl(channels,i);
					sscanf(line,"%s %d %lf %d %lf %lf %d %lf",
						netstachan,&channelno,&maxtime,&maxcts,&max_g,&mintime,&mincts,&min_g);
					split_srcname(netstachan,&parts);	
					strcpy(parts.src_suffix,"GENC");
					join_srcname(&parts,netstachan);
					if (flags.verbose>1) printf("%s,%s\n", netstachan,tdummy=strtime(triggertime));	
					if (chanmatch == 0 || 
							strmatches(parts.src_chan,chanmatch,&hook)) {
						if (flags.verbose) elog_notify(1,"putting detev for %s,%s\n", netstachan,tdummy=strtime(triggertime));	
						
						db=dblookup(db,0,"detev",0,"dbSCRATCH");
						dbputv(db,0,"sta",parts.src_sta,"chan",parts.src_chan,
							"filter",K2_FILTER,
							"time",	triggertime,
							"tron",  starttime - triggertime,
							"troff", starttime - triggertime + duration,
							"iphase","K2",
							"snr",(max_g * 1000.0  - min_g * 1000.0)/2.0,
							0);
						db2orbpkt(db,orbout);
					} else {
						if (flags.verbose>1) elog_notify(1,"ignoring %s,%s\n", netstachan,tdummy=strtime(triggertime));	

					}
				}
			}
			
	    }

	    last_pktid = pktid;
	    last_pkttime = pkttime;
	}

    }

    if (statefile != 0)
	bury ();

    end_time = now ();
    delta_t = end_time - start_time;
	if (flags.verbose>1) {
		if (totpkts > 0) {
		elog_notify (1,"\n%.0f %.2f byte packets (%.1f kbytes) in %.3f seconds\n\t%10.3f kbytes/s\n\t%10.3f kbaud\n\t%10.3f pkts/s\n",
			totpkts, totbytes / totpkts, totbytes / 1024,
			delta_t,
			totbytes / delta_t / 1024,
			totbytes / delta_t / 1024 * 8,
			totpkts / delta_t);
		} else {

		elog_notify (1,"\nno packets read\n");
		}
	}

    if (orbclose (orbin)) {
	elog_complain (1, "error closing read orb\n");
    }
    if (orbclose (orbout)) {
	elog_complain (1, "error closing write orb\n");
    }
    return 0;
}
Ejemplo n.º 2
0
RTlocate_Options parse_rt_options (Pf *pf)
{
	RTlocate_Options o;
	char failure_dirs[STRSZ] ;
	o.work_db=pfget_string(pf,"RT_working_db");
	if(o.work_db  == NULL) o.work_db = strdup("orbgenloc");
	o.logdir=pfget_string(pf,"RT_logfile_directory");
	if(o.logdir == NULL) {
	    o.logdir = strdup(".");
	} else { 
	    makedir ( o.logdir ) ; 
	}
	o.failure_sdir = pfget_string(pf,"RT_failure_subdir");
	strcpy ( failure_dirs, o.logdir ) ; 
	strcat ( failure_dirs, "/" ) ; 
	strcat ( failure_dirs, o.failure_sdir ) ; 
	makedir ( failure_dirs ) ; 
	if(o.failure_sdir == NULL) o.failure_sdir = strdup("failure");
	o.minimum_distance = pfget_double(pf,"RT_minimum_distance");
	o.maximum_distance = pfget_double(pf,"RT_maximum_distance");

	o.db_record_skip_timeout = pfget_int(pf,"RT_db_record_skip_limit");

	return(o);
}
/* These functions allow defaulting of double and ints respectively.*/
double pfget_double_wdef(Pf *pf, char *keyword, double def)
{
	if(pfget_string(pf,keyword) == NULL)
		return(def);
	else
		return(pfget_double(pf,keyword));
 }
Ejemplo n.º 4
0
static PyObject *
python_pfget_double( PyObject *self, PyObject *args ) {
	char	*usage = "Usage: _stock._pfget_double( pfname, pfkey )\n";
	char	*pfname;
	char	*pfkey;
	double	pfvalue;
	char	errmsg[STRSZ];
	Pf	*pf;

	if( ! PyArg_ParseTuple( args, "ss", &pfname, &pfkey ) ) {

		USAGE;

		return NULL;
	}

	if( ( pf = getPf( pfname ) ) == (Pf *) NULL ) {
		
		sprintf( errmsg, "Failure opening parameter file '%s'\n", pfname );

		raise_elog( ELOG_COMPLAIN, errmsg );

		return NULL;
	}

	pfvalue = pfget_double( pf, pfkey );

	return Py_BuildValue( "d", pfvalue );
}
Ejemplo n.º 5
0
MWbasis  *load_multiwavelets_pf(Pf *pf,int *nwavelets)
{
	int i,j,k;
	char *line;
	double f0,fw;
	int nsamples;
	Tbl *w;
	MWbasis *mw;
	int nrows;

	nsamples = pfget_int(pf,"nsamples");
	*nwavelets =  pfget_int(pf,"nwavelets");
	f0 = pfget_double(pf,"f0");
	fw = pfget_double(pf,"fw");
	w = pfget_tbl(pf,"wavelets");
	nrows = maxtbl(w);
	if(nrows != (nsamples*(*nwavelets)))
		elog_die(0,"Size mismatch in wavelet parameter file\nExpected %d from %d wavelets each %d long\nFound %d instead\n",
			nsamples*(*nwavelets),*nwavelets,nsamples,nrows);
	mw = (MWbasis *)calloc(*nwavelets, sizeof(MWbasis));
	if(mw == NULL)
		elog_die(0,"Cannot alloc %d multiwavelet structures\n",*nwavelets);
	for(i=0,k=0;i<(*nwavelets);++i)
	{
		mw[i].r = calloc(nsamples,sizeof(float));
		mw[i].i = calloc(nsamples,sizeof(float));
		if((mw[i].r == NULL) || (mw[i].i == NULL) )
			elog_die(0,"Cannot alloc %d samples for complex wavelet %d\n",
				nsamples,i);
		mw[i].n = nsamples;
		mw[i].f0 = f0;
		mw[i].fw = fw;
		for(j=0;j<nsamples;j++,k++)
		{
			line = gettbl(w,k);
			if(sscanf(line,"%g%g",&(mw[i].r[j]),&(mw[i].i[j])) != 2)
				elog_die(0,"Error reading wavelets from parameter file on line %d of wavelet tbl\n",
					k);
		}
	}
	return(mw);
}
/* This little function logs mw transform info converting 
nondimensional frequency band numbers stored with the basis
objects (mw) to frequency in hz based on sample rate read from
pf and decimation factors passed through decfac array of length
nbands (obtained from pf to avoid passing it ).
*/
void print_band_info(MWbasis *mw,int *decfac,Pf *pf)
{
	int nbands;
	double sample_interval;
	double f0,fw,fhigh,flow;
	double scale;
	int i;

	sample_interval = pfget_double(pf,"sample_interval");
	nbands = pfget_int(pf,"number_frequency_bands");

	fprintf(stdout,"Multiwavelet transform frequency bands\n\nBand\tf0\tf_low\tf_high\tfw\n");
	for(i=0;i<nbands;++i)
	{
		scale = 1.0/(2.0*sample_interval*decfac[i]);
		f0 = (mw->f0)*scale;
		fw = (mw->fw)*scale;
		flow = f0 - (fw/2.0);
		fhigh = f0 + (fw/2.0);
		fprintf(stdout,"%8d%8.4lf%8.4lf%8.4lf%8.4lf\n",
			i,f0,flow,fhigh,fw);
	}
}
Ejemplo n.º 7
0
int
main( int argc, char **argv )
{
	int	c;
	int	errflag = 0;
	int	orb;
	int	stop = 0;
	long	nrecs;
	char	*match = ".*/pf/st";
	char	*from = 0;
	char	*statefile = 0;
	char	*pfname = "orb2rrdc";
	char	*orbname;
	char	*dbcache;
	char	*rrdtool;
	char	command[STRSZ];
	char	net[STRSZ];
	char	sta[STRSZ];
	char	rrdvar[STRSZ];
	char	key[STRSZ];
	char	path[FILENAME_MAX];
	Dbptr	db;
	Dbptr	dbt;
	Pf	*pf;
	char	*Default_network;
	Tbl	*dlslines;
	Arr	*Dls_vars_dsparams;
	Arr	*Dls_vars_rras;
	Tbl	*Dls_vars_keys;
	char	*line;
	char	*dls_var;
	char	*dsparams;
	Tbl	*rras;
	int	i;
	int	j;
	OrbreapThr *ort;
	int	pktid;
	char	srcname[ORBSRCNAME_SIZE];
	double	time = 0;
	char	*packet = 0;
	int	nbytes = 0;
	int	bufsize = 0;
	Packet	*pkt = 0;
	int	rc;
	char	*s;
	Pf	*dlspf;
	Tbl	*dlspfkeys;
	char	*element;
	Tbl	*parts;
	double	val;
	Pf	*pfval = 0;

	elog_init( argc, argv );

	while( ( c = getopt( argc, argv, "vVd:s:p:m:f:" ) ) != -1 ) {

		switch( c ) {

		case 'd':
			CacheDaemon = optarg;
			break;

		case 'f':
			from = optarg;
			break;

		case 'm':
			match = optarg;
			break;

		case 'p': 
			pfname = optarg;
			break;

		case 's':
			statefile = optarg;
			break;
			
		case 'v':
			Verbose++;
			break;

		case 'V':
			VeryVerbose++;
			Verbose++;
			break;
		
		default:
			elog_complain( 0, "Unknown option '%c'\n", c );
			errflag++;
			break;
		}
	}

	if( errflag || argc - optind != 2 ) {

		usage();
	}

	if( Verbose ) {

		elog_notify( 0, "Starting at %s (%s $Revision$ $Date$)\n", 
				zepoch2str( str2epoch( "now" ), "%D %T %Z", "" ),
				Program_Name );
	}

	orbname = argv[optind++];
	dbcache = argv[optind++];

	pfread( pfname, &pf );

	rrdtool = pfget_string( pf, "rrdtool" );

	if( rrdtool == NULL || ! strcmp( rrdtool, "" ) ) {

		elog_die( 0, "Error: no rrdtool executable name specified in parameter file\n" );

	} else if( ( rrdtool[0] == '/' && ! is_present( rrdtool ) ) || ( rrdtool[0] != '/' && ! datafile( "PATH", rrdtool ) ) ) {

		elog_die( 0, "Error: can't find rrdtool executable by name of '%s' (check PATH environment " 
			"variable, or absolute path name if given)\n", rrdtool );

	} else if( rrdtool[0] == '/' ) {

		sprintf( command, "%s -", rrdtool );

	} else {

		sprintf( command, "rrdtool -" );
	}

	Suppress_egrep = pfget_string( pf, "suppress_egrep" );

	if( Suppress_egrep != NULL && strcmp( Suppress_egrep, "" ) ) {
		
		if( ! datafile( "PATH", "egrep" ) ) {

			elog_complain( 0, "Ignoring suppress_egrep parameter: can't find egrep on path\n" ); 

		} else {

			sprintf( command, "%s 2>&1 | egrep -v '%s'", command, Suppress_egrep );
		}
	}

	if( VeryVerbose ) {

		elog_notify( 0, "Executing command: %s\n", command );
	}

	Rrdfp = popen( command, "w" );

	if( Rrdfp == (FILE *) NULL ) {

		elog_die( 0, "Failed to open socket to rrdtool command\n" );
	}

	orb = orbopen( orbname, "r&" );

	if( orb < 0 ) {

		elog_die( 0, "Failed to open orb '%s' for reading. Bye.\n", orbname );
	}

	orbselect( orb, match );

	if( from != NULL && statefile == NULL ) {

		pktid = orbposition( orb, from );

		if( Verbose ) {

			elog_notify( 0, "Positioned to packet %d\n", pktid );
		}

	} else if( from != NULL ) {

		elog_complain( 0, "Ignoring -f in favor of existing state file\n" );
	}

	if( statefile != NULL ) {

		stop = 0;

		exhume( statefile, &stop, 15, 0 );

		orbresurrect( orb, &pktid, &time );

		if( Verbose ) {

			elog_notify( 0, "Resurrecting state to pktid %d, time %s\n",
				pktid, s = strtime( time ) );

			free( s );
		}

		orbseek( orb, pktid );
	}

	dbopen( dbcache, "r+", &db );

	if( db.database < 0 ) {
		
		elog_die( 0, "Failed to open cache database '%s'. Bye.\n", dbcache );

	} else {
		
		db = dblookup( db, "", "rrdcache", "", "" );

		if( db.table < 0 ) {

			elog_die( 0, "Failed to lookup 'rrdcache' table in '%s'. Bye.\n", dbcache );
		}
	}

	dbcrunch( db );

	dbt = dbsubset( db, "endtime == NULL", NULL );

	Rrd_files = newarr( 0 );

	dbquery( dbt, dbRECORD_COUNT, &nrecs );

	for( dbt.record = 0; dbt.record < nrecs; dbt.record++ ) {

		dbgetv( dbt, 0, "net", &net, "sta", &sta, "rrdvar", &rrdvar, NULL );

		dbfilename( dbt, (char *) &path );

		sprintf( key, "%s:%s:%s", net, sta, rrdvar );

		if( ! is_present( path ) ) {
			
			elog_complain( 0, "WARNING: rrd file '%s', listed in database, does not exist. "
				"Removing database entry.\n", path );

			dbmark( dbt );

		} else {

			setarr( Rrd_files, key, strdup( path ) );

			if( VeryVerbose ) {

				elog_notify( 0, "Re-using rrd file '%s' for '%s'\n", path, key );
			}
		}
	}

	Rrdfile_pattern = pfget_string( pf, "rrdfile_pattern" );
	Status_stepsize_sec = pfget_double( pf, "status_stepsize_sec" );
	Default_network = pfget_string( pf, "default_network" );
	dlslines = pfget_tbl( pf, "dls_vars" );

	Dls_vars_dsparams = newarr( 0 );
	Dls_vars_rras = newarr( 0 );

	for( i = 0; i < maxtbl( dlslines ); i++ ) {
		
		line = gettbl( dlslines, i );
		
		strtr( line, "\t", " " );
		rras = split( line, ' ' );

		dls_var = shifttbl( rras );
		dsparams = shifttbl( rras );

		setarr( Dls_vars_dsparams, dls_var, dsparams );
		setarr( Dls_vars_rras, dls_var, rras );
	}

	ort = orbreapthr_new( orb, -1., 0 );

	for( ; stop == 0; ) {

		orbreapthr_get( ort, &pktid, srcname, &time, &packet, &nbytes, &bufsize );

		if( statefile ) {

			rc = bury();

			if( rc < 0 ) {

				elog_complain( 0, "Unexpected failure of bury command! " 
					"(are there two orb2rrdc's running with the same state" 
					"file?)\n" );

				clear_register( 1 );
			}
		}

		rc = unstuffPkt( srcname, time, packet, nbytes, &pkt );

		if( rc == Pkt_pf ) {

			if( VeryVerbose ) {

				/* Parameter files generally too big for elog */

				fprintf( stderr, "Received a parameter-file '%s' at %s\n%s\n\n", 
						srcname, 
						s = strtime( time ), 
						pf2string( pkt->pf ) );

				free( s );

			} else if( Verbose ) {

				elog_notify( 0, "Received a parameter-file '%s' at %s\n", 
						srcname, s = strtime( time ) );

				free( s );
			}

			pfmorph( pkt->pf );

			if( VeryVerbose ) {

				fprintf( stderr, "Morphed parameter-file '%s' to interpret 'opt':\n%s\n\n", 
						srcname, 
						pf2string( pkt->pf ) );
			}

			pfget( pkt->pf, "dls", (void **) &dlspf );

			dlspfkeys = pfkeys( dlspf );
			Dls_vars_keys = keysarr( Dls_vars_dsparams );

			for( i = 0; i < maxtbl( dlspfkeys ); i++ ) {
			   
			   element = gettbl( dlspfkeys, i );

			   if( strcontains( element, "_", 0, 0, 0 ) ) {

				parts = split( (s = strdup( element )), '_' );

				sprintf( net, "%s", (char *) gettbl( parts, 0 ) );
				sprintf( sta, "%s", (char *) gettbl( parts, 1 ) );

				free( s );
				freetbl( parts, 0 );

			   } else {

				sprintf( net, "%s", Default_network );

				sprintf( sta, "%s", element );
			   }

			   for( j = 0; j < maxtbl( Dls_vars_keys ); j++ ) {

			   	dls_var = gettbl( Dls_vars_keys, j );

				sprintf( key, "%s{%s}", element, dls_var );

				if( pfresolve( dlspf, key, 0, &pfval ) < 0 ) {

					elog_complain( 0, "Unable to extract variable '%s' "
						"(not present or wrong type) from element '%s' "
						"in packet from '%s', timestamped '%s'; Skipping\n",
						key, element, srcname, s = strtime( time ) );

					free( s );

					pfval = 0;

					continue;

				} else if( pfval != (Pf *) NULL &&
					   pfval->value.s != (char *) NULL &&
					   ! strcmp( pfval->value.s, "-" ) ) {

					if( VeryVerbose ) {

						elog_notify( 0, "Non-floating point value '-' in variable '%s', "
							"in packet from '%s', timestamped '%s'; Skipping data point\n",
							key, srcname, s = strtime( time ) );

						free( s );
					}

					continue;

				} else {

					val = pfget_double( dlspf, key );
				}

				archive_dlsvar( db, net, sta, dls_var, 
						(char *) getarr( Dls_vars_dsparams, dls_var ),
						(Tbl *) getarr( Dls_vars_rras, dls_var ),
						time, val );
			   }

			}

			freetbl( dlspfkeys, 0 );
			freetbl( Dls_vars_keys, 0 );

		} else if( rc == Pkt_stash ) {

			; /* Do nothing */

		} else {

			if( Verbose ) {

				elog_notify( 0, "Received a packet that's not a parameter file " 
					"(type '%d' from unstuffPkt); skipping\n", rc );
			}
		}
	}
}
Ejemplo n.º 8
0
int main(int argc, char **argv)
{
	SEGYBinaryFileHeader reel;
	SEGYTraceHeader *header;
	char *dbin;
	char *outfile;
	FILE *fp;
	Pf *pf;
	Arr *channels;  /* channel order list */
	Arr *table_list;  /* array of valid tables */
	int nchan;
	char *stest;

	float **traces;
	char text_file_header[SEGY_TEXT_HEADER_SIZE];
	Dbptr db, trdb, dbj;
	Dbptr trdbss;
	int nsamp0;
	double time0, endtime0, samprate0;
	long int nsamp;
	double samprate;
	int i,j;
	char stime[30],etime[30];
	char s[128];
	double tlength;
	double phi, theta;
	char *newchan_standard[3]={"X1","X2","X3"};
	char *trsubset="chan=~/X./";
	char *newchan[3]={"R","T","Z"};
	Tbl *sortkeys=newtbl(0);
	char sta[10],chan[10];
	double lat, lon, elev, dnorth, deast, edepth;
	char segtype;
	char refsta[10];
	int total_traces=0;
	char *time_str;
	long int evid,shotid=1;
	int rotate=0;
	long int ntraces;
        int ichan;
	int map_to_cdp;  /* logical switch to output data like cdp stacked data */
	char *fmt="%Y %j %H %M %S %s";
	char *pfname;
	int Verbose=0;
	/* New features added 2009 */
	/* this is a boolean.  If true (nonzero) it is assumed stdin will
	contain four numbers:  time,lat, lon, elev.  If false, only the
	time field is read and remainder of any input on each line is dropped.*/
	int input_source_coordinates;
	/* scale factor for source coordinates.  Needed because segy uses
	an int to store source coordinates.  Sensible choices are
	3600 for arc seconds and 10000 for a pseudodecimal. Note this
	parameter is ignored unless input_source_coordinates is true.*/
	int coordScale;
	/* If true use passcal 32 bit extension num_samps as record length.
	SEGY standard uses a 16 bit entry that easily overflows with large
	shots at long offset.  In this ase assume the 16 bit quantity is
	meaningless. */
	int use_32bit_nsamp;
	/* This is switched on by argument switch.  When set to a nonzero
	(default) the reel headers are written.  When 0 `
	the reel headers will not be written -- used by seismic unix
	and passcal*/
	int write_reel_headers=1;

	/* SEG-Y version to output. Default is original 1975 spec (rev 0) */
	int16_t segy_format = SEGY_FORMAT_REV_0;

	/* dbsubset query string */
	char *substr=NULL;

	/* text_header_description is a buffer holding a user-supplied description
	 * to be placed in the 3200-byte text header block. It is controlled by
	 * the parameter file value text_header_description or by the -d command
	 * line option, with the latter taking precedence */
	char* text_header_description=NULL;

	if(argc < 3) usage();
	dbin = argv[1];
	outfile = argv[2];
	pfname = NULL;
	for(i=3;i<argc;++i)
	{
		if(!strcmp(argv[i],"-pf"))
		{
			++i;
			pfname = argv[i];
		}
		else if(!strcmp(argv[i],"-SU"))
		{
			write_reel_headers=0;
		}
		else if(!strcmp(argv[i],"-v"))
		{
			Verbose=1;
		}
		else if(!strcmp(argv[i],"-d"))
		{
			++i;
			text_header_description = strdup(argv[i]);
		}
		else if(!strcmp(argv[i],"-ss"))
		{
			++i;
			substr=argv[i];
		}
		else if(!strcmp(argv[i],"-V"))
		{
			++i;
			if     (!strcmp(argv[i],"0")) {segy_format = SEGY_FORMAT_REV_0;}
			else if(!strcmp(argv[i],"1")) {segy_format = SEGY_FORMAT_REV_1_0;}
			else if(!strcmp(argv[i],"SU"))
			{
				segy_format = SEGY_FORMAT_SU;
				write_reel_headers=0;
			}
			else
			{
				elog_complain(0, "SEG-Y Version must be either 1 or 0");
				usage();
			}
		}
		else
		{
			usage();
		}
	}
	/* Command-line parameter sanity checking */
	if (write_reel_headers==0 && segy_format != SEGY_FORMAT_SU){
		complain(0, "The SU option cannot be used with the -V option");
		usage();
	}
	if(pfname == NULL) pfname = strdup("db2segy");

	elog_init(argc, argv);

	if(pfread(pfname,&pf)) {
		elog_die(0,"pfread error for pf file %s.pf\n",argv[0]);
	}

	/* Read the text_header_description if we weren't passed the -d option */
	if (!text_header_description) {
		text_header_description=pfget_string(pf, "text_header_description");
	}

	/* rotation parameters */
	rotate=pfget_boolean(pf,"rotate");
	if(rotate)
	{
		phi = pfget_double(pf,"phi");
		theta = pfget_double(pf,"theta");
	}
	/* This function creates the channel order list keyed by
	station channel names */
	channels = build_stachan_list(pf,&nchan,Verbose);

	map_to_cdp = pfget_boolean(pf,"map_to_cdp");
	if(map_to_cdp && Verbose)
		elog_notify(0,"Casting data as CDP stacked section\n");
	if(dbopen(dbin,"r",&db) == dbINVALID)
	{
		elog_complain(1,"Cannot open db %s\n", dbin);
		usage();
	}
	/* We grab the sample rate and trace length (in seconds) and
	use this to define global sample rates for the data.
	SEG-Y REV0 REQUIRES fixed length records and sample rates, so
	irregular sample rates will cause this program to die.
	One could add a decimate/interpolate function, but this
	is not currently implemented */
	samprate0 = pfget_double(pf,"sample_rate");
	tlength = pfget_double(pf,"trace_length");
	nsamp0 = (int)(tlength*samprate0);
	use_32bit_nsamp=pfget_boolean(pf,"use_32bit_nsamp");
	if (ntohs(segy_format) >= 0x0100 && use_32bit_nsamp) {
		elog_complain(0,"The 32-bit extension field is incompatible with SEG-Y REV 1. Ignoring 'use_32bit_nsamp' from the parameter file");
		use_32bit_nsamp=0;
	}

	/* nsamp in segy is a 16 bit field.  Handling depends on
	setting of use_32bit_nsamp boolean */
	if(nsamp0 > SEGY_MAX_NSAMP)
	{
		if(use_32bit_nsamp)
		{
			elog_notify(0,"Warning:  segy uses a 16 bit entity to store number of samples\nThat field is garbage. Using the 32 bit extension field.");
		}
		else
		{
		elog_complain(0,
		  "Warning:  segy uses a 16 bit entity to store number of samples. Requested %d samples per trace.  Trucated to %d", nsamp0, SEGY_MAX_NSAMP);
		nsamp0 = SEGY_MAX_NSAMP;
		}
	}

	/* boolean.  When nonzero set coordinates as geographic arc seconds values */
	int use_geo_coordinates=pfget_boolean(pf,"use_geo_coordinates");

	/* boolean. When nonzero, output decimal degrees instead of arcseconds if
	 * the requested output format supports it (rev1 only) */
	int prefer_decimal_degrees=pfget_boolean(pf, "prefer_decimal_degrees");

	/* We now have enough information to decide the coordUnits for all traces */
	int coordUnits = 0;
	if (!use_geo_coordinates) {
		coordUnits=SEGY_TRACE_COORDUNITS_LENGTH;
	} else if (ntohs(segy_format) >= 0x0100 && prefer_decimal_degrees) {
		coordUnits=SEGY_TRACE_COORDUNITS_DECIMAL_DEGREES;
	} else {
		coordUnits=SEGY_TRACE_COORDUNITS_ARCSECONDS;
	}
	/* We should have set our coordinate units now */
	assert(coordUnits!=0);

	input_source_coordinates=pfget_boolean(pf,"input_source_coordinates");
	if(input_source_coordinates)
	{
		coordScale=pfget_int(pf,"coordinate_scale_factor");
	}
	else if (coordUnits==SEGY_TRACE_COORDUNITS_DECIMAL_DEGREES)
	{
		/* Use a sane scalar for decimal degrees. 10000 gives four decimal
		 * places of accuracy, which matches the CSS3.0 spec for lat and lon */
		coordScale=10000;
	}
	else
	{
		coordScale=1;
	}

	/* Print a diagnostic message if the user gave a sub-optimal value for the
	 * coordScale */
	if (coordUnits == SEGY_TRACE_COORDUNITS_DECIMAL_DEGREES &&
			coordScale < 10000)
	{
		elog_alert(0,
				"The supplied parameter 'coordinate_scale_factor' value of %d is less than 10000, and will cause loss of precision for decimal degree coordinates.",
				coordScale);
	}
    else if (coordUnits == SEGY_TRACE_COORDUNITS_ARCSECONDS)
    {
        if (coordScale > 1000) {
            elog_alert(0,
                    "The supplied parameter 'coordinate_scale_factor' value of %d is greater than 1000, and will cause loss of precision for arcsecond coordinates.",
                    coordScale);
        }
    }

	/* trace_gain_type: signed int */
	int16_t trace_gain_type = pfget_int(pf,"trace_gain_type");
	if (trace_gain_type < 0)
	{
		die(0, "The trace_gain_type must be zero or greater");
	}
	else
	{
		trace_gain_type=htons(trace_gain_type);
	}


	/* check list of tables defined in pf.  Return array of
	logicals that define which tables are valid and join
	tables. */
	table_list = check_tables(db,pf);
	check_for_required_tables(table_list);
	dbj = join_tables(db,pf,table_list);
	if(dbj.record == dbINVALID) elog_die(0,"dbjoin error\n");
	if(substr!=NULL) dbj=dbsubset(dbj,substr,0);
	long int ndbrows;
	dbquery(dbj,dbRECORD_COUNT,&ndbrows);
	if(ndbrows<=0)
	{
		elog_complain(1,"Working database view is empty\n");
		if(substr!=NULL) elog_complain(0,"Subset condtion =%s a likely problem\n",
				substr);
		usage();
	}

	fp = fopen(outfile,"w");
	if(fp == NULL)
	{
		elog_complain(0,"Cannot open output file %s\n",outfile);
		usage();
	}

	/* These are needed for sort below */
	pushtbl(sortkeys,"sta");
	pushtbl(sortkeys,"chan");

    /* Set up and write the Textual File Header */
	initialize_text_header(text_file_header, segy_format,
			text_header_description);

	if(write_reel_headers){
		if ( fwrite(text_file_header,1,SEGY_TEXT_HEADER_SIZE,fp) \
				!= SEGY_TEXT_HEADER_SIZE ) {
			elog_die(1,"An error occurred writing the textual file header");
		}
	}

	/* memory allocation for trace data.  This is a large matrix
	that is cleared for each event.  This model works because of
	segy's fixed length format.*/
	traces = calloc(nchan, sizeof(float*));
	if(traces == NULL)
		elog_die(1,"out of memory");
	for (int r = 0; r < nchan; r++)
	{
		traces[r] = calloc(nsamp0, sizeof(float));
		if(traces[r] == NULL)
			elog_die(1,"out of memory");
	}
	header = (SEGYTraceHeader *)calloc((size_t)nchan,sizeof(SEGYTraceHeader));
	if(header == NULL)
			elog_die(0,"Cannot alloc memory for %d segy header workspace\n",nchan);
	if(write_reel_headers)
	{
		if (Verbose) {
			elog_debug(0,"Binary Headers - Using segy_format code 0x%04X\n", ntohs(segy_format));
		}
		initialize_binary_file_header(&reel, segy_format);

		/* now fill in the binary reel header and write it */
		reel.kjob   = htonl(1);
		reel.kline  = htonl(1);
		reel.kreel  = htonl(1);
		reel.kntr   = htons((int16_t)nchan);
		reel.knaux  = htons(0);
		reel.sr     = htons((int16_t)(1000000.0/samprate0));
		reel.kfldsr = reel.sr;
		reel.knsamp = htons((int16_t)nsamp0);
		reel.kfsamp = htons((int16_t)nsamp0);
		reel.dsfc   = htons(5);  /* This is ieee floats*/
		reel.kmfold = htons(0);
		if(map_to_cdp)
			reel.ksort = htons(2);
		else
			reel.ksort = htons(1);
		reel.kunits = htons(1);  /* This sets units to always be meters */

		if(fwrite((void *)(&reel),sizeof(SEGYBinaryFileHeader),1,fp) != 1)
		{
			elog_die(1,"Write error for binary reel header");
		}
	}

	/* Now we enter a loop over stdin reading start times.
	Program will blindly ask for data from each start time to
	time+tlength.  The trace buffer will be initialized to
	zeros at the top of the loop always.  If nothing is found
	only zeros will be written to output.
	*/
	while((stest=fgets(s,80,stdin)) != NULL)
	{
		double slat,slon,selev;  /* Used when reading source location*/
		if(Verbose)
			elog_notify(0,"Processing:  %s\n",s);
		for(i=0;i<nchan;++i)
		{
			initialize_trace_header(&(header[i]), segy_format);
			header[i].gainType = trace_gain_type;
			header[i].lineSeq = htonl(total_traces + i + 1);
			header[i].reelSeq = header[i].lineSeq;
			if(map_to_cdp)
			{
				header[i].cdpEns = htonl(i + 1);
				header[i].traceInEnsemble = htonl(1);/* 1 trace per cdp faked */
			}
			else
			{
				header[i].channel_number = htonl(i + 1);
			}
			header[i].event_number   = htonl(shotid);
			header[i].energySourcePt = htonl(shotid);
			for(j=0;j<nsamp0;++j)  traces[i][j] = htonf((Trsample)0.0);
		}
		if(input_source_coordinates)
		{
			char stmp[40];
			sscanf(s,"%s%ld%lf%lf%lf",stmp,&shotid,&slon,&slat,&selev);
			time0=str2epoch(stmp);
			if(coordUnits == SEGY_TRACE_COORDUNITS_ARCSECONDS) {
				slat*=3600.0;
				slon*=3600.0;
			}
			slat *= (double)coordScale;
			slon *= (double)coordScale;
		}
		else
		{
			time0 = str2epoch(s);
		}
		endtime0 = time0 + tlength;
		sprintf(stime,"%20.4f",time0);
		sprintf(etime,"%20.4f",endtime0);
		trdb.database = -1;
		if(trload_css(dbj,stime,etime,&trdb,0, 0) < 0)
		{
			if(Verbose)
			{
			  elog_notify(0,"trload_css failed for shotid=%ld",shotid);
			  elog_notify(0,"  No data in time range %s to %s\n",
			  	strtime(time0),strtime(endtime0) );
			  elog_notify(0,"No data written for this shotid block.");
			  elog_notify(0,"  Handle this carefully in geometry definitions.\n");
			}

			continue;
		}
		/* This does gap processing */
		repair_gaps(trdb);

		trapply_calib(trdb);

		if(rotate)
		{
			if(rotate_to_standard(trdb,newchan_standard))
				elog_notify(0,"Data loss in rotate_to_standard for event %s to %s\n",
					stime, etime);
			/* This is need to prevent collisions of channel names */
			trdbss = dbsubset(trdb,trsubset,0);
			if(trrotate(trdbss,phi,theta,newchan))
				elog_notify(0,"Data loss in trrotate for event %s to %s\n",
					stime, etime);
		}
		if(Verbose)
			elog_notify(0,"Station  chan_name  chan_number seq_number shotid  evid\n");
		trdb = dbsort(trdb,sortkeys,0,0);
		dbquery(trdb,dbRECORD_COUNT,&ntraces);
		if(Verbose) elog_debug(0,"Read %ld traces for event at time%s\n",
			ntraces,strtime(time0));
		for(trdb.record=0;trdb.record<ntraces;++trdb.record)
		{
			Trsample *trdata;
			if(dbgetv(trdb,0,
			    "evid",&evid,
			    "sta",sta,
			    "chan",chan,
			    "nsamp", &nsamp,
			    "samprate",&samprate,
			    "data",&trdata,
			    "lat", &lat,
			    "lon", &lon,
			    "elev",&elev,
			    "refsta",refsta,
			    "dnorth",&dnorth,
			    "deast",&deast,
			    "edepth",&edepth,
			    "segtype",&segtype,
			    NULL) == dbINVALID)
			{
				elog_complain(0," dbgetv error reading record %ld. Trace will be skipped for station %s and channel %s",
				trdb.record,sta,chan);
				continue;
			}
			/* Allow 1 percent samprate error before killing */
			double fsrskew=fabs((samprate-samprate0)/samprate0);
			double frskewcut=0.01;
			if(fsrskew>frskewcut)
			{
				elog_complain(0,"%s:%s sample rate %f is significantly different from base sample rate of %f. Trace skipped -- segy requires fixed sample rates",
					sta,chan,samprate,samprate0);
				continue;
			}
			if(nsamp > nsamp0)
			{
				elog_complain(0,"%s:%s trace has extra samples=%ld. Truncated to length %d",
					sta, chan, nsamp, nsamp0);
				nsamp = nsamp0;
			}
			else if(nsamp < nsamp0)
			{
				elog_complain(0,"%s:%s trace is shorter than expected %d samples. Zero padded after sample %ld",
					sta, chan, nsamp0, nsamp);
			}

			ichan = get_channel_index(channels,sta,chan);
			if(ichan > nchan)
			{
				elog_die(0,"Channel index %d outside limit of %d. Cannot continue",
					ichan, nchan);
			}
			if(ichan >= 0)
			{
				if(Verbose)
					elog_debug(0,"%s:%s\t%-d\t%-d\t%-ld\t%-ld\n",
					sta,chan,ichan+1,
					ntohl(header[ichan].reelSeq),
					shotid, evid);
				header[ichan].traceID = get_trace_id_code_from_segtype(segtype);
				for(j=0;j<nsamp;++j) {
				   traces[ichan][j] = htonf((float)trdata[j]);
				}
				/* header fields coming from trace table */
				header[ichan].samp_rate = htonl(
						(int32_t) (1000000.0/samprate0));
				/* according to the behavior specified in the man page:
				 * if use_geo_coordinates is false:
				 * - coordUnits is length (meters)
				 * - therefore, we use deast for X and dnorth for Y
				 * if use_geo_coordinates is true:
				 * - we're using either arcseconds or decimal degrees
				 * - and therefore, we use lon for X and lat for Y
				 *
				 * coordUnits is based on use_arcseconds and the requested
				 * version of segY */

				/* set the coordinate units in the trace header */
				header[ichan].coordUnits = coordUnits;

				/* Pick the source db fields for our receiver X and Y */
				double recLongOrX = 0;
				double recLatOrY  = 0;
				if (coordUnits == SEGY_TRACE_COORDUNITS_LENGTH) {
					/* Use deast and dnorth
					 * CSS3.0 Schema specifies deast and dnorth are in KM.
					 * SEG-Y specifies easting and northing as meters,
					 * hence the 1000.0 multiplier here. */
					recLongOrX = deast  * 1000.0;
					recLatOrY  = dnorth * 1000.0;
				} else if (coordUnits == SEGY_TRACE_COORDUNITS_ARCSECONDS){
					/* Use lat and lon, converted to arcseconds */
					recLongOrX = lon * 3600.0;
					recLatOrY  = lat * 3600.0;
				} else {
					/* Default case, which covers decimal degrees */
					recLongOrX = lon;
					recLatOrY  = lat;
				}

				/* Apply our coordScale - the user can specify negative numbers,
				 * but they are treated as inverting the value, not as a divisor
				 * as in the SEG-Y field usage. See below where we always treat
				 * the scalar as a divisor in the SEG-Y field */
				recLongOrX *= (double)coordScale;
				recLatOrY  *= (double)coordScale;

				/* Set the coordScale in the header.
				 * Note negative here.  This is a oddity of segy that - means
				 * divide by this to get actual.  Always make this negative in
				 * case user inputs a negative number.
				 * Don't set it -1 for cosmetic reasons */
				if (abs(coordScale) == 1)
				{
					header[ichan].coordScale = htons(1);
				} else
				{
					header[ichan].coordScale = htons(-abs(coordScale));
				}

				/* Finally, write out the X and Y */
				header[ichan].recLongOrX
					= htonl((int32_t)recLongOrX);
				header[ichan].recLatOrY
					= htonl((int32_t)recLatOrY);

				/* CSS3.0 specfies elev as being in km, SEG-Y wants it in m */
				header[ichan].recElevation = htonl((int32_t)(elev*1000.0));

				header[ichan].deltaSample = htons(
						(int16_t) (1000000.0/samprate0));
				header[ichan].sampleLength = htons((int16_t)nsamp0);
				if (ntohs(segy_format)<0x0100)
				{
					header[ichan].num_samps = htonl((int32_t)nsamp0);
				}
				/* This cracks the time fields */
				time_str = epoch2str(time0,fmt);
				int16_t hyear, hday, hhour, hminute, hsecond, hm_secs;
				hyear=hday=hhour=hminute=hsecond=hm_secs=0;
				sscanf(time_str,"%hd %hd %hd %hd %hd %hd",
						&hyear, &hday, &hhour, &hminute, &hsecond, &hm_secs);
				header[ichan].year   = htons(hyear);
				header[ichan].day    = htons(hday);
				header[ichan].hour   = htons(hhour);
				header[ichan].minute = htons(hminute);
				header[ichan].second = htons(hsecond);
				header[ichan].m_secs = htons(hm_secs);
				if (ntohs(segy_format)<0x0100)
				{
					/* These are IRIS-PASSCAL extensions */
					header[ichan].trigyear   = header[ichan].year;
					header[ichan].trigday    = header[ichan].day;
					header[ichan].trighour   = header[ichan].hour;
					header[ichan].trigminute = header[ichan].minute;
					header[ichan].trigsecond = header[ichan].second;
				}
				free(time_str);
				if(input_source_coordinates)
				{
					/* Write out our pre-scaled and optionally
					 * arcsecond-converted source lat/lon plus our elevation */
					header[ichan].sourceLongOrX = htonl((int32_t)slon);
					header[ichan].sourceLatOrY  = htonl((int32_t)slat);
					header[ichan].sourceSurfaceElevation
						= htonl((int32_t)selev);
					/* No easy way to specify both elev and depth*/
					header[ichan].sourceDepth=htonl(0);
				}
				else if(map_to_cdp)
				{
				/* When faking CDP data we make this look
				like a zero offset, single fold data set */
					header[ichan].sourceLongOrX   = header[ichan].recLongOrX;
					header[ichan].sourceLatOrY    = header[ichan].recLatOrY;
					header[ichan].sourceSurfaceElevation
					                              = header[ichan].recElevation;
					header[ichan].sourceDepth     = htonl(0);
					header[ichan].sourceToRecDist = htonl(0);
				}
				else
				{
				/* This is the mechanism for adding other
				information with added tables.  The one
				table currently supported is a "shot" table
				that holds shot coordinates.  If other tables
				were added new functions could be added with
				a similar calling sequence.  This procedure
				silently does nothing if a shot table is not
				present.*/
					set_shot_variable(db,table_list,
						evid,&header[ichan]);
				}
			}
			else
			{
				if(Verbose)
					elog_notify(0,"Station %s and channel %s skipped\n",
						sta,chan);
			}

		}
		/* Now we write the data */
		for(i=0;i<nchan;++i)
		{
			if(fwrite((void *)(&(header[i])),sizeof(SEGYTraceHeader),1,fp) != 1)
				elog_die(0,"Write error on header for trace %d\n",total_traces+i);
			if(fwrite((void *)traces[i],sizeof(float),
					(size_t)nsamp0,fp) != nsamp0)
				elog_die(0,"Write error while writing data for trace %d\n",
					total_traces+i);
		}
		total_traces += nchan;
		trdestroy(&trdb);
		if(!input_source_coordinates) ++shotid;
	}
	return 0 ;
}
Ejemplo n.º 9
0
int main(int argc, char **argv)
{
	SegyReel reel;
	SegyHead *header;
	char *dbin;
	char *outfile;
	FILE *fp;
	Pf *pf;  
	Arr *channels;  /* channel order list */
	Arr *table_list;  /* array of valid tables */
	int nchan;
	char *stest;

	float **traces;
	char reel1[3200];
	Dbptr db, trdb, dbj;
	Dbptr trdbss;  
	int nsamp0;
	double time0, endtime0, samprate0;
	long int nsamp;
	double samprate;
	int i,j;
	char stime[30],etime[30];
	char s[128];
	double tlength;
	double phi, theta;
	char *newchan_standard[3]={"X1","X2","X3"};
	char *trsubset="chan=~/X./";
	char *newchan[3]={"R","T","Z"};
	Tbl *sortkeys=newtbl(0);
	char sta[10],chan[10];
	double lat, lon, elev, dnorth, deast, edepth;
	char refsta[10];
	int total_traces=0;
	char *time_str;
	long int evid,shotid=1;
	int rotate=0;
	long int ntraces;
        int ichan;
	int map_to_cdp;  /* logical switch to output data like cdp stacked data */
	char *fmt="%Y %j %H %M %S %s";
	char *pfname;
	int Verbose=0;
	/* New features added 2009 */
	/* this is a boolean.  If true (nonzero) it is assumed stdin will
	contain four numbers:  time,lat, lon, elev.  If false, only the
	time field is read and remainder of any input on each line is dropped.*/
	int input_source_coordinates;
	/* scale factor for source coordinates.  Needed because segy uses
	an int to store source coordinates.  Sensible choices are 
	3600 for arc seconds and 10000 for a pseudodecimal. Note this
	parameter is ignored unless input_source_coordinates is true.*/
	int coordScale;
	/* If true use passcal 32 bit extension num_samps as record length. 
	SEGY standard uses a 16 bit entry that easily overflows with large
	shots at long offset.  In this ase assume the 16 bit quantity is
	meaningless. */
	int use_32bit_nsamp;
	/* This is switched on by argument switch.  When set to a nonzero
	(default) the reel headers are written.  When 0 `
	the reel heades will not be written -- used by seismic unix 
r
	and passcal*/
	int write_reel_headers=1;
	char *substr=NULL;

	if(argc < 3) usage();
	dbin = argv[1];
	outfile = argv[2];
	pfname = NULL;
	for(i=3;i<argc;++i)
	{
		if(!strcmp(argv[i],"-pf"))
		{
			++i;
			pfname = argv[i];
		}
		else if(!strcmp(argv[i],"-SU"))
		{
			write_reel_headers=0;
		}
		else if(!strcmp(argv[i],"-v"))
		{
			Verbose=1;
		}
		else if(!strcmp(argv[i],"-ss"))
		{
			++i;
			substr=argv[i];
		}
		else
		{
			usage();
		}
	}
	if(pfname == NULL) pfname = strdup("db2segy");

	elog_init(argc, argv);

	if(pfread(pfname,&pf)) 
		elog_die(0,"pfread error for pf file %s.pf\n",argv[0]);
	/* rotation parameters */
	rotate=pfget_boolean(pf,"rotate");
	if(rotate)
	{
		phi = pfget_double(pf,"phi");
		theta = pfget_double(pf,"theta");
	}
	/* This function creates the channel order list keyed by
	station channel names */
	channels = build_stachan_list(pf,&nchan,Verbose);

	map_to_cdp = pfget_boolean(pf,"map_to_cdp");
	if(map_to_cdp && Verbose) 
		fprintf(stdout,"Casting data as CDP stacked section\n");
	if(dbopen(dbin,"r",&db) == dbINVALID) 
	{
		fprintf(stderr,"Cannot open db %s\n", dbin);
		usage();
	}
	/* We grab the sample rate and trace length (in seconds) and
	use this to define global sample rates for the data.  
	segy REQUIRES fixed length records and sample rates, so
	irregular sample rates will cause this program to die. 
	One could add a decimate/interpolate function, but this 
	is not currently implemented */
	samprate0 = pfget_double(pf,"sample_rate");
	tlength = pfget_double(pf,"trace_length");
	nsamp0 = (int)(tlength*samprate0);
	use_32bit_nsamp=pfget_boolean(pf,"use_32bit_nsamp");

	/* nsamp in segy is a 16 bit field.  Handling depends on
	setting of use_32bit_nsamp boolean */
	if(nsamp0 > 32767) 
	{
	    if(use_32bit_nsamp)
	    {
	    	elog_notify(0,"Warning:  segy ues a 16 bit entity to store number of samples\nThat field is garbage. Using the 32 bit extension field.\n");
	    }
	    else
	    {
		elog_complain(0,
		  "Warning:  segy uses a 16 bit entity to store number of samples\nRequested %d samples per trace.  Trucated to 32767\n",nsamp0);
		nsamp0 = 32767;
	    }
	}
	input_source_coordinates=pfget_boolean(pf,"input_source_coordinates");
	if(input_source_coordinates)
	{
		coordScale=pfget_int(pf,"coordinate_scale_factor");
	}
	else
	{
		coordScale=1;
	}
	/* boolean.  When nonzero set coordinates as geographic arc seconds values */
	int use_geo_coordinates=pfget_boolean(pf,"use_geo_coordinates");
	/* check list of tables defined in pf.  Return array of
	logicals that define which tables are valid and join 
	tables. */
	table_list = check_tables(db,pf);
	check_for_required_tables(table_list);
	dbj = join_tables(db,pf,table_list);
	if(dbj.record == dbINVALID) elog_die(0,"dbjoin error\n");
	if(substr!=NULL) dbj=dbsubset(dbj,substr,0);
	long int ndbrows;
	dbquery(dbj,dbRECORD_COUNT,&ndbrows);
	if(ndbrows<=0)
	{
		fprintf(stderr,"Working database view is empty\n");
		if(substr!=NULL) fprintf(stderr,"Subset condtion =%s a likely problem\n",
				substr);
		usage();
	}

	fp = fopen(outfile,"w");
	if(fp == NULL) 
	{
		fprintf(stderr,"Cannot open output file %s\n",outfile);
		usage();
	}

	/* These are needed for sort below */
	pushtbl(sortkeys,"sta");
	pushtbl(sortkeys,"chan");

	/*The reel1 header in true blue segy is ebcdic.  We are goingto 
	just fill it with nulls and hope for the best */
	for(i=0;i<3200;i++) reel1[i] = '\0';

	/* Just blindly write this turkey. Bad form, but tough*/
	if(write_reel_headers) fwrite(reel1,1,3200,fp);

	/* memory allocation for trace data.  This is a large matrix
	that is cleared for each event.  This model works because of
	segy's fixed length format.  This routine is a descendent of
	numerical recipes routine found in libgenloc.  This is not
	the most efficient way to do this, but it simplifies the
	algorithm a lot. */
	traces = matrix(0,nchan,0,nsamp0);
	if(traces == NULL) 
		elog_die(0,"Cannot alloc trace data matrix work space of size %d by %d\n",
			nchan, nsamp0);
	header = (SegyHead *)calloc((size_t)nchan,sizeof(SegyHead));
	if(header == NULL)
			elog_die(0,"Cannot alloc memory for %d segy header workspace\n",nchan);
	if(write_reel_headers)
	{

		/* now fill in the binary reel header and write it */
		reel.kjob = 1;
		reel.kline = 1;
		reel.kreel = 1;
		reel.kntr = (int16_t)nchan;
		reel.knaux = 0;
		reel.sr = (int16_t)(1000000.0/samprate0);
		reel.kfldsr = reel.sr;
		reel.knsamp = (int16_t)nsamp0;
		reel.kfsamp = (int16_t)nsamp0;
		reel.dsfc=5;  /* This is ieee floats*/
		reel.kmfold = 0;
		if(map_to_cdp)
			reel.ksort = 2;
		else
			reel.ksort = 1;
		reel.kunits = 1;  /* This sets units to always be meters */
		for(i=0;i<344;++i)reel.unused2[i]='\0';
	
		if(fwrite((void *)(&reel),sizeof(SegyReel),1,fp) != 1) 
		{
			fprintf(stderr,"Write error for binary reel header\n");
			exit(-2);
		}
	}

	/* Now we enter a loop over stdin reading start times.  
	Program will blindly ask for data from each start time to 
	time+tlength.  The trace buffer will be initialized to 
	zeros at the top of the loop always.  If nothing is found
	only zeros will be written to output.  
	*/
	while((stest=fgets(s,80,stdin)) != NULL)
	{
		double slat,slon,selev;  /* Used when reading source location*/
		if(Verbose)
			fprintf(stdout,"Processing:  %s\n",s);
		for(i=0;i<nchan;++i)
		{
			initialize_header(&(header[i]));
			header[i].lineSeq = total_traces + i + 1;
			header[i].reelSeq = header[i].lineSeq;
			if(map_to_cdp)
			{
				header[i].cdpEns = i + 1;
				header[i].traceInEnsemble = 1;  /* 1 trace per cdp faked */
			}
			else
			{
				header[i].channel_number = i + 1;
			}
			header[i].event_number = shotid;
			header[i].energySourcePt=shotid;
			for(j=0;j<nsamp0;++j)  traces[i][j] = (Trsample)0.0;
		}
		if(input_source_coordinates)
		{
			char stmp[40];
			sscanf(s,"%s%ld%lf%lf%lf",stmp,&shotid,&slon,&slat,&selev);
			time0=str2epoch(stmp);
		}
		else
		{
			time0 = str2epoch(s);
		}
		endtime0 = time0 + tlength;
		sprintf(stime,"%20.4f",time0);
		sprintf(etime,"%20.4f",endtime0);
		trdb.database = -1;
		if(trload_css(dbj,stime,etime,&trdb,0, 0) < 0)
		{
			if(Verbose) 
			{
			  fprintf(stdout,"trload_css failed for shotid=%ld",shotid);
			  fprintf(stdout,"  No data in time range %s to %s\n",
			  	strtime(time0),strtime(endtime0) );
			  fprintf(stdout,"No data written for this shotid block.");
			  fprintf(stdout,"  Handle this carefully in geometry definitions.\n");
			}

			continue;
		}
		/* This does gap processing */
		repair_gaps(trdb);
		
		trapply_calib(trdb);
			
		if(rotate)
		{
			if(rotate_to_standard(trdb,newchan_standard))
				elog_notify(0,"Data loss in rotate_to_standard for event %s to %s\n",
					stime, etime);
			/* This is need to prevent collisions of channel 
			names */
			trdbss = dbsubset(trdb,trsubset,0);
			if(trrotate(trdbss,phi,theta,newchan))
				elog_notify(0,"Data loss in trrotate for event %s to %s\n",
					stime, etime);
		}
		if(Verbose)
			fprintf(stdout,"Station  chan_name  chan_number seq_number shotid  evid\n");
		trdb = dbsort(trdb,sortkeys,0,0);
		dbquery(trdb,dbRECORD_COUNT,&ntraces);
		if(Verbose) fprintf(stdout,"Read %ld traces for event at time%s\n",
			ntraces,strtime(time0));
		for(trdb.record=0;trdb.record<ntraces;++trdb.record)
		{
			Trsample *trdata;
			if(dbgetv(trdb,0,
			    "evid",&evid,
			    "sta",sta,
			    "chan",chan,
			    "nsamp", &nsamp,
			    "samprate",&samprate,
			    "data",&trdata,
			    "lat", &lat,
			    "lon", &lon,
			    "elev",&elev,
			    "refsta",refsta,
			    "dnorth",&dnorth,
			    "deast",&deast,
			    "edepth",&edepth,
					NULL) == dbINVALID)
			{
				elog_complain(0," dbgetv error reading record %ld\nTrace will be skipped for station %s and channel %s\n",
				trdb.record,sta,chan);
				continue;
			}
			/* Allow 1 percent samprate error before killing */
			double fsrskew=fabs((samprate-samprate0)/samprate0);
			double frskewcut=0.01;
			if(fsrskew>frskewcut) 
			{
				elog_complain(0,"%s:%s sample rate %f is significantly different from base sample rate of %f\nTrace skipped -- segy requires fixed sample rates\n",
					sta,chan,samprate,samprate0);
				continue;
			}
			if(nsamp > nsamp0)
			{
				elog_complain(0,"%s:%s trace has extra samples=%ld\nTruncated to length %d\n",
					sta, chan, nsamp, nsamp0);
				nsamp = nsamp0;
			}
			else if(nsamp < nsamp0)
			{
				elog_complain(0,"%s:%s trace is shorter than expected %d samples\nZero padded after sample %ld\n",
					sta, chan, nsamp0, nsamp);
			}

			ichan = get_channel_index(channels,sta,chan);
			if(ichan > nchan) elog_die(0,"Channel index %d outside limit of %d\nCannot continue\n",
					ichan, nchan);
			if(ichan >= 0)
			{
				if(Verbose) 
				   fprintf(stdout,"%s:%s\t%-d\t%-d\t%-ld\t%-ld\n",
					sta,chan,ichan+1,
                                        header[ichan].reelSeq,
					shotid, evid);
				header[ichan].traceID = 1;
				for(j=0;j<nsamp;++j) 
				   traces[ichan][j] = (float)trdata[j];
				/* header fields coming from trace table */
				header[ichan].samp_rate = (int32_t)
						(1000000.0/samprate0);
				if(!use_geo_coordinates && ( coordScale==1))
				{
				  header[ichan].recLongOrX = (int32_t)(deast*1000.0);
				  header[ichan].recLatOrY = (int32_t)(dnorth*1000.0);
				}
				else
				{
				/* Note negative here.  This is a oddity
				of segy that - means divide by this to
				get actual.  Always make this negative in case 
				user inputs a negative number. */
				  header[ichan].coordScale=-abs(coordScale);
				  /* Force 2 = geographic coordinates.  Standard says when this is
				  so units are arc seconds, hence we multiply deg by 3600*coordScale */
				  if(use_geo_coordinates)
				  {
				    header[ichan].coordUnits=2;
				    header[ichan].recLongOrX
				     =(int32_t)(lon*3600.0*(double)coordScale);
				    header[ichan].recLatOrY
				     =(int32_t)(lat*3600.0*(double)coordScale);
				  }
				  else
				  {
				    header[ichan].recLongOrX
				     =(int32_t)(lon*(double)coordScale);
				    header[ichan].recLatOrY
				     =(int32_t)(lat*(double)coordScale);
				  }
				}
				header[ichan].recElevation = (int32_t)(elev*1000.0);
				header[ichan].deltaSample = (int16_t) 
						(1000000.0/samprate0);
				header[ichan].sampleLength = (int16_t)nsamp0;
				header[ichan].num_samps = (int32_t)nsamp0;
				/* This cracks the time fields */
				time_str = epoch2str(time0,fmt);
				sscanf(time_str,"%hd %hd %hd %hd %hd %hd",
					&header[ichan].year,
					&header[ichan].day,
					&header[ichan].hour,
					&header[ichan].minute,
					&header[ichan].second,
					&header[ichan].m_secs);
				/* These are PASSCAL extensions, but we'll
				go ahead and set them anyway.*/
				header[ichan].trigyear = header[ichan].year;
				header[ichan].trigday = header[ichan].day;
				header[ichan].trighour = header[ichan].hour;
				header[ichan].trigminute = header[ichan].minute;
				header[ichan].trigsecond = header[ichan].second;
				free(time_str);
				if(input_source_coordinates)
				{
				  if(use_geo_coordinates)
				  {
					slat*=3600.0;
					slon*=3600.0;
				  }
				  header[ichan].sourceLongOrX
				    =(int32_t)(slon*(double)coordScale);
				  header[ichan].sourceLatOrY
				    =(int32_t)(slat*(double)coordScale);
				  header[ichan].sourceSurfaceElevation
				             =(int32_t)selev;
				  /* No easy way to specify both elev and depth*/
				  header[ichan].sourceDepth=0;
				}
				else if(map_to_cdp)
				{
				/* When faking CDP data we make this look 
				like a zero offset, single fold data set */
				  header[ichan].sourceLongOrX = header[ichan].recLongOrX;
				  header[ichan].sourceLatOrY = header[ichan].recLatOrY;
				  header[ichan].sourceSurfaceElevation = header[ichan].recElevation;
				  header[ichan].sourceDepth = 0;
				  header[ichan].sourceToRecDist = 0;
				}
				else
				{
				/* This is the mechanism for adding other
				information with added tables.  The one
				table currently supported is a "shot" table 
				that holds shot coordinates.  If other tables
				were added new functions could be added with
				a similar calling sequence.  This procedure
				silently does nothing if a shot table is not
				present.*/
					set_shot_variable(db,table_list,
						evid,&header[ichan]);
				}
			}			
			else
			{
				if(Verbose)
					fprintf(stdout,"Station %s and channel %s skipped\n",
						sta,chan);
			}

		}
		/* Now we write the data */
		for(i=0;i<nchan;++i)
		{
			if(fwrite((void *)(&(header[i])),sizeof(SegyHead),1,fp) != 1)
				elog_die(0,"Write error on header for trace %d\n",total_traces+i);		
			if(fwrite((void *)traces[i],sizeof(float),
					(size_t)nsamp0,fp) != nsamp0)
				elog_die(0,"Write error while writing data for trace %d\n",
					total_traces+i);
		}
		total_traces += nchan;
		trdestroy(&trdb);		
		if(!input_source_coordinates) ++shotid;
	}
	return 0 ;
}
Ejemplo n.º 10
0
int main (int argc, char **argv)
{
	Dbptr master_db, dbtmp;
	char dbname[512];  /* dbtmp name assigned by maketmpdb */
	char *orbname;
	char *pffile=NULL;

	Pf *pf;  /* Input pf object handle */
	Arr *arr_sta;
	Arr *arr_a;  /*Array object associative array -- purely a place holder*/
	Arr *arr_phase;
	int i;
	char *statefile=NULL;
	Point origin;

	int orbin,orbout;  /* We establish both a read and write connection
				on seperate sockets so we can use orbreap on
				the input */
	int quit=0,last_pktid;
	double last_pkttime;
	int exhume_rcode;  /* value returned by exhume*/
	char *packet=0;
	int orid_used;
	Location_options o;
	RTlocate_Options rt_opts;
	ORB_Hypocenter hyp;

	
	/* This initialization is necessary for the orb_arrivals_in routine
	to work correctly on the first pass*/
	hyp.assocs = NULL;

	elog_init(argc, argv);
	elog_notify (0, "$Revision$ $Date$") ;
	if(argc < 2) usage(argv[0]);
	orbname = argv[1];

	for(i=2;i<argc;++i)
	{
		if(!strcmp(argv[i],"-pf"))
		{
			++i;
			pffile = argv[i];
		}
		else if(!strcmp(argv[i],"-S"))
		{
			++i;
			statefile = argv[i];
		}
		else
		{
/* For this kind of program it seems wise to make it a fatal error to 
have the arguments botched */
			elog_complain(0,"Unrecognized argument %s\n",argv[i]);
			usage(argv[0]);
		}
	}
        /* set default this way*/
        if(pffile == NULL) pffile = strdup(DEFAULT_PFFILE);
	if(statefile == NULL) statefile = strdup(DEFAULT_STATEFILE);

	/* parse parameter file and form all the genloc control and
	internal static data structures */
	i = pfread(pffile,&pf);
	if(i != 0) elog_die(1,"Pfread error\n");
	o = parse_options_pf (pf);
	arr_sta = load_station_table(pf);
	arr_a = load_array_table(pf);
 	arr_phase = parse_phase_parameter_file(pf);
	/* Note this is a slightly different use of these variables
	than that used by other genloc routines.  Here we use it
	like a coordinate system origin to select range of distances
	to use. We actually reset these again in the location function,
	but check them here to make sure these variables are in the
	parameter space.  pfget_double will cause the program to die
	if these aren't defined.*/
	origin.lat = pfget_double(pf,"center_latitude");
	origin.lon = pfget_double(pf,"center_longitude");
	origin.z = 0.0;

	rt_opts = parse_rt_options(pf);

	if(dbopen(rt_opts.work_db,"r+",&master_db ) == dbINVALID)
                elog_die(1,"Unable to open master database %s\n",
			rt_opts.work_db);


	/* Now we open the orb server connections */
	if( (orbin=orbopen(orbname,"r&")) < 0)
		elog_die(0,"Cannot open ring buffer %s for reading\n",orbname);
	
	if(orbselect(orbin,"/db/event|/db/origin|/db/assoc|/db/arrival") < 0)
		elog_die(0,"Cannot select any db records from ring buffer %s\n",
			orbname);

	/* These are the state saving routines.  quit is set nonzero 
	whenever the program catches a signal.  We call bury below when
	this happens.  exhume_state is a function because I expect
	it could be used again  */

	exhume_rcode = exhume ( statefile, 0, 0, 0 );
	exhume_state(exhume_rcode);  
        if ( orbresurrect ( orbin, &last_pktid, &last_pkttime ) == 0 )
		elog_complain( 0, "resurrection successful: repositioned to pktid #%d\n", last_pktid ) ;
        else
	{
		orbseek (orbin, ORBOLDEST);
		last_pktid = orbtell(orbin);
		elog_complain( 0, "resurrection unsuccessful\nStarting at beginning of current orb at packet id %d\n",last_pktid ) ;
	}
	/* The following is basically a trick to create a db pointer that
	never references any tables.  This is the preferred approach for
	orbpkt2db records which utilize the scratch record of this database
	pointer.  The fact that we destroy the file this creates turns
	out to be a feature of datascope we can exploit here.  */
	if (maketmpdb ("css3.0", &dbtmp, dbname) < 0) {
		elog_complain(0, "maketmpdb() error.\n");
		exit (1);
	}
	/* This little routine initilizes the null record for each table 
	used here.  This was necessary because we assemble records in the
	scratch record.  This sets proper nulls in fields that are not
	referenced by this program. */
	if(initialize_scratch_records(dbtmp) == dbINVALID)
		elog_complain(0,"Warning:  errors initializing null records in tables.  May generate invalid data in some fields\n");
/*
	unlink (dbname);
*/
	

	if( (orbout=orbopen(orbname,"w&")) < 0)
		elog_die(0,"Cannot open ring buffer %s for writing\n",orbname);

	/* This loop is broken only by an error.  We call bury after each 
	event is processed saving the current packet id.  This should 
	effectively skip events that cause orbgenloc to die for some
	reason. */
	while(1) 
	{
		int return_code;

		return_code = orb_arrivals_in(orbin, dbtmp, &hyp, 
			&last_pktid,rt_opts);
		if(return_code)
		{
		    if(return_code < 0)
			elog_complain(0,"Error reading db records from orb\nCurrent event skipped\n");
		    else
			elog_complain(0,"Sequencing error reading db packets from orbassoc.\nOne or more events were probably skipped\n");
		    continue;
		}
		if(bury())
			elog_complain(0,
			  "bury failed writing statefile %s\n",statefile);

		compute_location(o,rt_opts,arr_sta,arr_a,arr_phase,
				pf,master_db, dbtmp, hyp, orbout);

		/* when last_pktid is -1 orb_arrivals_in does not do 
		an orbseek, so we always reset it here */
		last_pktid = -1;
		/* This is the only appropriate place to release
		this space.  This block is malloced in orb_arrivals_in*/
		free(hyp.assocs);
		hyp.assocs = NULL;
	}
}
Ejemplo n.º 11
0
void compute_location(Location_options o,
	RTlocate_Options rtopts,
	Arr *stations, Arr *arrays, Arr *phases, 
	Pf *pf,
	Dbptr master_db, Dbptr dbtmp, ORB_Hypocenter hyp, int orbout)
{
	Tbl *ta,*tu;  /* Arrival and slowness tables respectively */
	Hypocenter h0;
	int ret_code;
	Tbl *converge_history,*reason_converged,*residual;
	Hypocenter *hypo;
	int niterations;
	char *vmodel;
	int i;
	char *s;
	int orid;
	Point origin;
	double delta, seaz;
	double **C;
	float *emodel;
	int nass;

	initialize_hypocenter(&h0);

	/* It is inefficient to reread these from the parameter
	space on each entry, but preferable to a burdensome
	argument list */  
	origin.lat = pfget_double(pf,"center_latitude");
	origin.lon = pfget_double(pf,"center_longitude");
	origin.z = 0.0;

	/* This routine translates hyp structure to return tbl
	of arrival object pointers */
	ta = orbhypo_to_genloc(&hyp,phases,stations);
	/* this is a pure place holder */
	tu = newtbl(0);

	vmodel = pfget_string(pf,"velocity_model_name");

	/* By default we use the location transmitted by orbassoc.
	This can be overriden in the parameter file by using the
	other options allowed in genloc*/
	s=pfget_string(pf,"initial_location_method");
	h0.lat = hyp.lat;
	h0.lon = hyp.lon;
	h0.z = hyp.depth;
	h0.time = hyp.time;
	/* this strange logic is to allow this parameter to be defaulted.
	If the "initial_location_method" is not defined, or set
	to "manual", we use the location given by orbassoc.  Otherwise
	we utilize genlocs suite of initial locate options. */
	if(s != NULL)
		if(strcmp(s,"manual"))
			h0 = initial_locate(ta, tu, o, pf);

	/* Now compute distance from origin, and process only if 
	the event falls in the specified range */
	dist(rad(origin.lat),rad(origin.lon),rad(h0.lat),rad(h0.lon),
			&delta,&seaz);
	delta = deg(delta);
	/* this is the distance sifting test to ignore things outside
	specified distance range */
	if( ((delta>=rtopts.minimum_distance) 
		&& (delta <= rtopts.maximum_distance)) )
	{

	/* Location with Generic Gauss_Newton code */
		orid = -1;
		nass = maxtbl(ta);
		ret_code = ggnloc(h0,ta,tu,o,
				&converge_history,&reason_converged,&residual);
        	if(ret_code < 0)
        	{
                	elog_notify (0,"ggnloc failed to produce a solution for evid %d\n",hyp.evid);
        	}
        	else
		{
			if(ret_code > 0)
				elog_notify(0,"Warning:  %d travel time calculator failures in ggnloc\nSolution ok for evid %d\n",
                                	ret_code,hyp.evid);
			C = dmatrix(0,3,0,3);
			emodel = (float *) calloc(4,sizeof(float));
			if((emodel == NULL) || (*C == NULL) )
				elog_die(0,"Malloc error for error arrays\n");
			niterations = maxtbl(converge_history);
                	hypo = (Hypocenter *)gettbl(converge_history,
							niterations-1);
			predicted_errors(*hypo, ta, tu, o, C, emodel);
               		orid = save_origin(nass,hyp.evid,master_db,
					 dbtmp,*hypo,o,orbout);

                	save_origerr(orid,*hypo,C,dbtmp,orbout);
			save_assoc(ta, tu, orid, vmodel, 
				*hypo, dbtmp,orbout);
			elog_notify(0,"orid %d converged in %d iterations\n",
				orid,niterations);
			elog_notify(0,"Reason(s) for convergence:  \n");
			for(i=0;i<maxtbl(reason_converged);++i)
                        	elog_notify(0,"%s",gettbl(reason_converged,i));
			elog_notify(0,"\n");
			s=format_hypo(hypo);
			elog_notify(0,"%s\n",s);
			free(emodel);
			free_matrix((char **)C,0,3,0);
			free(s);
		}
		write_to_logfile(rtopts, orid, hyp.evid,
			  pf, converge_history, reason_converged,residual);

		if(maxtbl(converge_history)>0)freetbl(converge_history,free);
		if(maxtbl(reason_converged)>0)freetbl(reason_converged,free);
		if(maxtbl(residual)>0)freetbl(residual,free);

	}
	destroy_data_tables(ta, tu);
	return;
}
Ejemplo n.º 12
0
/* This function is used to check a list of pf names to verify they
are in the parameter space.  It is useful for any program that uses
parameter files that cracks the pf space anywhere except up front.
That is, the pf space is a convenient place to store all the run time
parameters of any program and is a convenient way to pass a large
control structure.  However, because flow can be complex it is possible
to have parameters that are only accessed deep within a program and 
in these situations it is desirable to run a check at program initialization
to verify the required parameters will be there when required.  

Normally a string variable will not cause pfget to die, but it will
here if it is listed as required

Parameters to be checked are grouped by type.  Each numerical fields
can contain an optional range check.  This is not allowed for strings.
Code below only checks int, double, boolean, and string variables.  Because of
the complexity of Tbl and Arrs I thought this not worth messing with.
Furthermore, it is not unusual to have an empty Tbl list or Arr that
the program should handle correctly.  

Function will die on the first occurence of a problem parameter.
It is void because it only returns if everything checks out.

Author:  Gary L. Pavlis
*/
void check_required_pf(Pf *pf)
{
	Tbl *t,*testtbl;
	Pf *pf_required;
	char *key;
	int i,j,nitems;
	int itest, ilowcheck, ihighcheck;
	double dtest, dlowcheck, dhighcheck;
	int bool;
	char *line;
	char *ctest;
	char name[50];

	/* This cracks the "required" &Arr dies if it isn't present 
	at all.  This assumes you wouldn't call this routine if you
	weren't serious about checking */
	if(pfget(pf,"require",(void **)&pf_required) != PFARR)
		die(0,"Arr of required parameters (require &Arr) missing from parameter space\nMust be present to execute this program\n");
	t=pfkeys(pf_required);
	for(i=0;i<maxtbl(t);++i)
	{
		key = gettbl(t,i);
		if(!strcmp(key,"int"))
		{
			testtbl = pfget_tbl(pf_required,"int");
			for(j=0;j<maxtbl(testtbl);++j)
			{
				line = gettbl(testtbl,i);
				nitems = sscanf(line,"%s%d%d",name,&ilowcheck,
							&ihighcheck);
				itest = pfget_int(pf,name);
				if(nitems == 3)
				{
					if( (itest < ilowcheck)
					  || (itest > ihighcheck) ) die(0,
						"Parameter %s has value %d which is outside required range of %d to %d\n",
						   name,itest,ilowcheck,ihighcheck);
				}
			}
		}
		else if(!strcmp(key,"double"))
		{
			testtbl = pfget_tbl(pf_required,"double");
			for(j=0;j<maxtbl(testtbl);++j)
			{
				line = gettbl(testtbl,i);
				nitems = sscanf(line,"%s%lg%lg",name,&dlowcheck,
							&dhighcheck);
				dtest = pfget_double(pf,name);
				if(nitems == 3)
				{
					if( (dtest < dlowcheck)
					  || (dtest > dhighcheck) ) die(0,
						"Parameter %s has value %lg which is outside required range of %lg to %lg\n",
						   name,dtest,dlowcheck,dhighcheck);
				}
			}
		}
		else if(!strcmp(key,"boolean"))
		{
			testtbl = pfget_tbl(pf_required,"boolean");
			for(j=0;j<maxtbl(testtbl);++j)
			{
				line = gettbl(testtbl,i);
				itest = pfget_boolean(pf,line);
			}
		}
		else if(!strcmp(key,"string"))
		{
			testtbl=pfget_tbl(pf_required,"string");
			for(j=0;j<maxtbl(testtbl);++j)
			{
				line = gettbl(testtbl,i);
				ctest = pfget_string(pf,line);
				if(ctest == NULL)
					die(0,"Missing required string variable = %s\n",
						line);
			}
		}
		else
		{
			elog_notify(0,"Unknown required type name = %s\nRequired parameters under this heading will not be checked\n",
				key);
		}
	}
	freetbl(t,0);
}
/* Init function for uniform table.
 phase = phase name to tag this table with
 pf = input parameter file object to be parsed.


The following keys are required to be found in pf:
	int:
	nx, nz
	scalar double:
	dx, dz
	&Tbl:
	uniform_grid_time_slowness_table

The later contains the actual tables.  They are ascii tables make up
of nx*nz lines (x varies most rapidly) of the following format:
	time, slowness, slowness derivative wrt distance, branch

The "branch" variable is a character key defined in location.h

Optional parameters with defaults:
	scalar double:
	x0, y0 coordinates of first point in table  (default = (0,0))
	strings:

Notice that this routine requires mixed units.  dx, dz, x0, and y0
must all be specified in degrees.  Everything else has units derived
from km and s.  That is, time is is in seconds, slowness (p) is
assumed to be in s/km, and dpdx (slowness derivative) is (s/km)/km.
This was done because the input tables are ascii, and these numbers
are scaled to units that make sense to most of us.  This format is
connected to a related program called taup_convert that writes
ttables in this format using the tau-p library.

Returns 0 if no problems are encountered.  REturns 1 if a serious
error occurred that rendered setup impossible for this phase.
In the later case, register_error is always called and should be
handled by calling program.

There are some fatal errors that lead to die being called here from
things like malloc failures.
*/
int uniform_table_interpolate_init(char *phase, Pf *pf)
{
    XZ_table_uniform *ttable, *utable;

    Tbl *t;  /* pfget_tbl return to hold strings of prototables stored
		in the pf structure. */
    int i,j,k;

    GenlocVerbose = verbose_exists() ;

    if(time_tables_uniform==NULL) time_tables_uniform = newarr(0);
    if(slow_tables_uniform==NULL) slow_tables_uniform = newarr(0);

    ttable = (XZ_table_uniform *)malloc(sizeof(XZ_table_uniform));
    utable = (XZ_table_uniform *)malloc(sizeof(XZ_table_uniform));


    if( (ttable == NULL) || (utable == NULL) )
        elog_die(1,"Can't alloc memory in uniform_table_interpolate_init\n");

    /* This version requires t and u tables to be parallel.  This
    restriction would not be necessary, but it simplifies things
    greatly and we only have to store times in the values matrix
    and the slowness values in the slopes matrix. */

    ttable->nx = pfget_int(pf, "nx");
    ttable->nz = pfget_int(pf, "nz");
    utable->nx = ttable->nx;
    utable->nz = ttable->nz;
    ttable->dx = pfget_double(pf, "dx");
    ttable->dz = pfget_double(pf, "dz");
    utable->dx = ttable->dx;
    utable->dz = ttable->dz;
    /* These parameters default to 0 */
    if(pfget_string(pf,"x0")==NULL)
    {
        ttable->x0 = 0.0;
        utable->x0 = 0.0;
    }
    else
    {
        ttable->x0 = pfget_double(pf,"x0");
        utable->x0 = ttable->x0;
    }
    if(pfget_string(pf,"z0")==NULL)
    {
        ttable->z0 = 0.0;
        utable->z0 = 0.0;
    }
    else
    {
        ttable->z0 = pfget_double(pf,"z0");
        utable->z0 = ttable->z0;
    }

    /* IMPORTANT WARNING:  notice I only alloc one space for the
    slowness values array, although it gets placed in two different
    places -> values section of utable and slopes section of ttable
    This leaves a nasty dependency if this space is to be freed, but
    saves a lot of memory.  p.s  I did the same thing with velocity,
    but not with the branch array (see below) */

    ttable->values = dmatrix(0,(ttable->nx)-1,0,(ttable->nz)-1);
    if(ttable->values == NULL)
        elog_die(1,"Cannot alloc memory for travel time table of size %d by %d for phase %s\n",
                 ttable->nx, ttable->nz, phase);
    ttable->slopes = dmatrix(0,(ttable->nx)-1,0,(ttable->nz)-1);
    if(ttable->slopes == NULL)
        elog_die(1,"Cannot alloc memory for slowness table of size %d by %d for phase %s\n",
                 ttable->nx, ttable->nz, phase);
    ttable->branch = cmatrix(0,(ttable->nx)-1,0,(ttable->nz)-1);
    if(ttable->branch == NULL)
        elog_die(1,"Cannot alloc memory for time branch table for phase %s\n",
                 phase);
    utable->branch = cmatrix(0,(utable->nx)-1,0,(utable->nz)-1);
    if(utable->branch == NULL)
        elog_die(1,"Cannot alloc memory for slowness branch table for phase %s\n",
                 phase);

    ttable->velocity = (double *) calloc(ttable->nz,sizeof(double));
    if(ttable->velocity == NULL)
        elog_die(1,"Cannot alloc memory for velocity model for phase %s\n",
                 phase);

    utable->slopes = dmatrix(0,(utable->nx)-1,0,(utable->nz)-1);
    if(utable->slopes == NULL)
        elog_die(1,"Cannot alloc memory for dudr table of size %d by %d for phase %s\n",
                 utable->nx, utable->nz, phase);

    /* here is where we set the redundant pointers */
    utable->values = ttable->slopes;
    utable->velocity = ttable->velocity;


    /* Now it is time to actually parse the tables.  We assume the
    table is entered as a pf &Tbl, and table is scanned with x
    varying most rapidly.  (i.e. you get the tables for x=x0 first,
    then x=x0+dx, etc. Note we read three entries for each grid
    point:  time, slowness, branch_code */
    t = pfget_tbl(pf,"uniform_grid_time_slowness_table");
    if(t == NULL)
    {
        elog_log(1,"Can't find travel time-slowness table for phase %s\n",
                 phase);
        free_uniform_table(ttable, utable);
        return(1);
    }

    if( maxtbl(t) != ( (ttable->nx)*(ttable->nz) ) )
    {
        elog_log(1,"Table size mismatch for phase %s\nTable should have %d rows\nFound %ld\n",
                 phase, (ttable->nx)*(ttable->nz), maxtbl(t));
        free_uniform_table(ttable, utable);
        return(1);
    }

    for(j=0,k=0; j<ttable->nz; ++j)
    {
        for(i=0; i<ttable->nx; ++i)
        {
            char *s;
            int nitems;
            double tt,u,dudx;
            char b;
            s = gettbl(t,k);
            nitems = sscanf(s,"%lf%lf%lf%1s",
                            &tt, &u, &dudx,&b);
            if(nitems !=4)
            {
                elog_log(1,"Syntax error reading table for phase %s, Problem read value for i=%d, j=%d\n",
                         phase,i,j);
                free_uniform_table(ttable, utable);
                return(1);
            }
            ttable->values[i][j] = tt;
            ttable->slopes[i][j] = u;
            utable->slopes[i][j] = dudx;
            ttable->branch[i][j] = b;
            ++k;
        }
    }

    /* In order to utilize a common set of interpolation routines,
    scan the time->branch matrix.  Mark the crossover points for
    time as jump discontinuities for slowness (which they are) */
    for(j=0; j<ttable->nz; ++j)
        for(i=0; i<ttable->nx; ++i)
            if(ttable->branch[i][j] == CROSSOVER)
                utable->branch[i][j] = JUMP;
            else
                utable->branch[i][j] = ttable->branch[i][j];
    /* An error check is needed here so we don't have to worry about it
    later.  Other than a blunder, this can happen if x0 is anything
    other than 0, so we need to watch for this.  We could try to
    repair this automatically, but because it mostly likely indicates
    a serious blunder we abort */

    for(j=0; j<ttable->nz; ++j)
        if( (utable->branch[0][j] == CROSSOVER)
                || (ttable->branch[0][j] == CROSSOVER)
                || (utable->branch[0][j] == JUMP)
                || (ttable->branch[0][j] == JUMP) )
        {

            elog_log(1,
                     "Error in travel time table for phase %s\nFirst point cannot be marked as a crossover or jump discontinuity\n",phase);
            free_uniform_table(ttable, utable);
            return(1);
        }
    /* Now we read the velocity model parameters */
    t = pfget_tbl(pf,"velocities");
    if((ttable->nz) != maxtbl(t))
    {
        elog_log(1,"Error in phase parameter file.  \
Mismatch between velocity entries and table entries\n\
Tables have %d depth entries, but velocity vector is of length %ld\n",
                 ttable->nz, maxtbl(t));
        free_uniform_table(ttable,utable);
        return(1);
    }
    for(i=0; i<maxtbl(t); ++i)
    {
        char *s;
        s = gettbl(t,i);
        sscanf(s,"%lf", &(ttable->velocity[i]));
    }
    setarr(time_tables_uniform,phase,ttable);
    setarr(slow_tables_uniform,phase,utable);
    return(0);
}
Ejemplo n.º 14
0
/* This is the main processing function for this program.  

Arguments:
	dbv - db pointer to a complex view of the database to be 
		processed.  That is, it has these properties:
		1.  It is a join of:
			event->origin->assoc->arrival
		2.  subset to single arrival name AND orid==prefor
		3.  sorted by evid/sta

	pf - input parameter space

The main processing loop here keys on the grouping defined in the view
passed as dbgrp.  That is, seismograms for each event group are processed
as a complete gather.  After that, are nested loops to do the multiwavelet
processing as described in Bear and Pavlis (1999a,b).  

Author:  Gary Pavlis
Date:  March 1999+
*/
#define LAG_ERROR -100000 /* Computed lags smaller than this returned
			by compute_optimal_lag are treated as an error
			condition.  Should probably be in an include file*/
void mwap_process(Dbptr dbv,char *phase,  Pf *pf) 
{
	int nevents;  /* number of events=number of groups in dbgrp */
	MWbasis *mw;  /* Multiwavelet basis functions */
	Tbl **decimators;  /* List of loaded decimators used to construct
				multiwavelet transforms in lower bands */
        Tbl **dec_objects;  /*Actual decimation filter objects */
	/* Note:  mw and dec_objects define the multiwavelet transform */
	int nwavelets,nbands;

	/* sets coherence mode used to determine optimal lag */
	int coherence_type;
	
	Arr *stations;  /* This associative array holds MWstation objects
			that contain header like data that is station 
			dependent */
	Arr *badclocks;  /* associative array keyed by sta name holding
			list of time intervals with bad timing */
	char *refsta;  /* Name of reference station */
	double refelev;  /* reference elevation from parameter file */
	int nsta;  /* number of stations */
	int ntest;
	Dbptr db;  /* generic db lookup parameter */
	Dbptr dbgrp;  /* evid group db pointer */
	Dbptr tr;  /* trace database */
	Dbptr dbmps;  /* mwpredslow table */
	Tbl *sortkeys,*sortkeys2;  /* used because different tr routines require
				different sort orders */

	int *pad;  /* vector of length nbands holding computed time padding
			lengths for each band in samples */
	int tpad;  /*time pad actually used  (max of *pad) */
	Time_Window *swin, *nwin;  /* arrays defining time windows
		for signal and noise respectively (relative to arrival)*/
	Time_Window swinall, nwinall;  /*define read time intervals (extracted
			from swin and nwin arrays */
	int *decfac;  /* array of decimation factors needed at times */
	Arr *mwarr;  /* Holds indexed multiwavelet transformed trace objects*/
	/* We keep three copies of arrival time information.  
		arrival0 = original times read from db (never altered)
		arrivals = current working copy
		arrival_new = new estimate obtained from "arrivals" 
	*/
	Arr *arrival0,*arrivals,*arrival_new;
	Arr *static_result;  /* Holds error statistics for static estimates */
	MWSlowness_vector u0,u;
	int i,j;
	double avgamp, amperr;
	int ampndgf;
	int iterations;
	double ucovariance[9];
	char *array_name;
	int accumulate;

	/* These are channel code names used in trace library rotation
	functions rotate_to_standard and trrotate.  */
	char *stdchans[3]={ EW, NS , VERTICAL };
	char *pcchans[3]={"R","T","ZL"};

	Arr *mwsig_arr,*mwnoise_arr;  /* these index pointers to mw transformed
			signal and noise series */
	Arr **sn_ratios;  /* vector of Arr pointers of length nbands indexing
		signal to noise ratio estimates (stored in a structure) for
		every station */
	Spherical_Coordinate polarization0,polarization;
	Spherical_Coordinate polarz={1.0,0.0,0.0};
	Arr *model_times=NULL;
	MWSlowness_vector model_slow;
	double rctm[9];  /*ray coordinate transformation matrix*/
	double timeref;  /* time reference at reference station */
	double time;
	double t0,twin;
	double si;
	double fc,fwin;
	int evid;
	int lag;  /* optimal lab computed by coherence measure */
	double peakcm;  /*Peak value of coherence measure */
	/* For a given gather we set moveout computed moveout time in
	seconds relative to the reference station.  This time includes
	the combined current static estimates.  This is a vector workspace
	that is recycled for every gather.  It is alloced soon as we
	know the number of stations in the site table.  */
	double *moveout;
	MWgather **gathers;
	Particle_Motion_Ellipse *avgpm;
	Particle_Motion_Error *avgerr;
	char *pmtype_to_use;  /* type of particle motion estimate to use
				for polarization */
	Arr *pm_arr,*pmerr_arr;
	Arr *pmarray,*errarray;
	/* This vector defines the "up" direction.  For P waves this
	initialization is correct.  For S it may not be appropriate, but
	this is something to repair later */
	double up[3]={0.0,0.0,1.0};
	int bankid;  /* mutliwavelet group id */
	int band_exit = 0;
	/* name of parameter file produced by GUI to control this program */
	char *guipf;
	int stack_alignment;
	Pf *pfcontrol;
	int loopback;
	int numberpasses=0;
	/* These define the relative time window used for stack and
	particle motion.  s denotes stack, ts0 etc are pm */
	double sts0,ste0;  /* we don't need the equivalent of ts1 and te1 */
	double ts0,ts1,te1,te0;

	/* This is essential or copy_arrival_array can produce garbage */
	arrival0=NULL;
	arrivals = NULL;
	arrival_new=NULL;
	pm_arr = NULL;
	pmerr_arr = NULL;
	pmarray = NULL;
	errarray = NULL;
	si = pfget_double(pf,"sample_interval");
	/* First we need to load the multiwavelet functions and the 
	associated decimators for the transform.  Each of these
	routines will die if serious problems occur and have no
	error returns.  Wavelet functions can be loaded from a parameter
	file or a db.  */
	if(pfget_boolean(pf,"get_wavelets_from_database"))
	{	
		mw = load_multiwavelets_db(dbv,pf,&nwavelets,&bankid);
	}
	else
	{
        	mw = load_multiwavelets_pf(pf,&nwavelets);
		bankid = pfget_int(pf,"bankid");
	}
        decimators = define_decimation(pf,&nbands);
	allot(int *,decfac,nbands);
        dec_objects = build_decimation_objects(decimators,nbands,decfac);

	print_band_info(mw,decfac,pf);

	/* This creates the station objects.  The time extracted here
	is needed to sort out the ontime:endtime key in the site table.
	This is done is a less than bombproof fashion by randomly 
	grabbing the time in the first record view.
	Because of the way the site table works this will always work
	in some fashion.  It will only matter if a station ever moves
	and then we have a bad problem anyway.  */
	dbv.record = 0;
	dbgetv(dbv,0,"time",&time,0);
	stations = build_station_objects(dbv,pf,time);
	refsta = get_refsta(stations);
	array_name = pfget_string(pf,"array_name");
	if(array_name == NULL)
	{
		elog_complain(0,"WARNING:  array_name not defined in parameter file.  Set to default of ARRAY\n");
		array_name = strdup("ARRAY");

	}
	refelev = pfget_double(pf,"reference_elevation");
	/* This loads a definition of bad clocks from an extension
	table called timing.  This comes from libgenloc where it
	is used to handle automatic switching to S-P times. */
	badclocks=newarr(0);
	if(db_badclock_definition(dbv,pf,badclocks))
	{
		elog_notify(0,"Problems in setting up table of stations with timing problems\n");
	}
	/* This function can define stations as always having bad timing
	based on a parameter Tbl list of station names keyed by bad_clock.*/
	pfget_badclocks(pf,badclocks);

	pmtype_to_use = pfget_string(pf,"array_particle_motion_to_use");
	if(pmtype_to_use==NULL) pmtype_to_use=strdup(PMOTION_BEAM);
	/* this used to be a variable, but we no longer have a choice.*/
	coherence_type=USE_COHERENCE;
	
	/* This variable sets if we should reset the arrival estimates
	to starting values for each band.  When true the results accumulate
	from band to band.  That is we keep adding corrections from previous
	band to progressively higher frequency.*/
	accumulate = pfget_boolean(pf,"accumulate_statics");
	/* compute time pad lengths for each band of the mw transforms */
	pad = compute_tpad(dec_objects, mw, stations,pf);

	/* These routine parses the parameter file for noise and
	analysis time window information respectively returning
	arrays of Time_Window structures of length nbands*/
	decfac = get_decimation_factors(dec_objects, pf);
	swin = get_signal_windows(decfac,pad,pf);
	nwin = get_noise_windows(decfac,pad,pf);
	print_window_data(decfac,nbands,swin,nwin,pf);	

	/* This gets time windows for signal and noise needed for
	reading data (i.e. largest time ranges needed) */
	swinall = compute_time_window(swin,decfac,nbands);
	nwinall = compute_time_window(nwin,decfac,nbands);

	guipf = pfget_string(pf,"mwapcontrol");
	/* better safe than sorry */
	if(guipf==NULL)
	{
		elog_die(0,"Missing required parameter mwapcontrol");
	}

	/* We can create these works spaces now for efficiency so 
	we don't have to constantly recreate them dynamically below */
	allot(double *,moveout,cntarr(stations));
	allot(MWgather **,gathers,nwavelets);

	/* This associative array holds indexed pointers to multiwavelet
	transformed traces.  We create it here, but it is repeatedly
	freed and cleared below */
	mwarr = newarr(0);
	/* This one has to be initialized*/
	static_result=newarr(0);

	/* We need this table repeatedly below so we avoid constant 
	lookups */
	dbmps = dblookup(dbv,0,"mwpredslow",0,0);
	if(dbmps.record == dbINVALID)
		elog_die(0,"db lookup failed for mwpredslow table\nMWavelet schema extensions are required\n");

	/* Now we loop through the outer loop event by event.  
	This is structured here by using a dbgroup defined db pointer
	that is passed through the argument list.  The db pointer 
	is incremented and then the bundle is taken apart to crack
	apart each group of traces (the gather).  Note we use
	a defined name to look up the evid grouped table. */
	dbgrp = dblookup(dbv,0,EVIDBDLNAME,0,0);
	if (dbgrp.record == dbINVALID)
		elog_die(0,"Error in dblookup for named evid group table = %s\n",
			EVIDBDLNAME);
        dbquery(dbgrp,dbRECORD_COUNT,&nevents);
        fprintf(stdout,"Processing begins for %d events\n",nevents);

	sortkeys = newtbl(0);
	pushtbl(sortkeys,"sta");
	pushtbl(sortkeys,"chan");
	pushtbl(sortkeys,"time");
	sortkeys2 = newtbl(0);
	pushtbl(sortkeys2,"time");
	pushtbl(sortkeys2,"sta");
	pushtbl(sortkeys2,"chan");

	for(dbgrp.record=0;dbgrp.record<nevents;++dbgrp.record)
	{
		Dbptr db_bundle;
		int evid; 
		int is, ie; 
		int ierr;
		double modaz;

		if(dbgetv(dbgrp,0,"evid", &evid,
                        "bundle", &db_bundle,0) == dbINVALID)
		{
                        elog_complain(1,"dbgetv error for row %d of event group\nAttempting to continue by skipping to next event\n",
                                dbgrp.record);
			continue;
		}

                dbget_range(db_bundle,&is,&ie);

		if(ie-is<3)
		{
			elog_complain(0,"Insufficient data to process for evid %d\nNeed at least three station -- found only %d\n",
				evid,ie-is);
			continue;
		}
		/* We utilize what we call plane wave statics here
		to approximately correct for wavefront curvature.
		We set the record number to is so we can access 
		the correct origin information from the db.  Because
		we used a join allrows of this group should have the
		same origin data.  */
		ierr = set_pwstatics(stations,refsta,phase,db_bundle,pf);
		if(ierr)elog_complain(0,"%d errors computing %d plane wave statics for evid %d\n",
			ierr,ie-is,evid);

		/* This routine loads an Arr of arrival times from 
		the input db to be used to compute initial slowness
		vector and initial statics.  */
		arrival0 = get_arrivals(db_bundle);

		/* We edit the MWstation array to flag stations
		with bad timing in this function */
		MWcheck_timing(arrival0,stations,badclocks);

		/* Save these times */
		copy_arrival_array(arrival0,&arrivals);


		/* Initialize slowness vector to 0 and then estimate
		it from data using current arrival times */
		u0.ux = 0.0;  u0.uy = 0.0;  u0.refsta = refsta;
		timeref = compute_time_reference(stations,arrivals,refsta,u0);
		/* for the first pass we use weights defined for the 
		lowest frequency band.  This is done because it asssumed
		that if frequency dependent weighting is actually used
		the lowest band would have the widest effective aperture. */
		ierr = estimate_slowness_vector(u0,arrivals,stations,
			refsta, refelev, timeref, phase, nbands-1,&u);
		/* It is necessary to reset the time reference to handle 
		the case correctly when the reference station does not
		actually record this event.  This function uses a moveout
		correction that depends upon the slowness vector, so it can
		float about a bit in that situation */
		if(ierr>0)
			elog_notify(0,"%d nonfatal errors in estimate_slowness_vetor for evid %d\n",ierr,evid);
		else if(ierr < 0)
		{
			elog_complain(0,"estimate_slowness_vector failed for initial slowness estimate for evid %d\nData for this event will be skipped\n",
				evid);
			continue;
		}
		/* This routine returns the slowness vector and an arr of 
		estimated arrival times.  The slowness vector is saved
		in the mwpredslow table immediately below.  Arrival times
		are used to compute residuals later. */
		ierr = MWget_model_tt_slow(stations, refsta, phase,
			db_bundle, pf, &model_times, &model_slow);

		timeref = compute_time_reference(stations,arrivals,refsta,u);
		polarization0=estimate_initial_polarization(model_slow,stations,
			refsta,phase);

		modaz = atan2(model_slow.ux,model_slow.uy);

		if(dbaddv(dbmps,0,"sta",array_name,
			"evid",evid,
			"phase",phase,
			"time",timeref,
			"slo",hypot(model_slow.ux,model_slow.uy),
			"azimuth",deg(modaz),
			"majoraz",deg(polarization0.phi),
			"majorema",deg(polarization0.theta),
			"vmodel",pfget_string(pf,"TTmodel"),0) == dbINVALID)
		{
			elog_complain(0,"dbaddv error for evid %d on mwpredslow table\n",
				evid);
		}

		/* This function reads in the trace data for this event
		using time windows defined above */
		tr = mwap_readdata(dbgrp,arrivals,swinall, nwinall);
		if(tr.record == dbINVALID)
		{
			elog_complain(0,"Serious problems reading data for evid %d -- no data processed for this event\n",evid);
			continue;
		}
		tr = dblookup(tr,0,"trace",0,0);
		/* We first glue together any possible recording break
		generated entries -- common with continuous data.
		This also seems to require a resort because of the
		way data was read in.   */
/*
		tr = dbsort(tr,sortkeys,0,0);
*/
		trsplice(tr,0.1,0,0);

		/* We run trsplit to break up waveform segments at real gaps.
		I'm not sure later code will work correctly if it isn't an 
		all or nothing situations (e.g. gap in Z component, but 
		not in N or E).  In any case, we have to deal with 
		potential multiple segments later.  */
		trsplit(tr,0,0);

		trapply_calib(tr);
		trdemean_seg(tr);
		/* Now we have reorder the traces or this will not work
		correctly*/
		tr = dbsort(tr,sortkeys2,0,0);
		ierr = rotate_to_standard(tr,stdchans);
		if(ierr<0)
		{
			elog_complain(0,"rotate_to_standard failed processing evid %d -- no data processed for this event\n",
				evid);
			continue;
		}
		if(ierr>0)elog_complain(0,"rotate_to_standard failed for %d stations\n",
				ierr);

		/* This releases the space held by the raw data traces
		keeping only the rotate_to_standard outputs */
		free_noncardinal_traces(tr);

		elog_log(0,"Computing multiwavelet transform:  be\
 patient as this can take a while with many channels\n");
		/* This function computes the multiwavelet transform
		of all traces currently in tr for signals around arrival*/
		mwsig_arr = tr_mwtransform(tr,arrivals,swin,decfac,dec_objects,
				nbands,mw,nwavelets);

		/* We repeat the same thing for noise windows */
		mwnoise_arr = tr_mwtransform(tr,arrivals,nwin,decfac,
				dec_objects,nbands,mw,nwavelets);
		/* Now compute signal to noise ratio figures for all
		nbands storing the structures that define the results
		in an Arr keyed by station. Note this is actually 
		a vector of Arr pointers of length nbands.  Further
		note the following function creates this complicated
		object, and it must be freed after each event is 
		processed. */
		sn_ratios=compute_signal_to_noise(mwsig_arr,mwnoise_arr,
					stations,arrivals,swin,nwin,
					nbands,nwavelets);

		/* Now we get to the heart of this program.  This is
		the outer loop over frequency.  Note the loop goes
		backward because the lowest frequencies are the final
		row of the mw transform matrices of pointers */

		copy_MWslowness_vector(&u,&u0);
		if(numberpasses>0)
		{
			fprintf(MWpout,"NEWEVENT %d\n",evid);
		}
		for(i=nbands-1;i>=0;--i)
		{
			if(!accumulate)
				copy_arrival_array(arrival0,&arrivals);

			copy_arrival_array(arrivals,&arrival_new);
			fc = (mw[i].f0)/(2.0*si*decfac[i]);
			fwin = (mw[i].fw)/(2.0*si*decfac[i]);

			fprintf(stdout,"Processing begins on band %d with center frequency %lf\nWait for -Hit Accept button when ready- prompt\n",
				i,fc);

			/* This builds the basic working gathers for
			each wavelet and builds a shortcut of pointers
			to MWtraces that are related */
			for(j=0;j<nwavelets;++j)
			{
				gathers[j] = build_MWgather(i,j,
						mwsig_arr,stations,
						sn_ratios[i],pf);
			}
			fprintf(stdout,"Working gather for this band has %d stations\n",
				gathers[0]->nsta);
			/* Testing band 0 should be sufficient.  The
			signal-to-noise is averaged overall wavelets so
			the same stations should be deleted in all
			wavelet of the group */
			if(gathers[0]->nsta < 3)
			{
				elog_notify(0,"Insufficient data in band %d to passed signal-to-noise cutoff defined for this band for evid %d\nSkipping to next frequency band\n",
					i,evid);
				continue;
			}
			/* This may not be necessary, but it is certainly 
			important for debugging.  We check that all
			the gathers in the group have the same length.  
			If they aren't, we are in trouble because we use
			a single vector to hold moveout information */
			check_gather_consistency(gathers,nwavelets);

			/* Now we compute the moveout information assuming
			stations are in the same order in the gather for
			each wavelet */
			if(compute_total_moveout(*gathers,stations,refsta,
				u,refelev,phase,moveout))
			{
				elog_die(0,"Cannot find reference station to compute moveout:  Should not happen unless program overwrites itself\n");
			}

			if(numberpasses>0)
			{
				fprintf(MWpout,"NEWBAND %d\n",i);
				fflush(MWpout);
			}
			else
			{
				char ctmp[40];
				fprintf(stdout,"Starting processing of first event\nSelect and options and press the Start button when ready\n");
				fprintf(MWpout,"STARTUP %d %d\n", 
					evid,i);
				fflush(MWpout);
				fgets(ctmp,40,MWpin);
			}
			++numberpasses;

			/* This is placed here to allow changing the
			alignment options on the fly.  Choice may
			depend on data. */
			pfread(guipf,&pfcontrol);
			stack_alignment=get_stack_align_mode(pfcontrol);
			pffree(pfcontrol);
			
			/* kind of a odd loop construct here made 
			necessary by differences in stackalignment
			options.  If we align with theoretical value
			or use the vertical we do not need to repeat
			this loop and we fall out the bottom.  If we
			use the pm estimate, however, we have to 
			realign the stack rotated to the new major
			ellipse estimate.  In that case we have to
			repeat the whole procedure.*/
			loopback=2;
			do {
				MWstack *stack;
				switch(stack_alignment)
				{
				case PMTHEORY:
					copy_polarization(&polarization0,&polarization);
					loopback=0;
					break;
				case PMZ:
					copy_polarization(&polarz,&polarization);
					loopback=0;
					break;
				case PMESTIMATE:
				default:
				/* This uses theoretical version for the
				first pass then the estimate on the 
				second */
					if(loopback==2)
					  copy_polarization(&polarization0,
						&polarization);
				}
				stack=MWcompute_arrival_times(gathers,
    					   nwavelets,timeref,moveout,
    					   polarization,swin[i],
					   sn_ratios[i],guipf,
    					   &arrival_new,&static_result,
                                            &avgamp, &amperr, &ampndgf);
				if(stack==NULL)
				{
					/* I use a flag to avoid an
					evil goto here */
					band_exit = 1;
					/* This is strange but necessary
					to stop string of bogus errors from
					copy_arrival_array function when
					this loops back */
					if(arrival_new!=NULL)
						freearr(arrival_new,free);
					arrival_new = NULL;

					break;
				}
					
					
				/* Note this routine updates residual
				static values to new values relative to
				the new slowness vector estimate */
	                	ierr = estimate_slowness_vector(u0,
					arrival_new,stations,
                        		refsta, refelev, timeref, 
					phase, i, &u);
				/* We need to recompute the moveout to 
				now be relative to the new slowness vector
				estimate.  We then use this for particle 
				motion analysis which can change the 
				polarization vector */
				compute_total_moveout(*gathers,stations,refsta,
				u,refelev,phase,moveout);
				/* This segment converts particle motions
				for 3-c arrays.  */
				if(gathers[0]->ncomponents==3)
				{
					MWstack *spm; 
					Time_Window pmtwindow;
					double *timeweight;
					
					/* We extract the time window
					from a control parameter file which
					is assumed to be created by a GUI
					with tcl/tk */
					pfread(guipf,&pfcontrol);
					ts0=pfget_double(pfcontrol,"pm_ts0");
					ts1=pfget_double(pfcontrol,"pm_ts1");
					te1=pfget_double(pfcontrol,"pm_te1");
					te0=pfget_double(pfcontrol,"pm_te0");
					/* we need these below, not here */
					sts0=pfget_double(pfcontrol,"stack_ts0");
					ste0=pfget_double(pfcontrol,"stack_te0");
					twin = ste0-sts0;
					pffree(pfcontrol);
					pmtwindow.tstart = nint(ts0/(stack->dt));
					pmtwindow.tend = nint(te0/(stack->dt));

					spm = MWextract_stack_window(stack,
						&pmtwindow);
					if(spm==NULL)
						elog_die(0,
						  "Fatal error in MWextract_stack_window\n");
					/* Sets time weight function for 
					a trapezoidal window */
					timeweight=MWstack_set_trapezoidal_window(spm->tstart,
						spm->dt,spm->nt,
						ts0,ts1,te1,te0);
					dcopy(spm->nt,timeweight,1,spm->timeweight,1);
					free(timeweight);
					MWstack_apply_timeweight(spm);

					if(MWcompute_array_particle_motion(gathers,
					  nwavelets,spm,timeref,moveout,
					  up,&pmarray,&errarray, &pm_arr,&pmerr_arr) )
					{
					  elog_complain(0,"Errors in MWcompute_array_particle_motion\n");
					}
					avgpm = (Particle_Motion_Ellipse *)getarr(pmarray,pmtype_to_use);
					avgerr = (Particle_Motion_Error *)getarr(pmarray,pmtype_to_use);

					polarization
					  =unit_vector_to_spherical(avgpm->major);
					destroy_MWstack(spm);
				}
				peakcm=stack->coherence[idamax(
					stack->nt,
					stack->coherence,1)];
				copy_arrival_array(arrival_new,&arrivals);
				freearr(arrival_new,free);
				arrival_new = NULL;
				destroy_MWstack(stack);
				if(stack_alignment==PMESTIMATE)
						--loopback;
			}while(loopback>0);
			if(band_exit)
			{
				band_exit = 0;
				continue;
			}

			/* This routine computes the covariance of
			the estimated slowness vector */
			if(compute_slowness_covariance(stations,static_result,
				ucovariance) )
				elog_complain(0,"Problems computing slowness vector covariance estimate for evid %d and band %d\n",
					evid, i);
			/* routines below save a time window.  We compute
			the lag corrected start time at the reference station
			here as t0 to simplify this in functions that
			need this.*/
			t0 = timeref + sts0;
			/* This series of functions save results in a set
			of css3.0 extension tables.  */

			/* ampndgf+1 here is a cheap solution to the
			number of stations used in a solution.  This 
			confusion is necessary because autoediting reduces
			the data set.  Poor planning caused me to not
			force this to be saved explicitly, but ampndgf is
			an exact surrogate.  The +1 is needed because the
			calculation uses number_used - 1 since the average
			amplitude is extracted as a free parameter.
			*/
			if(MWdb_save_slowness_vector(phase,&u,t0,twin,
				array_name,evid,bankid,fc,fwin,
				ucovariance,ampndgf+1,3,
				coherence_type,peakcm,dbv))
					dbsave_error("mwslow",evid,i);
			if(MWdb_save_avgamp(array_name, evid, bankid, phase,
				fc, t0, twin, avgamp,amperr,ampndgf,
				dbv) )
					dbsave_error("mwavgamp",evid,i);
			if(MWdb_save_statics(evid, bankid, phase, fc, t0,
				twin,refelev,*gathers,moveout,static_result,
				stations,sn_ratios[i],
				arrivals, model_times,dbv))
					dbsave_error("mwtstatic:mwastatic:mwsnr",evid,i);
			t0=timeref+ts0;
			twin = te0-ts0;
			if(MWdb_save_pm(array_name,evid,bankid,phase,fc,t0,
				twin,*gathers,moveout,pm_arr,pmerr_arr,
				avgpm,avgerr,dbv)  )
					dbsave_error("mwpm",evid,i);
			/* We have to release the memory held in these
			associative arrays.  In the earlier loop the 
			function that creates them always clears them
			before continuing when they are not null.  
			The explicit NULL set after the free is done
			to make sure in looping back the particle
			motion routine clears these correctly.  */
			freearr(pm_arr,free);
			pm_arr = NULL;
			freearr(pmerr_arr,free);
			pmerr_arr = NULL;
			/* same for static arr */
			freearr(static_result,free);
			static_result = NULL;
		}
		/*release main work spaces with this series of complicated free routines.
		Here is where you really wish C had garbage collection */
		free_sn_ratios_arr(sn_ratios,nbands);
		free_MWtransform_arr(mwsig_arr,nbands,nwavelets);
		free_MWtransform_arr(mwnoise_arr,nbands,nwavelets);
		trdestroy(&tr);
		freearr(arrival0,free);
		freearr(arrivals,free);
		/* This may not be necessary, but better safe than sorry */
		arrivals = NULL;   arrival0 = NULL;   arrival_new = NULL;
	}
	free(moveout);
	free(swin);
	free(nwin);
	free(refsta);
}
Ejemplo n.º 15
0
int dbpmel_save_results(Dbptr db,
	int nevents,
	long *evid,
	Hypocenter *h,
	Tbl **ta,
	Location_options o,
	Pf *pf)
#endif
{
	Dbptr dbe,dbo,dba,dboe; 
	Dbptr dbes,dbos,dbas;
	Dbptr dbs;  /* subset view created by dblist2subset */
	Tbl *opat,*aspat,*aspat2;
	Tbl *matches=NULL,*match2;  /* output list of matching records */
	/* Dan Q advises it is wise to have a separate hook for each
	table passed through dbmatches */
	Hook *hooke=NULL,*hooko=NULL,*hooka=NULL,*hooka2=NULL;
	long prefor;
	int i,j;
	char *auth;
	Arrival *a;
	long orid;
	int nmatch;
	double **C;
	float emodel[4];
	char *alg=(char *)strdup("dbpmel");
	/* A collection of variables from assoc that have to be 
	copied.  Earlier algorithm using dbget raw on a subset 
	view failed so I have to copy by this mechanism */
	double belief;
	char timedef[2],slodef[2],azdef[2];
	double azres,slores,emares;
	Tbl *utbl;  


	/* This is needed as a stub for the predicted_error function.
	Because we don't support slowness vector data in pmel this 
	has to be an empty (NOT NULL) tbl list */
	utbl=newtbl(0);
	/* All of these are used repeatedly so we do one lookup at the
	top */
	dbe = dblookup(db,0,"event",0,0);
	dbo = dblookup(db,0,"origin",0,0);
	dba = dblookup(db,0,"assoc",0,0);
	dboe = dblookup(db,0,"origerr",0,0);
	dbes = dblookup(db,0,"event",0,0);
	dbos = dblookup(db,0,"origin",0,0);
	dbas = dblookup(db,0,"assoc",0,0);
	dbes.record = dbSCRATCH;
	dbos.record = dbSCRATCH;
	dbas.record = dbSCRATCH;

	opat = strtbl("orid",NULL );
	aspat = strtbl("orid",NULL );
	aspat2 = strtbl("arid","orid","sta",NULL );

	auth = pfget_string(pf,"author");

	C = dmatrix(0,3,0,3);
	/* outer loop over nevents */
	for(i=0;i<nevents;++i)
	{		
    		double conf;
		char *modtype;
		int model;
		double smajax,sminax,strike,sdepth,stime;
		int rc;

		/* Save nothing for events marked no use */
		if(h[i].used==0) continue;  
		/* Start with event table to get prefor */
		dbputv(dbes,0,"evid",evid[i],NULL );
		dbe.record = dbALL;
		if(dbmatches(dbes,dbe,0,0,&hooke,&matches)!=1)
			elog_complain(0,"WARNING:  multiple records in event table have evid=%ld.\nThis is a serious database problem that should be corrected.  Using first one found in table\n",
				evid[i]);
		dbe.record = (long)gettbl(matches,0);
		/* this is excessively paranoid, but better safe than sorry*/
		if(dbe.record<0)
		{
			elog_complain(0,"dbmatches invalid record %ld\nSkip saving evid %ld\n",
				dbe.record,evid[i]);
			continue;
		}
		dbgetv(dbe,0,"prefor",&prefor,NULL );
		freetbl(matches,0);
		matches=NULL;

		dbputv(dbos,0,"orid",prefor,NULL );
		dbo.record = dbALL;
		nmatch=dbmatches(dbos,dbo,&opat,&opat,&hooko,&matches);
		if(nmatch>1)
			elog_complain(0,"WARNING:  multiple records in origin table match orid=%ld.\nThis is a serious database problem that should be corrected.  Using first one found in table\n",
				prefor);
		else if(nmatch<=0)
		{
			elog_complain(0,"Cannot find matching origin\
record for orid %ld prefor of event %ld\n",
				prefor,evid[i]);
		}
		dbo.record = (long)gettbl(matches,0);
		if(dbget(dbo,0)==dbINVALID)
		{
			elog_complain(0,"dbget error on origin table for orid %ld\nData for evid %ld will not be saved\n",
				prefor,evid[i]);
			continue;
		}
		freetbl(matches,0);
		matches=NULL;

		/* origerr code cloned from dbgenloc */
		conf = pfget_double(pf,"confidence");
		modtype = pfget_string(pf,"ellipse_type");
     		if(modtype == NULL)
     		{
        		elog_complain(0,"parameter ellipse_type not defined--default to chi_square");
        		model = CHI_SQUARE;
     		}
     		else if( strcmp( modtype, "chi_square" ) == 0 )
     		{
        		model = CHI_SQUARE;
     		}
     		else if( strcmp( modtype, "F_dist" ) == 0 )
     		{
        		model = F_DIST;
     		}
     		else
     		{
        		elog_complain(0, "parameter ellipse_type %s incorrect (must be F_dist or chi_square)--default to chi_square", modtype );
        		model = CHI_SQUARE;
     		}
		predicted_errors(h[i],ta[i],utbl,o,C,emodel);
    		rc = project_covariance( C, model, &conf,
                             h[i].rms_weighted, h[i].degrees_of_freedom,
                             &smajax, &sminax, &strike, &sdepth, &stime );

    		if( rc != 0 )
    		{
        		elog_complain(0, "project_covariance failed." );
        		smajax = -1;
        		sminax = -1;
        		strike = -1;
        		sdepth = -1;
        		stime = -1;
        		conf = 0.;
    		}
		orid = dbnextid(dbo,"orid");

		if(dbaddv(dboe,0,
                	"orid", orid,
                	"sxx",C[0][0],
                	"syy",C[1][1],
                	"szz",C[2][2],
                	"stt",C[3][3],
                	"sxy",C[0][1],
                	"sxz",C[0][2],
                	"syz",C[1][2],
                	"stx",C[0][3],
                	"sty",C[1][3],
                	"stz",C[2][3],
                	"sdobs", h[i].rms_raw,
                	"smajax", smajax,
                	"sminax", sminax,
                	"strike", strike,
                	"sdepth", sdepth,
                	"stime", stime,
                	"conf", conf,
                		NULL ) < 0 )
		{
			elog_complain(0,"Problem adding origerr record for evid %ld\n",
				evid[i]);
		} 


		/* This edits the scratch record and adds it to the end 
		of the origin table */
		dbputv(dbos,0,"orid",orid,
				"lat",h[i].lat,
				"lon",h[i].lon,
				"depth",h[i].z,
				"time",h[i].time,
				"algorithm",alg,
				"auth",auth,NULL );

/*
		printf("Added to origin table: %8d %9.4lf %9.4lf %9.4lf"
			" %17.5lf %-15s %-15s\n", orid, h[i].lat, 
			h[i].lon, h[i].z, h[i].time, alg, auth);
*/

		if(dbadd(dbo,0)==dbINVALID)
			elog_complain(0,"dbadd error for origin table\
for new orid %ld of evid %ld\n",
				orid,evid[i]);
		/* The assoc tables is much more complex.  Rather than
		do a row for row match against each arrival in ta, I
		use a staged reduction.  Than is I first match the full
		assoc table against orid=prefor only to get a full list
		of records for that event.  We then run matches against
		the smaller table for sta/phase in the arrival list.
		Untested but from previous experience with dbmatches on
		large tables I'm fairly sure this is a necessary 
		complication to keep this from be very slow*/
		dbputv(dbas,0,"orid",prefor,NULL );
		dba.record = dbALL;
		nmatch=dbmatches(dbas,dba,&aspat,&aspat,&hooka,&matches);
		if(nmatch<=0)
		{
			elog_complain(0,"No assoc records for orid %ld\
found\nFail to create new assoc records for orid %ld\n",
				prefor,orid);
			freetbl(matches,0);
			continue;
		}