/* 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, &err, &ndgf); 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); }
int grtr_sc_create(Dbptr dbsc, char *net_expr, char *sta_expr, char *chan_expr, double tstart, double tend, char *gap, int calib, int ir, Dbptr *trscgr) { char time_str[100]; char endtime_str[100]; int ret, n, n2, i; double time, time2, endtime, endtime2; char sta[32], chan[32]; char sta2[32], chan2[32]; char string[1024]; char string2[64]; int new_view = 0; int is, crunch; Response *resp; Dbptr db; /* Subset input view */ 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 (string[0]) { strcat (string, " )"); dbsc = dbsubset (dbsc, string, 0); new_view = 1; } dbquery (dbsc, dbRECORD_COUNT, &n); if (n < 1) { register_error (0, "grtr_sc_create: No data to process.\n"); if (new_view) dbfree (dbsc); return (-1); } /* Read in data */ if (tstart == 0.0 && tend == 0.0) { dbquery (dbsc, dbRECORD_COUNT, &n); for (dbsc.record = 0; dbsc.record < n; dbsc.record++) { if (dbgetv (dbsc, 0, "time", &time, "endtime", &endtime, 0) == dbINVALID) { register_error (0, "grtr_sc_create: dbgetv() error.\n"); if (new_view) dbfree (dbsc); return (-1); } if (tstart == 0.0 && tend == 0.0) { tstart = time; tend = endtime; } else { if (time < tstart) tstart = time; if (endtime > tend) tend = endtime; } } } sprintf (time_str, "(%.5f)", tstart); sprintf (endtime_str, "(%.5f)", tend); dbsc.record = dbALL; ret = trload_css (dbsc, time_str, endtime_str, trscgr, "wfdisc", 0); /* Split, splice, apply calib */ if (gap == NULL) strcpy (string, "seg"); else strcpy (string, gap); if (!strcmp(string, "leave")) { } else if (!strcmp(string, "seg")) { trsplit (*trscgr, 0, 0); trsplice (*trscgr, 0.5, 0, 0); } else if (!strcmp(string, "interp")) { register_error (0, "grtr_sc_create: gap value '%s' not implemented yet.\n", string); if (new_view) dbfree (dbsc); return (-1); } else if (!strcmp(string, "zero")) { register_error (0, "grtr_sc_create: gap value '%s' not implemented yet.\n", string); if (new_view) dbfree (dbsc); return (-1); } else if (!strcmp(string, "drop")) { trsplit (*trscgr, 0, 0); trsplice (*trscgr, 0.5, 0, 0); crunch = 0; dbquery (*trscgr, dbRECORD_COUNT, &n); strcpy (sta2, ""); strcpy (chan2, ""); n2 = 0; db = *trscgr; for (trscgr->record=0; trscgr->record<n; (trscgr->record)++) { if (dbgetv (*trscgr, 0, "sta", sta, "chan", chan, 0) == dbINVALID) { register_error (0, "grtr_sc_create: dbgetv() error.\n"); if (new_view) dbfree (dbsc); return (-1); } if (strcmp(sta, sta2) || strcmp(chan, chan2)) { if (n2 > 1) { for (db.record = is; db.record < is+n2; db.record++) { trfree (db); crunch = 1; } } n2 = 1; is = trscgr->record; strcpy (sta2, sta); strcpy (chan2, chan); continue; } n2++; } if (n2 > 1) { for (db.record = is; db.record < is+n2; db.record++) { trfree (db); crunch = 1; } } if (crunch) { dbcrunch (db); } } else { register_error (0, "grtr_sc_create: Illegal gap value '%s'.\n", string); if (new_view) dbfree (dbsc); return (-1); } if (calib) trapply_calib (*trscgr); /* Read in instrument responses. */ if (ir ) { /* Run this section if instrument response is to be loaded */ dbsc.record = 0; if (dbgetv (dbsc, 0, "instrument.inid", &i, 0) != dbINVALID && i >= 0) { dbquery (*trscgr, dbRECORD_COUNT, &n); dbquery (dbsc, dbRECORD_COUNT, &n2); for (trscgr->record=0; trscgr->record<n; (trscgr->record)++) { if (dbgetv (*trscgr, 0, "sta", sta, "chan", chan, "time", &time, 0) == dbINVALID) { register_error (0, "grtr_sc_create: dbgetv() error.\n"); if (new_view) dbfree (dbsc); return (-1); } for (dbsc.record=0; dbsc.record<n2; dbsc.record++) { if (dbgetv (dbsc, 0, "sta", sta2, "chan", chan2, "time", &time2, "endtime", &endtime2, 0) == dbINVALID) { register_error (0, "grtr_sc_create: dbgetv() error.\n"); if (new_view) dbfree (dbsc); return (-1); } if (strcmp(sta, sta2)) continue; if (strcmp(chan, chan2)) continue; if (time < time2) continue; if (time >= endtime2) continue; dbextfile (dbsc, "instrument", string); resp = (Response *) getarr (resp_arr, string); dbputv (*trscgr, 0, "response", resp, 0); break; } } } } clear_register (0); if (new_view) dbfree (dbsc); /* Normal exit. */ return (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; }