/* The trace library routines that existed at the time this code
was written were heavy handed about dealing with taps.  trload_css
calls trgetwf which in turn calls gaps2tr.  This sets all gaps to 
the fillgap value for the specified data type.  Unfortunately, 
this causes a problem with clipped data.  A clip is indeed a "gap"
of a type, but there is a difference between a + and - full scale
reading.  We call tr2gaps below, which is not a clean inverse
of gaps2tr because it only recovers the + full scale values 
correctly leaving a worse tear for negative values.  I circumvent 
this here by checking the sign of the sample preceeding a gap and
flipping the sign when appopriate.  
*/
void repair_gaps(Dbptr trdb)
{
	Trsample *trdata;
	long int nsamp;
	char datatype[4];
	long int ntraces;
	int i,i0;
	Wftype *g;

	dbquery(trdb,dbRECORD_COUNT,&ntraces);
	for(trdb.record=0;trdb.record<ntraces;++trdb.record)
	{
		if(dbgetv(trdb,0,
			"datatype",datatype,
			"data",&trdata,
			"nsamp",&nsamp,
		NULL) == dbINVALID)
		{
			elog_die(0,"dbgetv error during gap processing\n");
		}
		g = trwftype(datatype);
		/* this function is supposed to set values to g->fill*/
		tr2gaps(trdata,nsamp,datatype);
		/* this will fill a gaps at the front or end of a trace with
		zeros*/
		if(trdata[nsamp-1] >= (g->fill))
		{
			i=nsamp-1;
			while(trdata[i] >= (g->fill))
			{
				trdata[i] = (Trsample)0.0;
				--i;
			}
		}
		if(trdata[0] >= (g->fill))
		{
			i0=0;
			while(trdata[i0] >= (g->fill))
			{
				trdata[i0] = (Trsample)0.0;
				++i0;
			}
 

		}
		else
		{
			i0 = 1;
		}
		/* This is the repair for negative clips.  We start
		at one or we can induce a seg fault, but this means
		start transients are possible.  I judged this not
		worth messing with.  Note this assumes that g->fill
		is a positive number.  All the examples in gaps.pf are.*/
		for(i=i0;i<nsamp;i++)
		{
			if(trdata[i] >= (g->fill))
			{
				if(trdata[i-1] < 0.0)
				{
					while((trdata[i]>=(g->fill)) && (i<nsamp))
					{
						trdata[i]=(Trsample)((g->lower));
						++i;
					}
				}
				else
				{
					while((trdata[i]>=(g->fill)) && (i<nsamp))
						++i;
				}
			}
		}
	}
}
Beispiel #2
0
int main (int argc, char **argv) {
	int             c,
                    errflg = 0;
    Dbptr      db, tr;
    char       *database,*outfile, *pfname=0;
    Flags	   flags ;
    Pf          *pf,*pf_def,*pf_sta=NULL,*pf_stas;
    Tbl		   *input;
    char	   *start, *stop, *triggertimestring=NULL ;
    char	   *subset=0 ;
    long	    nrecords,nsamp1 ;
	int 		duration,nframes,sampsperframe;
	double		tstart, tstop, triggertime=0;
	char 		sta[STA_LEN],sta1[STA_LEN];
	char 		chan[STA_LEN],chan1[STA_LEN];
	double 		samprate,samprate1,t1,t2;
	FILE 			*fout;
	size_t			nw;
	unsigned char *hdrbuf=malloc(2040);
	unsigned char *framebuf=malloc(32);
	unsigned char *tagbuf=malloc(16);
	unsigned short cksum;
	unsigned char wfarr[3 * 12 * 100]; /*1000sps * 0.1 sec * 12 chan * 3bytes*/
	int sampindex=0;

	K2EvtFile *myhdr=malloc(2040);
	K2EvtTag *mytag=malloc(sizeof(K2EvtTag));
	K2EvtFrame *myframe=malloc(sizeof(K2EvtFrame));
	float *data[12] ;
	unsigned short channelBitmap=0;
	int	pf_serialno,pf_sensortype;
	double pf_sensitivity, pf_fullscale, pf_lat, pf_lon, pf_elev;

    memset ( &flags, 0, sizeof(flags)); 
    elog_init ( argc, argv ) ; 


    while ((c = getopt (argc, argv, "do:p:s:t:v")) != -1) {
		switch (c) {

			case 'd':
				flags.display = 1 ; 
				break ; 

			case 'p':
				pfname= optarg ;
				break;

			case 's':
				subset = optarg ; 
				break ;

			case 't':
				triggertimestring = optarg ; 
				break ;

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

			default:
				errflg++;
				break ;
		}
    }

    if (errflg || argc-optind != 4)
		usage ();

	if (pfname==NULL) {
		pfname=Program_Name;
	}
    if (pfread (pfname, &pf) != 0)
		die (0, "Can't read parameter file %s\n",pfname);

	database = argv[optind++];
	outfile = argv[optind++];
	start = argv[optind++];
	stop = argv[optind++];
	tstart=str2epoch(start);
	tstop=str2epoch(stop);
	tstart=ceil(tstart);	/* make sure we have second boundaries, 
							   this also makes sure we have a integer number of frames */
	tstop=floor(tstop);
	duration=tstop - tstart;
    if ( dbopen(database, "r", &db) ) { 
        die ( 0, "Can't open database %s", database ) ;
    }

	input = pfget_tbl (pf, "view" ) ;
  	db = dbprocess ( db, input, 0 ) ;

	if (subset) {
		db=dbsubset(db,subset,0);
	}

    tr = dbinvalid() ;
    if ( trload_css ( db, start, stop, &tr, 0, 0 ) ) { 
		die ( 1, "trload_css failed" ) ; 
    }

    if ( trsplit(tr, 0, 0) ) { 
		complain ( 0, "trsplit failed" ) ; 
    }

    if ( trsplice(tr, 0, 0, 0) ) { 
		complain ( 0, "trsplice failed" ) ; 
    }

    if ( flags.display ) { 
		trdisp (tr, "will try to convert this stuff to evt") ;
    }
	tr.record=0;
	dbgetv(tr,0,"time",&t1,"endtime",&t2,"sta",sta1,"chan",chan1,"samprate",&samprate1,"nsamp",&nsamp1,NULL);
	samprate1=round(samprate1);
	

	dbquery ( tr, dbRECORD_COUNT, &nrecords ) ; 
	if (nrecords > 12) {
		printf("will only use the first 12 channels, consider modifying the subset...");
		nrecords=12;
	}
	for ( tr.record = 0 ; tr.record < nrecords ; tr.record++ ) { 
		double ts,te;
		dbgetv(tr,0,"time",&ts,"endtime",&te,"samprate",&samprate,"sta",sta,"chan",chan,NULL);
		samprate=round(samprate);
		if (t1 != ts || t2 != te) {
			die ( 0, "this simplistic version only works with 101% correct times and/or subsets, sorry..." ) ;
		}	
		if (strcmp(sta,sta1) !=0) {
			die ( 0, "%s <=> %s this simplistic version only works with ONE station, but the subset left more",sta,sta1 ) ;
		}
		if (samprate != samprate1) {
			die ( 0, "all channels in a K2-EVT File MUST have the same samplerate!" );
		}
	}

	newFileHeader(&myhdr, pf, sta);

	if (parse_param (pf, "sta_defaults", P_ARRPF, 1, &pf_def) < 0) {
		elog_die (0, "error parsing array sta_defaults.\n");
	}
	if (parse_param (pf, "sta_params", P_ARRPF, 1, &pf_stas) < 0) {
		elog_die (0, "error parsing array sta_params.\n");
	}
	if (parse_param (pf_stas, sta, P_ARRPF, 0, &pf_sta) < 0) {
		elog_die (0, "error parsing sta_params{%s}\n.",sta);
	}

	if (parse_param(pf_def,"sensortype",P_LINT,1,&pf_sensortype)< 0 ) {
		        elog_die (0, "error parsing default sensortype.\n");
	}
	if (parse_param(pf_def,"serialno",P_LINT,1,&pf_serialno)< 0 ) {
		        elog_die (0, "error parsing default serialno.\n");
	}
	if (parse_param(pf_def,"sensitivity",P_DBL,1,&pf_sensitivity)< 0 ) {
		        elog_die (0, "error parsing default sensitivity.\n");
	}
	if (parse_param(pf_def,"fullscale",P_DBL,1,&pf_fullscale)< 0 ) {
		        elog_die (0, "error parsing default fullscale.\n");
	}
	if (parse_param(pf_def,"lat",P_DBL,1,&pf_lat)< 0 ) {
		        elog_die (0, "error parsing default lat.\n");
	}
	if (parse_param(pf_def,"lon",P_DBL,1,&pf_lon)< 0 ) {
		        elog_die (0, "error parsing default lon.\n");
	}
	if (parse_param(pf_def,"elev",P_DBL,1,&pf_elev)< 0 ) {
		        elog_die (0, "error parsing default elev.\n");
	}
	if (pf_sta==NULL) {
		elog_notify (0, "can't parse array sta_params{%s}, will use defaults\n.",sta);
		pf_sta=pf_def;

	} else {
		if (parse_param(pf_def,"sensortype",P_LINT,0,&pf_sensortype)< 0 ) {
					elog_die (0, "error parsing sensortype.\n");
		}
		if (parse_param(pf_sta,"serialno",P_LINT,0,&pf_serialno)< 0 ) {
					elog_die (0, "error parsing serialno.\n");
		}
		if (parse_param(pf_sta,"sensitivity",P_DBL,0,&pf_sensitivity)< 0 ) {
					elog_die (0, "error parsing sensitivity.\n");
		}
		if (parse_param(pf_sta,"fullscale",P_DBL,0,&pf_fullscale)< 0 ) {
					elog_die (0, "error parsing fullscale.\n");
		}
		if (parse_param(pf_sta,"lat",P_DBL,0,&pf_lat)< 0 ) {
					elog_die (0, "error parsing lat.\n");
		}
		if (parse_param(pf_sta,"lon",P_DBL,0,&pf_lon)< 0 ) {
					elog_die (0, "error parsing lon.\n");
		}
		if (parse_param(pf_sta,"elev",P_DBL,0,&pf_elev)< 0 ) {
					elog_die (0, "error parsing elev.\n");
		}
	}
	myhdr->rw_stream.sps=samprate;		/* sampling rate */
	myhdr->rw_stream.preEvent=1;	/* in seconds */
	myhdr->rw_stream.postEvent=5;	/* in seconds */
	myhdr->rw_stream.minRunTime=6;	/* in seconds */
	myhdr->ro_stream.duration=duration;
	myhdr->ro_stream.nscans=duration* 10;
	myhdr->ro_stream.startTime=epoch2k2time(t1);
	myhdr->ro_stream.startTimeMsec=0;
	int ttms=0;
	if (triggertimestring) {
		triggertime=str2epoch(triggertimestring);
		ttms=remainder(triggertime,1.0 ) * 1000.0; 
		triggertime=epoch2k2time(triggertime);
	} else {
		triggertime=epoch2k2time(t1)+5;
		ttms=0;
	}
	myhdr->ro_stream.triggerTime=triggertime;
	myhdr->ro_stream.triggerTimeMsec=ttms;
	myhdr->rw_misc.nchannels=nrecords;
	for (int channo=0;channo< nrecords;channo++) {
		myhdr->rw_channel[channo].sensitivity=pf_sensitivity;	
		myhdr->rw_channel[channo].sensitivity=pf_fullscale;	
	}
	myhdr->rw_misc.elevation=pf_elev;		/* meters above sea level */
	myhdr->rw_misc.latitude=pf_lat;			/* degrees north */
	myhdr->rw_misc.longitude=pf_lon;		/* degrees east */

	nframes=duration * 10;
	myhdr->ro_stream.duration=nframes;
	myhdr->ro_stream.nscans=duration*samprate;

	channelBitmap=chanbitmap(nrecords);

	for ( tr.record = 0 ; tr.record < nrecords ; tr.record++ ) { 
		unsigned long i ; 
		int nsamp;
		char chan[7];
		unsigned long minoffset=0;
		unsigned long maxoffset=0;
		int	max=INT_MIN;
		int min=INT_MAX;
	    dbgetv(tr, 0, "chan",chan,"data", &data[tr.record], "nsamp", &nsamp, NULL ) ; 
	    for ( i=0 ; i<nsamp ; i++ ) { 
			if (data[tr.record][i] > max) {
				max=data[tr.record][i];
				maxoffset=i;
			}
			if (data[tr.record][i] < min) {
				min=data[tr.record][i];
				minoffset=i;
			}
			
	    }
		myhdr->ro_channel[tr.record].maxPeak=max;
		myhdr->ro_channel[tr.record].maxPeakOffset=maxoffset;
		myhdr->ro_channel[tr.record].minPeak=min;
		myhdr->ro_channel[tr.record].minPeakOffset=minoffset;
		memcpy(myhdr->rw_channel[tr.record].id,chan,K2EVT_CHANNEL_ID_LENGTH);
	}
	for ( tr.record = 0 ; tr.record < nrecords ; tr.record++ ) { 

	}

	newTag(&mytag,0, 2040, 0, 128,1234);
	encodek2header(hdrbuf,myhdr);
	cksum=k2_checksum(hdrbuf,2040);
	
	mytag->length=2040;/*header size*/
	mytag->dataLength=0;
	mytag->checksum=cksum;
	encodek2tag(tagbuf,mytag);
	fout=fopen(outfile,"w+");
	nw=fwrite(tagbuf,16,1,fout);
	nw=fwrite(hdrbuf,2040,1,fout);

	
	double t=t1 ;
	double k2t=round(epoch2k2time(t));
	newFrameHeader(&myframe,128,(sampsperframe*3*nrecords)+32, k2t);
	sampsperframe=TIME2SAMP(0,samprate,0.1);/*samples per frame*/
	
	for (int fn=0;fn < nframes;fn++) {
		cksum=0;
		sampindex=0;
		for (int s=0;s<sampsperframe;s++) {
			long val;
			unsigned char buf[4];
			for ( int channo = 0 ; channo < nrecords ; channo++ ) { 
				int index=((fn*sampsperframe) + s);
				val=round(data[channo][index]);
				/*debugging...*/
				//val=66051;/*0x010203*/
				memcpy(&buf,&val,4);
				val <<=8;
#ifdef WORDS_BIGENDIAN
				cksum+=buf[1];
				cksum+=buf[2];
				cksum+=buf[3];
				wfarr[sampindex++]=buf[1];
				wfarr[sampindex++]=buf[2];
				wfarr[sampindex++]=buf[3];
#else
				cksum+=buf[2];
				cksum+=buf[1];
				cksum+=buf[0];
				wfarr[sampindex++]=buf[2];
				wfarr[sampindex++]=buf[1];
				wfarr[sampindex++]=buf[0];
#endif
			}
		}

		mytag->checksum=cksum;
		mytag->length=32;/*header size*/
		mytag->dataLength=sampsperframe * nrecords * 3;
		myframe->frameSize=(sampsperframe*3*nrecords)+32;
		myframe->blockTime=round(k2t);
		myframe->msec=fmod(k2t,1.0) * 1000;
		myframe->channelBitMap=channelBitmap;
		
		encodek2Frame(framebuf,myframe);
		mytag->checksum+=k2_checksum(framebuf,32);
		encodek2tag(tagbuf,mytag);
		k2t+=0.1;
		//k2t=round((k2t+0.1)*10.0)/10.0;
		nw=fwrite(tagbuf,1,16,fout);
		if (nw!= 16) {
			die(0,"could not write file tag, wrote %d bytes instead of 16",nw);
		}
		nw=fwrite(framebuf,32,1,fout);
		nw=fwrite(&wfarr, 1,sampsperframe * 3 * nrecords, fout);
	}
	
	
	fclose(fout);

    tr.table = dbALL ;
    trfree(tr) ;
    pffree(pf) ; 
    return 0;
}
Tbl *dbload_arrival_table(Dbptr db,int row_start,int row_end,
	Arr *stations, Arr *arrphase)
{
	Arrival *a;
	char *prog="dbform_arrival_table";
	Tbl *t;

	/* Values set by dbgetv from row of view */
	char staname[12];
	double time, deltat;
	char phase_name[10];
	char timedef[2];
	

	t = newtbl(0);

	for(db.record=row_start;db.record<row_end;++db.record)
	{
		a = (Arrival *) malloc(sizeof(Arrival));
		if(a == NULL)
				die(1,"%s:  Cannot malloc Arrival structure\n",
					prog);
                InitializeResidual(&(a->res));
		if((dbgetv( db, 0,
			"arid",&(a->arid),
			"sta",staname,
			"assoc.phase",phase_name,
			"arrival.time",&time,
			"arrival.deltim",&deltat,
			"timedef",timedef,
			NULL )) == dbINVALID) die(1,"%s:  dbgetv error\n",prog);

		/* Added to skip arrivals with timedef set to turn off */
		if(!strcmp(timedef,"n"))
		{
			free(a);
			continue;
		}

		a->sta = (Station *) getarr(stations,staname);
		/* This error would be fatal for the relocate program, but
		this function might be used for other interfaces to this
		code so we only make it a warning */
		if(a->sta == NULL)
		{
			complain(1,"%s:  Cannot find coordinates for station %s\n%s phase arrival for this station skipped\n",
				prog, staname, phase_name);
			free(a);
			continue;
		}				
		a->time = time;
		a->phase = (Phase_handle *) getarr(arrphase,phase_name);
		if(a->phase == NULL)
		{
			complain(1,"%s:  Don't know how to handle phase %s\nArrival at %s at time %f skipped\n",
				prog,phase_name,staname,time);
			free(a);
			continue;
		}
		/* This assumes nonset values of the uncertainty in an arrival
		table are returned as a negative number.  Because how one 
		defines a nonset value in a database is variable, this could
		produce problems if this were changed */
		a->deltat = deltat;
		if( (a->deltat) <= 0.0 ) a->deltat = (double)a->phase->deltat0;
                pushtbl(t,a);
	}
	return(t);
}
/* Input routine for db records for orbgenloc.  

Arguments:
orb - input orb 
dbtmp - temporary database used by orbpkt2db
hyp - returned data structure (see orbgenloc.h)
last_pktid - if nonzero, call orbseek to start at that location
opt - orbgenloc control structure (see orbgenloc.h)


Returns:

-1 = error, data returned is invalid
0 = aok
1 = inconsistency error.  Data are certainly incomplete and should
be ignored.

IMPORTANT:  this routine mallocs a single block of memory to 
hold the hyp->assocs structure.  This MUST be freed externally.

*/
int
orb_arrivals_in (int orb, Dbptr dbtmp, ORB_Hypocenter *hyp, 
int *last_pktid, RTlocate_Options opt)

