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

Revision 3212, 57.4 KB checked in by paulf, 12 years ago (diff)

sync from hydra_proj circa Oct 2007

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