source: trunk/src/seismic_processing/glass/src/modules/Glass/glass.cpp @ 2176

Revision 2176, 54.6 KB checked in by paulf, 13 years ago (diff)

added from hydra_proj, new version

  • Property svn:eol-style set to native
  • Property svn:keywords set to Author Date Id Revision
Line 
1/*
2 *   THIS FILE IS UNDER RCS - DO NOT MODIFY UNLESS YOU HAVE
3 *   CHECKED IT OUT USING THE COMMAND CHECKOUT.
4 *
5 *    $Id$
6 *
7 *    Revision history:
8 *     $Log$
9 *     Revision 1.2  2006/05/22 16:01:25  paulf
10 *     added from hydra_proj, new version
11 *
12 *     Revision 1.2  2005/10/17 06:29:46  davidk
13 *     Added code to stop the focus mechanism from fighting with the locator.
14 *     The focus now attempts at most one refocus per change in origin-pick
15 *     association
16 *
17 *     Revision 1.1.1.1  2005/06/22 19:30:48  michelle
18 *     new directory tree built from files in HYDRA_NEWDIR_2005-06-20 tagged hydra and earthworm projects
19 *
20 *     Revision 1.14  2005/04/18 20:55:42  davidk
21 *     Part of the integration of glass algorithms into hydra.
22 *     Extracted the nucleating code from the auxilliary Associate()
23 *     function (and this source file) into a hydra library function AssociatePicks().
24 *
25 *     Revision 1.13  2005/02/28 18:14:37  davidk
26 *      Added code to filter out spurious associated phases at time of publication.
27 *     Added function PrunePick() so the publisher can communicate to the associator
28 *     that a particular pick should be pruned from an origin.
29 *     Added a MarkOriginAsScavenged flag to UnassociatePickWOrigin()
30 *     in order to control the amount of origin rehashing that gets done.  Now
31 *     the origin no longer gets scheduled for rehash when pruned by the publisher.
32 *
33 *     Revision 1.12  2005/02/15 19:33:28  davidk
34 *     Added additional debugging information.
35 *
36 *     Revision 1.11  2004/12/02 20:57:03  davidk
37 *     Moved temporary hack validation code out of ValidateOrigin() and into
38 *     an external  AlgValidateOrigin() function, in order to separate core glass
39 *     code from network specific corrections/filtering.
40 *
41 *     Revision 1.10  2004/12/01 06:16:52  davidk
42 *     refining temporary filtering criteria in ValidateOrigin()
43 *
44 *     Revision 1.9  2004/12/01 02:35:31  davidk
45 *     Added temporary validation constraints to ValidateOrigin() function,
46 *     that places events in NorthAmerica and the Western Hemisphere,
47 *     under more stringent quality constraints.
48 *
49 *     Revision 1.8  2004/11/23 00:50:49  davidk
50 *     Fixed bug in Focus() where code was not checking the return code from the
51 *     focus message, and was always reporting that the origin was refocussed,
52 *     causing further processing to occur.
53 *     Code now reports the appropriate return code from the focus message, so
54 *     that further processing only occurs if the message indicated that refocussing
55 *     occurred.
56 *
57 *     Revision 1.7  2004/11/02 19:11:32  davidk
58 *     Modified UnPutOrigin() to BROADCAST "OriginDel" messages, so that
59 *     they can be received by multiple modules, instead of DISPATCHing them,
60 *     where they are only picked up by one module.
61 *
62 *     Revision 1.6  2004/11/01 18:01:18  davidk
63 *     Changed the number of picks required to go through association from 4 to a
64 *     number derived from the nCut parameter.
65 *     A weenie attempt to improve performance.
66 *
67 *     Revision 1.5  2004/11/01 06:31:31  davidk
68 *     Modified to work with new hydra traveltime library.
69 *
70 *     Revision 1.4  2004/09/16 00:53:25  davidk
71 *     Added glass_assoc.d config param  NumLocatorIterations.
72 *     (param gets converted to glass internal msg, and sent to locator).
73 *     Moved all old code to the bottom of the file.
74 *
75 *     Revision 1.3  2004/08/06 00:34:16  davidk
76 *     Modified PutOrigin() function so that it no longer outputs "AssOrigin"
77 *     messages each time a Pick is associated with an origin, but instead puts
78 *     out "OriginAdd" and "OriginMod" messages when a new origin is created
79 *     or updated respectively.
80 *
81 *     Added UnPutOrigin() function that creates an "OriginDel" message.
82 *
83 *     Modified PutLink() and PutUnLink() functions  to create "OriginLink"
84 *     and "OriginUnLink" intra-glass messages, instead of "AssLink" and
85 *     "AssUnLink" messages.  (Used to sound a lot like a conga-line).
86 *
87 *     Added call to UnPutOrigin() in DeleteOrigin().  UnPutOrigin() is
88 *     called after the picks are stripped from an Origin, but prior
89 *     to the actual deletion of the origin from Glint.
90 *
91 *     Changed the format of the Pick string that is printed to the
92 *     GUI status tool.
93 *
94 *     Changed the handling of the return code from the Glock locator.
95 *     Now the number of location-calculations is only increment when
96 *     Glock actually RELOCATES the origin.
97 *
98 *     Added code to increment the Quake counter when a new origin
99 *     is created.
100 *
101 *     Revision 1.2  2004/04/01 22:05:43  davidk
102 *     v1.11 update
103 *     Added internal state-based processing.
104 *
105 *     Revision 1.3  2003/11/07 22:27:54  davidk
106 *     Added RCS header.
107 *     Removed algorithmic changes (such as periodic event processing)
108 *     that had been added as part of v1.0, but were deemed undesirable.
109 *     Improved the way that glass updates the "Monitor" during times
110 *     of inactivity.
111 *
112 *
113 **********************************************************/
114
115// glass.cpp
116
117#include <windows.h>
118#include <stdio.h>
119#include <math.h>
120#include <ITravelTime.h>
121#include "glass.h"
122#include "spock.h"
123#include "monitor.h"
124#include "GlassMod.h"
125#include "IGlint.h"
126#include "date.h"
127#include "str.h"
128#include <Debug.h>
129#include <opcalc.h>
130#include <AssociatePicks.hpp>
131
132extern "C" {
133#include "utility.h"
134}
135
136static int nPck;
137static int nXYZ;
138static PICK *Pck[MAXPCK];
139static double dXYZ[6*MAXPCK];
140
141static double dTest;            // Temporary for testing
142
143//---------------------------------------------------------------------------------------CGlass
144CGlass::CGlass() {
145        nAss = 0;
146        pMod = 0;
147        pMon = 0;
148        pTT = 0;
149        dTest = 0.0;
150        nCut = 5;
151        dCut = 50.0;    // Cluster parameter (km)
152        strcpy(sPick, "");
153        strcpy(sDisp, "");
154        nPick = 0;
155        nAssoc = 0;
156        nQuake = 0;
157        iLapse = 0;
158        tDone = Secs();
159//      dXYZ = new double[6*MAXPCK];
160        bAssociate = true;
161        bLocate = true;
162
163        // Adjustable tuning parameters
164        nCut = 5;                                       // Number of partial locations in starting cluster
165        dCut = 50.0;                                    // Cluster distance threshold (km)
166        dTimeBefore = -120.0;           // Time previous to pick for nucleation consideration
167        dTimeAfter = 30.0;                      // Time after pick for nucleaation consideration
168        dTimeOrigin = -300.0;           // Time before pick containing trail origins
169        dTimeStep = 10.0;                       // Nucleation time mesh (seconds)
170        nShell = 0;                                     // Number of nucleation shells
171        dShell[nShell++] = 0.5;         // Nucleation shell depths (km)
172        dShell[nShell++] = 50.0;
173        dShell[nShell++] = 100.0;
174        dShell[nShell++] = 200.0;
175        dShell[nShell++] = 400.0;
176        dShell[nShell++] = 800.0;
177        memset(Mon,0,sizeof(Mon));  // DK CHANGE 060303  initializing Mon
178  // DK 1.0 PULL iReportInterval = ORIGIN_EXTPROC_INTERVAL;
179
180  InitGlassStateData();
181}  // end CGlass()
182
183//---------------------------------------------------------------------------------------~CGlass()
184CGlass::~CGlass() {
185}
186
187//---------------------------------------------------------------------------------------Params
188// Read parameter file
189bool CGlass::Params(char *file) {
190        CComFile cf;
191        CStr cmd;
192        int nc;
193        bool b = true;
194// DK REMOVE    double prob2;
195
196  //DebugBreak();
197
198        if(!cf.Open(file))
199  {
200    CDebug::Log(DEBUG_MAJOR_ERROR,"CGlass::Params():  Unable to open config file(%s).\n",
201                file);
202    exit(-1);
203                return false;
204  }
205        while(true) {
206                nc = cf.Read();
207                if(nc < 0) {
208                        break;
209                }
210                if(nc < 1)
211                        continue;
212    CDebug::Log(DEBUG_MAJOR_INFO, "Params() New command <%s>\n", cf.Card().GetBuffer());
213
214                cmd = cf.Token();
215                if(cmd.GetLength() < 1)
216                        continue;
217                if(cf.Is("#"))
218                        continue;
219                if(cf.Is("Cut")) {
220                        nCut = cf.Long();
221                        dCut = cf.Double();
222                        continue;
223                }
224                if(cf.Is("TimeRange")) {
225                        dTimeBefore = cf.Double();
226                        dTimeAfter = cf.Double();
227                        dTimeOrigin = cf.Double();
228                        continue;
229                }
230                if(cf.Is("TimeStep")) {
231                        dTimeStep = cf.Double();
232                        continue;
233                }
234                if(cf.Is("Shell")) {
235                        if(b) {
236                                b = false;
237                                nShell = 0;
238                        }
239                        dShell[nShell++] = cf.Double();
240                        continue;
241                }
242                if(cf.Is("Tran")) 
243    {
244      ConfigureTransitionRule(&cf);
245      continue;
246                }
247                if(cf.Is("NumLocatorIterations")) 
248    {
249      IMessage *m;
250
251      m = pMod->CreateMessage("NumLocatorIterations");
252      m->setInt("Num",cf.Long());
253      pMod->Dispatch(m);
254      m->Release();
255      continue;
256                }
257  }   // end while(true)
258        cf.Close();
259        return true;
260}  // end Params()
261
262
263
264//---------------------------------------------------------------------------------------PutOrigin
265void CGlass::PutOrigin(char *idorg, bool bNew)
266{
267  IMessage *m;
268  if(bNew)
269  {
270        m = pMod->CreateMessage("OriginAdd");
271          m->setStr("idOrigin",idorg);
272  }
273  else
274  {
275        m = pMod->CreateMessage("OriginMod");
276          m->setStr("idOrigin",idorg);
277  }
278        pMod->Dispatch(m);
279        m->Release();
280}
281
282//---------------------------------------------------------------------------------------PutOrigin
283void CGlass::UnPutOrigin(char *idorg)
284{
285        IMessage *m = pMod->CreateMessage("OriginDel");
286        m->setStr("idOrigin",idorg);
287        pMod->Broadcast(m);
288        m->Release();
289}
290
291//---------------------------------------------------------------------------------------PutLink
292void CGlass::PutLink(char *idorg, char *idpck) 
293{
294        IMessage *m = pMod->CreateMessage("OriginLink");
295        m->setStr("idPick",idpck);
296        m->setStr("idOrigin",idorg);
297        pMod->Dispatch(m);
298        m->Release();
299}
300
301//---------------------------------------------------------------------------------------PutLink
302void CGlass::PutUnLink(char *idorg, char *idpck) 
303{
304        IMessage *m = pMod->CreateMessage("OriginUnLink");
305        m->setStr("idPick",idpck);
306        m->setStr("idOrigin",idorg);
307        pMod->Dispatch(m);
308        m->Release();
309}
310
311//---------------------------------------------------------------------------------------Poll
312void CGlass::Poll() {
313        if(!pMon)
314                return;
315        int lapse = (int)(Secs() - tDone);
316        if(lapse != iLapse) {
317                iLapse = lapse;
318// DK PERF              pMon->Refresh();
319                pMon->UpdateStatus();
320        }               
321}
322
323int CGlass::DeleteOrigin(char * idOrigin)
324{
325  ORIGIN * pOrigin;
326  PICK * pPick;
327
328  CDebug::Log(DEBUG_MAJOR_INFO, "Attempting to Delete origin %s\n", idOrigin);
329  if(!(pOrigin = pGlint->getOrigin(idOrigin)))
330  {
331    CDebug::Log(DEBUG_MAJOR_INFO, "Origin %s not found.  Ignoring delete request.\n", idOrigin);
332    return(false);
333  }
334
335  // check origin parameters to ensure it is still viable
336  if(pOrigin->nPh > 0)
337  {
338    // Remove Phases
339    int iPickRef=0;
340    while(pPick = pGlint->getPicksFromOrigin(pOrigin,&iPickRef))
341    {
342      UnAssociatePickWOrigin(pOrigin->idOrigin,pPick,false);
343    }
344  }
345
346   CDebug::Log(DEBUG_MINOR_WARNING, "Deleting origin %s\n", idOrigin);
347   UnPutOrigin(idOrigin);
348
349   if(pGlint->deleteOrigin(idOrigin))
350     return(true);
351   else
352     return(false);
353}  // end DeleteOrigin()
354
355bool CGlass::ValidateOrigin(char * idOrigin)
356{
357  ORIGIN * pOrigin;
358
359  PhaseType  ptPhase;
360  PhaseClass pcPhase;
361
362  CDebug::Log(DEBUG_MINOR_INFO,"Origin %s: Attempting to Validate!\n",
363              idOrigin);
364
365  if(!(pOrigin = pGlint->getOrigin(idOrigin)))
366  {
367    CDebug::Log(DEBUG_MINOR_WARNING,"Origin %s: can't retrieve origin info!\n",
368                idOrigin);
369    return(false);
370  }
371
372  // check origin parameters to ensure it is still viable
373  if(pOrigin->nPh < nCut || pOrigin->nEq < nCut)
374  {
375    CDebug::Log(DEBUG_MAJOR_INFO,"Origin %s/%d, too few picks(%d/%d).  Invalidating!\n",
376                pOrigin->idOrigin, pOrigin->iOrigin, pOrigin->nPh,pOrigin->nEq);
377    return(false);
378  }
379
380  // DK 020604  Check to make sure we still have the requisite
381  //            number of Primary phases (Pup, P, PDif)
382  int iPickRef=0;
383  PICK * pck;
384  int iPCtr = 0;
385  while(pck = pGlint->getPicksFromOrigin(pOrigin, &iPickRef))
386  {
387    if(!pck->bTTTIsValid)
388      continue;
389    ptPhase = GetPhaseType(pck->ttt.szPhase);
390    pcPhase = GetPhaseClass(ptPhase);
391    if(pcPhase == PHASECLASS_P)
392    {
393      iPCtr++;
394      if(iPCtr == nCut)
395      {
396        pGlint->endPickList(&iPickRef);
397        break;
398      }
399    }
400  }
401  if(iPCtr < (nCut - 1))   // -1 is for leniency (sp?)
402  {
403    CDebug::Log(DEBUG_MAJOR_INFO,"Origin %s/%d, too few P picks(%d).  Invalidating!\n",
404                pOrigin->idOrigin, pOrigin->iOrigin, iPCtr);
405    return false;
406  }
407  // End DK 020604  Check for number of P Phases
408
409  return(AlgValidateOrigin(pOrigin, pGlint, nCut));
410}  // end ValidateOrigin()
411
412
413
414//---------------------------------------------------------------------------------------Origin
415// Load origin, assumes coordinates are geographic
416void CGlass::Origin(double t, double lat, double lon, double depth) {
417        ORIGIN org;
418        CDate dt(t);
419        CDebug::Log(DEBUG_MINOR_INFO, "Origin: %s %.4f %.4f %.2f\n", dt.Date20().GetBuffer(), lat, lon, depth);
420        if(!pGlint)
421                return;
422        org.iVersion = GLINT_VERSION;
423        org.dT = t;
424        org.dLat = lat;
425        org.dLon = lon;
426        org.dZ = depth;
427        org.nEq = 0;
428        org.dRms = 0.0;
429        org.dDelMin = 0.0;
430        org.dDelMod = 0.5;
431        org.dDelMax = 1.0;
432        sprintf(org.sTag, "0.0.0.0");
433        pGlint->putOrigin(&org);
434        Grok(org.idOrigin);
435        dTest = t;
436}
437
438//---------------------------------------------------------------------------------------Pick
439void CGlass::Pick(char *sta, char *comp, char *net, char * loc, char *phase,
440                double t, double lat, double lon, double elev,
441                char *logo, int iseq)
442{
443
444  /*********************************************************
445   * This is the entry point for triggered glass association.
446   * This routine is called everytime a new "pick" enters
447   * the system.
448   *********************************************************/
449
450        char scn[32];
451        PICK pck;
452        double tpick;
453//      double t1;
454//      double t2;
455        double a;
456        double b;
457//      bool bres;
458
459  // STEP 1: Record the pick's attributes, and save the pick in GLINT
460        if(!pGlint)
461                return;
462  // DK CLEANUP - this is BAD!! nScheduledActions = 0;   // CARL 120303
463        MON *mon = &Mon[0];
464        MON *avg = &Mon[1];
465        tpick = Secs();
466
467  memset(&pck,0,sizeof(pck));
468        pck.iVersion = GLINT_VERSION;
469        pck.dT = t;
470        pck.dLat = lat;
471        pck.dLon = lon;
472        pck.dElev = elev;
473        pck.dAff = 0.0;
474        sprintf(pck.sTag, "%s.%d", logo, iseq);
475        strncpy(pck.sPhase, phase, sizeof(pck.sPhase)-1);
476        strncpy(pck.sSite, sta, sizeof(pck.sSite)-1);
477        strncpy(pck.sComp, comp, sizeof(pck.sComp)-1);
478        strncpy(pck.sNet, net, sizeof(pck.sNet)-1);
479        strncpy(pck.sLoc, loc, sizeof(pck.sLoc)-1);
480
481        if(pMon) {
482    _snprintf(scn, sizeof(scn), "%s.%s.%s.%s",sta,comp,net,loc);
483    scn[sizeof(scn)-1] = 0x00;
484    CDate dt(t);
485
486    _snprintf(sPick, sizeof(sPick), "%8d: %-14s %-1s %02d:%02d:%05.2f %4d/%02d/%02d", 
487              iseq, scn, phase, dt.Hour(), dt.Minute(), dt.Secnds(), 
488              dt.Year(), dt.Month(), dt.Day());
489    sPick[sizeof(sPick)-1] = 0x00;
490        }
491        if(!nPick) {
492                tDone = tpick;
493                CatOut();
494        }
495        mon->tIdle = tpick - tDone;
496        mon->tAsn = 0.0;
497        mon->tAss = 0.0;
498        mon->tLoc = 0.0;
499        pGlint->putPick(&pck);
500
501  /**********   removed // CARL 120303
502  // STEP 2: Attempt to associate the Pick with one of the existing
503  //         quakes.
504        t1 = Secs();
505        bres = Assign(pck.idPick);
506        t2 = Secs();
507        mon->tAsn = t2 - t1 - mon->tLoc;
508
509  // STEP 2.1: If we were able to associate the pick,
510  //           we're done.  Update the perf. counters
511        if(bres)
512  {
513    // NOW SET IN AssociatePick()  nAssoc++;
514                strcpy(sDisp, "       Assigned");
515                goto pau;
516        }
517
518  // STEP 3: If desired, try to associate the pick into a new quake.
519        if(bAssociate)
520  {
521    // STEP 3.1: Try to associate a new quake, from the
522    //           the new pick and the existing unassociated
523    //           picks.
524                bres = false;
525                t1 = Secs();
526                bres = Associate(pck.idPick);
527                t2 = Secs();
528                mon->tAss = t2 - t1 - mon->tLoc;
529
530    // STEP 3.2: If we were able to associate the pick,
531    //           we're done.  Update the perf. counters
532                if(bres) {
533                        nQuake++;
534                        strcpy(sDisp, "       New Event");
535                        goto pau;
536                }
537        }
538
539  // STEP 4:   No further processing to do.  Declare the
540  //           pick an orphin.  Update perf counters.
541        strcpy(sDisp, "       Hapless waif");
542
543pau:
544
545   end // CARL 120303  ***************/
546
547        // Schedule for assignment:
548  //  attempting to associate a Pick with one of
549  //  the existing quakes.
550  RegisterUnassociatedPick(pck.idPick);
551
552  // Process defered processing
553        Action();
554
555  // wrapup
556        tDone = Secs();
557        mon->tOther = tDone - tpick - mon->tAsn - mon->tAss - mon->tLoc;
558        if(nPick)
559                a = 0.95;
560        else
561                a = 0.0;
562        b = 1.0 - a;
563        avg->tIdle  = a*avg->tIdle  + b*mon->tIdle;
564        avg->tAsn   = a*avg->tAsn   + b*mon->tAsn;
565        avg->tAss   = a*avg->tAss   + b*mon->tAss;
566        avg->tLoc   = a*avg->tLoc   + b*mon->tLoc;
567        avg->tOther = a*avg->tOther + b*mon->tOther;
568        nPick++;
569        if(pMon)
570                pMon->Refresh();
571//      Debug("--------------------\n");
572}
573
574#define szPARAMLOG_BASE_FILENAME "glass_params_log.txt"
575static char szGlassParamLogFilename[256];
576
577//---------------------------------------------------------------------------------------CatOut
578// Initialize catalog.txt with detection parameters
579// Overwrites previous catalog.txt
580void CGlass::CatOut() 
581{
582  FILE *f;
583 
584 
585  char * szEW_LOG = getenv("EW_LOG");
586  if(!szEW_LOG)
587    szEW_LOG = "";
588
589  // set the ParamLogfile name
590  _snprintf(szGlassParamLogFilename,sizeof(szGlassParamLogFilename),"%s%s",szEW_LOG,szPARAMLOG_BASE_FILENAME);
591  szGlassParamLogFilename[sizeof(szGlassParamLogFilename) - 1] = 0x00;
592
593  if(!(f = fopen(szGlassParamLogFilename, "w")))
594  {
595    CDebug::Log(DEBUG_MINOR_ERROR,"CGlass::CatOut():  ERROR! Could not open param log file <%s>.\n",
596      szGlassParamLogFilename);
597    return;
598  }
599 
600        fprintf(f, "Association parameters...\n");
601        fprintf(f,   "%6d nCut           Minimum cluster size to nucleate new event\n", nCut);
602        fprintf(f, "%6.1f dCut           Cluster distance (km)\n", dCut);
603        fprintf(f, "%6.0f dTimeBefore    Time previous to current pick to consider\n", dTimeBefore);
604        fprintf(f, "%6.0f dTimeAfter     Time after current pick to consider\n", dTimeAfter);
605        fprintf(f, "%6.0f dTimeOrigin    Time before previous pick for trial loccations\n", dTimeOrigin);
606        fprintf(f, "%6.0f dTimeStep      Trial location origin time granularity\n", dTimeStep);
607        for(int i=0; i<nShell; i++) {
608                fprintf(f, "%6.0f               Shell[%d]\n", dShell[i], i);
609        }
610        fprintf(f, "\n");
611        fclose(f);
612  f = NULL;
613}
614
615//---------------------------------------------------------------------------------------Grok
616// Create grok message
617void CGlass::Grok(char *idorg) {
618        IMessage *m;
619        m = pMod->CreateMessage("Grok");
620        m->setStr("Quake", idorg);
621        pMod->Broadcast(m);
622        m->Release();
623}
624
625
626/*********  // CARL 120303 REPLACE  function Assign
627//---------------------------------------------------------------------------------------Assign
628// Scan quake list and try to assocate pick with existing origin
629bool CGlass::Assign(char *idpick) {
630        ORIGIN *org;
631        PICK *pck;
632        TTT *ttt;
633  TTT tttLocal;
634        char idorg[32]="";
635        double ares;
636        double bres;
637        double d;
638        double az;
639        double t1;
640        double t2;
641        double t;
642        double z;
643
644  // Parameters of the best fitting origin
645        double bT;
646        double bZ;
647        double bD;
648
649  // STEP 0: Insure we have access to the traveltime tables.
650        if(!pTT)
651                return false;
652
653  // STEP 1:   Obtain the full information for the pick
654  //           from GLINT.
655        pck = pGlint->getPickFromidPick(idpick);
656        if(!pck)
657                return false;
658
659  // STEP 2: Select a time range (t1 - t2), within which
660  //         we will search for origins that the pick could
661  //         be associated with.
662        t2 = pck->dT;
663        t1 = t2 - 1680; // 28 minutes
664        bres = 100000.0;
665
666  // STEP 3: For each origin within our time range
667  //         attempt to associate the pick with the origin.
668  //         Find the origin (if any exists) with the best
669  //         residual fit.
670        while(org = pGlint->getOrigin(t1, t2))
671  {
672    // STEP 3.1:
673    //         Calculate the deltaT(sec)
674    //                       deltaZ(km) - depth
675    //                   and deltaD(deg) - angle (pick/earth center/hypocenter)
676    //         between the pick and the hypocenter
677                t = pck->dT - org->dT;
678                z = org->dZ;
679                d = pTT->Delta(org->dLat, org->dLon, pck->dLat, pck->dLon);
680                az = pTT->Azimuth(org->dLat, org->dLon, pck->dLat, pck->dLon);
681
682    // STEP 3.2:
683    //         Obtain the most likely phase type, based upon
684    //         angle, time, and depth.
685                ttt = pTT->Best(d, t, z);
686
687    // STEP 3.3:
688    //         If there wasn't a likely phase for this origin,
689    //         go on to the next origin.
690                if(!ttt)
691                        continue;
692    else
693      memcpy(&tttLocal,ttt,sizeof(tttLocal));
694
695    // STEP 3.4:
696    //         Calculate the residual as the ABSOLUTE differnce
697    //         between the traveltimetable value for the chosen
698    //         phase and the actual traveltime.
699                ares = pck->dT - org->dT - tttLocal.dT;
700                if(ares < 0.0)
701                        ares = -ares;
702
703    // STEP 3.5:
704    //         If the residual for the current origin is
705    //         within an acceptable range and better
706    //         than previous origins, then record
707    //         the origin, residual, and phase name
708    if(ares < GLASS_RESIDUAL_THRESHOLD && ares < bres)
709    {
710      strncpy(pck->sPhase, tttLocal.sPhs, sizeof(pck->sPhase));
711      pck->sPhase[sizeof(pck->sPhase)-1] = 0x00;
712
713                        bres = ares;
714                        bT = t;
715                        bZ = z;
716                        bD = d;
717                        strncpy(idorg, org->idOrigin, sizeof(idorg)-1);
718      idorg[sizeof(idorg)-1] = 0x00;
719                }
720       //               CDebug::Log(DEBUG_MINOR_INFO,"    iTTT:%d sPhs:%s az:%.2f"
721       //                                " dD:%.2f dT:%.2f dZ:%.2f dToa:%.2f"
722       //                                " dTdD:%.2f dTdZ:%.2f\n",
723       //                                 ttt->iTTT, ttt->sPhs, az, ttt->dD, ttt->dT, ttt->dZ,
724       //               ttt->dToa, ttt->dTdD, ttt->dTdZ);
725  }  // end while(there are origins the meet the given time criteria)
726
727  // STEP 4: If we found an acceptable origin, officially associate
728  //         the pick with the origin. 
729        if(bres < GLASS_RESIDUAL_THRESHOLD)
730  {
731    BOOL bRetCode;
732
733        ttt = pTT->Best(bD, bT, bZ);
734    // STEP 3.3:
735    //         If there isn't a likely phase, then something is fishy!
736                if(!ttt)
737    {
738            CDebug::Log(DEBUG_MINOR_ERROR,
739                    "Inconsistency in the traveltime code.  Asked for "
740                    "traveltime record for Origin match that was rated"
741                    "the best, and now no record is available.  Think "
742                    "memory corruption!\n Params(d t z) (%.2f %.2f %.2f\n",
743                  bD,bT,bZ);
744      return(false);
745    }
746    else
747      memcpy(&tttLocal,ttt,sizeof(tttLocal));
748
749          CDebug::Log(DEBUG_MINOR_INFO, "Pick:%s associated with Origin:%s\n", pck->idPick, idorg);
750
751// STEP 4.1:
752//       Perform the association.
753//         Return true, indicating that the pick was associated.
754    if(bRetCode=AssociatePickWOrigin(idorg,pck,bLocate,&tttLocal))
755    {
756// DK 1.0 PULL        if(org=pGlint->getOrigin(idorg))
757// DK 1.0 PULL        {
758// DK 1.0 PULL          // STEP 4.1.1:
759// DK 1.0 PULL          //       Determine if Extended Processing should be done at this time
760// DK 1.0 PULL          //       to the affected origin .
761// DK 1.0 PULL          if(org->nPh > org->nNextExtProc)
762// DK 1.0 PULL          {
763// DK 1.0 PULL            PerformExtendedProcessing(org);
764// DK 1.0 PULL            org->nNextExtProc = org->nPh + iReportInterval;
765// DK 1.0 PULL          }
766// DK 1.0 PULL        }
767// DK 1.0 PULL        else
768// DK 1.0 PULL        {
769// DK 1.0 PULL                CDebug::Log(DEBUG_MINOR_ERROR, "Assign(): Could not obtain origin "
770// DK 1.0 PULL                                         "from Glint for idorigin:%s\n", idorg);
771// DK 1.0 PULL        }
772      return(true);
773    }  // end if AssociatePickWOrigin()
774    // STEP 4.2:
775    //       If something went wrong with the association,
776    //         return false, indicating that the pick was not associated.
777    else
778    {
779      return(false);
780    }
781  }
782  // STEP 5: If we didn't find an acceptable origin, return false,
783  //         indicating that the pick was NOT associated.
784  else  // if bres < GLASS_RESIDUAL_THRESHOLD
785  {
786                return false;
787  }
788}  // end Assign()
789
790*********  END // CARL 120303 REPLACE  function Assign   */
791
792
793// CARL 120303 REPLACEMENT  function Assign
794//---------------------------------------------------------------------------------------Assign
795// Scan quake list and try to assocate pick with existing origin
796// Action returns
797//              0: Pick not assigned
798//              1: Pick assigned
799int CGlass::Assign(char *idpick) {
800        ORIGIN *org;
801        PICK *pck;
802        PICK CurrentPick,BestPick;
803        char idorg[18]="";
804        double affmax;
805        double t1;
806        double t2;
807  bool bRetCode;
808  int iRetCode;
809
810  // STEP 0: Ensure we have access to the traveltime tables.
811        if(!pTT)
812                return false;
813
814  // STEP 1:   Obtain the full information for the pick
815  //           from GLINT.
816        pck = pGlint->getPickFromidPick(idpick);
817        if(!pck)
818                return false;
819
820  // STEP 1.1:   Ensure that the pick is a WAIF.  This is
821  //             a check to make sure we don't have a bug
822  //             in the system that is causing us to try
823  //             to re-associate already associated picks.
824  if(pck->iState != GLINT_STATE_WAIF)
825  {
826    // STEP 1.1.1:   Pick's not a waif.  Complain. Return failure.
827    CDebug::Log(DEBUG_MINOR_ERROR, 
828                "Assign(): Error: Pick (%s/%s) is not a waif! (%s/%s/%s/%s - %.2f)\n"
829                "iPick %d, iOrigin %d\n",
830                idpick, pck->idPick, pck->sSite, pck->sComp, pck->sNet, pck->sLoc,
831                pck->dT, pck->iPick, pck->iOrigin);
832   return(0);
833  }
834
835
836  // STEP 2: Select a time range (t1 - t2), within which
837  //         we will search for origins that the pick could
838  //         be associated with.
839        t2 = pck->dT;
840        t1 = t2 - OPCALC_dSecondaryAssociationPrePickTime;
841
842  // Initialize the max affinity to the highest possible
843  //  non-associable value.  (Instead of initializing to
844  //  0, which would cause us to do affmax update, even
845  //  if the affinity wasn't high enough to associate)
846        affmax = OPCALC_dAffMinAssocValue * 0.99;
847
848  // STEP 3: For each origin within our time range
849  //         attempt to associate the pick with the origin.
850  //         Find the origin (if any exists) with the best
851  //         residual fit.
852        while(org = pGlint->getOrigin(t1, t2)) 
853  {
854
855    // STEP 3.1:
856    //         Copy the pick's params to a temp structure (CurrentPick)
857                memmove(&CurrentPick, pck, sizeof(CurrentPick));
858
859    // STEP 3.2:
860    //         Obtain the most likely phase-type (based upon angle, time, and depth),
861    //         and calculate the affinity of this pick as that phase-type, to the
862    //         current origin.
863                if(iRetCode = OPCalc_CalcPickAffinity(org, &CurrentPick))
864      if(iRetCode < 0)
865      {
866        CDebug::Log(DEBUG_MINOR_ERROR,"OPCalc_CalcPickAffinity() failed with code %d\n",
867                    iRetCode);
868        return(0);
869      }
870      else
871      {
872        continue;
873      }
874
875    // STEP 3.3:
876    //         If the current origin is the best match (so far), save it's ID.
877    //         and the origin-pick params (stored in Pick structure)
878                if(CurrentPick.dAff > affmax) 
879    {
880                        affmax = CurrentPick.dAff;
881                        strcpy(idorg, org->idOrigin);
882      memcpy(&BestPick, &CurrentPick, sizeof(CurrentPick));
883                }
884       //               CDebug::Log(DEBUG_MINOR_INFO,"    iTTT:%d sPhs:%s az:%.2f"
885       //                                " dD:%.2f dT:%.2f dZ:%.2f dToa:%.2f"
886       //                                " dTdD:%.2f dTdZ:%.2f\n",
887       //                                 ttt->iTTT, ttt->sPhs, az, ttt->dD, ttt->dT, ttt->dZ,
888       //               ttt->dToa, ttt->dTdD, ttt->dTdZ);
889  }  // end while(each eligible origin in list)
890
891  // STEP 4: If we found an acceptable origin, officially associate
892  //         the pick with the origin. 
893        if(affmax >= OPCALC_dAffMinAssocValue)
894  {
895    CDebug::Log(DEBUG_MINOR_INFO, "Assigning Pick(%s) to Origin:%s\n", pck->idPick, idorg);
896
897    // STEP 4.1:
898    //       Save the Origin-Pick params from BestPick to pck
899    memcpy(pck,&BestPick,sizeof(BestPick));
900
901    // STEP 4.2:
902    //       Perform the association.
903    if(bRetCode=AssociatePickWOrigin(idorg,pck))
904    {
905      // STEP 4.2.1:
906      //       Success, Pick Associated.
907      //       Return 1, indicating that the pick was associated.
908      return(1);
909    }
910  }
911  return(0);  // failed to associate.
912}  // end Assign()
913
914
915//------------------------------------------------------------------------AssociatePickWOrigin
916// Associate a pick with a hypocenter
917bool CGlass::AssociatePickWOrigin(char *idorg, PICK * pck) 
918{
919  // Formally associate a Pick with an Origin
920  // Assumes that the preliminary Origin-Pick parameters
921  // have been calculated (TOA, Phase Type, Residual, TTT)
922  // and stored in pck.
923
924  // STEP 0:   Validate the input params.
925  //           Retrieve the origin from glint, based on the given ID
926
927  if(!(idorg && pck))
928  {
929    CDebug::Log(DEBUG_MINOR_ERROR,"AssociatePickWOrigin(): Bad input params: "
930                                   "idorg(%u), pck(%u)\n",
931                                   idorg, pck);
932    return(false);
933  }
934  ORIGIN * pOrg = pGlint->getOrigin(idorg);
935
936  if(!pOrg)
937  {
938    CDebug::Log(DEBUG_MINOR_ERROR,"AssociatePickWOrigin(): Could "
939                                   "not retrieve origin for id(%s)\n",
940                idorg);
941    return(false);
942  }
943
944
945  // STEP 1:   Check to make sure the association doesn't violate any rules
946
947  // STEP 1.1: Make sure there aren't any matching picks already associated with
948  //           this event.
949  if(!HandleMatchingPicks(pOrg, pck))
950    return(false);
951
952  // STEP 2:   origin-pick params are ALREADY set in the Pick
953
954  // STEP 3:   Record the association in glint
955        if(!pGlint->OriginPick(idorg, pck->idPick))
956    return(false);
957
958  // STEP 4:   Update the performance counter.
959  nAssoc++;
960
961  // STEP 5:   Change the state of the pick to ASSOC
962  pck->iState = GLINT_STATE_ASSOC;
963
964  // STEP 6:   Export the new origin-pick-link
965        PutLink(idorg, pck->idPick);
966
967  // reinitialized stored focus location if any
968  pOrg->dFocusedT = 0.0;
969  pOrg->dFocusedZ = 0.0;
970
971  // STEP 7:   Done.  Return true.
972        return(true);
973}  // end AssociatePickWOrigin()
974
975
976
977//------------------------------------------------------------------------AssociatePickWOrigin
978// Associate a pick with a hypocenter
979bool CGlass::UnAssociatePickWOrigin(char *idorg, PICK * pck, bool bMarkOriginAsScavenged) 
980{
981  // Formally unassociate a Pick with an Origin
982
983  // STEP 0:   Validate the input params.
984  //           Retrieve the origin from glint, based on the given ID
985
986  if(!(idorg && pck))
987  {
988    CDebug::Log(DEBUG_MINOR_ERROR,"UnAssociatePickWOrigin(): Bad input params: "
989                                   "idorg(%u), pck(%u)\n",
990                                   idorg, pck);
991    return(false);
992  }
993  ORIGIN * pOrg = pGlint->getOrigin(idorg);
994
995  if(!pOrg)
996  {
997    CDebug::Log(DEBUG_MINOR_ERROR,"UnAssociatePickWOrigin(): Could "
998                                   "not retrieve origin for id(%s)\n",
999                idorg);
1000    return(false);
1001  }
1002
1003
1004  // STEP 1:   Record the association in glint
1005        pGlint->UnOriginPick(idorg, pck->idPick);
1006
1007  // STEP 2:   Update the performance counter.
1008  nAssoc--;
1009
1010  // STEP 3:   Change the state of the pick to WAIF
1011  pck->iState = GLINT_STATE_WAIF;
1012
1013  // STEP 4:   Export the new un-origin-pick-link
1014        PutUnLink(idorg, pck->idPick);
1015
1016  // STEP 5:   If desired, mark the origin as scaveneged to give it a chance
1017  //           to clean itself up.
1018  if(bMarkOriginAsScavenged)
1019    MarkOriginAsScavenged(pOrg->idOrigin);
1020
1021
1022  // STEP 6:   Done.  Return true.
1023        return(true);
1024}  // end UnAssociatePickWOrigin()
1025
1026
1027//---------------------------------------------------------------------------------------Waif
1028// Scan unassociated picks for inclusion in recently modified hypocenter
1029//  returns:
1030//              0: No changes
1031//              1: Waifs associated, need to relocate
1032int CGlass::Waif(char *idorg) {
1033        ORIGIN *org;
1034        PICK *pck;
1035        double t1;
1036        double t2;
1037        int n=0;  // Initialize "number of picks associated" to 0
1038  //TTEntry tttLocal;
1039
1040  int iRetCode;
1041  // CARL 120303 remove
1042        // TTT *ttt;
1043        // double tres;
1044        // double t;
1045        // double z;
1046        // double d;
1047
1048  // CARL 120303
1049  PICK CurrentPick;
1050  int res=0;
1051  //double aff;
1052
1053  // STEP 0: Validate parameters
1054  // If we don't have access to traveltime tables, abort.
1055        if(!(pTT && idorg))
1056  {
1057    CDebug::Log(DEBUG_MINOR_ERROR, "Waif(): pTT(%u) and idorg(%u) are both "
1058                                   "needed as input params. Returning error!\n",
1059                pTT, idorg);
1060    return NULL;
1061  }
1062
1063  // STEP 1:   Retrieve full information for the Origin from GLINT.
1064  //           Abort if Origin is not found.
1065        org = pGlint->getOrigin(idorg);
1066        if(!org)
1067                return 0;
1068
1069  // STEP 2:   Calculate a time range (t1 - t2), for which to look
1070  //           for picks that might be associatable with the Origin.
1071  t1 = org->dT;
1072        t2 = t1 + OPCALC_dSecondaryAssociationPrePickTime;  // 28 minutes
1073
1074  // STEP 3:   For each unassociated pick within the timerange, attempt
1075  //           to associate the pick.
1076  int iPickRef=0;
1077        while(pck = pGlint->getWaifsForTimeRange(t1, t2, &iPickRef)) 
1078  {
1079    if(pck->iState != GLINT_STATE_WAIF)
1080    {
1081      CDebug::Log(DEBUG_MINOR_ERROR, "Pick %s retrieved in getWaifsXXX() call, but is not waif(%d)\n",
1082                  pck->idPick, pck->iState);
1083      continue;
1084    }
1085                memmove(&CurrentPick, pck, sizeof(PICK));
1086    // STEP 3.1:   For each unassociated pick within the timerange, attempt
1087    //           to associate the pick.
1088                iRetCode = OPCalc_CalcPickAffinity(org, &CurrentPick);
1089    // STEP 3.2:   Ensure we were successfully able to calc an affinity
1090    if(iRetCode != 0)
1091    {
1092      if(iRetCode < 0)
1093      {
1094        CDebug::Log(DEBUG_MINOR_ERROR,"Waif(): Error during OPCalc_CalcPickAffinity(%s)\n",
1095                    CurrentPick.idPick);
1096        return(0);
1097      }
1098      continue;
1099    }
1100
1101    // STEP 3.2:   If the pick has a high enough affinity, associate
1102    //             it with the Origin.
1103    if(CurrentPick.dAff >= OPCALC_dAffMinAssocValue) 
1104    {
1105      memcpy(pck,&CurrentPick, sizeof(CurrentPick));
1106      if(AssociatePickWOrigin(idorg,pck))
1107      {
1108        n++;
1109        res = 1;
1110      }
1111    }
1112  }  // end while(each waif in time range)
1113        return res;
1114}  // end Waif()
1115
1116
1117//---------------------------------------------------------------------------------------Locate
1118// Locate.   (Actual Location done by 'glock' module)
1119//  returns
1120//              0: Location not changed
1121//              1: Location changed
1122//    2: Location unresolvable
1123int CGlass::Locate(char *idorg, char *mask) 
1124{
1125        double t = Secs();
1126        IMessage *m;
1127  int res;
1128
1129  ORIGIN * pOrg = pGlint->getOrigin(idorg);
1130  if(!pOrg)
1131    return(0);
1132
1133  CDebug::Log(DEBUG_MINOR_INFO, "Locate: starting Origin(%.2f/%.2f/%.0f - %.2f  %d,%d\n",
1134              pOrg->dLat, pOrg->dLon, pOrg->dZ, pOrg->dT, pOrg->nPh, pOrg->nEq);
1135
1136  // Send out a Locate Message (for GLOCK)
1137        m = pMod->CreateMessage("Locate");
1138        m->setStr("Quake", idorg);
1139        if(mask)
1140                m->setStr("Mask", mask);
1141        pMod->Dispatch(m);
1142
1143  // Get the result
1144  res = m->getInt("Res");
1145
1146  // Release the message
1147        m->Release();
1148
1149//  if(res== 0 || res == 1)
1150    if(res== 0)
1151          pOrg->nLocate++;
1152
1153  // DK REMOVED  - Locator will calculate Affinity during sanity check
1154        // Affinity(org);
1155        Mon[0].tLoc += Secs() - t;
1156
1157  CDebug::Log(DEBUG_MINOR_INFO, "Locate: ending Origin(%.2f/%.2f/%.0f - %.2f  %d,%d\n",
1158              pOrg->dLat, pOrg->dLon, pOrg->dZ, pOrg->dT, pOrg->nPh, pOrg->nEq);
1159
1160  // This was an Algorithmic change added by DK in v1.0 and subsequently pulled
1161  // DK 1.0 PULL  // Trim picks with outlying residuals.
1162  // DK 1.0 PULL  TrimOutliers(pOrg);
1163
1164  // Export the Origin
1165        PutOrigin(idorg,false);
1166  return(1);
1167}  // end Locate()
1168
1169
1170int CGlass::UpdateGUI(char * idOrigin)
1171{
1172  // Update the GUI
1173        Grok(idOrigin);
1174  return(0);
1175}  // UpdateGUI()
1176
1177//---------------------------------------------------------------------------------------Focus
1178// Calculate new origin from refocussing algoritm
1179// Action returns
1180//              0: No change
1181//              1: New location assisgned
1182int CGlass::Focus(char *idorg) {
1183        IMessage *m;
1184        m = pMod->CreateMessage("Focus");
1185        m->setStr("Quake", idorg);
1186        pMod->Dispatch(m);
1187
1188  // Get the result
1189  int res = m->getInt("Res");
1190
1191  // Release the message
1192        m->Release();
1193
1194  if(res == 0)
1195          return 1;
1196  else
1197    return 0;
1198}
1199
1200//---------------------------------------------------------------------------------------Prune
1201// Action returns
1202//              0: No change
1203//              1: Picks disassociated
1204int CGlass::Prune(char *idorg) 
1205{
1206        PICK *pPick;
1207        ORIGIN *pOrg;
1208        int res;
1209
1210        pOrg = pGlint->getOrigin(idorg);
1211        if(!pOrg)
1212                return 0;
1213        res = 0;
1214  int iPickRef=0;
1215  while(pPick = pGlint->getPicksFromOrigin(pOrg,&iPickRef))
1216  {
1217    if(pPick->bTTTIsValid && pPick->dAff >= (OPCALC_dAffMinAssocValue - OPCALC_dAffinitySlop))
1218      continue;
1219
1220    // Deassociate if affinity too low
1221          CDebug::Log(DEBUG_MINOR_INFO,
1222                            "Pick(%d   %s - %s - %.0f, %.1f %3.0f) (%4.1f=%4.1f*%4.1f*%4.1f*%4.1f) - %4.1f being pruned from Origin(%s)\n",
1223                            pPick->idPick, pPick->sSite, pPick->sPhase, pPick->dDelta, pPick->tRes, pPick->dAzm, 
1224                pPick->dAff, pPick->dAffRes, pPick->dAffDis, pOrg->dAffGap, pOrg->dAffNumArr, pOrg->dAff, idorg );
1225         
1226          UnAssociatePickWOrigin(pOrg->idOrigin,pPick,false);
1227          res = 1;
1228  }
1229        return res;
1230}
1231
1232//---------------------------------------------------------------------------------------Prune
1233// Action returns
1234//              0: No change
1235//              1: Picks disassociated
1236int CGlass::PrunePick(char *idOrigin, char * idPick) 
1237{
1238  PICK *pPick;
1239  ORIGIN *pOrg;
1240 
1241  pOrg = pGlint->getOrigin(idOrigin);
1242  if(!pOrg)
1243    return(0);
1244 
1245  pPick = pGlint->getPickFromidPick(idPick);
1246  if(!pOrg)
1247    return(0);
1248 
1249  UnAssociatePickWOrigin(pOrg->idOrigin, pPick, false);
1250  return(1);
1251}
1252
1253//---------------------------------------------------------------------------------------Scavenge
1254// Action returns
1255//              0: No change
1256//              1: Picks scavenged and added to primary
1257int CGlass::Scavenge(char *idorg) {
1258        PICK CurrentPick;
1259        PICK *pPick;
1260        ORIGIN *pOrg;
1261        ORIGIN *pOrg2;
1262        double t1;
1263        double t2;
1264  int iNumScavenged = 0;
1265
1266        pOrg = pGlint->getOrigin(idorg);
1267        if(!pOrg)
1268                return 0;
1269        t1 = pOrg->dT - 10.0;
1270        t2 = pOrg->dT + 2000.0;
1271  int iPickRef=0;
1272        while(pPick = pGlint->getPicksForTimeRange(t1, t2, &iPickRef)) 
1273  {
1274                // Already associated
1275                if(pPick->iState == GLINT_STATE_ASSOC && pPick->iOrigin == pOrg->iOrigin)
1276                        continue;
1277                // Caculate affinity for new association
1278                memmove(&CurrentPick, pPick, sizeof(PICK));
1279
1280                CurrentPick.iState = GLINT_STATE_WAIF;
1281                OPCalc_CalcPickAffinity(pOrg, &CurrentPick);
1282                if(pPick->iState == GLINT_STATE_WAIF) 
1283    {
1284                        if(CurrentPick.dAff > OPCALC_dAffMinAssocValue) 
1285      {
1286        //Associate  (try to associate, if error, then oh-well)
1287        AssociatePickWOrigin(pOrg->idOrigin,pPick);
1288                        }
1289                }
1290    else
1291    {
1292      // Belongs to another quake
1293      // Check to see if the existing origin/pick affinity
1294      // is better than ours.
1295      if(CurrentPick.dAff > pPick->dAff)
1296      {
1297
1298        CDebug::Log(DEBUG_MAJOR_INFO,
1299                    "Pick(%d   %s - %s - %.0f, %.1f) being scavenged from Origin(%s)\n",
1300                    pPick->idPick, pPick->sSite, pPick->sPhase, pPick->dDelta, pPick->tRes, idorg);
1301         
1302       
1303        // Unassociate the pick with the other origin
1304        if(pOrg2 = pGlint->getOriginForPick(pPick))
1305        {
1306          UnAssociatePickWOrigin(pOrg2->idOrigin,pPick,true);
1307        }
1308        else
1309          CDebug::Log(DEBUG_MINOR_ERROR,
1310                      "Pick(%s) supposively associated with Origin(%d), but origin "
1311                      "could not be retrieved.\n",  pPick->idPick, pPick->iOrigin);
1312
1313       
1314        // Associate the pick with the current origin.
1315        memcpy(pPick,&CurrentPick,sizeof(CurrentPick));
1316        if(AssociatePickWOrigin(pOrg->idOrigin,pPick))
1317          iNumScavenged++;
1318      }
1319    }
1320  }  // end while(each pick in range)
1321  if(iNumScavenged > 0)
1322    return(1);
1323  else
1324          return 0;
1325}  // end Scavenge()
1326
1327
1328// Primary associate, collect all waif that are possible candidates for inclusion with
1329// pick provided and attempt to create a new origin.
1330//  returns
1331//              0: No change
1332//              1: New quake nucleated
1333int CGlass::Associate(char *idpck) {
1334        ORIGIN org;
1335        CSpock *spock;
1336        PICK *pck;              // Primary pick
1337
1338  // STEP 1:   Obtain the full information for the pick
1339  //           from GLINT.
1340        pck = pGlint->getPickFromidPick(idpck);
1341        if(!pck)
1342                return false;
1343//      Debug("Glint succeeded\n");
1344
1345  // STEP 2: Select a time range (t1 - t2), within which
1346  //         we will search for picks that could
1347  //         be associated with the current pick.
1348        double t1 = pck->dT + dTimeBefore;
1349        double t2 = pck->dT + dTimeAfter;
1350        Pck[0] = pck;
1351        nPck = 1;
1352
1353  // STEP 3: For each pick within our time range
1354  //         copy the pick into our private Pick array.
1355  //         Don't exceed MAXPCK picks.
1356  int iPickRef=0;
1357        while(pck = pGlint->getWaifsForTimeRange(t1, t2, &iPickRef)) {
1358//              Debug("Waif[%d] %s\n", nPck, pck->idPick);
1359                if(pck->iPick == Pck[0]->iPick)
1360                        continue;
1361                Pck[nPck] = pck;
1362                if(nPck >= MAXPCK)
1363    {
1364      pGlint->endPickList(&iPickRef);
1365                        break;
1366    }
1367                nPck++;
1368  }  // end while picks
1369
1370  // STEP 4: We can't associate with less than
1371  //         four picks.  If we have less than
1372  //         four, we're done.  Quit and go home.
1373  //         Quit and go home if we don't have
1374  //         a number approaching nCut, since it
1375  //         will be cut later, because of lack of
1376  //         nCut points, even if it associates well.
1377        if(nPck < (nCut / 1.25))
1378                return false;
1379
1380        double a;
1381        double z;
1382        double t;
1383        double lat;
1384        double lon;
1385        double abest = 10000.0;
1386        double t0;
1387        double lat0;
1388        double lon0;
1389        double z0;
1390        int i;
1391
1392
1393  // STEP 5: Only use Primary phases (P,Pup,Pdiff) for association
1394  //         of new origins.
1395
1396  // STEP 6: Select a time range (t1 - t2), within which
1397  //         we think an Origin could have occurred, assuming
1398  //         the given phase is a P-ish arrival.
1399        t2 = Pck[0]->dT - 0.9;
1400        t1 = t2 + dTimeOrigin;
1401
1402 
1403  // STEP 7: Attempt to associate the picks in the array at
1404  //         different time/depth points.  Find the best
1405  //         origin, based on a residual-value.  Record the parameters
1406  //         of the best trial origin.
1407  //
1408  //         For each depth shell that we are configured to use,
1409  //         iterate through possible origin times.
1410        for(i=0; i<nShell; i++) 
1411  {
1412                z = dShell[i];
1413
1414    // STEP 7.1:
1415    //       For each timestep within our (t1-t2) timerange.  Attempt to
1416    //       associate the picks in the array into an origin, at
1417    //       the given depth(z).
1418                for(t=t1; t<t2; t+=dTimeStep) 
1419    {
1420
1421      // STEP 7.1.1:
1422      //     Attempt to associate the picks in the array into an origin,
1423      //     recording a residual value for the origin.
1424      //     (See Associate() for a description of how the
1425      //      residual-value is calculated.)
1426                        a = Associate(t, z, &lat, &lon);
1427
1428
1429      // STEP 7.1.2:
1430      //     If the residual value of the current origin, is the
1431      //     smallest so far, save the parameters of the current
1432      //     origin: time, lat, lon, and depth(z)
1433                        if(a < abest) {
1434                                abest = a;
1435                                t0 = t;
1436                                lat0 = lat;
1437                                lon0 = lon;
1438                                z0 = z;
1439                        }
1440    }  // end for each timestep
1441  }    // end for each depth shell
1442
1443
1444  // STEP 8: Record the best origin location, even if it doesn't
1445  //         have the required nucleation distance.
1446  //
1447        dAss[nAss%MAXASS] = abest;
1448        nAss++;
1449
1450
1451  // STEP 9: If our origin meets the required distance nucleation
1452  //         criteria, process it.
1453  //
1454        if(abest < dCut) 
1455  {
1456    // STEP 9.1:
1457    //       Record the new origin in GLINT.
1458                org.iVersion = GLINT_VERSION;
1459                org.dT = t0;
1460                org.dLat = lat0;
1461                org.dLon = lon0;
1462                org.dZ = z0;
1463                org.nEq = 0;
1464    org.nPh = 0;
1465                org.dRms = 0.0;
1466                org.dDelMin = 0.0;
1467                org.dDelMod = 0.5;
1468                org.dDelMax = 1.0;
1469    org.dGap = 360.0;
1470    org.dAffGap = org.dAffNumArr = 1.0;
1471   
1472// DK 1.0 PULL      org.nNextExtProc = iReportInterval;
1473                CDate dt(t0);
1474                CDebug::Log(DEBUG_MINOR_INFO, "Origin: %s %.4f %.4f %.2f (%.4f)\n",
1475                        dt.Date20().GetBuffer(), lat0, lon0, z0, abest);
1476                sprintf(org.sTag, "0.0.0.0");
1477                pGlint->putOrigin(&org);
1478                CDebug::Log(DEBUG_MINOR_INFO, "Nucleated %s: %d lat:%.4f lon:%.4f z:%.4f\n", org.idOrigin, org.iOrigin, org.dLat, org.dLon, org.dZ);
1479
1480    // STEP 9.2:
1481    //       Export the new origin to Earthworm or some other seismic processing system.
1482    PutOrigin(org.idOrigin,true);
1483    nQuake++;
1484
1485    // STEP 9.2.1:
1486    //       Associate the starting pick with the Origin.  (FORCE THIS ASSOCIATION)
1487    //       It can always be pruned later.
1488    pck = pGlint->getPickFromidPick(idpck);
1489    if(!AssociatePickWOrigin(org.idOrigin, pck))
1490      return(false);
1491
1492
1493    // STEP 9.3:
1494    //       Attempt to associate any/all of the unassociated picks with
1495    //       the new origin.
1496                Waif(org.idOrigin);
1497
1498    // STEP 9.4:
1499    //       Write Associator debug info to the log file if desired.
1500    //       (We will need to rerun the secondary associate on
1501    //        the origin to get all the parameters for logging)
1502                if(pMod->bSpockReport) {
1503                        spock = new CSpock();
1504                        spock->Init(this, pMod->pReport);
1505      Associate(t0, z0, &lat, &lon);
1506                        spock->Report(t0, lat0, lon0, z0, nXYZ, dXYZ);
1507                        delete spock;
1508                }
1509
1510    // STEP 9.5:
1511    //       Locate the new origin.  (Attempt to improve the location
1512    //         through iterative hypocenter adjustments)
1513    //Locate(org.idOrigin, 0);
1514    // DK  No need to call Locate, state-logic will handle the transition
1515    // LocateOrigin(org.idOrigin);
1516
1517
1518    // STEP 9.6:
1519    //       Done.  Return true indicating that we succesfully associated
1520    //       a new quake around the given phase.
1521        return true;
1522        }
1523               //       Debug("Association failed\n");
1524
1525  // STEP 10:Done.  Return false indicating that we were not able
1526  //         to associate the given phase into a new acceptable hypocenter.
1527  return false;
1528}  //end Associate(idPck)
1529
1530//---------------------------------------------------------------------------------------Associate
1531// Auxilliary association (called once for each origin time and depth shell
1532// This function must be called by the primary Associate() function, because
1533//   the primary fills in the Pck[] array with picks eligible to be used in
1534//   the auxilliary.
1535double CGlass::Associate(double torg, double depth, double *lat, double *lon) 
1536{
1537  return(AssociatePicks(torg, depth, lat, lon, Pck, nPck, pTT,nCut));
1538}
1539
1540//------------------------------------------------------------------------HandleMatchingPicks
1541// Scan origin for any picks matching the given one (Phase and SCNL are the same)
1542// Handle any unassociation deemed neccessary.
1543// Return true if the given pick should be associated with Origin, or
1544// false if it should not.
1545bool CGlass::HandleMatchingPicks(ORIGIN * pOrg, PICK * pPick)
1546{
1547    PICK * pAltPick;
1548    // We should do a check here.  We should make sure that we are not associating
1549    // a new pick with a Phase that is already associated for an existing channel
1550    // If we already have a pick from XYZ that is associated with quake as P phase,
1551    // then we should not associate another XYZ pick with the quake as a P phase.
1552    // There should be only one P phase per channel per quake.
1553    // To be fancy, we could check to see if the residual for the new pick is better
1554    // than the residual for the old pick.
1555    // To be really fancy, we could try to do a distance/tt fit based upon the time
1556    // between one pick and the next.
1557    //       Retrieve the selected phasetype for the pick from the traveltime
1558    //       record.
1559
1560  if(!(pOrg && pPick))
1561  {
1562    CDebug::Log(DEBUG_MINOR_ERROR,"HandleMatchingPicks(): Bad input params: "
1563                                   "pOrg(%u), pPick(%u),\n",
1564                pOrg, pPick);
1565    return(false);
1566  }
1567   
1568  int iPickRef=0;
1569        while(pAltPick = pGlint->getPicksFromOrigin(pOrg,&iPickRef)) 
1570  {
1571    // If the channel's don't match (SCNL), we're OK.  Continue
1572    if(pGlint->ComparePickChannels(pAltPick,pPick))
1573      continue;
1574
1575    // If the phase type's don't match (P vs. PP), we're OK.  Continue
1576    if(strcmp(pAltPick->sPhase,pPick->sPhase))
1577      continue;
1578
1579    // Now we're in trouble.  We have two matching phases
1580    //    example:   AAA EHZ US "P" and AAA EHZ US "P"
1581
1582    // Calculate the affinity for the new pick (pPick)
1583    // ASSUME: we assume that the
1584    // affinity for the new pick already calculated prior to
1585    // AssociatePickWOrigin() call.
1586
1587    // Calculate the residual for the old pick (pAltPick)
1588    // Affinity for the old pick already calculated during last
1589    // location, or when it was associated with the origin.
1590
1591    if(pAltPick->dAff >= pPick->dAff)
1592    {
1593      // We can't improve on the affinity of the old pick.
1594      // Leave well enough alone.  Don't associate this
1595      // pick with the origin, because there's already
1596      // a matching phase and the new one is no better.
1597      if(pAltPick->dT == pPick->dT)
1598      {
1599        CDebug::Log(DEBUG_MINOR_INFO,
1600                    "HandleMatchingPicks(): DUPLICATE PICKS found.  \n"
1601                    "%s:%.2f (old %s) (new %s)\n",
1602                    pAltPick->sSite, pAltPick->dT, pAltPick->sTag,
1603                    pPick->sTag);
1604      }
1605      CDebug::Log(DEBUG_MINOR_INFO,
1606                    "HandleMatchingPicks(): duplicate found.  \n"
1607                    "Keeping old (%s:%s (old %.2f-%5.2f) (new %.2f-%5.2f)\n",
1608                  pAltPick->sSite, pAltPick->sPhase, 
1609                  pAltPick->dT, pAltPick->dAff,
1610                  pPick->dT, pPick->dAff);
1611      pGlint->endPickList(&iPickRef);
1612      return(false);
1613    }
1614    else
1615    {
1616      // Now we're in trouble.  The new phase is a better fit
1617      // than the old phase.  Disassociate the old phase!
1618      CDebug::Log(DEBUG_MAJOR_INFO,
1619                    "HandleMatchingPicks(): duplicate found.  \n"
1620                    "Using new   (%s:%s (old %.2f-%5.2f) (new %.2f-%5.2f)\n",
1621                  pAltPick->sSite, pAltPick->sPhase, 
1622                  pAltPick->dT, pAltPick->dAff,
1623                  pPick->dT, pPick->dAff);
1624            UnAssociatePickWOrigin(pOrg->idOrigin, pAltPick, true);
1625      pGlint->endPickList(&iPickRef);
1626      break;  // there should be at most one matching pick.
1627    }
1628  }  // end while picklist
1629  return(true);
1630}  // end HandleMatchingPicks()
1631
1632
1633bool CGlass::SetTravelTimePointer(ITravelTime * ptt)
1634{
1635  if(ptt)
1636  {
1637    pTT = ptt;
1638    OPCalc_SetTravelTimePointer(pTT);
1639    return(true);
1640  }
1641  else
1642  {
1643    return(false);
1644  }
1645}
1646
1647
1648/************************** DK REMOVE from v1.0
1649int CGlass::PerformExtendedProcessing(ORIGIN * pOrg)
1650{
1651  int iNumPhases;
1652
1653  CDebug::Log(DEBUG_MAJOR_INFO, "Attempting to scavenge picks for origin:%s\n",
1654              pOrg->idOrigin);
1655
1656  // Attempt to scavenge picks from smaller quakes.
1657  iNumPhases = Scavenge(pOrg);
1658
1659  CDebug::Log(DEBUG_MAJOR_INFO, "Scavenged %d picks for origin %s!\n",
1660              iNumPhases, pOrg->idOrigin);
1661
1662  PutOrigin(pOrg->idOrigin, true);
1663
1664  return(0);
1665}
1666
1667
1668// Remove picks with high residuals
1669bool CGlass::TrimOutliers(ORIGIN * pOrg)
1670{
1671  double tRes;
1672  PICK * pPick;
1673
1674  // STEP 1: Insure that we have a valid origin pointer
1675  if(!pOrg)
1676    return(false);
1677
1678  // STEP 2: For each pick associated with the given origin
1679  //         check to make sure the residual(s) is within an
1680  //         acceptable range.
1681  int iPickRef=0;
1682  while(pPick = pGlint->getPicksFromOrigin(pOrg,&iPickRef))
1683  {
1684    // STEP 2.1:   
1685    //         Calculate the residual(sec) between the traveltime for the
1686    //         selected phase and the actual deltaT
1687                tRes = pPick->dT - pOrg->dT - pPick->dTrav;
1688                if(tRes > GLASS_RESIDUAL_THRESHOLD || tRes < (0 - GLASS_RESIDUAL_THRESHOLD))
1689                {
1690      CDebug::Log(DEBUG_MAJOR_INFO, "Triming Pick %s from Origin %s because of residual(%s:%.2f)\n",
1691                  pPick->idPick, pOrg->idOrigin, pPick->sPhase, tRes);
1692      pGlint->UnOriginPick(pOrg->idOrigin, pPick->idPick);
1693    }
1694  }  // end while picks
1695  return(true);
1696}
1697
1698
1699//---------------------------------------------------------------------------------------Scavenge
1700// Scan unassociated picks for inclusion in recently modified hypocenter
1701int CGlass::Scavenge(ORIGIN * pOrg) {
1702        PICK *pck;
1703        TTT *ttt;
1704  ORIGIN * pAltOrigin;
1705        double tres;
1706        double t1;
1707        double t2;
1708        double t;
1709        double z;
1710        double d;
1711  TTT tttLocal;
1712        int n=0;  // Initialize "number of picks associated" to 0
1713
1714  // If we don't have access to traveltime tables, abort.
1715        if(!pTT)
1716                return 0;
1717
1718  // STEP 1:   Calculate a time range (t1 - t2), for which to look
1719  //           for picks that might be associatable with the Origin.
1720        t1 = pOrg->dT;
1721        t2 = t1 + 1680.0;
1722
1723  // STEP 2:   For each pick within the timerange, attempt
1724  //           to associate the pick(assuming it doesn't already
1725  //           belong to the current event or a larger one.
1726  int iPickRef=0;
1727        while(pck = pGlint->getPicksForTimeRange(t1, t2, &iPickRef))
1728  {
1729    // Don't try to steal picks from ourself.
1730                if(pck->iOrigin == pOrg->iOrigin)
1731                        continue;
1732
1733    // STEP 2.1:
1734    //        Make sure we're allowed to use this pick
1735    //        (It's unassociated, or associated with a smaller
1736    //         quake. )
1737    if(pck->iState == GLINT_STATE_ASSOC)
1738    {
1739      pAltOrigin = pGlint->getOriginForPick(pck);
1740      if(pAltOrigin  && pAltOrigin->nPh > pOrg->nPh)
1741      {
1742        // we don't have precedence to steal this phase from
1743        // the other quake.  Continue to the next phase.
1744        continue;
1745      }
1746    }
1747    else
1748    {
1749      pAltOrigin = NULL;
1750    }
1751    // STEP 2.2:   
1752    //         Calculate the following params for use in fitting
1753    //         the pick to the closest theoretical phase via
1754    //         the traveltime tables:
1755    //             t:  deltaT between origin time and pick time
1756    //             z:  depth of the origin(km)
1757    //             d:  radial distance(rad) between origin and pick
1758                t = pck->dT - pOrg->dT;
1759                z = pOrg->dZ;
1760                d = pTT->Delta(pOrg->dLat, pOrg->dLon, pck->dLat, pck->dLon);
1761
1762
1763    // STEP 2.3:   
1764    //         Retrieve the most likely phase type from the traveltime tables.
1765                ttt = pTT->Best(d, t, z);
1766
1767
1768    // STEP 2.4:   
1769    //         If there is no likely phase for this pick, continue on
1770    //         to the next pick.
1771                if(!ttt)
1772                        continue;
1773    else
1774      memcpy(&tttLocal,ttt,sizeof(tttLocal));
1775
1776
1777    // STEP 2.5:   
1778    //         Calculate the residual(sec) between the traveltime for the
1779    //         selected phase and the actual deltaT
1780                tres = pck->dT - pOrg->dT - tttLocal.dT;
1781
1782
1783    // STEP 2.6:   
1784    //         If the residual is within the acceptable
1785    //         threshold (+/- GLASS_RESIDUAL_THRESHOLD),
1786    //         associate the pick with the Origin.
1787                if(tres > (0 - GLASS_RESIDUAL_THRESHOLD) && tres < GLASS_RESIDUAL_THRESHOLD)
1788                {
1789      CDebug::Log(DEBUG_MAJOR_INFO, "Pick:%s(%s) associated with Origin:%s "
1790                                    "(scavenged from Origin %s)\n",
1791                                    pck->idPick, pck->sSite, pOrg->idOrigin,
1792                                    pAltOrigin ? pAltOrigin->idOrigin: "<NULL>");
1793     
1794      // STEP 2.6.1:   
1795      //       Unassociate the pick from any existing origin
1796      //       if it is already associated.
1797      if(pAltOrigin)
1798      {
1799        pGlint->UnOriginPick(pAltOrigin->idOrigin, pck->idPick);
1800      }
1801
1802      // STEP 2.6.2:   
1803      //       Formally associate the waif pick w/origin
1804      if(!AssociatePickWOrigin(pOrg->idOrigin,pck))
1805        CDebug::Log(DEBUG_MAJOR_INFO, "AssociatePickWOrigin() failed for (%s,%s)\n",
1806                    pOrg->idOrigin, pck->idPick);
1807
1808
1809      // STEP 2.6.3:   
1810      //       Update the return value counter
1811      n++;
1812                }
1813  }   // end while picks
1814
1815  // STEP 3:   If we matched up atleast one pick with the modified
1816  //           origin, then re-locate the origin.
1817  if(n)
1818  {
1819    if(bLocate)
1820      Locate(pOrg->idOrigin, NULL);
1821    else
1822      Locate(pOrg->idOrigin, "TNEZ");
1823  }
1824        CDebug::Log(DEBUG_MAJOR_INFO, "Scavenge n=%d\n", n);
1825
1826
1827  // STEP 5:   Return the number of waif picks associated with the Origin.
1828        return n;
1829}  // end Scavenge(idOrg)
1830********************* END DK PULL from v1.0 ***************************************/
1831
1832
Note: See TracBrowser for help on using the repository browser.