{
	int pktid, nbytes, bufsize=0;
	char *packet=NULL;
	char srcname[64];
	double time;
	Dbptr db;
	char *table_name;
	int evid, orid, arid, prefor;
	char auth[64];
	int n;
	int number_skipped;

	if (*last_pktid > -1) orbseek (orb, *last_pktid);

	/* The algorithm here is to the following sequence:
	(1)  hunt for a db packet that is an event record.
	(2)  if the event record is auth=orbassoc, start processing, otherwise
	     ignore it.
	(3)  next hunt for an origin record from orbassoc skipping any
	     other embedded origin records (needed in case other locators 
	     are running)
	(4)  Then grab interleaved assoc->arrival rows.  The algorithm 
	     is smart and hunts for an arrival that matches the arid 
	     of the previous assoc record skipping any other db records
	     that do not match.  

	Important assumptions of this are that only one process is emitting
	assoc records into the orb. In addition, this program will block
	and wait forever if an error causes a missing arrival row to never
	appear that has an arid matching a previous output assoc row.  
	We may need a timeout or skip count parameter to avoid this
	potential pitfall.  
	*/

	/* This loop is part (1) of the algorithm */
	while (1) {
		if(orbreap (orb, &pktid, srcname, &time, 
					&packet, &nbytes, &bufsize)) 
		{
			elog_log(0,"orbreap error at packet id %d\nContinuing\n",pktid);
			continue;
		}
		if (strncmp(srcname, "/db/", 4)) continue;
		db = orbpkt2db (packet, nbytes, dbtmp);
		dbquery (db, dbTABLE_NAME, &table_name);
		if (strcmp(table_name, "event")) continue;
		if (dbgetv (db, 0,
				"auth", hyp->auth,
				"evid", &(hyp->evid),
				"prefor", &prefor,
				0) == dbINVALID) {
			elog_log(0, "orbin: dbgetv() error.\n");
			return (-1);
		}
		if (strcmp(hyp->auth, "orbassoc")) continue;
		*last_pktid = pktid;

		/* This is part (2) */
		while (1) {
			orbreap (orb, &pktid, srcname, &time, 
					&packet, &nbytes, &bufsize);
			if (strncmp(srcname, "/db/", 4)) continue;
			db = orbpkt2db (packet, nbytes, dbtmp);
			dbquery (db, dbTABLE_NAME, &table_name);
			if (strcmp(table_name, "origin")) continue;
			if (dbgetv (db, 0,
					"auth", auth,
					"evid", &evid,
					"orid", &(hyp->orid),
					"nass", &(hyp->nass),
					"ndef", &(hyp->ndef),
					"time", &(hyp->time),
					"lat", &(hyp->lat),
					"lon", &(hyp->lon),
					"depth", &(hyp->depth),
					0) == dbINVALID) {
				elog_log(0, "orbin: dbgetv() error.\n");
				return (-1);
			}
			if (strcmp(auth, "orbassoc")) continue;
			if (evid != hyp->evid) continue;
			if (prefor > 0 && prefor != hyp->orid) continue;
			if (hyp->assocs == NULL || hyp->nass > hyp->assocs_size) {
				if (hyp->assocs) free (hyp->assocs);
				hyp->assocs = (Association *) malloc (hyp->nass*sizeof(Association));
				if (hyp->assocs == NULL) {
					elog_log(1, "orbin: malloc() error.\n");
					return (-1);
				}
				hyp->assocs_size = hyp->nass;
			}

			/* This is parts (3) and (4) for assoc->arrival */
			n = 0;
			while (1) {
				orbreap (orb, &pktid, srcname, &time, 
						&packet, &nbytes, &bufsize);
				if (strncmp(srcname, "/db/", 4)) continue;
				db = orbpkt2db (packet, nbytes, dbtmp);
				dbquery (db, dbTABLE_NAME, &table_name);
				if (strcmp(table_name, "assoc")) continue;
				if (dbgetv (db, 0,
						"orid", &orid,
						"arid", &(hyp->assocs[n].arid),
						"delta", &(hyp->assocs[n].delta),
						"seaz", &(hyp->assocs[n].seaz),
						"esaz", &(hyp->assocs[n].esaz),
						"timeres", &(hyp->assocs[n].timeres),
						"timedef", hyp->assocs[n].timedef,
						0) == dbINVALID) {
					elog_log(0, "orbin: dbgetv() error.\n");
					return (-1);
				}
				if (orid != hyp->orid) continue;
				/* This is the safe code to avoid an infinite loop */
				number_skipped = 0;
				while (number_skipped <= opt.db_record_skip_timeout) {
					orbreap (orb, &pktid, srcname, &time, 
							&packet, &nbytes, &bufsize);
					if (strncmp(srcname, "/db/", 4)) continue;
					db = orbpkt2db (packet, nbytes, dbtmp);
					dbquery (db, dbTABLE_NAME, &table_name);
					if (strcmp(table_name, "arrival")) 
					{
						++number_skipped;
						continue;
					}
					if (dbgetv (db, 0,
							"arid", &arid,
							"time", &(hyp->assocs[n].time),
							"sta", hyp->assocs[n].sta,
							"chan", hyp->assocs[n].chan,
							"iphase", hyp->assocs[n].iphase,
							0) == dbINVALID) {
						elog_log(0, "orbin: dbgetv() error.\n");
						return (-1);
					}
					if (arid == hyp->assocs[n].arid) break;
				}
				if(number_skipped >= opt.db_record_skip_timeout) 
				{
					elog_log(0,"Record skipping limit reached while hunting for arrival row to match assoc row.\nResynching\nOne or more events were probably skipped\n");
					return(1);
				}
				n++; 
				if (n >= hyp->nass) break;
			}
			return (0);
		}
	}
}
Beispiel #5
0
int
grdb_sc_loadcss (Dbptr dbin, char *net_expr, char *sta_expr, char *chan_expr, double tstart, double tend,
		 int coords, int ir, int orient, Dbptr *dbscgr, Dbptr *dbsc)

/*
Dbptr            dbin;
char *                 net_expr;
char *                           sta_expr;
char *                                     chan_expr;
double                                                tstart, tend;
int              coords, ir, orient;
Dbptr *                              dbscgr;
Dbptr *                                      dbsc;
*/
{
	Dbptr dbout, db, dbout2;
	char string[1024];
	char string2[1024];
	char sta_wfdisc[32], chan_wfdisc[32];
	int i, j, n, sensor=0, ok;
	Tbl *pat1, *pat2;
	Tbl *sortfields, *groupfields;
	FILE *file;
	Response *resp;

	/* Subset the wfdisc by station-channel-time sifters. */

	dbout = dblookup (dbin, 0, "wfdisc", 0, 0);
	strcpy (string, "");
	if (sta_expr) {
		strcpy (string, "( ");
        	sprintf (string2, "sta =~ /%s/", sta_expr);
        	strcat (string, string2);
	}
	if (chan_expr) {
		if (string[0]) strcat (string, " && ");
		else strcpy (string, "( ");
        	sprintf (string2, "chan =~ /%s/", chan_expr);
        	strcat (string, string2);
	}
	if (tstart != 0.0 || tend != 0.0) {
		if (string[0]) strcat (string, " && ");
		else strcpy (string, "( ");
        	sprintf (string2, "(time < %.5f && endtime > %.5f)", tend, tstart);
        	strcat (string, string2);
	}
	if (string[0]) {
		strcat (string, " )");
		dbout = dbsubset (dbout, string, 0);
	}
        dbquery (dbout, dbRECORD_COUNT, &n);
        if (n < 1) {
		register_error (0, "grdb_sc_loadcss: No wfdisc rows to process.\n");
		return (-1);
        }

        /* Make the necessary joins and check for completeness. */

        if (coords) {
        	db = dblookup (dbin, 0, "site", 0, 0);
        	dbout = dbjoin (dbout, db, 0, 0, 1, 0, 0);
        	dbquery (dbout, dbRECORD_COUNT, &n);
        	if (n < 1) {
			register_error (0, "grdb_sc_loadcss: No data rows to process.\n");
			return (-1);
        	}
        	for (dbout.record=0; dbout.record<n; dbout.record++) {
        		if (dbgetv (dbout, 0, "wfdisc.sta", sta_wfdisc,
        				"wfdisc.chan", chan_wfdisc,
        				"site.sta", string, 0) == dbINVALID) {
			    register_error (0, "grdb_sc_loadcss: dbgetv() error while checking site.\n");
			    return (-1);
			}
        		if (coords > 1 && strcmp(string, sta_wfdisc)) {
        			register_error (0, "grdb_sc_loadcss: Cannot find site parameters for %s %s.\n", 
        									sta_wfdisc, chan_wfdisc);
        			return (-1);
        		}
        	}
        }
        if (ir) {
        	db = dblookup (dbin, 0, "sensor", 0, 0);
        	dbout = dbjoin (dbout, db, 0, 0, 1, 0, 0);
        	dbquery (dbout, dbRECORD_COUNT, &n);
        	if (n < 1) {
			register_error (0, "grdb_sc_loadcss: No data rows to process.\n");
			return (-1);
        	}
        	for (dbout.record=0; dbout.record<n; dbout.record++) {
        		if (dbgetv (dbout, 0, "wfdisc.sta", sta_wfdisc,
        				"wfdisc.chan", chan_wfdisc,
        				"sensor.sta", string, 0) == dbINVALID) {
			    register_error (0, "grdb_sc_loadcss: dbgetv() error while checking sensor.\n");
			    return (-1);
			}
        		if (ir > 1 && strcmp(string, sta_wfdisc)) {
        			register_error (0, "grdb_sc_loadcss: Cannot find sensor parameters for %s %s.\n", 
        									sta_wfdisc, chan_wfdisc);
        			return (-1);
        		}
        	}
        	sensor = 1;
        	db = dblookup (dbin, 0, "instrument", 0, 0);
        	dbout = dbjoin (dbout, db, 0, 0, 1, 0, 0);
        	dbquery (dbout, dbRECORD_COUNT, &n);
        	if (n < 1) {
			register_error (0, "grdb_sc_loadcss: No data rows to process.\n");
			return (-1);
        	}
        	for (dbout.record=0; dbout.record<n; dbout.record++) {
        		if (dbgetv (dbout, 0, "wfdisc.sta", sta_wfdisc,
        				"wfdisc.chan", chan_wfdisc,
        				"sensor.inid", &j,
        				"instrument.insname", string2,
        				"instrument.inid", &i, 0) == dbINVALID) {
			    register_error (0, "grdb_sc_loadcss: dbgetv() error while checking instrument.\n");
			    return (-1);
			}
        		if (ir > 1 && (i != j)) {
        			register_error (0, "grdb_sc_loadcss: Cannot find instrument parameters for %s %s.\n", 
        									sta_wfdisc, chan_wfdisc);
        			return (-1);
        		}
        		if (i >= 0) {
				if (resp_arr == NULL) {
					resp_arr = newarr (0);
					if (resp_arr == NULL) {
        					register_error (0, "grdb_sc_loadcss: newarr() error.\n");
        					return (-1);
					}
				}
				dbextfile (dbout, "instrument", string);
				resp = (Response *) getarr (resp_arr, string);
				if (resp == NULL) {
					file = fopen (string, "r");
					if (file == NULL) {
						if (ir > 1) {
        						register_error (1, "grdb_sc_loadcss: fopen('%s') error.\n", string);
        						return (-1);
						}
					} else {
						if (read_response (file, &resp)) {
        						register_error (0, "grdb_sc_loadcss: read_response('%s') error.\n", string);
        						return (-1);
						}
						fclose (file);
						resp->insname = strdup(string2);
					}
					setarr (resp_arr, string, resp);
				}
			}
        	}
        }
        if (orient) {
        	ok = 1;
        	db = dblookup (dbin, 0, "sitechan", 0, 0);
        	dbout2 = dbjoin (dbout, db, 0, 0, 1, 0, 0);
        	dbquery (dbout2, dbRECORD_COUNT, &n);
        	if (n < 1) {
        		ok = 0;
        	} else {
        		for (dbout2.record=0; dbout2.record<n; dbout2.record++) {
        			dbgetv (dbout2, 0, "wfdisc.sta", sta_wfdisc,
        				"wfdisc.chan", chan_wfdisc,
        				"sitechan.sta", string, 0);
        			if (strcmp(string, sta_wfdisc)) {
        				ok = 0;
        				break;
        			}
        		}
		}
		if (ok) {
			dbout = dbout2;
		} else {
			if (!sensor) {
        			db = dblookup (dbin, 0, "sensor", 0, 0);
        			dbout = dbjoin (dbout, db, 0, 0, 1, 0, 0);
        			dbquery (dbout, dbRECORD_COUNT, &n);
        			if (n < 1) {
					register_error (0, "grdb_sc_loadcss: No data rows to process.\n");
					return (-1);
        			}
        			for (dbout.record=0; dbout.record<n; dbout.record++) {
        				if (dbgetv (dbout, 0, "wfdisc.sta", sta_wfdisc,
        						"wfdisc.chan", chan_wfdisc,
        						"sensor.sta", string, 0) == dbINVALID) {
			    			register_error (0, "grdb_sc_loadcss: dbgetv() error while checking sensor.\n");
			    			return (-1);
					}
        				if (orient > 1 && strcmp(string, sta_wfdisc)) {
        					register_error (0, "grdb_sc_loadcss: Cannot find sensor parameters for %s %s.\n", 
        											sta_wfdisc, chan_wfdisc);
        					return (-1);
        				}
        			}
			}
        		db = dblookup (dbin, 0, "sitechan", 0, 0);
        		pat1 = newtbl(1);
        		if (pat1 == NULL) {
        			register_error (0, "grdb_sc_loadcss: newtbl() error.\n");
        			return (-1);
        		}
        		pat2 = newtbl(1);
        		if (pat2 == NULL) {
        			register_error (0, "grdb_sc_loadcss: newtbl() error.\n");
        			return (-1);
        		}
        		settbl (pat1, 0, strdup("sensor.chanid"));
        		settbl (pat2, 0, strdup("sitechan.chanid"));
        		dbout = dbjoin (dbout, db, &pat1, &pat2, 1, 0, 0);
        		freetbl (pat1, free);
        		freetbl (pat2, free);
        		dbquery (dbout, dbRECORD_COUNT, &n);
        		if (n < 1) {
				register_error (0, "grdb_sc_loadcss: No data rows to process.\n");
				return (-1);
        		} else {
        			for (dbout.record=0; dbout.record<n; dbout.record++) {
        				if (dbgetv (dbout, 0, "wfdisc.sta", sta_wfdisc,
        					"wfdisc.chan", chan_wfdisc,
        					"sitechan.sta", string, 0) == dbINVALID) {
			    		   register_error (0, "grdb_sc_loadcss: dbgetv() error while checking sitechan.\n");
			    		   return (-1);
					}
        				if (orient > 1 && strcmp(string, sta_wfdisc)) {
        					register_error (0, "grdb_sc_loadcss: Cannot find sitechan parameters for %s %s.\n", 
        											sta_wfdisc, chan_wfdisc);
        					return (-1);
        				}
        			}
			}
		}
        }

        /* Sort and group the output view. */

	sortfields = newtbl (3);
	if (sortfields == NULL) {
		register_error (0, "grdb_sc_loadcss: newtbl() error.\n");
		return (-1);
	}
	settbl (sortfields, 0, strdup("wfdisc.sta"));
	settbl (sortfields, 1, strdup("wfdisc.chan"));
	settbl (sortfields, 2, strdup("wfdisc.time"));
        *dbsc = dbsort (dbout, sortfields, 0, 0);
	groupfields = newtbl (2);
	if (groupfields == NULL) {
		register_error (0, "grdb_sc_loadcss: newtbl() error.\n");
		return (-1);
	}
	settbl (groupfields, 0, strdup("sta"));
	settbl (groupfields, 1, strdup("chan"));
	*dbscgr = dbgroup (*dbsc, groupfields, 0, 1);
	freetbl (sortfields, free);
	freetbl (groupfields, free);

	/* Normal exit */

	return (0);
}
void main(int argc, char **argv)
{
	Dbptr db, dbv, dbge, dbgg;
	/*ensemble_mode is primary grouping, grouping_on set if secondary on*/
	int ensemble_mode,grouping_on;
	Tbl *ensemble_keys;
	Tbl *group_keys;
	int i;
	char *pfi=NULL;
	Pf *pf,*pfo_head,*pfo_total;
	Tbl *process_list;
	int dryrun=0;
	char *sift_exp=NULL;
	int sift;
/*Attributes listed in require will abort program if missing
passthrough parameters will generate an error message but not
cause the program to abort.  Both contain pointers to Attribute_map*/
	Tbl *require,*passthrough;
	Attribute_map *amap;
	FILE *fp;
	Tbl *error_list;
	char *tag;
	int sleep_time;  

	DB2PFS_verbose=0;

/*crack the command line*/
	if(argc<3) usage();
	elog_init(argc,argv);
	if(dbopen(argv[1],"r",&db)==dbINVALID)
	{
		elog_complain(0,"dbopen failed on database %s\n",argv[1]);
		usage();
	}

	for(i=3;i<argc;++i)
	{
		if(!strcmp(argv[i],"-pf"))
		{
			++i;
			if(i>argc) usage();
			pfi=argv[i];
		}
		else if(!strcmp(argv[i],"-V"))
			usage();
		else if(!strcmp(argv[i],"-v"))
			DB2PFS_verbose=1;
		else if(!strcmp(argv[i],"-n"))
			dryrun=1;
		else if(!strcmp(argv[i],"-sift"))
		{
			++i;
			if(i>argc) usage();
			sift=1;
			sift_exp=argv[i];
		}
		else
			usage();
	}
	if(!dryrun)
	{
		fp=fopen(argv[2],"r+");
		if(fp==NULL) usage();
	}
	
	if(pfi==NULL) pfi=strdup("db2pfstream");
	if(pfread(pfi,&pf))
		elog_die(0,"Error reading parameter file %s.pf\n",pfi);
	sleep_time=pfget_int(pf,"sleep_time");
	/* The output view gets a virtual table name that tags the
	overall collection of stuff.  This comes from the parameter file
	to make this program general, BUT it must be coordinated with
	the reader code. */
	tag = pfget_string(pf,"virtual_table_name");
	if(tag==NULL)elog_die(0,"Required parameter (virtual_table_name) missing from parameter file\n");
	ensemble_mode = pfget_boolean(pf,"ensemble_mode");
	if(ensemble_mode)
	{
		ensemble_keys=pfget_tbl(pf,"ensemble_keys");
		if(ensemble_keys==NULL)
			elog_die(0,
			 "ensemble_mode is on, but no grouping keys defined\nCheck parameter file\n");
		group_keys=pfget_tbl(pf,"group_keys");
		if(group_keys==NULL)
			grouping_on = 0;
		else
		{
			if(maxtbl(group_keys)>0)
				grouping_on = 1;
			else
				grouping_on = 0;
		}
	}
	if(DB2PFS_verbose && ensemble_mode)
	{
		char sm[128];
		char *key;
		strcpy(sm,"Defining ensemble with keys: ");
		for(i=0;i<maxtbl(ensemble_keys);++i)
		{
			key=gettbl(ensemble_keys,i);
			strcat(sm,key);
		}
		elog_log(0,"%s\n",sm);
		if(grouping_on)
		{
			strcpy(sm,"Grouping ensemble with keys:  ");
			for(i=0;i<maxtbl(group_keys);++i)
			{
				key = gettbl(group_keys,i);
				strcat(sm,key);
			}
			elog_log(0,"%s\n",sm);
		}
	}

	
	/*This function calls dbprocess using a tbl from pf*/
	dbv=dbform_working_view(db,pf,"dbprocess_list");
	if(dbv.record==dbINVALID)
		elog_die(0,"dbprocess failed:  check database and parameter file parameter dbprocess_list\n");
	if(sift_exp!=NULL)dbv=dbsubset(dbv,sift_exp,0);
	/*Now we form the groupings if needed */
	if(ensemble_mode)
	{
		dbge = dbgroup(dbv,ensemble_keys,"ensemble",1);
		if(dbge.record == dbINVALID)
			elog_die(0,"dbgroup with ensemble keys failed\n");
		if(grouping_on)
		{
			dbgg = dbgroup(dbv,group_keys,"groups",2);
			if(dbgg.record == dbINVALID)
				elog_die(0,"dbgroup on secondary grouping keys failed\n");
		}
	}

/*This builds the maps of which attributes will be saved */
	require = pfget_Attribute_map(pf,"require");
	if(require==NULL)
		elog_die(0,"Error in parameter file for parameter require\n");
	passthrough = pfget_Attribute_map(pf,"passthrough");
	if(passthrough==NULL)
		elog_die(0,"Error in parameter file for parameter passthrough\n");
	/* Unfortunately, we have two different loops for ensemble mode
	 and single object mode */
	if(ensemble_mode)
	{
		int number_ensembles;
		Dbptr db_bundle_1;
		Dbptr db_bundle_2;
		int is_ensemble, ie_ensemble;
		int isg, ieg;
		int number_groups;

		pfo_head=pfnew(0);
		pfput_tbl(pfo_head,"ensemble_keys",ensemble_keys);
		if(grouping_on) pfput_tbl(pfo_head,"group_keys",group_keys);
	

		dbquery(dbge,dbRECORD_COUNT,&number_ensembles);
		if(DB2PFS_verbose) elog_log(0,"database has %d ensembles\n",
					number_ensembles);
		if(grouping_on) 
		{
			dbgg.record=0;
			dbquery(dbgg,dbRECORD_COUNT,&number_groups);
			if(DB2PFS_verbose)
			  elog_log(0,"database has %d subgroups\n",
				number_groups);
		}
		for(dbge.record=0;dbge.record<number_ensembles;
					++dbge.record)
		{
			Pf_ensemble *pfe;
			int nmembers;
			char *grp_records;
			Tbl *grplist;

			dbgetv(dbge,0,"bundle",&db_bundle_1,0);
			dbget_range(db_bundle_1,&is_ensemble,&ie_ensemble);
			nmembers = ie_ensemble-is_ensemble;
			/* pfe does not need to hold the group records
			for this application so the ngroups variable is 
			passed as 0*/
			pfe=create_Pf_ensemble(nmembers,0);
			/*Now loop through and load the array of pf's
			with parameters defined by the attribute maps*/
			for(i=0,dbv.record=is_ensemble;i<nmembers;
				++i,++dbv.record)
			{
				pfe->pf[i]=pfnew(PFARR);
				error_list=db2pf(dbv,require,pfe->pf[i]);
				if(maxtbl(error_list)>0)
				{
				    if(dryrun)
				    {
					elog_log(0,"Ensemble %d at input database view record %d lacks required attributes\n",
						dbge.record,dbv.record);
					log_error_list(error_list);
				    }
				    else
				    {
					fprintf(fp,"%s\n",END_OF_DATA_SENTINEL);
					fflush(fp);
					elog_log(0,"FATAL ERROR: ensemble %d at input database view record %d lacks required attributes\nOUTPUT DATA STREAM TRUNCATED\n",
						i,dbv.record);
					log_error_list(error_list);
					exit(-1);
				    }
				}
				freetbl(error_list,free);
				error_list=db2pf(dbv,passthrough,pfe->pf[i]);
				if(DB2PFS_verbose)
				{
					elog_log(0,"Warning:  null passthrough attributes for ensemble %d at row %d\n",
						dbge.record,dbv.record);
					log_error_list(error_list);
				}
				freetbl(error_list,free);
				pfput_boolean(pfe->pf[i],"data_valid",1);
			}
			
			if(grouping_on)
			{
				grplist=newtbl(0);
				do {
				     dbgetv(dbgg,0,"bundle",&db_bundle_2,0);
				     dbget_range(db_bundle_2,&isg,&ieg);
				     grp_records=malloc(30);
				     sprintf(grp_records,"%d %d",
					isg-is_ensemble,ieg-is_ensemble-1);
				     pushtbl(grplist,grp_records);
				     ++dbgg.record;
				}
				while (ieg<ie_ensemble);
				pfput_tbl(pfo_head,"group_records",grplist);
			}

			pfo_total=build_ensemble(1,tag,pfo_head,pfe);
			free_Pf_ensemble(pfe);
			if(!dryrun) 
			{
				pfout(fp,pfo_total);
				fprintf(fp,"%s\n",ENDPF_SENTINEL);
				fflush(fp);
			}
			pffree(pfo_total);
			if(grouping_on)freetbl(grplist,free);
		}
	}
	else
	{
	/*This is the simpler, single block mode */
		int nrecords;
		Pf *pfo;

		dbquery(dbv,dbRECORD_COUNT,&nrecords);
		pfo=pfnew(PFARR);
		for(dbv.record=0;dbv.record<nrecords;++dbv.record)
		{
			error_list=db2pf(dbv,require,pfo);
			if(maxtbl(error_list)>0)
			{
			    if(dryrun)
			    {
				elog_log(0,"Input database view at row %d lacks required parameters\n",
					dbv.record);
				log_error_list(error_list);
			    }
			    else
			    {
				fprintf(fp,"%s\n",END_OF_DATA_SENTINEL);
				fflush(fp);
				elog_log(0,"FATAL: input database view at row %d lacks required parameters\n",
					dbv.record);
				log_error_list(error_list);
				exit(-1);
			    }
			}
			freetbl(error_list,free);
			error_list=db2pf(dbv,passthrough,pfo);
			pfput_boolean(pfo,"data_valid",1);
			if(DB2PFS_verbose)
			{
				elog_log(0,"Warning:  null passthrough attributes for row %d of input database view\n",
					dbv.record);
			}
			if(!dryrun)
			{
				pfout(fp,pfo);
				fprintf(fp,"%s\n",ENDPF_SENTINEL);
			}
		}
	}
	if(!dryrun)
	{
		fprintf(fp,"%s\n",END_OF_DATA_SENTINEL);
		fflush(fp);
		sleep(sleep_time);
		fclose(fp);
	}
	exit(0);
}
Trace *
off_read_trace (Dbptr db, double tstart, double tend)

{
    char fname[1024];
    char dtype[8];
    char segtype[8];
    long foff, nsamp;
    void *data;
    Trace *trace;
    double time, endtime, samprate;
    double calib, calper;
    int isamp, jsamp, size, nbytec;
    int ret;

    dbgetv (db, 0, "time", &time, "endtime", &endtime,
            "samprate", &samprate,
            "nsamp", &nsamp, "datatype", dtype,
            "segtype", segtype, "foff", &foff,
            "calib", &calib, "calper", &calper, NULL);
    switch (dtype[0]) {
    default:
        break;
    case 'c':
        nbytec = nsamp;
        nsamp = (endtime - time)*samprate + 1.5;
        break;
    }
    isamp = (tstart - time)*samprate - 1.5;
    jsamp = (tend - time)*samprate + 1.5;
    if (isamp < 0) isamp = 0;
    if (jsamp > nsamp-1) jsamp = nsamp-1;
    nsamp = jsamp+1;
    size = atoi(&dtype[strlen(dtype)-1]);
    nsamp -= isamp;
    time += isamp/samprate;
    if (nsamp < 0) nsamp = 0;
    data = NULL;
    if (nsamp > 0) {
        if (dbfilename (db, fname) < 1) {
            fprintf (stderr, "read_trace: Unable to find input file '%s'\n",
                     fname);
            nsamp = 0;
            data = NULL;
        } else {
            switch (dtype[0]) {
            default:
                foff += isamp*size;
                if (!read_file (fname, foff, dtype, &nsamp, &data)) {
                    fprintf (stderr, "read_trace: Unable to read input file '%s'\n",
                             fname);
                    return (NULL);
                }
                break;
            case 'c':
                data = malloc (nsamp*size);
                if (data == NULL) {
                    fprintf (stderr, "read_trace: malloc() error.\n");
                    return (NULL);
                }
                dtype[0] = 's';
                ret = wf_read_idacompress (fname, foff, nbytec, isamp, nsamp, size, data);
                if (ret < 0) {
                    fprintf (stderr, "read_trace: wf_read_idacompress() error.\n");
                    free (data);
                    return (NULL);
                }
                if (ret < nsamp) nsamp = ret;
                break;
            }
        }
    }
    trace = (Trace *) malloc (sizeof(Trace));
    if (trace == NULL) {
        fprintf (stderr, "read_trace: Malloc error on Trace structure.\n");
        free (data);
        return (NULL);
    }
    trace->tstart = time;
    trace->dt = 1.0/samprate;
    trace->nsamps = nsamp;
    trace->calib = calib;
    trace->calper = calper;
    strcpy (trace->rawdata_format, dtype);
    strcpy (trace->rawdata_type, segtype);
    trace->data = NULL;
    trace->data_free = NULL;
    trace->data_malloc = 0;
    trace->raw_data = data;
    trace->rawdata_free = data;
    if (data) trace->rawdata_malloc = nsamp*size;
    else trace->rawdata_malloc = 0;
    trace->prev = NULL;
    trace->next = NULL;
    if (data) trace = (Trace *) SCV_trace_fixgaps (trace, "segment");
    return (trace);
}
Beispiel #8
0
long save_origin(Dbptr dbi, long is, long ie, int depth_fixed,
	Hypocenter h, Dbptr dbo)
{
	long orid;

	/* These are parameters copied from input db -- names = css names */
	long evid;
	long jdate;
	long grn;
	long srn;
	char etype[8];
	double mb;
	long mbid;
	double ms;
	long msid;
	double ml;
	long mlid;
	/* These obtained from this solution */

	long nass;
	long ndef;
	char dtype[2];
	char algorithm[16]="genloc-nlls";
	char auth[20];
	double lddate;
	

	/* these are intentionally left null: ndp,depdp,commid*/


	/* set but obtained directly from hypo structure 
	lat, lon, depth, time */

	dbo = dblookup(dbo,0,"origin",0,0);
	
	/* Grab what we need from the input db for copying.  Note
	that because the joins used here, each of the input db
	records have the same origin entries.  Thus, we just fetch
	stuff from row is.  */
	dbi.record = is;
	if( dbgetv(dbi,0,
		"origin.evid", &evid,
		"origin.jdate", &jdate,
		"origin.grn", &grn,
		"origin.srn", &srn,
		"origin.etype", etype,
		"origin.mb", &mb,
		"origin.mbid", &mbid,
		"origin.ms", &ms,
		"origin.msid", &msid,
		"origin.ml", &ml,
		"origin.mlid", &mlid,
				NULL) == dbINVALID)
	{
		die(1,"save_origin: dbgetv error reading origin fields of input view at record %ld\n",
				is);
	}
	nass = ie - is;
	/* ndef is potentially wrong by this calculation.  We set ndef 
	from the number of degrees of freedom in the solution + npar
	where npar is 3 when depth is fixed and 4 otherwise.  This does
	not match the real definition of ndef, especially when array 
	data are used because each arrival then then has 3 data points
	used to constrain the solution.  These is either an error in 
	my (glp) understanding of the css3.0 schema or a flaw in its 
	design.*/
	if(depth_fixed)
	{
		ndef = h.degrees_of_freedom + 3;
		strcpy(dtype,"r");
	}
	else
	{
		ndef = h.degrees_of_freedom + 4;
		strcpy(dtype,"f");
	}
	my_username(auth);
	lddate = now();
	orid = dbnextid(dbo,"orid");
	if(dbaddv(dbo,0,
                "lat",h.lat,
                "lon",h.lon,
                "depth",h.z,
                "time",h.time,
                "orid",orid,
                "evid",evid,
                "jdate",jdate,
                "nass",nass,
                "ndef",ndef,
                "grn",grn,
                "srn",srn,
                "etype",etype,
                "dtype",dtype,
                "mb",mb,
                "mbid",mbid,
                "ms",ms,
                "msid",msid,
                "ml",ml,
                "mlid",mlid,
                "algorithm",algorithm,
                "auth",auth,
                "lddate",lddate,
			NULL) == dbINVALID)
	{
		die(1,"save_origin: dbaddv error writing orid %ld\n",
				orid);
	}
	return(orid);
}
static int
autodrm_response (Dbptr db)
{

    Dbptr           dbstage;
    static Hook    *hook = 0;
    char            sta[MAX_STA_SIZE],
                    chan[MAX_CHAN_SIZE];
    double          time,
                    endtime;
    long            stageid;
    char           *s;
    Response       *response;
    Response_group *group;
    char            iunits[96],
                    ounits[96];
    char            gtype[100];
    long            i,
                    j;
    Paz            *paz;
    Fir            *fir;
    Fap            *fap;
    Fap2           *fap2;
    FILE           *file;
    double          samprate,
                    gnom,
                    gcalib;
    double          calper=0.0;
    long            decifac;
    char            dir[100],
                    dfile[100];
    char            filename[STRSZ];
    long            nmatches;
    int             errors = 0;
    Tbl            *tbl,
                   *stbl;
    double          mintime=0,
                    maxtime=0;
    char            segtype;
    static Tbl     *keys1 = 0,
                   *keys2 = 0;

    if (keys1 == 0) {
	keys1 = strtbl ("sta", "chan", "time", NULL);
	keys2 = strtbl ("sta", "chan", "time::endtime", NULL);
    }
    dbstage = dblookup (db, 0, "stage", 0, 0);
    nmatches = dbmatches (db, dbstage, &keys1, &keys2, &hook, &tbl);

    switch (nmatches) {
      case dbINVALID:
      case 0:
	dbgetv (db, 0, "sta", sta, "chan", chan, "time", &time, NULL);
	complain (0, "Can't match record for %s:%s @ %s in stage table",
		  sta, chan, s = strydtime (time));
	free (s);
	errors++;
	break;

      default:
	stbl = newtbl (maxtbl (tbl));
	for (i = 0; i < nmatches; i++) {
	    dbstage.record = (long) gettbl (tbl, i);
	    dbgetv (dbstage, 0,
		    "stageid", &stageid,
		    "time", &time,
		    "endtime", &endtime,
		    NULL);
	    if (i == 0) {
		mintime = time;
		maxtime = endtime;
	    } else {
		mintime = MAX (time, mintime);
		maxtime = MIN (endtime, maxtime);
	    }
	    settbl (stbl, stageid - 1, (char *) i);
	}
	if (maxtbl (tbl) != maxtbl (stbl)) {
	    dbgetv (db, 0, "sta", sta, "chan", chan, "time", &time, NULL);
	    complain (0, "stageid numbers for %s:%s @ %s don't add up.",
		      sta, chan, s = strydtime (time));
	    free (s);
	    errors++;
	} else {
	    errors += write_cal2 (db, mintime, maxtime, &calper);

	    for (i = 0; i < nmatches; i++) {
		j = (long) gettbl (stbl, i);
		dbstage.record = (long) gettbl (tbl, j);
		dbgetv (dbstage, 0,
			"sta", sta,
			"chan", chan,
			"time", &time,
			"endtime", &endtime,
			"stageid", &stageid,
			"decifac", &decifac,
			"samprate", &samprate,
			"gnom", &gnom,
			"gcalib", &gcalib,
			"dir", dir,
			"dfile", dfile,
			"gtype", gtype,
			"iunits", iunits,
			"ounits", ounits,
			NULL);

		if (gcalib > 0.0) {
		    gnom *= gcalib;
		} else if (gcalib < 0.0) {
		    complain (0, "gcalib = %10.3f < 0. is invalid for %s:%s @ %s.\n",
			      gcalib, sta, chan, s = strydtime (time));
		    free (s);
		    errors++;
		}
		if (*dir != '-' || *dfile != '-') {
		    long            mark;
		    dbextfile (dbstage, "stage", filename);
		    mark = elog_mark ();
		    elog_log (0, "response file is '%s'", filename);
		    if ((file = fopen (filename, "r")) == 0
			    || read_response (file, &response) < 0) {
			register_error (0,
			      "Can't read response file %s  for %s_%s @ %s",
				 filename, sta, chan, s = strydtime (time));
			free (s);
			fclose (file);
			errors++;
		    } else {
			fclose (file);
			if (response->ngroups > 1) {
			    register_error (0,
			      "stage response file %s has %d stages, not 1",
					    filename, response->ngroups);
			    errors++;
			} else {

			    group = response->groups;

			    switch (group->id) {

			      case PAZ:
				/* The normalization frequency chosen in the
				 * response file may not necessarily be the
				 * same as the one chosen by calibration
				 * table for insertion into the seed volumes.
				 * Consequently, we have to adjust the
				 * specified gnom to be correct for the seed
				 * normalization frequency.  Since the gain
				 * is
				 * 
				 * G(f) = gnom_db * A_response_file * P(f) =
				 * gnom_seed * A_seed * P(f)
				 * 
				 * We have
				 * 
				 * gnom_seed = gnom_db * A_response_file /
				 * A_seed
				 * 
				 * gnom_db is just the gnom from the stage
				 * table. A_response_file is the
				 * normalization from the response file, left
				 * in the stage structure. Below, we
				 * calculate A_seed by setting
				 * A_response_file to 1.0.
				 * 
				 */

				paz = (Paz *) group->pvt;
				for (j = 0; j < strlen (iunits); j++) {
				    iunits[j] = tolower (iunits[j]);
				}
				s = getarr (Segtype, iunits);
				if (s == 0) {
				    segtype = 'D';
				} else {
				    segtype = *s;
				}
				adwrite_paz (stageid, 0, gnom, segtype, ounits, paz);
				break;

			      case IIR:
				paz = (Paz *) group->pvt;
				for (j = 0; j < strlen (iunits); j++) {
				    iunits[j] = tolower (iunits[j]);
				}
				s = getarr (Segtype, iunits);
				if (s == 0) {
				    segtype = 'D';
				} else {
				    segtype = *s;
				}
				adwrite_paz (stageid, 1, gnom, segtype, ounits, paz);
				break;

			      case FIR:
				fir = (Fir *) group->pvt;
				errors += adwrite_fir (stageid, gnom, fir);
				break;

			      case FAP:
				fap = (Fap *) group->pvt;
				errors += adwrite_fap (stageid, ounits, fap);
				break;

			      case FAP2:
				fap2 = (Fap2 *) group->pvt;
				errors += adwrite_fap2 (stageid, ounits, fap2);
				break;


			      default:
				complain (0, "Unknown filter type %d in response file %s\n",
					  group->id, filename);
				errors++;
				break;

			    }
			}
		    }
		    elog_flush (mark, 0);
		} else {
		    char           *desc = "";

		    if (gcalib > 0.0) {
			gnom *= gcalib;
		    } else if (gcalib < 0.0) {
			complain (0, "gcalib = %10.3f < 0. is an invalid value.\n", gcalib);
			errors++;
		    }
		    if (strcmp (gtype, "digitizer") == 0
		    /* following hack for psd2db */
			    || strcmp (gtype, "sensor") == 0) {
			fprintf (stdout, "DIG2 %2ld %15.8e %11.5f %s\n",
				 stageid, gnom, samprate, desc);
		    } else if (strcmp (gtype, "amplifier") == 0) {
			/* no corners */
			fprintf (stdout, "GEN2 %2ld %c %15.8e %7.3f                 0 %s\n",
				 stageid, *ounits, gnom, calper, desc);
		    } else {
			complain (0, "Unrecognized gtype='%s' for %s:%s @ %s",
				  gtype, sta, chan, s = strydtime (time));
			free (s);
			errors++;
		    }
		}
	    }
	}
	freetbl (stbl, 0);
	break;

    }
    freetbl (tbl, 0);
    return errors;
}
MWbasis *load_multiwavelets_db(Dbptr db, Pf *pf,int *nwavelets, int *bankid)
{
	MWbasis *mwb;
	int nw;
	char *select_condition;
	Dbptr dbv;
	int nrecords;
	/* These are the attribute in the mwdisc table minus
	those returned in the argument list */

	int nsamp,foff;
	double f0,fw;
	char datatype[4],mworder[4];
	char fname[128];
	FILE *fp;
	int i,j,jj;
	
	dbv = dblookup(db,0,"mwdisc",0,0);
	if(dbv.record == dbINVALID) elog_die(0,"load_multiwavelets_db:  no mwdisc table in input database\nThese are required for multiwavelet transform\nCheck database descriptor\n");
	select_condition=pfget_string(pf,"multiwavelet_select_condition");
	if(select_condition==NULL)
		elog_die(0,"Missing required parameter string called multiwavelet_select_condition\nThis is required when loading multiwavelets from a database\n");
	dbv=dbsubset(dbv,select_condition,0);
	dbquery(dbv,dbRECORD_COUNT,&nrecords);
	if(nrecords<=0)
		elog_die(0,"load_multiwavelet_db:  no records in mwdisc match condition: %s\n",
			select_condition);
	else if (nrecords>1)
		elog_complain(0,"load_multiwavelet_db:  multiple records in mwdisc match the condition %s\nUsing first record found\n",
			select_condition);
	dbv.record=0;
	dbgetv(dbv,0,"bankid",bankid,
		"nsamp",&nsamp,
		"nwavelets",nwavelets,
		"f0",&f0,
		"fw",&fw,
		"datatype",datatype,
		"foff",&foff,
		"mworder",mworder,0);
	if(strcmp(datatype,"t4"))
		elog_die(0,"multiwavelets must be in t4 binary form\n");
	if(strcmp(mworder,"ti") || strcmp(mworder,"ts") )
	{
		if(dbextfile(dbv,0,fname)<=0)
			elog_die(0,"load_multiwavelet_db: multiwavelet basis file %s not found\n",
				fname);
		fp = fopen(fname,"r");
		if(foff>0) fseek(fp,foff,0);
		allot(MWbasis *,mwb,*nwavelets);
		for(i=0;i<*nwavelets;++i)
		{
			allot(float *,mwb[i].r,nsamp);
			allot(float *,mwb[i].i,nsamp);
			mwb[i].n=nsamp;
			mwb[i].f0=f0;
			mwb[i].fw=fw;
		}
		
		if(!strcmp(mworder,"ti"))
		{
			/* This is case for storage as complex number */
			float *buffer;
			allot(float *,buffer,2*nsamp);
			for(i=0;i<*nwavelets;++i)
			{
				if(fread(buffer,sizeof(float),2*nsamp,fp)
					!= (2*nsamp))
				{
					elog_die(0,"read error on file %s while reading wavelet %d\n",
						fname,i);
				}
				for(j=0,jj=0;j<nsamp;++j,jj+=2)
				{
					mwb[i].r[j]=buffer[jj];
					mwb[i].i[j]=buffer[jj+1];
				}
			
			}
			free(buffer);
		}
		else
		{
			for(i=0;i<*nwavelets;++i)
static int
write_cal2 (Dbptr db, double time, double endtime, double *calperp)
{
    static Dbptr    dbx = INVALID_DBPTR;
    static double   null_endtime = 0.0;
    Dbptr           dbcalibration;
    long            nmatches;
    char            sta[MAX_STA_SIZE],
                    chan[MAX_CHAN_SIZE],
                    units[16],
                    instype[16];
    double          calib,
                    calper=0;
    long            j;
    int             errors = 0;
    Tbl            *tbl;
    static Hook    *hook = 0;
    char           *ontime,
                   *offtime;
    char           *aux = "";
    char           *s,
                   *t;
    char            segtype;
    double          samprate;

    if (dbx.database == dbINVALID) {
	dbx = dblookup (db, 0, "wfdisc", 0, 0);
	dbx.record = dbNULL;
	dbgetv (dbx, 0, "endtime", &null_endtime, NULL);
	dbx.record = dbSCRATCH;
    }
    dbgetv (db, 0, "sta", sta, "chan", chan, NULL);
    dbputv (dbx, 0, "sta", sta, "chan", chan, "time", time, "endtime", endtime, NULL);

    errors += get_instype (dbx, instype, &samprate);

    dbcalibration = dblookup (db, 0, "calibration", 0, 0);
    nmatches = dbmatches (dbx, dbcalibration, 0, 0, &hook, &tbl);
    switch (nmatches) {
      case dbINVALID:
      case 0:
	dbgetv (db, 0, "sta", sta, "chan", chan, "time", &time, NULL);
	complain (0, "no matches in calibration table for %s:%s @ %s",
		  sta, chan, s = strydtime (time));
	free (s);
	break;

      default:
	dbgetv (db, 0, "sta", sta, "chan", chan, "time", &time, NULL);
	complain (0, "too many matches (%ld) in calibration table for %s:%s @ %s - %s",
	nmatches, sta, chan, s = strydtime (time), t = strydtime (endtime));
	free (s);
	free (t);
	errors++;
	/* FALLTHRU */

      case 1:
	dbcalibration.record = (long) gettbl (tbl, 0);
	dbgetv (dbcalibration, 0,
		"sta", sta,
		"chan", chan,
		"calib", &calib,
		"calper", &calper,
		"units", units,
		NULL);
	*calperp = calper;

	for (j = 0; j < strlen (units); j++) {
	    units[j] = tolower (units[j]);
	}
	s = getarr (Segtype, units);
	if (s == 0) {
	    segtype = 'D';
	} else {
	    segtype = *s;
	}
	switch (segtype) {
	  case 'A':
	    calib *= SQR (calper / (2 * M_PI));
	    break;

	  case 'V':
	    calib *= calper / (2 * M_PI);
	    break;

	  default:
	    break;
	}

	ontime = epoch2str (time, "%Y/%m/%d %H:%M");
	if (endtime == null_endtime) {
	    offtime = strdup ("");
	} else {
	    offtime = epoch2str (endtime, "%Y/%m/%d %H:%M");
	}
	fprintf (stdout, "\nCAL2 %-5.5s %-3.3s %4.4s %-6.6s %15.8e %7.3f %11.5f %s %s\n",
	 sta, chan, aux, instype, calib, calper, samprate, ontime, offtime);
	free (ontime);
	free (offtime);
	break;
    }

    freetbl (tbl, 0);
    return errors;
}
Beispiel #12
0
int
main( int argc, char **argv )
{
	int	c;
	int	errflag = 0;
	int	orb;
	int	stop = 0;
	int	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, "vVs:p:m:f:" ) ) != -1 ) {

		switch( c ) {

		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 -" );
	}

	Rrdfp = popen( command, "r+" );

	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" );
		}
	}

	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( db, (char *) &path );

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

		setarr( Rrd_files, key, path );
	}

	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 {

					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 );
			}
		}
	}
}
/* 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);
}
Beispiel #14
0
void save_assoc(Dbptr dbi, long is, long ie, long orid, char *vmodel,
	Tbl *residual,Hypocenter h, Dbptr dbo)
{
	/* These fields are copied from input assoc table */
	long arid;
	char sta[8];
	char phase[10];
	double belief;
	/* These fields are set here */
	double delta;
	double seaz;
	double esaz;
	double timeres;
	double azres;
	double slores;
	double lddate;
	double wgt;
	char timedef[2],slodef[2], azdef[2];
	
	/* intentionally ignored:  emares, commid */


	/* passed through arg list;  orid*/

	/* We use this to produce a keyed arr list of the residual 
	list passed into here as a Tbl */

	Arr *residual_array;
	long i;
	char key[40]; 

	double r, w, reswt,uxresid, uyresid;
	double stalat, stalon; 
	double ux, uy, azimuth;
	double u,phi;  /* polar form of measured slowness vector */
	double duphi;

	dbo = dblookup(dbo,0,"assoc",0,0);
	lddate = now();

	/* We build an associate array for the residual tbl keying
	each entry with a sta/phase/type key  where type is 
	set in ggnloc as time, ux, or uy.  This complication is
	needed to sort out array residuals. */
	residual_array = newarr(0);
	for(i=0;i<maxtbl(residual);++i)
	{
		char *s;
		char keysta[10], keyphase[10], keytype[5];
		s = (char *)gettbl(residual,i);
		sscanf(s,"%s %s %s",keysta,keyphase,keytype);
		/* handle S-P case by having the same residual mapped
		to each half of - phase pair */
		if(strchr(keyphase,'-'))
		{
			char *phase1,*phase2;
			/* algorithm to split phase names cloned from dbgenloc */
			phase1 = strdup(keyphase);
			phase2= strchr(phase1,'-');
			*phase2 = '\0';
			++phase2;
			sprintf(key,"%s %s %s",keysta,phase1,keytype);
			setarr(residual_array,key,s);
                        sprintf(key,"%s %s %s",keysta,phase2,keytype);
                        setarr(residual_array,key,s);
			free(phase1);
		}
		else
		{
			/* normal phases are one to one */
			sprintf(key,"%s %s %s",keysta,keyphase,keytype);
			setarr(residual_array,key,s);
		}
	}
		

	for(dbi.record=is;dbi.record < ie;++dbi.record)
	{
		char *time_residual_record;
		char *ux_residual_record,*uy_residual_record;
		if( dbgetv(dbi,0,
      	    		"assoc.arid",&arid,
          		"assoc.sta",sta,
          		"assoc.phase",phase,
          		"assoc.belief",&belief,
				NULL) == dbINVALID)
		{
		  die(1,"save_assoc: dbgetv error reading assoc fields of input view at record %ld\n",
				dbi.record);
		}
		if( dbgetv(dbi,0,
			"site.lat",&stalat,
			"site.lon",&stalon,
				NULL) == dbINVALID)
		{
		  die(1,"save_assoc: dbgetv error reading site fields of input view at record %ld\n",
				dbi.record);
		}
		/* Find the time residual record for this arrival */
		sprintf(key,"%s %s time",sta,phase);
		time_residual_record = (char *)getarr(residual_array,key);
		if(time_residual_record == NULL)
		{
			complain(1,"save_assoc:  getarr mismatch for key %s\nCannot set residual\n",key);
			timeres = TIMENULL;
			wgt = 0.0;
			strcpy(timedef,"n");
		}
		else
		{
                        /* Changed by JN to avoid gcc warning */
			/* sscanf(time_residual_record,"%*s%*s%*s%*lg%lg%lg%lg", */
			sscanf(time_residual_record,"%*s%*s%*s%*g%lg%lg%lg",
				&r,&w,&reswt);
			timeres = r;
			wgt = w*reswt;
			strcpy(timedef,"d");
		}

		sprintf(key,"%s %s ux",sta,phase);		
		ux_residual_record = (char *)getarr(residual_array,key);
		sprintf(key,"%s %s uy",sta,phase);
		uy_residual_record = (char *)getarr(residual_array,key);
                /* Corrected by JN
		if( (ux_residual_record == NULL) 
			|| (ux_residual_record == NULL))
                */
		if( (ux_residual_record == NULL) 
			|| (uy_residual_record == NULL))
		{
			/* This trick is not documented.  By setting 
			the record filed to dbNULL, and then calling dbgetv
			each of the fields will be set to their NULL value */
			dbo.record = dbNULL;
			dbgetv(dbo,0,"azres",&azres,"slores",&slores,NULL );
			strcpy(azdef,"n");
			strcpy(slodef,"n");
		}
		else
		{
		/* This gets nasty because we have to convert to polar 
		coordinates from ux, uy components */
			sscanf(ux_residual_record,"%*s%*s%*s%*g%lg",&uxresid);

			sscanf(uy_residual_record,"%*s%*s%*s%*g%lg",&uyresid);
		/* We fetch the measured slowness vector to convert */
			if( dbgetv(dbi,0,
				"arrival.slow",&u,
				"arrival.azimuth",&phi,
					NULL) == dbINVALID)
			{
		  	  die(1,"save_assoc: dbgetv error reading arrival fields of input view at record %ld\n",
				dbi.record);
			}
			/* css stores slowness in s/deg, but we use
			s/km internally here so we have to convert */

			slores = sqrt(uxresid*uxresid+uyresid*uyresid);
			slores *= KMPERDEG;

			/* this is the azimuth term */
			u /= KMPERDEG;
			duphi = ux*cos(rad(azimuth)) - uy*sin(rad(azimuth));
			duphi /= u;
			azres = deg(duphi);
			strcpy(azdef,"d");
			strcpy(slodef,"d");

		}
		dist(rad(h.lat),rad(h.lon),rad(stalat),rad(stalon),
				&delta,&esaz);
		dist(rad(stalat),rad(stalon),rad(h.lat),rad(h.lon),
				&delta,&seaz);
		delta = deg(delta);
		seaz = deg(seaz);
		esaz = deg(esaz);
			
		if(dbaddv(dbo,0,
                        "arid",arid,
                        "orid",orid,
                        "sta",sta,
                        "phase",phase,
                        "belief",belief,
                        "delta",delta,
                        "seaz",seaz,
                        "esaz",esaz,
                        "timeres",timeres,
                        "timedef",timedef,
                        "azres",azres,
                        "azdef",azdef,
                        "slores",slores,
                        "slodef",slodef,
                        "wgt",wgt,
                        "vmodel",vmodel,
                        "lddate",lddate,
			NULL ) == dbINVALID)
		{
			die(1,"save_assoc: dbaddv error writing assoc record for arid %ld\n",
				arid);
		}
	}
	freearr(residual_array,0);
}
Beispiel #15
0
Trace *
read_trace (Dbptr db, double tstart, double tend)

{
    char fname[1024];
    char dtype[8];
    char segtype[8];
    long foff, nsamp;
    void *data;
    Trace *trace;
    double time, samprate;
    double calib, calper;
    double ts, te;
    int size;
    int i, ret;

    if (dbextfile (db, "wfdisc", fname) < 1) {
        fprintf (stderr, "read_trace: Unable to find input file '%s'\n",
                 fname);
        return (NULL);
    }
    dbgetv (db, 0, "time", &time, "samprate", &samprate,
            "nsamp", &nsamp, "datatype", dtype,
            "segtype", segtype, "foff", &foff,
            "calib", &calib, "calper", &calper, NULL);

    data = NULL;
    ret = trgetwf (db, NULL, (Trsample **) &data, 0, tstart, tend,
                   &ts, &te, &nsamp, 0, 0);
    size = 4;

    switch (ret) {
    default:
    case 0:
        if (ret < 0) data = NULL;
        if (ts == 0.0 && te == 0.0) data = NULL;
        break;

    case -9: /* no data */
        clear_register (0);
        data = NULL;
        break;

    case -1:
    case -2:
    case -3:
    case -5:
    case -6:
    case -7:
    case -8:
        complain (0,
                  "read_trace: trgetwf() error.\n");
        return (NULL);
    }

    if (data == (void *) -1) {
        data = NULL;
    }

    if (data == (void *) -2) {
        clear_register (0);
        data = NULL;
    }
    trace = newtrace();
    if (trace == NULL) {
        fprintf (stderr, "read_trace: newtrace() error.\n");
        my_free (data);
        return (NULL);
    }
    trace->scv = NULL;
    trace->tstart = ts;
    trace->dt = 1.0/samprate;
    trace->nsamps = nsamp;
    trace->calib = calib;
    trace->calper = calper;
    strcpy (trace->rawdata_format, "t4");
    strcpy (trace->rawdata_type, segtype);
    strcpy (trace->input_units, "");
    strcpy (trace->output_units, "");
    trace->data = NULL;
    trace->data_free = NULL;
    trace->data_malloc = 0;
    trace->raw_data = data;
    trace->rawdata_free = data;
    if (data) trace->rawdata_malloc = nsamp*size;
    else trace->rawdata_malloc = 0;
    trace->prev = NULL;
    trace->next = NULL;
    for (i=0; i<trace->nsamps; i++) if (((float *)data)[i] < 0.9e30) break;
    if (i >= trace->nsamps) {
        trace->nsamps = 0;
        trace->raw_data = NULL;
        trace->rawdata_free = NULL;
        free (data);
    } else {
        if (data) {
            trace = (Trace *) SCV_trace_fixgaps (trace, "segment");
        }
    }
    return (trace);
}
Beispiel #16
0
int main(int argc, char **argv)
{
	char *dbin;  /* Input db name */
	char *dbout;  /* output db name */
	Dbptr db;  /* input db pointer */
	Dbptr dbo;  /* base output db pointer */
	Dbptr dbv;  /* set to view formed by join */
	char *pfin=NULL;  /* input parameter file */
	char *sift_exp;  /* sift expression for subset */
	int sift = 0;  /* default is no sift.  */
	Tbl *sortkeys;
	Tbl *joinkey1, *joinkey2;
	/*Pointers to views returned by dbgroup (keyed to origin and event
	respectively */
	Dbptr dborigin_group;
	Tbl *origin_group;  /* relation keys used in grouping*/
	long nevents;
	/* db row variables */
	long evid;
	long nrows, nrows_raw;

	int useold=0;
	Pf *pf;
	Tbl *ta,*tu;
	Tbl *reason_converged, *residual;
	Location_options o;
	Arr *arr_phase;
	int i;
	Tbl *converge_history;

	Hypocenter h0;
	Hypocenter *hypos;
	long niterations;

	char *vmodel;

	int ret_code;  /* ggnloc return code */
	double **C;   /* covariance matrix*/
	float emodel[4];  

	/* entries for S-P feature */
	long nbcs;
	Arr *badclocks;
	/* need global setting of this to handle fixed depth solutions*/
	int global_fix_depth;

	C=dmatrix(0,3,0,3);

	if(argc < 3) usage();
	dbin = argv[1];
	dbout = argv[2];
	for(i=3;i<argc;++i)
	{
		if(!strcmp(argv[i],"-pf"))
		{
			++i;
			if(i>=argc) usage();
			pfin = argv[i];
		}
		else if(!strcmp(argv[i],"-sift"))
		{
			++i;
			if(i>=argc) usage();
			sift_exp = argv[i];
			sift = 1;
		}
		else if(!strcmp(argv[i],"-useold"))
			useold = 1;
		else
			usage();
	}
	/* set default this way*/
	if(pfin == NULL) pfin = strdup("relocate");


	/* Initialize the error log and write a version notice */
	elog_init (argc, argv) ;
	cbanner("Version $Revision$ $Date$\n",
			"relocate inputdb outputdb [-pf pf -sift expression -useold]\n",
			"Gary Pavlis",
                        "Indiana University",
                        "*****@*****.**");

	/* Alway join assoc, arrival, and site.  We join site 
	to make sure station table is properly dynamic to account for
	time changes.  With this setup, the stations can even move
	around and this should still work.*/


	if(dbopen(dbin,"r",&db) == dbINVALID) 
		die(1,"Unable to open input database %s\n",dbin);
	if(dbopen(dbout,"r+",&dbo) == dbINVALID) 
		die(1,"Unable to open output database %s\n",dbout);

	dbv = dbjoin ( dblookup(db,0,"event",0,0),
		dblookup(db,0,"origin",0,0),
		0,0,0,0,0);
	if(dbv.table == dbINVALID)
		die(1,"event->origin join failed\n");
	dbv = dbjoin ( dbv, dblookup(db,0,"assoc",0,0),
			0,0,0,0,0);
	if(dbv.table == dbINVALID)
		die(1,"event->origin->assoc join failed\n");
	dbv = dbjoin ( dbv, dblookup(db,0,"arrival",0,0),
			0,0,0,0,0);
	if(dbv.table == dbINVALID)
		die(1,"event->origin->assoc->arrival join failed\n");
	/* We will explicitly set the keys for this join because it
	was found to fail sometimes */
	joinkey1 = newtbl(0);
	joinkey2 = newtbl(0);
	pushtbl(joinkey1,"arrival.sta");
	pushtbl(joinkey1,"arrival.time");
	pushtbl(joinkey2,"sta");
	pushtbl(joinkey2,"ondate::offdate");
	dbv = dbjoin ( dbv, dblookup(db,0,"site",0,0),
			&joinkey1,&joinkey2,0,0,0);
	if(dbv.table == dbINVALID)
		die(1,"event->origin->assoc->arrival->site join failed\n");

	/* Subset using sift_key if requested */
	if(sift)
	{
		dbv = dbsubset(dbv,sift_exp,0);
		if(dbv.record == dbINVALID)
			die(1,"dbsubset of %s with expression %s failed\n",
				dbin, sift_exp);
	}
	/* This keeps only the prefered origin records intact */
	dbv = dbsubset(dbv,"orid == prefor", 0);
	if(dbv.record == dbINVALID)
			die(1,"Subset to preferred origin records failed\n");

	/* First we have to run a unique key sort in the following order
	to remove redundant picks made on multiple channels.  We will
	issue a warning if the record count changes. */
	dbquery(dbv, dbRECORD_COUNT, &nrows_raw);
	sortkeys = newtbl(0);
	pushtbl(sortkeys,"evid");
	pushtbl(sortkeys,"sta");
	pushtbl(sortkeys,"phase");
	dbv = dbsort(dbv,sortkeys,UNIQUE,0);
	dbquery(dbv, dbRECORD_COUNT, &nrows);
	if(nrows != nrows_raw)
		complain(0,"Input database has duplicate picks of one or more phases on multiple channels\n\
Which picks will be used here is unpredictable\n\
%ld total picks, %ld unique\nContinuing\n", nrows_raw, nrows);

	/* This sort is the required one for the grouping that follows*/

	sortkeys = newtbl(3);
	pushtbl(sortkeys,"evid");
	pushtbl(sortkeys,"orid");
	pushtbl(sortkeys,"arrival.time");
	dbv = dbsort(dbv,sortkeys,0,0);
	if(dbv.record == dbINVALID)
		die(1,"dbsort on evid,orid,arrival.time failed\n");

	/* Set up grouping by events */
	origin_group = newtbl(0);
	pushtbl(origin_group, "evid");
	dborigin_group = dbgroup(dbv, origin_group, "origin_group",1);
	if(dborigin_group.record == dbINVALID)
		die(1,"dbgroup by origin failed\n");

	dbquery(dborigin_group,dbRECORD_COUNT,&nevents);
	elog_notify(0,"Attempting to relocate %ld events in subsetted database\n",
		nevents);
	

	/* DB is now set up correctly, now we turn to the parameter files */
	i = pfread(pfin,&pf);
	if(i != 0) die(1,"Pfread error\n");

	o = parse_options_pf (pf);
	global_fix_depth=o.fix[2];
 	arr_phase = parse_phase_parameter_file(pf);
	vmodel = pfget_string(pf,"velocity_model_name");

	/* set up minus phase for bad clock problems */
	badclocks = newarr(0);
	if(db_badclock_definition(db,pf,badclocks))
		elog_complain(0,"Warning:  problems in database definitions of bad clock time periods\n");
	pfget_badclocks(pf,badclocks);
	nbcs = cntarr(badclocks);
	if(nbcs>0) fprintf(stdout,"relocate:  bad clock feature enabled\n\n");
        /* Change by JN to output evid and orid. */
        /* fprintf(stdout,"lat lon depth time rms wrms interquartile ndata ndgf iterations\n"); */
	fprintf(stdout,"evid orid lat lon depth time rms wrms interquartile ndata ndgf iterations\n");

	/* Main loop.  We utilize the group views and loop through by 
	events */
	for(dborigin_group.record=0;
		dborigin_group.record< nevents;++dborigin_group.record)
	{
		Dbptr db_bundle;  /* db pointer returned from bundle field 
				of dborigin_group for current event */
		Arr *station_table;
		Arr *array_table;
		long is, ie; 
		long orid;  /* orid assigned relocated event in output db */

		if(dbgetv(dborigin_group,0,"evid", &evid,
			"bundle", &db_bundle,NULL ) == dbINVALID)
			complain(1,"dbgetv error for row %ld of event group\n",
				dborigin_group.record);
		dbget_range(db_bundle,&is,&ie);

		station_table = dbload_station_table(dbv,
						is,ie,pf);
		array_table = dbload_array_table(dbv,
						is,ie,pf);
		ta = dbload_arrival_table(dbv,
				is,ie,station_table, arr_phase);


		tu = dbload_slowness_table(dbv,
				is,ie,array_table, arr_phase);
		/* this actually sets up the minus phase feature for bad clocks*/
		if(nbcs)
		{
			if(minus_phases_arrival_edit(ta,arr_phase,badclocks))
				elog_complain(0,"Warning(relocate):  problems in minus_phase_arrival_edit function\n");
		}
		if(useold)
		{
			char dtype[2];
			h0 = db_load_initial(dbv,is);
			/* keep fixed depth if done before.  
			setting dbv.record here is a bit of
			a potential maintenance problem */
			dbv.record=is;
			dbgetv(dbv,0,"dtype",dtype,NULL );
			if( (!strcmp(dtype,"g")) || (!strcmp(dtype,"r")) )
				o.fix[2]=1;
			
		}
		else
			h0 = initial_locate(ta, tu, o, pf);

		ret_code = ggnloc(h0,ta,tu,o,
			&converge_history,&reason_converged,&residual);
			
		if(ret_code < 0)
		{
			complain(1,"ggnloc failed to produce a solution\n");
		}
		else 
		{
			if(ret_code > 0)
			    complain(1,"%d travel time calculator failures in ggnloc\nSolution ok\n",
				ret_code);
			
			niterations = maxtbl(converge_history);
			hypos = (Hypocenter *)gettbl(converge_history,
								niterations-1);
			predicted_errors(*hypos,ta,tu,o,C,emodel);

                        /* Next 3 calls changed by JN to output evid, orid and number_data */
			orid = save_origin(dbv,is,ie,o.fix[3],*hypos,dbo);
			evid = save_event(dbv,is,ie,orid,dbo);

			fprintf(stdout,"%ld %ld %lf %lf %lf %lf %g %g %g %d %d %ld\n",
					evid,
					orid,
					hypos->lat,hypos->lon,hypos->z,hypos->time,
					hypos->rms_raw, hypos->rms_weighted,
					hypos->interquartile,
					hypos->number_data,
					hypos->degrees_of_freedom,
					niterations);
	
			save_origerr(orid,*hypos,C,dbo);
			save_assoc(dbv,is,ie,orid,vmodel,residual,*hypos,dbo);
			/* These save genloc add on tables */
			save_emodel(orid,emodel,dbo);
			save_predarr(dbo,ta,tu,*hypos,orid,vmodel);
		}
		o.fix[2]=global_fix_depth;
		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(tu, ta);
		destroy_network_geometry_tables(station_table,array_table);
	}
	return(0);
}
Beispiel #17
0
int
main(int argc, char **argv)
{
	int             c, verbose = 0, errflg = 0;


	char           *dbname= NULL;
	Point          *poly;
	long             nvertices;

	Dbptr           db;
	long             i;
	long 		 	nrecs;
	char           *subset_expr=NULL;
	char            pname[STRSZ], closed[STRSZ];

	elog_init(argc, argv);

	for (argc--, argv++; argc > 1; argc--, argv++) {
		if (!strcmp(*argv, "-subset")) {
			argc--;
			argv++;
			if (argc < 1) {
				elog_complain(0, "Need -subset argument.\n");
				usage();
				exit(1);
			}
			subset_expr = *argv;
		} else if (!strcmp(*argv, "-v")) {
			verbose++;
		} else if (**argv != '-') {
			break;
		} else {
			 elog_complain(0, "Unrecognized argument '%s'.\n",
			 *argv); usage(); exit(1);
				usage();
				exit(1);
		}
	}
	if (argc < 1) {
		complain(0, "Need db argument.\n");
		usage();
		exit(1);
	}
	dbname = *argv;
	argc--;
	argv++;

	dbopen_database(dbname, "r", &db);
	if (db.table <0) {
		db=dblookup(db,0,"polygon",0,0);
	}
	if (subset_expr) {
		db=dbsubset(db,subset_expr,0);
	}

	dbquery(db, dbRECORD_COUNT, &nrecs);
	printf("records:%ld \n",nrecs);
	for (db.record = 0; db.record < nrecs; db.record++) {
		nvertices = readPolygon(db, &poly);
		if (nvertices > 0) {
			dbgetv(db, 0, "pname", &pname, "closed", &closed, NULL );
			printf(">\n");
			for (i = 0; i < nvertices; i++) {
				printf("%.4f %.4f\n", poly[i].lon, poly[i].lat);
			}
			if (yesno(closed) == -1 &&
			    ((poly[0].lat != poly[nvertices - 1].lat) ||
			     (poly[0].lon != poly[nvertices - 1].lon))) {
				printf("%.4f %.4f\n", poly[0].lon, poly[0].lat);
			}
		}
	}
	dbclose(db);
	return (0);
}
Beispiel #18
0
int main(int argc, char *argv[])
{
  int    j,nsta,ns,delaytype;
  double lat[MXSTA],lon[MXSTA],rx,ry;
  double reflat,reflon,kx,ky;
  double slow,baz,distance,azimuth,shift,delay[MXSTA];
  char   refsta[7],asta[7],searchExpr[80];
  char   *arrayname,*arrayfile,*dbname,*dfile;
  char   sta[MXSTA][7],chan[MXSTA][9];
  FILE   *fp;
  Dbptr  db,dba,dbs;

  arrayname = malloc(9);
  arrayfile = malloc(13);
  dbname = malloc(80);
  dfile = malloc(80);

  if (argc < 8)
  {
    printf("Usage: %s slow baz delaytype arrayname refsta dbname dfile\n",argv[0]);
    return 1;
  }

  sscanf(argv[1],"%lf",&slow);
  sscanf(argv[2],"%lf",&baz);
  sscanf(argv[3],"%d",&delaytype);
  arrayname = argv[4];
  sscanf(argv[5],"%s",refsta);
  dbname = argv[6];
  dfile = argv[7];

/*Open the array file and get array info.*/
  memcpy(arrayfile,"\0",1);
  strcpy(arrayfile,arrayname);
  strcat(arrayfile,".arr");
  if ( (fp = fopen(arrayfile,"r")) == NULL)
  {
    complain(0,"Could not open array file.\n");
    return 1;
  }

  nsta = 0;
  while(fscanf(fp, "%s %s %lf", sta[nsta],chan[nsta],&delay[nsta]) != EOF)
  {
    nsta = nsta + 1;
  }
  fclose(fp);
  printf("# of stations = %d\n",nsta);

  if (dbopen(dbname,"r",&db) < 0)
  {
    complain(0,"Could not open database.\n");
    return 1;
  }

  dbs  = dblookup(db,0,"site",0,0);

/*Find reference station and put all station coordinates relative to it.*/
  dbquery(dbs,dbRECORD_COUNT,&ns);
  for(dbs.record=0;dbs.record<ns;dbs.record++)
  {
    dbgetv(dbs,NULL,"sta",asta,"lat",&reflat,"lon",&reflon,NULL);
    if (strcmp(refsta,asta) == 0) break;
  }

  kx = slow*cos((90 - baz)/rad2dg);
  ky = slow*sin((90 - baz)/rad2dg);

  printf("computing time delays for a wave at array = %s\n",arrayname);
  printf("refsta,reflat,reflon = %s %f %f\n",refsta,reflat,reflon);
  printf("slowness(s/km), back azimuth(dg cw from north)   = %f %f\n",slow,baz);
  printf("x and y are Cartesian coordinates (+x is east; +y is north)\n");
  printf("positive delay means wave arrives later; negative means sooner\n");
  printf("output file has: station  channel  delay(s)\n");

  if ( (fp = fopen(dfile,"w")) == NULL)
  {
    complain(0,"Could not open output file.\n");
    return 1;
  }

  for (j=0;j<nsta;j++)
  {
    sprintf( searchExpr, "sta =~ /%s/",sta[j]);
    dba = dbsubset(dbs,searchExpr,NULL);
    dba.record = 0;
    dbgetv(dba,NULL,"lat",&lat[j],"lon",&lon[j],NULL);
/*  Note: dist returns distance in radians and azimuth in radians.*/
    dist(reflat/rad2dg,reflon/rad2dg,lat[j]/rad2dg,lon[j]/rad2dg,&distance,&azimuth);
    distance = distance*rad2dg*dg2km;
    rx=distance*cos(pi/2 - azimuth);
    ry=distance*sin(pi/2 - azimuth);
    shift = kx*rx+ky*ry;
    if (delaytype == 1) delay[j] = -shift + delay[j];
    if (delaytype == 0) delay[j] = -shift;
    printf("%3d %-5s %13.3f %7.2f %7.2f\n",j+1,sta[j],delay[j],rx,ry);
    fprintf(fp,"%-5s %-5s %13.3f\n",sta[j],chan[j],delay[j]);
  }

  dbclose(db);
  fclose(fp);

  return 0;
}
long readPolygon(Dbptr db, Point **Poly) {
	char fname[PATH_MAX];
	char ftype[6];
	long npoints;
	long foff;
	int pcode;
	FILE *df;

	Data dp; /* union of pointers, a pointer */
	long i;

	/*dbquery(db,dbRECORD_COUNT,&nrec);
	if (nrec != 1) {
		elog_log(0,"readPolygon: more than one row given...");
		return -1;
	}
	*/
	if (dbextfile(db,0,fname) <1) {
		elog_log(0,"readPolygon: problem finding data in %s (are dir and dfile set properly?)",fname);
		return -1;
	}
	if (is_file(fname) !=1) {
		elog_log(0,"readPolygon: file %s not found!",fname);
		return -1;
	}

	dbgetv(db,0,"ftype",&ftype,"npoints",&npoints,"foff",&foff,NULL );


	if ((pcode = polycode(ftype)) == -1) {
		elog_log(0,"readPolygon: unknown storage format %s",ftype);
		return -1;
	}
	
	*Poly = malloc((npoints+2) * sizeof(Point));
	dp.c=malloc(8 * 2 * (npoints +2 ));
	df=fopen(fname,"r");
	fseek(df,foff,0);
	
	switch (pcode) {
		case polyGSHHS:
			break;
		case polyINT:
			/*
			   fread( rawdata,1,2 * sizeof(int) * npoints,df);
			N2H4(rawdata,dp.i,2 * npoints);
			*/
			fread(dp.i, sizeof(int), npoints*2, df);
			N2H4((char *) dp.i, (char *) dp.i, 2*npoints);
			for (i=0; i< npoints; i++) {
				(*Poly)[i].lon= dp.i[i*2] / 1.0e6;
				(*Poly)[i].lat= dp.i[i*2+1] / 1.0e6;
			}
			
			break;
		case polyINTELINT:
			fread( dp.i, sizeof(int), 2*npoints, df);
			#ifdef WORDS_BIGENDIAN
				swap4(dp.i,dp.i,2 * npoints);
			#endif
			for (i=0; i< npoints; i++) {
				(*Poly)[i].lon= dp.i[i*2] / 1.0e6;
				(*Poly)[i].lat= dp.i[i*2+1] / 1.0e6;
			}
			
			break;
		case polyFLOAT:
			fread( dp.f, sizeof(float), 2*npoints, df);
			N2H4((char *)dp.f,(char *)dp.f,2 * npoints);
			for (i=0; i <npoints; i++) {
				(*Poly)[i].lon= dp.f[i*2];
				(*Poly)[i].lat= dp.f[i*2+1];
			}
			break;	
		case polyINTELFLOAT:
			fread( dp.f, sizeof(float), 2*npoints, df);
			#ifdef WORDS_BIGENDIAN
				swap4((char *)dp.f,(char *)dp.f,2 * npoints);
			#endif
			for (i=0; i <npoints; i++) {
				(*Poly)[i].lon= dp.f[i*2];
				(*Poly)[i].lat= dp.f[i*2+1];
			}
			break;	
		default:
			elog_log(0,"readPolygon: no code for storage format %s",ftype);
			free(dp.c);
			fclose(df);
			return -1;
	}
	free(dp.c);
	fclose(df);
	return npoints;
}
Beispiel #20
0
static char *
generate_sqlrow_insert( Dbptr db, char *(*createsync)(Dbptr db), long flags )
{
	void	*stk = 0;
	char	*table;
	Tbl	*fields;
	Dbvalue	dbvalue;
	char	*field;
	long	ifield;
	long	ftype;
	char	*fformat;
	char	part[STRSZ];
	char	*sync;
	char	*copy;

	if( db.record < 0 && 
	    db.record != dbSCRATCH && 
	    db.record != dbNULL ) {

		return NULL;
	}

	dbquery( db, dbTABLE_NAME, &table );
	dbquery( db, dbTABLE_FIELDS, &fields );

	pushstr( &stk, "INSERT INTO `" );
	pushstr( &stk, table );

	pushstr( &stk, "` VALUES(" );

	for( ifield = 0; ifield < maxtbl( fields ); ifield++ ) {
		
		field = gettbl( fields, ifield );

		db = dblookup( db, "", "", field, "" );

		dbquery( db, dbFIELD_TYPE, &ftype );
		dbquery( db, dbFIELD_FORMAT, &fformat );

		dbgetv( db, 0, field, &dbvalue, NULL );

		if( ifield > 0 ) {

			pushstr( &stk, ", " );
		}

		if( ! ( flags & DB2SQL_USE_DATASCOPE_NULLS ) && dbfield_isnull( db ) ) {

			pushstr( &stk, "NULL" );

			continue;
		}

		memset( part, '\0', STRSZ );

		switch( ftype ) {

		case dbSTRING:
			pushstr( &stk, "'" );
			if( strchr( dbvalue.s, '\'' ) == (char *) NULL ) {
				pushstr( &stk, dbvalue.s );
			} else {
				allot( char *, copy, 2 * strlen( dbvalue.s ) );
				strsub( dbvalue.s, "'", "\\'", copy );
				pushstr( &stk, copy );
				free( copy );
			}
			pushstr( &stk, "'" );
			break;

		case dbREAL:
		case dbTIME:
			sprintf( part, fformat, dbvalue.d );
			pushstr( &stk, part );
			break;

		case dbINTEGER:
		case dbYEARDAY:
			sprintf( part, fformat, dbvalue.i );
			pushstr( &stk, part );
			break;

		case dbDBPTR:
			sprintf( part, "%ld %ld %ld %ld", 
					dbvalue.db.database, 
					dbvalue.db.table, 
					dbvalue.db.field, 
					dbvalue.db.record );
			pushstr( &stk, part );
			break;
		}
	}

	if( ! ( flags & DB2SQL_OMIT_SYNC ) ) {

		if( createsync != (char *(*)(Dbptr db)) NULL ) {

			sync = (*createsync)( db );

		} else {

			sync = (char *) NULL;
		}

		pushstr( &stk, ", '" );

		if( sync != (char *) NULL ) {

			pushstr( &stk, sync );

		} else {

			pushstr( &stk, DB2SQL_SYNCFIELD_NULL );
		}

		pushstr( &stk, "'" );

		if( sync != (char *) NULL ) {

			free( sync );
		}
	}

	pushstr( &stk, ");\n" );

	return popstr( &stk, 1 );
}
Dbptr inWhichPolygons(Dbptr db,Point P) {
	Point *poly;
	long i;
	long nrec;
	Dbptr dbr= dblookup(db,0,"polygon",0,0);
	double lat,lon;
	Dbptr dbs;
	long npoints;
	char expr[STRSZ];
	char temp[STRSZ];
	long pid;
	int first;
	int found=0;
	char name[STRSZ];

	lat= P.lat;
	lon= P.lon;
	
	dbs=dblookup(db,0,"polygon",0,0);
/*
   Nice idea, but breaks too many programs (older versions of the polygon-schema)
   sprintf(expr,"closed=~/y/ && north >= %f && south <= %f && east >= %f && west <= %f",
   */
	sprintf(expr,"north >= %f && south <= %f && east >= %f && west <= %f",
			lat,lat,lon,lon);
	dbs=dbsubset(dbs,expr,0);
	dbquery(dbs, dbRECORD_COUNT,&nrec);
	if (nrec < 1) {
		/*
		elog_log(0,"inWhichPolygons: initial check of Bounding Box returns 0!");
		*/
		dbr=dbinvalid();
		return dbr;
	}
	first=1;
	for (i= 0; i< nrec; i++) {
		dbs.record=i;
		dbgetv(dbs,0,"pname",&name,NULL );

		if ((npoints=readPolygon(dbs,&poly))>0) {
			if (isGeographicallyInside(P,poly,npoints)) {
				found=1;
				dbgetv(dbs,0,"pid",&pid,NULL );
				if (first) {
					sprintf(expr,"pid==%ld",pid);
					first=0;
				} else {
					sprintf(temp,"|| pid==%ld",pid);
					strcat(expr,temp);
				}
			}
			free(poly);
		}
	}
	
	/*dbr=dblist2subset(dbs,list);*/
	if (found) {
		dbr=dbsubset(dbs,expr,0);
	} else {
		dbr=dbinvalid();
	}
	dbfree(dbs);
	return dbr;
}
/*  This function adds a list of attributes stored in one
row of a datascope database to a pf.  What attributes are extracted
and converted is controlled by the Attribute_map list stored
in t.  

Arguments:
	db - row of database to use to extract info to create or
		update pf.
	t - Tbl containing pointers to Attribute_map objects that
		define which attributes to extract and possible renaming in pf
	pf - destination pf object.

Returns:
	The routine returns a Tbl list of attribute names that were null
	on this database row.  This is used in dryrun mode to flag database
	problems.  IMPORTANT:  a valid Tbl is always returned.  The caller
	must free this list.  A test for now errors is maxtbl()==0.

Author:  Gary L. Pavlis
Written:  September 2002
Modified:  march 2003
Used to return only an int. It now returns a Tbl described above.
*/
Tbl *db2pf(Dbptr db, Tbl *t, Pf *pf)
{
	int i;  
	char *nullvalue;
	int iattrib, inull;
	double dattrib, dnull;
	char sattrib[128];
	Attribute_map *m;
	Dbptr dbf;
	char *bad_attrib;
	Tbl *error_list=newtbl(0);

	for(i=0;i<maxtbl(t);++i)
	{
		m = (Attribute_map *)gettbl(t,i);
		dbf=dblookup(db,0,0,m->dbname,0);
		dbquery(dbf,dbNULL,&nullvalue);
		switch(m->type)
		{
		case DBREAL:
			if(dbgetv(db,0,m->dbname,&dattrib,0)==dbINVALID)
			{
				elog_die(0,"dbgetv error for %s\n",
					m->dbname);
			}
			dnull=atof(nullvalue);
			if(dattrib==dnull)
			{
				bad_attrib=strdup(m->dbname);
				pushtbl(error_list,bad_attrib);
				break;
			}
			pfput_double(pf,m->pfname,dattrib);
			break;
		case DBTIME:
			if(dbgetv(db,0,m->dbname,&dattrib,0)==dbINVALID)
			{
				elog_die(0,"dbgetv error for %s\n",
					m->dbname);
			}
			dnull=atof(nullvalue);
			if(dattrib==dnull)
			{
				bad_attrib=strdup(m->dbname);
				pushtbl(error_list,bad_attrib);
				break;
			}
			pfput_time(pf,m->pfname,dattrib);
			break;
		case DBINT:
			if(dbgetv(db,0,m->dbname,&iattrib,0)==dbINVALID)
			{
				elog_die(0,"dbgetv error for %s\n",
					m->dbname);
			}
			inull=atoi(nullvalue);
			if(iattrib==inull)
			{
				bad_attrib=strdup(m->dbname);
				pushtbl(error_list,bad_attrib);
				break;
			}
			pfput_int(pf,m->pfname,iattrib);
			break;
		case DBSTR:
		default:
			if(dbgetv(db,0,m->dbname,sattrib,0)==dbINVALID)
			{
				elog_die(0,"dbgetv error for %s\n",
					m->dbname);
			}
			/*conversion not necessary here since dbNULL
			query returns a string for null value*/
			if(!strcmp(sattrib,nullvalue))
			{
				bad_attrib=strdup(m->dbname);
				pushtbl(error_list,bad_attrib);
				break;
			}
			pfput_string(pf,m->pfname,sattrib);
		}
	}
	return(error_list);
}
int proc_sta( Dbptr db, int nrec, Event *event )
{
    double ts, te, et ;
    double stime, endtime, calib;
    double samprate;
    int pos, retcode;
    int nsamp, arid, npts;
    float *buf=0;
    char sta[8], key[64];



    for( db.record = 0 ; db.record < nrec; db.record++)   {

       if( (dbgetv( db, 0,
	  "time", &stime,
          "endtime", &endtime,
          "calib", &calib,
          "samprate", &samprate,
          "arid", &arid,
          "nsamp", &nsamp,
          "sta", sta,
           0 )) == dbINVALID )
           elog_die( 0, "dbgetv faild for record #%d\n", db.record );

/*
fprintf( stderr, "%s: %lf %lf %d %lf \n", sta, stime, endtime, nsamp,event->otime );
*/
       if( strncmp( event->sta, sta, strlen(sta) )) continue;

       if( stime >= event->etime )   {
           elog_complain( 0, "can't get data for %s %lf - %lf.\n", 
                         sta, event->otime, event->etime);
           return 0;
       }
       if( endtime <= event->stime ) continue;
       if( arid != event->arid ) continue;
      
       trgetwf(
           db, 0, &buf, 0, event->otime, event->etime, &ts, &te, &npts, 0, 0) ; 
       if( npts <= 0 )  {
           if(buf != 0) free(buf);
	   buf = 0;
           continue;
       }

/*
fprintf( stderr, "%lf %lf - %lf %lf %d \n", 
         event->otime, event->etime, ts, te, npts );

*/
       if( buf == 0 )  { 
           elog_complain( 0, "can't get data for %s from %lf to %lf\n", 
                        event->sta, event->otime, event->etime ); 
           continue;
       }
       if( te <= event->otime ) continue;
       if( ts > event->stime ) {
           elog_complain( 0, "trace start time is more than SWA time. %lf > %lf\n",
                     ts, event->stime );
           if(buf) {
	    	free(buf);
		buf = 0;
	   }
	   return 0;
       }  else {
           if( ( pos = (int) ( event->stime - ts ) * samprate) >= npts ) {
               elog_complain( 0,  
               "no data for %s from %lf to %lf.\n", sta, event->stime, event->etime ); 
           	if(buf) {
	 	   free(buf);
		   buf = 0;
		}
                continue;
           }

           if( !(retcode = domag( buf, ts, samprate, npts, pos, calib, event)) ) 
               elog_complain( 0,  
               "can't calculate MS for %s. ( no data or too many FULL scale values).\n", sta); 
           if( buf != 0 && *buf != 0 ) free( buf );
           return retcode;
       }
  }

}
Tbl *dbload_slowness_table(Dbptr db,int row_start,int row_end,
	Arr *arrays, Arr *arrphase)
{
	Slowness_vector *u;
	char *prog="dbform_slowness_table";
	Tbl *t;

	/* Values set by dbgetv from row of view */
	char staname[14];
	double slow,azimuth;
	double delslo;
	char phase_name[10];
	long arid;
	

	t = newtbl(0);

	for(db.record=row_start;db.record<row_end;++db.record)
	{
	    int retcode;
	    char slodef[2],azdef[2];
	    /* First make sure def is set for slowness vectors */
	    retcode=dbgetv(db,0,"slodef",slodef,"azdef",azdef,NULL );
	    if(retcode==dbINVALID) die(1,"%s: dbgetv error in read_slowness_vector\n",prog);
	    /* don't load data unless slowness vector is defined */
	    if( (!strcmp(slodef,"d")) && (!strcmp(azdef,"d")) )
	    {
		/* I (glp) am inserting a prejudice here.  Uncertainties
		in azimuth are hard to convert to a useable form in genloc
		because of the exclusive use of cartesian components rather
		than the polar form.  The approach here is to use the value
		of delslo, when set, and use the same value for both components.
		This is reasonable for most arrays with a nearly round beam
		pattern, but will be quite wrong in colored noise.*/

		retcode=dbgetv( db, 0,
			"arid",&arid,
			"sta",staname,
			"phase",phase_name,
			"slow",&slow,
			"delslo",&delslo,
			"azimuth",&azimuth,NULL );
		if(retcode==dbINVALID) die(1,"%s: dbgetv error in read_slowness_vector\n",prog);

		/* The current schema says slow is set to -1.0 for a null
		value.  I'll use a safer test for >= 0 since negative 
		slowness is always meaningless. */
		if(slow >= 0.0 )
		{
			u = (Slowness_vector *) malloc(sizeof(Slowness_vector));
			if(u == NULL)
				die(1,"%s:  Cannot malloc Slowness_vector structure\n",
					prog);
			u->arid=arid;
			u->array = (Seismic_Array *)  getarr(arrays,staname);

		/* This error would be fatal for the relocate program, but
		this function might be used for other interfaces to this
		code so we only make it a warning */
			if(u->array == NULL)
			{
				complain(1,"%s:  Cannot find coordinates for station %s\n%s phase arrival for this station skipped\n",
				    prog, staname, phase_name);
				free(u);
				continue;
			}
			u->phase = (Phase_handle *) getarr(arrphase,phase_name);
			if(u->phase == NULL)
			{
				complain(1,"Warning (%s):  No phase handle for phase name %s\nSlowness vector for array %s skipped\n",
				   prog,phase_name,staname);
				free(u);
				continue;
			}

		/* CSS3.0 records slowness vectors in polar form with 
		the magnitude measured in second/degree and azimuth in
		degrees.  genloc uses only components internally in
		units of seconds/km.  We now convert the slow, azimuth
		values to ux and uy in s/km.  Oh, another possible
		confusion.  For all the data I've seen, azimuth is 
		really the receiver backazimuth which points 180 
		degrees away from the propagation direction.  Internally
		I use the azimuth, so this formula makes that conversion
		too through the negative sign on each component.*/
			slow /= KMPERDEG;
			u->ux = -slow*sin(azimuth*M_PI/180.0);
			u->uy = -slow*cos(azimuth*M_PI/180.0);
		/* her we set the uncertainties equal to delslo as noted above */
			if(delslo > 0.0)
			{
				u->deltaux = delslo/KMPERDEG;
				u->deltauy = delslo/KMPERDEG;
			}
			else
			{
				u->deltaux = (double)u->phase->deltau0;
				u->deltauy = (double)u->phase->deltau0;
			}
                	pushtbl(t,u);
		}
	    }
	}
	return(t);
}
Beispiel #25
0
/* This function computes theoretical arrival times and a slowness vector
(at the reference station for an array) based on a model and method
defined in a parameter file and using the generic travel time interface
of datascope/antelope.  

Arguments:
///inputs////
	stations - Associative array of MWstation objects used in 
			multiwavelet programs
	refsta - name of reference station to use.  The slowness 
		vector is computed based on a source location accessed
		through the db pointer (see below) and the location of
		the reference station.  If the refsta is not found in 
		the stations array the first element of the sorted list
		of stations will be used in an attempt to recover.  For
		most arrays this would be a minor error.
	phase - name of seismic phase to compute theoretical times and
		slowness vector for.  
	db - This db pointer MUST point to a single row of a db view with 
		the origin table joined as part of the view.   The hypocenter
		information is read with dbgetv passing this db pointer 
		directly.
	pf - parameter space pointer.  We search for model and method
		fields from pf to get the interface right. 
///outputs///
	times - associative array keyed by station name of theoretical
		arrival times (stored as double * s).  If there are 
		problems computing any travel times they will be absent
		from this array.  When this array is used, be aware you
		can't assume all the times are filled.
	slow - theoretical slowness vector.  If the slowness vector
		calculation fails this is set to 0 and the refsta field
		is set to "BAD".  This allows the use of the slowness 
		vector without errors in a less than ideal way.  The 
		BAD condition should be trapped.

Return codes:
	0 = normal return, no problems
	> 0 = count of travel time failures
	< 0 = nothing was computed.  Both slowness and times should be
		assumed invalid.

Author:  Gary Pavlis
Written: December 2000
*/

static Hook *hook=0;  /*Used by ttcalc */
int MWget_model_tt_slow(Arr *stations,
			char *refsta,
			char *phase,
			Dbptr db,
			Pf *pf,
			Arr **times,
			MWSlowness_vector *slow)
{
	Tbl *t;  /* used to hold keys with keysarr */
	char *key;  /* key returned from Tbl *t */
	int i;
	MWstation *s, *s0; 
	char *model;
	char *method;
	TTGeometry geometry;
	TTTime *atime;
	TTSlow *u0;
	Tbl *treturn=NULL,*ureturn=NULL;
	int error_count=0;
	double *twork;

	s0 = (MWstation *)getarr(stations,refsta);
	if(s0 == NULL) elog_complain(0,"MWget_model_tt_slow:  cannot find reference station %s\nWill arbitarily pick first station found as refererence for computing model based time and slowness\n",refsta);
	if(dbgetv(db,0,"origin.lat",&(geometry.source.lat),
		"origin.lon",&(geometry.source.lon),
		"origin.depth",&(geometry.source.z),
		"origin.time",&(geometry.source.time),NULL) == dbINVALID)
	{
		elog_complain(0,"MWget_model_tt_slow:  dbgetv error reading origin data\nCannot compute theoretical arrival times and slowness\n");
		return(-1);	
	}
	model = pfget_string(pf,"TTmodel");
	method = pfget_string(pf,"TTmethod");
	if( (model == NULL) || (method == NULL) )
	{
		elog_complain(0,"MWget_model_tt_slow:  TTmodel or TTmethod missing from parameter file\nCannot compute theoretical travel times and slowness vector\n");
		return(-1);
	}
	t = keysarr(stations);
	if(maxtbl(t)<=0)
	{
		elog_complain(0,"MWget_model_tt_slow:  no data to process\n");
		return(-1);
	}
	/* recover from reference station error */
	if(s0==NULL)
	{
		key = gettbl(t,0);
		
		elog_log(0,"Setting reference station to %s for travel time computation\n",
			key);
	}
	/* We now compute the slowness vector estimated for the reference
	station location at 0 elevation. */
	strcpy(geometry.receiver.name,s0->sta);
	geometry.receiver.lat = s0->lat;
	geometry.receiver.lon = s0->lon;
	geometry.receiver.z = 0.0;
	if(slow->refsta == NULL) slow->refsta = strdup(refsta);
	if(ucalc(method,model,phase,0,&geometry,&ureturn,&hook))
	{
		elog_complain(0,"MWget_model_tt_slow:  slowness vector calculation failed for reference station %s\nSetting model slowness vector to zero and attempting to continue.\n",
			s0->sta);
		slow->ux = 0.0;
		slow->uy = 0.0;
	}
	else
	{
		u0 = (TTSlow *)gettbl(ureturn,0);
		slow->ux = u0->ux;
		slow->uy = u0->uy;
	}
	/* If the output times array is not empty we have to free it up 
	and start fresh.  Otherwise we will have a memory leak or access
	old values stored there.  This probably should be handled 
	externally, but better to be redundant.*/
	if(*times != NULL) freearr(*times,free);
	*times = newarr(0);

	/* Look through the station list */
	for(i=0;i<maxtbl(t);i++)
	{
		double estatic;
		key = gettbl(t,i);
		s = (MWstation *)getarr(stations,key);
		strcpy(geometry.receiver.name,s->sta);
		geometry.receiver.lat = s->lat;
		geometry.receiver.lon = s->lon;
		geometry.receiver.z = 0.0;
		if(ttcalc(method,model,phase,0,&geometry,&treturn,&hook))
		{
			elog_complain(0,"MWget_model_tt_slow: Travel time computation failed computing travel time for station %s\nCannot compute residuals\n",
				s->sta);
			++error_count;
		}
		else
		{
			atime = (TTTime *)gettbl(treturn,0);
			estatic = compute_elevation_static(s,*slow,0.0,phase);
			allot(double *,twork,1);
			*twork = geometry.source.time
				+ (atime->value) + estatic;
			setarr(*times,key,twork);
		}
	}
	freetbl(ureturn,0);
	freetbl(treturn,0);
	return(error_count);
}
void mexFunction ( int nlhs, mxArray *plhs[], int nrhs, const mxArray *prhs[] )
{
	Dbptr	db;
	Point	*polygon;
	int 	nrec;
	int 	single_record;
	double 	NaN;
	double	*lat;
	double	*lon;
	int		nvertices;
	int 	nsaved,closed;
	int		i,j;
	double  *lat_pr, *lon_pr;
	Expression	*expr;
	int		maxneeded;
	int		sumpoints;
	int		*nanindices;
	char 	closedstr[2];

	
	NaN=mxGetNaN();

	if ( nrhs != 1 ) {
		antelope_mexUsageMsgTxt ( USAGE ); return;
	} else if ( ! get_dbptr( prhs[0], &db ) ) {
		antelope_mexUsageMsgTxt ( USAGE ); return;
	} else if ( nlhs != 2 ) {
		antelope_mexUsageMsgTxt ( USAGE ); return;
	}

	if (dbquery( db, dbRECORD_COUNT, &nrec) < 0) {
		antelope_mex_clear_register( 1 );
		mexErrMsgTxt("readpolygon: dbquery(recordcount) failed\n");
	}
	if (nrec <= 0 ) {
		mexErrMsgTxt("readpolygon: no rows in database view\n");
	}
	if (db.record == dbALL) {
		if (nrec == 1) {
			single_record= 1;
			db.record=0;
			dbgetv(db,0,"npoints",&sumpoints,0);
			maxneeded= (nrec*2) + sumpoints;
		} else {
			single_record=0;
			db.record=0;
			dbex_compile(db,"sum(npoints)",&expr,dbINTEGER);
			dbex_eval(db,expr,0,&sumpoints);
			dbex_free(expr);
			maxneeded= (nrec*2) + sumpoints;
			nanindices=mxCalloc(nrec,sizeof(int));
		}
	} else {
		if (db.record >= 0) {
			single_record= 1;
			dbgetv(db,0,"npoints",&sumpoints,"closed",&closedstr,0);
			maxneeded= (nrec*2) + sumpoints;
		} else {
			mexErrMsgTxt("readpolygon: unspecified subset?!?\n");
		}
	}
	
	nsaved= 0;
	nvertices= readPolygon(db,&polygon);
	lat= mxCalloc(maxneeded+1, sizeof(double));
	lon= mxCalloc(maxneeded+1, sizeof(double));
	for (j= 0; j < nvertices; j++) {
		lat[j]= polygon[j].lat;
		lon[j]= polygon[j].lon;
	}
	nsaved += nvertices;
	free(polygon);
	/* eventually close polygon*/
	if (strncmp(closedstr,"y",1)==0) {
		if ( (lat[nvertices-1] != lat[0]) || (lon[nvertices-1] != lon[0]) ) {
			nsaved++;
			lat[nsaved-1]= lat[0];
			lon[nsaved-1]= lon[0];
		}
	}
	if ( (single_record == 0) && (nrec > 1) ) {
		for (i= 1; i < nrec; i++) {
			db.record=i;
			dbgetv(db,0,"closed",&closedstr,0);
			nvertices= readPolygon(db,&polygon);
			/* separate (sub)polygons by NaN */
			lat[nsaved + 1]=NaN;
			lon[nsaved + 1]=NaN;
			nanindices[i-1]= nsaved+1;
			nsaved++;
			for (j= 0; j < nvertices; j++) {
				lat[j+nsaved]= polygon[j].lat;
				lon[j+nsaved]= polygon[j].lon;
			}
			nsaved += nvertices;
			/* eventually close polygon*/
			if (strncmp(closedstr,"y",1)==0) {
				if ( (lat[nvertices-1] != lat[0]) || (lon[nvertices-1] != lon[0]) ) {
					lat[nsaved]= lat[nsaved-nvertices];
					lon[nsaved]= lon[nsaved-nvertices];
					nsaved++;
				}
			}	
			free(polygon);
		}
	}
	plhs[0] = mxCreateDoubleMatrix(nsaved,1,mxREAL);
	lat_pr=(double *)mxGetPr(plhs[0]);
	memcpy(lat_pr, lat, nsaved*sizeof(double));	
	
	plhs[1] = mxCreateDoubleMatrix(nsaved,1,mxREAL);
	lon_pr=(double *)mxGetPr(plhs[1]);
	memcpy(lon_pr, lon, nsaved*sizeof(double));	
	/* NaN does NOT pass the memcpy */
	if (single_record == 0) {
		for (i=0; i < nrec-1; i++) {
			lat_pr[nanindices[i]-1]=NaN;
			lon_pr[nanindices[i]-1]=NaN;
		}
		mxFree(nanindices);
	}

	mxFree(lat);
	mxFree(lon);
}
int load_station_geometry(Dbptr db, Arr *a, double time)
{
	Dbptr dbs;
	int i,j,nset;
	Tbl *t;
	char *key;
	int yrday;
	Dbptr dbscr;
	static Hook *hook=NULL;
	Tbl *match_tbl;
	MWstation *s;
	int ondate,offdate;
	char refsta[10];  /*This is used as input buffer that
				is duped to store in each s object*/
	char refsta0[10];  /* Used for comparison to guarantee there
				is no change in refsta */

	yrday = yearday(time);
	t = keysarr(a);
	db = dblookup(db,0,"site",0,0);
	dbs = dblookup(db,0,"site",0,0);
	dbs.record = dbSCRATCH;	
	dbaddnull(dbs);

	for(i=0,nset=0;i<maxtbl(t);i++)
	{
		int nmatch;
		key = gettbl(t,i);
		s = (MWstation *)getarr(a,key);
		dbputv(dbs,0,"sta",s->sta,0);
		nmatch = dbmatches(dbs,db,0,0,&hook,&match_tbl);
		if(nmatch == dbINVALID)
			elog_die(0,"dbmatches error looking for entries for station %s\n",s->sta);
		else if(nmatch < 1)
		{
			elog_notify(0,"load_station_geometry:  cannot find station %s in site table -- deleted from geometry list\n",
				s->sta);
			delarr(a,s->sta);
			free_MWstation(s);
		}
		else
		{
			/* when when there is only one match, we just use it, otherwise
			we have to search for the correct entry based on ondate/offdate */

			if(nmatch == 1)
			{
				db.record = (int )gettbl(match_tbl,0);
			}
			else
			{
				for(j=0;j<maxtbl(match_tbl);j++)
				{
					db.record = (int)gettbl(match_tbl,j);
					if(dbgetv(db,0,"ondate",&ondate,
							"offdate",&offdate,0)
						== dbINVALID)
					{
						elog_notify(0,"load_station_geometry:  dbgetv error while searching for ondate/offdate match for station %s\nBlundering on\n", 
							s->sta);
						continue;
					}
					if((yrday >= ondate) && (yrday <= offdate)) break;
				}
			}
			/* note if the date match fails,we still end up here 
			using the last record in the db */
			freetbl(match_tbl,0);
			if(dbgetv(db,0,
				"lat",&(s->lat),
				"lon",&(s->lon),
				"elev",&(s->elev),
				"dnorth",&(s->dnorth),
				"deast",&(s->deast),
				"refsta",refsta,
				0) == dbINVALID)
			{
				elog_notify(0,"load_station_geometry:  dbgetv error reading record %d for station %s in site table\nStation deleted from list\n",
					db.record,s->sta);
				delarr(a,s->sta);
				free_MWstation(s);
			}
			else
			{
				if(nset==0) strcpy(refsta0,refsta);
				s->refsta = strdup(refsta0);
				if(!strcmp(s->sta,refsta0))
				{
					if(((s->dnorth)!=0.0) 
						|| ((s->deast)!=0.0))
						elog_die(0,"load_station_geometry:  reference station in site table must have dnorth and deast set to 0.0\nFound refstat = %s with (dnorth,deast)=(%lf,%lf)\n",
							s->sta,s->dnorth,
							s->deast);
					++nset;
				}
				else
				/* This deletes stations != refsta with dnorth 
				and deast not set properly.  */
				{
					if(((s->dnorth)==0.0) && ((s->deast)==0.0))
					{
						elog_notify(0,"load_station_geometry:  unset dnorth and deast entries for station %s\nStation deleted from list\n",
							s->sta);
						delarr(a,s->sta);
						free_MWstation(s);
					}
					else if(strcmp(refsta0,refsta))
						elog_die(0,"load_station_geometry:  reference station change not allowed.\nAll stations to be processed must have a common refsta in site table\n");
					else
						++nset;
				}
			}
		}
	}		
	return(nset);
}
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 ;
}
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;
		}