source: trunk/src/seismic_processing/eqprelim/eqprelim.c @ 2724

Revision 2724, 44.1 KB checked in by paulf, 13 years ago (diff)

fixed a ton of windows warnings

  • Property svn:eol-style set to native
  • Property svn:keywords set to Author Date Id Revision
Line 
1
2/*
3 *   THIS FILE IS UNDER RCS - DO NOT MODIFY UNLESS YOU HAVE
4 *   CHECKED IT OUT USING THE COMMAND CHECKOUT.
5 *
6 *    $Id$
7 *
8 *    Revision history:
9 *     $Log$
10 *     Revision 1.8  2007/02/26 19:50:03  paulf
11 *     fixed a ton of windows warnings
12 *
13 *     Revision 1.7  2007/02/26 13:44:40  paulf
14 *     fixed heartbeat sprintf() to cast time_t as long
15 *
16 *     Revision 1.6  2005/03/11 18:08:12  dietz
17 *     Modified to make pick/quake FIFO lengths configurable
18 *
19 *     Revision 1.5  2004/05/17 22:16:53  dietz
20 *     Modified to work with TYPE_PICK_SCNL and TYPE_CODA_SCNL as input
21 *     and to output TYPE_EVENT_SCNL.
22 *
23 *     Revision 1.4  2002/06/05 15:48:52  patton
24 *     Made logit changes.
25 *
26 *     Revision 1.3  2001/05/09 18:38:18  dietz
27 *     Changed to shut down gracefully if the transport flag is
28 *     set to TERMINATE or MyPID.
29 *
30 *     Revision 1.2  2000/07/24 20:38:44  lucky
31 *     Implemented global limits to module, installation, ring, and
32 *     message type strings.
33 *
34 *     Revision 1.1  2000/02/14 17:10:42  lucky
35 *     Initial revision
36 *
37 *
38 */
39
40/*
41 * eqprelim.c : Send out a preliminary event notification
42 *              after a user-set number of picks are associated
43 *              with it.
44 */
45#include <stdio.h>
46#include <stdlib.h>
47#include <string.h>
48#include <time.h>
49#include <math.h>
50#include <chron3.h>
51#include <earthworm.h>
52#include <kom.h>
53#include <rdpickcoda.h>
54#include <site.h>
55#include <tlay.h>
56#include <transport.h>
57
58#define ABS(x) (((x) >= 0.0) ? (x) : -(x))
59#define X(lon) (facLon * ((lon) - orgLon))
60#define Y(lat) (facLat * ((lat) - orgLat))
61#define hypot(x,y) (sqrt((x)*(x) + (y)*(y)))
62
63/* Functions in this source file
64 *******************************/
65void  eqprelim_config ( char * );
66void  eqprelim_lookup ( void );
67int   eqprelim_pickscnl( char * );
68int   eqprelim_codascnl( char * );
69int   eqprelim_link   ( char * );
70int   eqprelim_quake2k( char * );
71int   eqprelim_compare( const void *, const void * );
72void  eqprelim_notify ( int );
73void  eqprelim_status ( unsigned char, short, char * );
74char *eqprelim_phscard( int, char * );
75char *eqprelim_hypcard( int, char * );
76
77static SHM_INFO  Region;         /* shared memory region to use for input  */
78
79#define   MAXLOGO   8
80MSG_LOGO  GetLogo[MAXLOGO];     /* array for requesting module,type,instid */
81short     nLogo;
82
83/* Things to read from configuration file
84 ****************************************/
85static char RingName[MAX_RING_STR];       /* transport ring to read from    */
86static char MyModName[MAX_MOD_STR];      /* speak as this module name/id    */
87static int  LogSwitch;          /* 0 if no logging should be done to disk   */
88static char NextProc[150];      /* actual command to start next program     */
89static int  ReportS;            /* if 0, don't send S to next process       */
90static int  NumPickNotify;      /* send prelim eq if it has this many picks */
91static char LocalCode;          /* single char to label local picks with    */
92static long HeartbeatInt;       /* #seconds between heartbeats              */
93
94/* Things to look up in the earthworm.h tables with getutil.c functions
95 **********************************************************************/
96static long          RingKey;       /* key of ring for input         */
97static unsigned char InstId;        /* local installation id         */
98static unsigned char MyModId;       /* Module Id for this program    */
99static unsigned char TypeHeartBeat;
100static unsigned char TypeError;
101static unsigned char TypeQuake2K;
102static unsigned char TypeLink;
103static unsigned char TypePickSCNL;
104static unsigned char TypeCodaSCNL;
105static unsigned char TypeEventSCNL;
106static unsigned char TypeKill;
107
108static char  EqMsg[MAX_BYTES_PER_EQ]; /* char array to hold eq message  */
109
110/* Error messages used by eqprelim
111 *********************************/
112#define  ERR_MISSMSG            0
113#define  ERR_TOOBIG             1
114#define  ERR_NOTRACK            2
115#define  ERR_PICKREAD           3
116#define  ERR_CODAREAD           4
117#define  ERR_QUAKEREAD          5
118#define  ERR_LINKREAD           6
119#define  ERR_UNKNOWNSTA         7
120#define  ERR_TIMEDECODE         8
121
122#define  MAXSTRLEN            256
123static char  Text[MAXSTRLEN];  /* string for log/error messages */
124
125#define MAXHYP 100     /* default quake fifo length */
126typedef struct {
127        double  trpt;  /* time the event was reported */
128        double  t;
129        double  lat;
130        double  lon;
131        double  z;
132        long    id;
133        float   rms;
134        float   dmin;
135        float   ravg;
136        float   gap;
137        int     nph;
138        short   flag;    /* 0=virgin, 1=modified, 2=reported, -1=killed  */
139} RPT_HYP;
140RPT_HYP *Hyp; /* alloc to length=maxHyp */
141
142#define MAXPCK 1000   /* default pick fifo length */
143long nPck = 0;
144typedef struct {
145        double          t;
146        long            quake;
147        int             id;
148        unsigned char   src;
149        unsigned char   instid;
150        int             site;
151        char            phase;
152        char            ie;
153        char            fm;
154        char            wt;
155        long            pamp[3];
156        long            paav;
157        long            caav[6];
158        short           clen;
159        time_t          timeout;
160} RPT_PCK;
161RPT_PCK *Pck; /* alloc to length=maxPck */
162
163int nSrt;
164typedef struct {
165        double  t;
166        int     ip;
167} SRT;
168SRT *Srt; /* alloc to length=maxPck */
169
170/* Parameters
171 ************/
172double orgLat;
173double orgLon;
174double facLat;
175double facLon;
176size_t maxHyp = MAXHYP;         /* Quake FIFO length                    */
177size_t maxPck = MAXPCK;         /* Pick  FIFO length                    */
178pid_t  MyPID=0;
179
180int main( int argc, char **argv )
181{
182   char       rec[MAXSTRLEN];   /* actual retrieved message  */
183   long       recsize;          /* size of retrieved message */
184   MSG_LOGO   reclogo;          /* logo of retrieved message */
185   int        res;
186   int        iq;
187   int        is;
188   time_t     timeNow;          /* current time                */
189   time_t     timeLastBeat;     /* time of previous heartbeat  */
190
191/* Check command line arguments
192 ******************************/
193   if ( argc != 2 )
194   {
195        fprintf( stderr, "Usage: eqprelim <configfile>\n" );
196        exit( 0 );
197   }
198
199/* Initialize name of log-file & open it
200 ***************************************/
201   logit_init( argv[1], 0, MAXSTRLEN*2, 1 );
202
203/* Read the configuration file(s)
204 ********************************/
205   eqprelim_config( argv[1] );
206   logit( "" , "eqprelim: Read command file <%s>\n", argv[1] );
207
208/* Look up important info from earthworm.h tables
209 ************************************************/
210   eqprelim_lookup();
211
212/* Store my own processid
213 ************************/
214   MyPID = getpid();
215 
216/* Reinitialize logit to desired logging level
217 *********************************************/
218   logit_init( argv[1], 0, MAXSTRLEN*2, LogSwitch );
219
220/* Allocate space for Quake FIFO, Pick FIFO, sorting array
221 *********************************************************/
222   Hyp = (RPT_HYP *) calloc( maxHyp, sizeof( RPT_HYP ) );
223   if( Hyp == (RPT_HYP *) NULL ) {
224      logit( "et","eqprelim: Error allocating quake FIFO at length=%ld; "
225             "exiting!\n", maxHyp );
226      exit( -1 );
227   }
228   logit( "", "eqprelim: Allocated quake fifo (length=%ld)\n", maxHyp );
229
230   Pck = (RPT_PCK *) calloc( maxPck, sizeof( RPT_PCK ) );
231   if( Pck == (RPT_PCK *) NULL ) {
232      logit( "et","eqprelim: Error allocating pick FIFO at length=%ld; "
233             "exiting!\n", maxPck );
234      free( Hyp );
235      exit( -1 );
236   }
237   logit( "", "eqprelim: Allocated pick fifo (length=%ld)\n", maxPck );
238
239   Srt = (SRT *) calloc( maxPck, sizeof( SRT ) );
240   if( Srt == (SRT *) NULL ) {
241      logit( "et","eqprelim: Error allocating sort array at length=%ld; "
242             "exiting!\n", maxPck );
243      free( Hyp );
244      free( Pck );
245      exit( -1 );
246   }
247
248/* Initialize some variables
249 ***************************/
250   nPck   = 0;                  /* no picks have been processed    */
251   for(iq=0; iq<(int)maxHyp; iq++)   /* set all hypocenter id's to zero */
252   {
253        Hyp[iq].id  = 0;
254   }
255
256/* Attach to PICK shared memory ring & flush out all old messages
257 ****************************************************************/
258   tport_attach( &Region, RingKey );
259   logit( "", "eqprelim: Attached to public memory region %s: %d\n",
260          RingName, RingKey );
261   while( tport_getmsg( &Region, GetLogo, nLogo,
262                        &reclogo, &recsize, rec, MAXSTRLEN ) != GET_NONE );
263
264/* Start the next processing program & open pipe to it
265 *****************************************************/
266   if( pipe_init( NextProc, 0 ) < 0 ) {
267        logit( "et",
268               "eqprelim: Error opening pipe to %s; exiting!\n", NextProc);
269        tport_detach( &Region );
270        free( Hyp );
271        free( Pck );
272        free( Srt );
273        exit( -1 );
274   }
275   logit( "e", "eqprelim: piping output to <%s>\n", NextProc );
276
277/* Calculate network origin
278 **************************/
279   logit( "", "eqprelim: nSite = %d\n", nSite );
280   orgLat = 0.0;
281   orgLon = 0.0;
282   for(is=0; is<nSite; is++) {
283        orgLat += Site[is].lat;
284        orgLon += Site[is].lon;
285   }
286   orgLat /= nSite;
287   orgLon /= nSite;
288   facLat = (double)(40000.0 / 360.0);
289   facLon = facLat * cos(6.283185 * orgLat / 360.0);
290
291/* Force a heartbeat to be issued in first pass thru main loop
292 *************************************************************/
293   timeLastBeat = time(&timeNow) - HeartbeatInt - 1;
294
295/*----------------- setup done; start main loop -----------------------*/
296
297   while(1)
298   {
299     /* Send eqprelim's heartbeat
300      ***************************/
301        if ( time(&timeNow) - timeLastBeat  >=  HeartbeatInt )
302        {
303            timeLastBeat = timeNow;
304            eqprelim_status( TypeHeartBeat, 0, "" );
305        }
306
307     /* Process all new hypocenter, pick-time, pick-coda, & link messages
308      *******************************************************************/
309        do
310        {
311        /* see if a termination has been requested
312         *****************************************/
313           if ( tport_getflag( &Region ) == TERMINATE  ||
314                tport_getflag( &Region ) == MyPID )
315           {
316           /* send a kill message down the pipe */
317                pipe_put( "", TypeKill );
318                logit("e","eqprelim: sent TYPE_KILL msg to pipe.\n");
319           /* detach from shared memory */
320                tport_detach( &Region );
321           /* free allocated memory */
322                free( Hyp );
323                free( Pck );
324                free( Srt );
325           /* write a few more things to log file and close it */
326                logit( "t", "eqprelim: Termination requested; exiting!\n" );
327           /* close down communication to child */
328                pipe_close();
329                fflush( stdout );
330                return( 0 );
331           }
332
333        /* Get next message from shared memory; check return code
334         ********************************************************/
335           res = tport_getmsg( &Region, GetLogo, nLogo,
336                               &reclogo, &recsize, rec, MAXSTRLEN-1 );
337
338           if( res == GET_NONE )           /* no new messages */
339           {
340                break;
341           }
342           else if( res == GET_TOOBIG )    /* next msg too big for target; */
343           {                               /* complain & try for another   */
344                sprintf(Text,
345                        "Retrieved msg[%ld] (i%u m%u t%u) too big for rec[%d]",
346                        recsize, reclogo.instid, reclogo.mod, reclogo.type,
347                        MAXSTRLEN-1 );
348                eqprelim_status( TypeError, ERR_TOOBIG, Text );
349                continue;
350           }
351           else if( res == GET_MISS )      /* got a message, but missed some */
352           {
353                sprintf( Text,
354                        "Missed msg(s)  i%u m%u t%u  region:%ld.",
355                         reclogo.instid, reclogo.mod, reclogo.type, Region.key);
356                eqprelim_status( TypeError, ERR_MISSMSG, Text );
357           }
358           else if( res == GET_NOTRACK )   /* got a message; couldn't tell */
359           {                               /* if any were missed or not    */
360                sprintf( Text,
361                        "Msg received i%u m%u t%u; transport.h NTRACK_GET exceeded",
362                         reclogo.instid, reclogo.mod, reclogo.type );
363                eqprelim_status( TypeError, ERR_NOTRACK, Text );
364           }
365
366        /* Process the new message
367         *************************/
368           rec[recsize] = '\0';         /*null terminate the message*/
369         /*logit( "", "type:%u\n%s", reclogo.type, rec );*/   /*DEBUG*/
370
371           if( reclogo.type == TypePickSCNL )
372           {
373               eqprelim_pickscnl( rec );
374           }
375           else if( reclogo.type == TypeCodaSCNL )
376           {
377               eqprelim_codascnl( rec );
378           }
379           else if( reclogo.type == TypeQuake2K )
380           {
381               eqprelim_quake2k( rec );
382           }
383           else if( reclogo.type == TypeLink )
384           {
385               eqprelim_link( rec );
386           }
387
388        } while( res != GET_NONE );  /*end of message-processing-loop */
389
390        sleep_ew( 500 );  /* wait a bit for more messages to show up  */
391
392   }
393/*-----------------------------end of main loop-------------------------------*/
394}
395
396/******************************************************************************
397 *   eqprelim_config() processes command file(s) using kom.c functions        *
398 *                   exits if any errors are encountered                      *
399 ******************************************************************************/
400#define ncommand 10         /* # of required commands you expect to process   */
401void eqprelim_config( char *configfile )
402{
403   char     init[ncommand]; /* init flags, one byte for each required command */
404   int      nmiss;          /* number of required commands that were missed   */
405   char    *com; 
406   char    *str;
407   char     processor[64];
408   int      nfiles;
409   int      success;
410   int      i;
411
412/* Set to zero one init flag for each required command
413 *****************************************************/
414   for( i=0; i<ncommand; i++ )  init[i] = 0;
415   nLogo = 0;
416
417/* Open the main configuration file
418 **********************************/
419   nfiles = k_open( configfile );
420   if ( nfiles == 0 ) {
421        logit( "e",
422                "eqprelim: Error opening command file <%s>; exiting!\n",
423                 configfile );
424        exit( -1 );
425   }
426
427/* Process all command files
428 ***************************/
429   while(nfiles > 0)   /* While there are command files open */
430   {
431        while(k_rd())        /* Read next line from active file  */
432        {
433            com = k_str();         /* Get the first token from line */
434
435        /* Ignore blank lines & comments
436         *******************************/
437            if( !com )           continue;
438            if( com[0] == '#' )  continue;
439
440        /* Open a nested configuration file
441         **********************************/
442            if( com[0] == '@' ) {
443               success = nfiles+1;
444               nfiles  = k_open(&com[1]);
445               if ( nfiles != success ) {
446                  logit( "e",
447                          "eqprelim: Error opening command file <%s>; exiting!\n",
448                           &com[1] );
449                  exit( -1 );
450               }
451               continue;
452            }
453
454        /* Process anything else as a command
455         ************************************/
456            strcpy( processor, "eqprelim_config" );
457
458         /* Numbered commands are required
459          ********************************/
460  /*0*/     if( k_its("HeartbeatInt") ) {
461                HeartbeatInt = k_int();
462                init[0] = 1;
463            }
464  /*1*/     else if( k_its("LogFile") ) {
465                LogSwitch = k_int();
466                init[1] = 1;
467            }
468  /*2*/     else if( k_its("MyModuleId") ) {
469                str = k_str();
470                if(str) strcpy( MyModName, str );
471                init[2] = 1;
472            }
473  /*3*/     else if( k_its("RingName") ) {
474                str = k_str();
475                if(str) strcpy( RingName, str );
476                init[3] = 1;
477            }
478
479         /* Enter installation & module to get picks & codas from
480          *******************************************************/
481  /*4*/     else if( k_its("GetPicksFrom") ) {
482                if ( nLogo+1 >= MAXLOGO ) {
483                    logit( "e",
484                            "eqprelim: Too many <Get*> commands in <%s>",
485                             configfile );
486                    logit( "e", "; max=%d; exiting!\n", (int) MAXLOGO/2 );
487                    exit( -1 );
488                }
489                if( ( str=k_str() ) ) {
490                   if( GetInst( str, &GetLogo[nLogo].instid ) != 0 ) {
491                       logit( "e",
492                               "eqprelim: Invalid installation name <%s>", str );
493                       logit( "e", " in <GetPicksFrom> cmd; exiting!\n" );
494                       exit( -1 );
495                   }
496                   GetLogo[nLogo+1].instid = GetLogo[nLogo].instid;
497                }
498                if( ( str=k_str() ) ) {
499                   if( GetModId( str, &GetLogo[nLogo].mod ) != 0 ) {
500                       logit( "e",
501                               "eqprelim: Invalid module name <%s>", str );
502                       logit( "e", " in <GetPicksFrom> cmd; exiting!\n" );
503                       exit( -1 );
504                   }
505                   GetLogo[nLogo+1].mod = GetLogo[nLogo].mod;
506                }
507                if( GetType( "TYPE_PICK_SCNL", &GetLogo[nLogo].type ) != 0 ) {
508                    logit( "e",
509                               "eqprelim: Invalid message type <TYPE_PICK_SCNL>" );
510                    logit( "e", "; exiting!\n" );
511                    exit( -1 );
512                }
513                if( GetType( "TYPE_CODA_SCNL", &GetLogo[nLogo+1].type ) != 0 ) {
514                    logit( "e",
515                               "eqprelim: Invalid message type <TYPE_CODA_SCNL>" );
516                    logit( "e", "; exiting!\n" );
517                    exit( -1 );
518                }
519            /*    printf("GetLogo[%d] inst:%d module:%d type:%d\n",
520                        nLogo, (int) GetLogo[nLogo].instid,
521                               (int) GetLogo[nLogo].mod,
522                               (int) GetLogo[nLogo].type ); */  /*DEBUG*/
523            /*    printf("GetLogo[%d] inst:%d module:%d type:%d\n",
524                        nLogo+1, (int) GetLogo[nLogo+1].instid,
525                               (int) GetLogo[nLogo+1].mod,
526                               (int) GetLogo[nLogo+1].type ); */  /*DEBUG*/
527                nLogo  += 2;
528                init[4] = 1;
529            }
530         /* Enter installation & module to get associations from
531          ******************************************************/
532  /*5*/     else if( k_its("GetAssocFrom") ) {
533                if ( nLogo+1 >= MAXLOGO ) {
534                    logit( "e",
535                            "eqprelim: Too many <Get*From> commands in <%s>",
536                             configfile );
537                    logit( "e", "; max=%d; exiting!\n", (int) MAXLOGO/2 );
538                    exit( -1 );
539                }
540                if( ( str=k_str() ) ) {
541                   if( GetInst( str, &GetLogo[nLogo].instid ) != 0 ) {
542                       logit( "e",
543                               "eqprelim: Invalid installation name <%s>", str );
544                       logit( "e", " in <GetAssocFrom> cmd; exiting!\n" );
545                       exit( -1 );
546                   }
547                   GetLogo[nLogo+1].instid = GetLogo[nLogo].instid;
548                }
549                if( ( str=k_str() ) ) {
550                   if( GetModId( str, &GetLogo[nLogo].mod ) != 0 ) {
551                       logit( "e",
552                               "eqprelim: Invalid module name <%s>", str );
553                       logit( "e", " in <GetAssocFrom> cmd; exiting!\n" );
554                       exit( -1 );
555                   }
556                   GetLogo[nLogo+1].mod = GetLogo[nLogo].mod;
557                }
558                if( GetType( "TYPE_QUAKE2K", &GetLogo[nLogo].type ) != 0 ) {
559                    logit( "e",
560                               "eqprelim: Invalid message type <TYPE_QUAKE2K>" );
561                    logit( "e", "; exiting!\n" );
562                    exit( -1 );
563                }
564                if( GetType( "TYPE_LINK", &GetLogo[nLogo+1].type ) != 0 ) {
565                    logit( "e",
566                               "eqprelim: Invalid message type <TYPE_LINK>" );
567                    logit( "e", "; exiting!\n" );
568                    exit( -1 );
569                }
570            /*    printf("GetLogo[%d] inst:%d module:%d type:%d\n",
571                        nLogo, (int) GetLogo[nLogo].instid,
572                               (int) GetLogo[nLogo].mod,
573                               (int) GetLogo[nLogo].type ); */  /*DEBUG*/
574            /*    printf("GetLogo[%d] inst:%d module:%d type:%d\n",
575                        nLogo+1, (int) GetLogo[nLogo+1].instid,
576                               (int) GetLogo[nLogo+1].mod,
577                               (int) GetLogo[nLogo+1].type ); */  /*DEBUG*/
578                nLogo  += 2;
579                init[5] = 1;
580            }
581
582         /* Enter next process to hand the event to
583          *****************************************/
584   /*6*/    else if( k_its("PipeTo") ) {
585                str = k_str();
586                if(str) strcpy( NextProc, str );
587                init[6] = 1;
588            }
589
590         /* Enter rule for making prelimary notification
591          **********************************************/
592   /*7*/    else if( k_its("NumPickNotify") ) {
593                NumPickNotify = k_int();
594                init[7] = 1;
595            }
596
597         /* Single char to label locally-made picks with
598          **********************************************/
599   /*8*/    else if( k_its("LocalCode") ) {
600                if ( str=k_str() ) {
601                   LocalCode = str[0];
602                }
603                init[8] = 1;
604            }
605
606        /* Set switch for sending S-phases to next process
607          *************************************************/
608  /*9*/    else if( k_its("ReportS") ) {
609                ReportS = k_int();
610                init[9] = 1;
611            }
612
613         /* Optional commands to change default settings
614          **********************************************/
615            else if( k_its("pick_fifo_length") ) {
616                maxPck = (size_t) k_val();
617            }
618
619            else if( k_its("quake_fifo_length") ) {
620                maxHyp = (size_t) k_val();
621            }
622
623         /* Some commands may be processed by other functions
624          ***************************************************/
625            else if( t_com()    )  strcpy( processor, "t_com"    );
626            else if( site_com() )  strcpy( processor, "site_com" );
627            else {
628                logit( "e", "eqprelim: <%s> Unknown command in <%s>.\n",
629                         com, configfile );
630                continue;
631            }
632
633        /* See if there were any errors processing the command
634         *****************************************************/
635            if( k_err() ) {
636               logit( "e",
637                       "eqprelim: Bad <%s> command for %s() in <%s>; exiting!\n",
638                        com, processor, configfile );
639               exit( -1 );
640            }
641        }
642        nfiles = k_close();
643   }
644
645/* After all files are closed, check init flags for missed commands
646 ******************************************************************/
647   nmiss = 0;
648   for ( i=0; i<ncommand; i++ )  if( !init[i] ) nmiss++;
649   if ( nmiss ) {
650       logit( "e", "eqprelim: ERROR, no " );
651       if ( !init[0] )  logit( "e", "<HeartbeatInt> "  );
652       if ( !init[1] )  logit( "e", "<LogFile> "       );
653       if ( !init[2] )  logit( "e", "<MyModuleId> "    );
654       if ( !init[3] )  logit( "e", "<RingName> "      );
655       if ( !init[4] )  logit( "e", "<GetPicksFrom> "  );
656       if ( !init[5] )  logit( "e", "<GetAssocFrom> "  );
657       if ( !init[6] )  logit( "e", "<PipeTo> "        );
658       if ( !init[7] )  logit( "e", "<NumPickNotify> " );
659       if ( !init[8] )  logit( "e", "<LocalCode> "     );
660       if ( !init[9] )  logit( "e", "<ReportS> "       );
661       logit( "e", "command(s) in <%s>; exiting!\n", configfile );
662       exit( -1 );
663   }
664
665   return;
666}
667
668/*****************************************************************************
669 *  eqprelim_lookup( ) Look up important info from earthworm.h tables        *
670 *****************************************************************************/
671void eqprelim_lookup( void )
672{
673/* Look up keys to shared memory regions
674   *************************************/
675   if( ( RingKey = GetKey(RingName) ) == -1 ) {
676        fprintf( stderr,
677                "eqprelim:  Invalid ring name <%s>; exiting!\n", RingName);
678        exit( -1 );
679   }
680
681/* Look up installations of interest
682   *********************************/
683   if ( GetLocalInst( &InstId ) != 0 ) {
684      fprintf( stderr,
685              "eqprelim: error getting local installation id; exiting!\n" );
686      exit( -1 );
687   }
688
689/* Look up modules of interest
690   ***************************/
691   if ( GetModId( MyModName, &MyModId ) != 0 ) {
692      fprintf( stderr,
693              "eqprelim: Invalid module name <%s>; exiting!\n", MyModName );
694      exit( -1 );
695   }
696
697/* Look up message types of interest
698   *********************************/
699   if ( GetType( "TYPE_HEARTBEAT", &TypeHeartBeat ) != 0 ) {
700      fprintf( stderr,
701              "eqprelim: Invalid message type <TYPE_HEARTBEAT>; exiting!\n" );
702      exit( -1 );
703   }
704   if ( GetType( "TYPE_ERROR", &TypeError ) != 0 ) {
705      fprintf( stderr,
706              "eqprelim: Invalid message type <TYPE_ERROR>; exiting!\n" );
707      exit( -1 );
708   }
709   if ( GetType( "TYPE_QUAKE2K", &TypeQuake2K ) != 0 ) {
710      fprintf( stderr,
711              "eqprelim: Invalid message type <TYPE_QUAKE2K>; exiting!\n" );
712      exit( -1 );
713   }
714   if ( GetType( "TYPE_LINK", &TypeLink ) != 0 ) {
715      fprintf( stderr,
716              "eqprelim: Invalid message type <TYPE_LINK>; exiting!\n" );
717      exit( -1 );
718   }
719   if ( GetType( "TYPE_PICK_SCNL", &TypePickSCNL ) != 0 ) {
720      fprintf( stderr,
721              "eqprelim: Invalid message type <TYPE_PICK_SCNL>; exiting!\n" );
722      exit( -1 );
723   }
724   if ( GetType( "TYPE_CODA_SCNL", &TypeCodaSCNL ) != 0 ) {
725      fprintf( stderr,
726              "eqprelim: Invalid message type <TYPE_CODA_SCNL>; exiting!\n" );
727      exit( -1 );
728   }
729   if ( GetType( "TYPE_EVENT_SCNL", &TypeEventSCNL ) != 0 ) {
730      fprintf( stderr,
731              "eqprelim: Invalid message type <TYPE_EVENT_SCNL>; exiting!\n" );
732      exit( -1 );
733   }
734   if ( GetType( "TYPE_KILL", &TypeKill ) != 0 ) {
735      fprintf( stderr,
736              "eqprelim: Invalid message type <TYPE_KILL>; exiting!\n" );
737      exit( -1 );
738   }
739   return;
740}
741
742/****************************************************************************
743 *  eqprelim_quake2k() processes a TYPE_QUAKE2K message from binder_ew      *
744 ****************************************************************************/
745int eqprelim_quake2k( char *msg )
746{
747   char       cdate[25];
748   char       corg[25];
749   char       timestr[20];
750   double     t;
751   double     lat, lon, z;
752   float      rms, dmin, ravg, gap;
753   long       qkseq;
754   int        nph;
755   int        iq;
756   int        narg;
757
758/* Read info from ascii message
759 ******************************/
760   narg = sscanf( msg,
761                 "%*d %*d %ld %s %lf %lf %lf %f %f %f %f %d",
762                  &qkseq, timestr, &lat, &lon, &z,
763                  &rms, &dmin, &ravg, &gap, &nph );
764
765   if ( narg < 10 )
766   {
767       sprintf( Text, "eqprelim_quake2k: Error reading ascii quake msg: %s", msg );
768       eqprelim_status( TypeError, ERR_QUAKEREAD, Text );
769       return( 0 );
770   }
771
772   t = julsec17( timestr );
773   if ( t == 0. )
774   {
775       sprintf( Text, "eqprelim_quake2k: Error decoding quake time: %s", timestr );
776       eqprelim_status( TypeError, ERR_TIMEDECODE, Text );
777       return( 0 );
778   }
779
780/* Store all hypo info in eqprelim's RPT_HYP structure
781 *****************************************************/
782   iq = qkseq % maxHyp;
783
784   if( qkseq != Hyp[iq].id )        /* initialize flags the 1st  */
785   {                                /* time a new quake id#      */
786        Hyp[iq].flag  = 0;
787        Hyp[iq].id    = qkseq;
788   }
789   Hyp[iq].t    = t;
790   Hyp[iq].trpt = 0.0;
791   Hyp[iq].lat  = lat;
792   Hyp[iq].lon  = lon;
793   Hyp[iq].z    = z;
794   Hyp[iq].rms  = rms;
795   Hyp[iq].dmin = dmin;
796   Hyp[iq].ravg = ravg;
797   Hyp[iq].gap  = gap;
798   Hyp[iq].nph  = nph;
799
800   if (Hyp[iq].flag != 2)             /* don't reflag if the event */
801        Hyp[iq].flag =  1;            /* has already been reported */
802   if (Hyp[iq].nph  == 0)
803        Hyp[iq].flag = -1;            /* flag an event as killed   */
804
805/* Write out the time-stamped hypocenter to the log file
806 *******************************************************/
807   t = tnow();
808   date20( t, cdate );
809   date20( Hyp[iq].t, corg );
810   logit( "",
811         "%s:%8ld %s%9.4f%10.4f%6.2f%5.2f%5.1f%5.1f%4.0f%3d\n",
812          cdate+10, Hyp[iq].id, corg+10,
813          Hyp[iq].lat, Hyp[iq].lon, Hyp[iq].z,
814          Hyp[iq].rms, Hyp[iq].dmin, Hyp[iq].ravg,
815          Hyp[iq].gap, Hyp[iq].nph);
816
817/* Send event2k message if it passes
818 ***********************************/
819   eqprelim_notify( iq );
820
821   return( 1 );
822}
823
824/*****************************************************************************
825 *  eqprelim_link() processes a MSG_LINK                                     *
826 *****************************************************************************/
827int eqprelim_link( char *msg )
828{
829   long          lp1;
830   long          lp2;
831   long          lp;
832   int           ip, narg;
833   long          qkseq;
834   int           pkseq;
835   unsigned char pksrc;
836   unsigned char pkinstid;
837   int           isrc, iinstid, iphs;
838
839   narg  = sscanf( msg, "%ld %d %d %d %d",
840                  &qkseq, &iinstid, &isrc, &pkseq, &iphs );
841
842   if ( narg < 5 )
843   {
844       sprintf( Text, "eqprelim_link: Error reading ascii link msg: %s", msg );
845       eqprelim_status( TypeError, ERR_LINKREAD, Text );
846       return( 0 );
847   }
848   pksrc    = (unsigned char) isrc;
849   pkinstid = (unsigned char) iinstid;
850
851   lp2 = nPck;
852   lp1 = lp2 - maxPck;
853   if(lp1 < 0)
854        lp1 = 0;
855   for( lp=lp1; lp<lp2; lp++ )   /* loop from oldest to most recent */
856   {
857        ip = lp % maxPck;
858        if( pkseq    != Pck[ip].id )      continue;
859        if( pksrc    != Pck[ip].src )     continue;
860        if( pkinstid != Pck[ip].instid )  continue;
861        Pck[ip].quake = qkseq;
862        Pck[ip].phase = (char) iphs;
863        return( 1 );
864   }
865   return( 0 );
866}
867
868/*****************************************************************************
869 * eqprelim_pickscnl() decodes a TYPE_PICK_SCNL message from ascii to binary *
870 *****************************************************************************/
871int eqprelim_pickscnl( char *msg )
872{
873   EWPICK   pick;
874   time_t   t_in;
875   int      isite;
876   int      lp, lp1, lp2, ip;
877   int      i;
878
879/* Make note of current system time
880 **********************************/
881   time( &t_in );
882
883 /* Read the pick into an EWPICK struct
884 *************************************/
885   if( rd_pick_scnl( msg, strlen(msg), &pick ) != EW_SUCCESS )
886   {
887      sprintf( Text, "eqprelim_pickscnl: Error reading pick: %s", msg );
888      eqprelim_status( TypeError, ERR_PICKREAD, Text );
889      return( 0 );
890   }
891 
892/* Get site index (isite)
893 ************************/
894   isite = site_index( pick.site, pick.net, pick.comp, pick.loc );
895   if( isite < 0 )
896   {
897      sprintf( Text, "eqprelim_pickscnl: %s.%s.%s.%s - Not in station list.",
898               pick.site, pick.comp, pick.net, pick.loc );
899      eqprelim_status( TypeError, ERR_UNKNOWNSTA, Text );
900      return( 0 );
901   }
902       
903/* Try to find coda part in existing pick list
904 *********************************************/
905   lp2 = nPck;
906   lp1 = lp2 - maxPck;
907   if(lp1 < 0)
908         lp1 = 0;
909   for( lp=lp2-1; lp>=lp1; lp-- )  /* loop from most recent to oldest */
910   {
911      ip = lp % maxPck;
912      if( pick.instid != Pck[ip].instid ) continue;
913      if( pick.modid  != Pck[ip].src    ) continue;
914      if( pick.seq    != Pck[ip].id     ) continue;
915      Pck[ip].t       = pick.tpick + (double)GSEC1970; /* use gregorian time */
916      Pck[ip].site    = isite;
917      Pck[ip].phase   = 0;
918      Pck[ip].fm      = pick.fm;
919      Pck[ip].ie      = ' ';
920      Pck[ip].wt      = pick.wt;
921      Pck[ip].timeout = 0;
922      for( i=0; i<3; i++ ) {
923         Pck[ip].pamp[i] = pick.pamp[i];
924      }
925      return( 1 );
926   }
927
928/* Coda was not in list; load pick info into list
929 ************************************************/
930   ip  = nPck % maxPck;
931   Pck[ip].instid  = pick.instid;
932   Pck[ip].src     = pick.modid;
933   Pck[ip].id      = pick.seq;
934   Pck[ip].t       = pick.tpick + (double)GSEC1970; /* use gregorian time */
935   Pck[ip].site    = isite;
936   Pck[ip].phase   = 0;
937   Pck[ip].fm      = pick.fm;
938   Pck[ip].ie      = ' ';
939   Pck[ip].wt      = pick.wt;
940   for( i=0; i<3; i++ ) {
941         Pck[ip].pamp[i] = pick.pamp[i];
942   }
943   Pck[ip].quake   = 0;
944   Pck[ip].timeout = t_in + 150;
945   nPck++;
946
947/* Coda was not in list; zero-out all coda info;
948   will be filled by TYPE_CODA_SCNL later.
949 ***********************************************/
950   for( i=0; i<6; i++ ) {
951      Pck[ip].caav[i] = 0;
952   }
953   Pck[ip].clen   = 0;
954
955   return ( 1 );
956}
957
958
959/*****************************************************************************
960 *  eqprelim_codascnl() processes a TYPE_CODA_SCNL message                   *
961 *****************************************************************************/
962
963int eqprelim_codascnl( char *msg )
964{
965   EWCODA  coda;
966   long    lp, lp1, lp2;
967   int     i, ip;
968
969/* Read the coda into an EWCODA struct
970 *************************************/
971   if( rd_coda_scnl( msg, strlen(msg), &coda ) != EW_SUCCESS )
972   {
973      sprintf( Text, "eqprelim_codascnl: Error reading coda: %s", msg );
974      eqprelim_status( TypeError, ERR_CODAREAD, Text );
975      return( 0 );
976   }
977 
978/* Try to find pick part in existing pick list
979 *********************************************/
980   lp2 = nPck;
981   lp1 = lp2 - maxPck;
982   if( lp1 < 0 ) lp1 = 0;
983 
984   for( lp=lp2-1; lp>=lp1; lp-- )  /* loop from most recent to oldest */
985   {
986      ip = lp % maxPck;
987      if( coda.instid != Pck[ip].instid )  continue;
988      if( coda.modid  != Pck[ip].src )     continue;
989      if( coda.seq    != Pck[ip].id )      continue;
990      for( i=0; i<6; i++ ) {
991         Pck[ip].caav[i] = coda.caav[i];
992      }
993      Pck[ip].clen     = coda.dur;
994      Pck[ip].timeout  = 0;
995      return( 1 );
996   }
997
998/* Pick was not in list; load coda info into list
999 ************************************************/
1000   ip  = nPck % maxPck;
1001   Pck[ip].instid = coda.instid;
1002   Pck[ip].src    = coda.modid;
1003   Pck[ip].id     = coda.seq;
1004   for( i=0; i<6; i++ ) {
1005      Pck[ip].caav[i] = coda.caav[i];
1006   }
1007   Pck[ip].clen   = coda.dur;
1008   Pck[ip].quake  = 0;
1009   nPck++;
1010
1011/* Pick was not in list; zero-out all pick info;
1012   will be filled by TYPE_PICK_SCNL later.
1013 ***********************************************/
1014   Pck[ip].t      = 0.0;
1015   Pck[ip].site   = 0;
1016   Pck[ip].phase  = 0;
1017   Pck[ip].fm     = ' ';
1018   Pck[ip].ie     = ' ';
1019   Pck[ip].wt     = '9';
1020   for( i=0; i<3; i++ ) {
1021      Pck[ip].pamp[i] = (long) 0.;
1022   }
1023   Pck[ip].timeout  = 0;
1024   return( 1 );
1025}
1026
1027/*****************************************************************************
1028 * eqprelim_phscard() builds a char-string phase-card from RPT_PCK structure *
1029 *****************************************************************************/
1030char *eqprelim_phscard( int ip, char *phscard )
1031{
1032   char   timestr[19];
1033   int    is, iph;
1034   char   datasrc;
1035   char   imported = 'I';
1036
1037/*--------------------------------------------------------------------------
1038Sample Earthworm format phase card (variable-length whitespace delimited):
1039CMN VHZ NC -- U1 P 19950831183134.902 953 1113 968 23 201 276 289 0 0 7 W\n
1040----------------------------------------------------------------------------*/
1041 
1042/* Get a character to denote the data source
1043 *******************************************/
1044   if   ( Pck[ip].instid == InstId )  datasrc = LocalCode;
1045   else                               datasrc = imported;
1046
1047/* Convert julian seconds character string
1048 *****************************************/
1049   date18( Pck[ip].t, timestr );
1050   is  = Pck[ip].site;
1051   iph = Pck[ip].phase;
1052
1053/* Write all info to an Earthworm phase card
1054 *******************************************/
1055   sprintf( phscard,
1056           "%s %s %s %s %c%c %s %s %ld %ld %ld %ld %ld %ld %ld %ld %ld %hd %c\n",
1057            Site[is].name,
1058            Site[is].comp,
1059            Site[is].net,
1060            Site[is].loc,
1061            Pck[ip].fm,
1062            Pck[ip].wt,
1063            Phs[iph],
1064            timestr,
1065            Pck[ip].pamp[0],
1066            Pck[ip].pamp[1],
1067            Pck[ip].pamp[2],
1068            Pck[ip].caav[0],
1069            Pck[ip].caav[1],
1070            Pck[ip].caav[2],
1071            Pck[ip].caav[3],
1072            Pck[ip].caav[4],
1073            Pck[ip].caav[5],
1074            Pck[ip].clen,
1075            datasrc );
1076 
1077 /*logit( "", "%s", phscard );*/ /*DEBUG*/
1078   return( phscard );
1079}
1080
1081/******************************************************************************
1082 * eqprelim_hypcard() builds char-string hypocenter card from RPT_HYP struct  *
1083 ******************************************************************************/
1084char *eqprelim_hypcard( int iq, char *hypcard )
1085{
1086   char   timestr[19];
1087   char   version = '0';  /* 0=preliminary (no mag); 1=final with Md */
1088 
1089/*------------------------------------------------------------------------------------
1090Sample binder-based hypocenter as built below (whitespace delimited, variable length);
1091Event id from binder is added at end of card.
109219920429011704.653 36.346578 -120.546932 8.51 27 78 19.8 0.16 10103 1\n
1093--------------------------------------------------------------------------------------*/
1094 
1095 /* Convert julian seconds character string
1096 *****************************************/
1097   date18( Hyp[iq].t, timestr );
1098
1099/* Write all info to hypocenter card
1100 ***********************************/
1101   sprintf( hypcard,
1102           "%s %.6lf %.6lf %.2lf %d %.0f %.1f %.2f %ld %c\n",
1103            timestr,
1104            Hyp[iq].lat,
1105            Hyp[iq].lon,
1106            Hyp[iq].z,
1107            Hyp[iq].nph,
1108            Hyp[iq].gap,
1109            Hyp[iq].dmin,
1110            Hyp[iq].rms,
1111            Hyp[iq].id,
1112            version );
1113 
1114/* logit( "", "%s", hypcard );*/ /*DEBUG*/
1115   return( hypcard );
1116}
1117
1118/******************************************************************************
1119 *  eqprelim_compare() compare 2 times                                        *
1120 ******************************************************************************/
1121int eqprelim_compare( const void *p1, const void *p2 )
1122{
1123   SRT *srt1;
1124   SRT *srt2;
1125
1126   srt1 = (SRT *) p1;
1127   srt2 = (SRT *) p2;
1128   if(srt1->t < srt2->t)   return -1;
1129   if(srt1->t > srt2->t)   return  1;
1130   return 0;
1131}
1132
1133
1134/******************************************************************************
1135 * eqprelim_notify() writes message for a hypocenter that passes the          *
1136 *                   preliminary notification rule                            *
1137 ******************************************************************************/
1138void eqprelim_notify( int iq )  /* iq is the index into Hyp    */
1139{
1140   struct Greg  g;
1141   long         minute;
1142   char         cdate[40];       /* string for current time      */
1143   double       t;               /* current time                 */
1144   double       xs, ys;          /* x,y coordinates of station   */
1145   double       xq, yq, zq;      /* x,y,x coords of hypocenter   */
1146   double       r;               /* epicentral distance (km)     */
1147   double       dtdr, dtdz;      /* travel-time stuff            */
1148   double       tres;            /* travel-time residual         */
1149   long         lp, lp1, lp2;    /* indices into pick structure  */
1150   int          i, is, ip, iph;  /* working indices              */
1151   int          nphs_P;          /* number of P-phases           */
1152   int          nsend;           /* number of phases to ship out */
1153   char        *eqmsg;           /* working pointer into EqMsg   */
1154
1155/* See if this hypocenter passes the notification rule
1156 *****************************************************/
1157   if( Hyp[iq].flag == 2 )             return;   /* already reported it   */
1158   if( Hyp[iq].nph  < NumPickNotify )  return;   /* not enough phases yet */
1159
1160/* Note current system time
1161 **************************/
1162   t = tnow();
1163   date20( t, cdate );
1164
1165/* Loop thru all picks, collecting associated picks
1166 **************************************************/
1167   nSrt   = 0;
1168   nphs_P = 0;
1169   lp2    = nPck;
1170   lp1    = lp2 - maxPck;
1171   if(lp1 < 0) lp1 = 0;
1172   for(lp=lp1; lp<lp2; lp++)
1173   {
1174      ip  = lp % maxPck;
1175      if(Pck[ip].quake != Hyp[iq].id) continue;  /* not assoc w/this quake */
1176      if(Pck[ip].phase%2 == 0) {      /* It's a P-phase... */
1177         nphs_P++;                    /* ...count them     */
1178      }
1179      else {                          /* It's an S-phase... */
1180         if(ReportS == 0) continue;   /* ...see if it should be skipped */
1181      }
1182      Srt[nSrt].= Pck[ip].t;       /* load info for sorting  */
1183      Srt[nSrt].ip = ip;
1184      nSrt++;                         /* count total # phases   */
1185   }
1186
1187/* Make sure we have the minimum number of P-phases before notifying
1188 *******************************************************************/
1189   if ( nphs_P < NumPickNotify )  {
1190      logit( "",
1191            "%s:%8ld #### Report delayed: %3d P-phs; %3d picks total\n",
1192            cdate+10, Hyp[iq].id, nphs_P, Hyp[iq].nph );
1193      return;
1194   }
1195
1196/* Report this event
1197 *******************/
1198   minute = (long) (Hyp[iq].t / 60.0);
1199   grg(minute, &g);
1200   logit( "", "%s:%8ld #### Preliminary report: %04d%02d%02d%02d%02d%_%02d\n",
1201          cdate+10, Hyp[iq].id, g.year, g.month, g.day,
1202          g.hour, g.minute, (int) (Hyp[iq].id % 100) );
1203   date20( Hyp[iq].t, cdate );
1204   logit("", "%8ld %s%9.4f%10.4f%6.2f%5.2f%5.1f%5.1f%4.0f%3d\n",
1205         Hyp[iq].id, cdate,
1206         Hyp[iq].lat, Hyp[iq].lon, Hyp[iq].z,
1207         Hyp[iq].rms, Hyp[iq].dmin,
1208         Hyp[iq].ravg, Hyp[iq].gap, Hyp[iq].nph);
1209   xq = X(Hyp[iq].lon);
1210   yq = Y(Hyp[iq].lat);
1211   zq = Hyp[iq].z;
1212
1213/* Loop thru all associated picks, writing logfile output
1214 ********************************************************/
1215   for(i=0; i<nSrt; i++ )
1216   {
1217      ip  = Srt[i].ip;
1218      is  = Pck[ip].site;
1219      iph = Pck[ip].phase;
1220      date20(Pck[ip].t, cdate);
1221      xs  = X(Site[is].lon);
1222      ys  = Y(Site[is].lat);
1223      r   = hypot(xs - xq, ys - yq);
1224      tres = Pck[ip].t - Hyp[iq].t
1225             - t_phase(iph, r, zq, &dtdr, &dtdz);
1226      logit("", "%-5s %-3s %-2s %-2s %s %-2s%c%c%6.1f%7.2f\n",
1227            Site[is].name, Site[is].comp, 
1228            Site[is].net, Site[is].loc, 
1229            cdate, Phs[iph], Pck[ip].fm,
1230            Pck[ip].wt, r, tres);
1231   }
1232
1233/* Build an event message an write it to the pipe
1234 ************************************************/
1235/* write binder's hypocenter to message */
1236   eqprelim_hypcard(iq, EqMsg);
1237/* sort picks by time and add them to message */
1238   qsort(Srt, nSrt, sizeof(SRT), eqprelim_compare);
1239   nsend = nSrt;
1240   if( nsend > MAX_PHS_PER_EQ ) nsend = MAX_PHS_PER_EQ;
1241   for (i=0; i<nsend; i++) {
1242      eqmsg = EqMsg + strlen(EqMsg);
1243      eqprelim_phscard(Srt[i].ip, eqmsg);
1244   }
1245/* write event message to pipe */
1246   if ( pipe_put( EqMsg, TypeEventSCNL ) != 0 )
1247      logit("et","eqprelim_check: Error writing eq message to pipe.\n");
1248
1249/* Flag event as reported & note the time
1250 ****************************************/
1251   Hyp[iq].flag = 2;
1252   Hyp[iq].trpt = t;
1253
1254   return;
1255}
1256
1257
1258/******************************************************************************
1259 * eqprelim_status() builds a heartbeat or error msg & puts it into shared    *
1260 *                   memory                                                   *
1261 ******************************************************************************/
1262void eqprelim_status( unsigned char type, short ierr, char *note )
1263{
1264   char     msg[256];
1265   time_t   t;
1266
1267/* Build the message
1268 *******************/
1269   time( &t );
1270
1271   if( type == TypeHeartBeat )
1272   {
1273        sprintf( msg, "%ld %d\n", (long) t, (int) MyPID );
1274   }
1275   else if( type == TypeError )
1276   {
1277        sprintf( msg, "%ld %d %s\n\0", (long) t, ierr, note);
1278        logit( "et", "eqprelim:  %s\n", note );
1279   }
1280
1281/* Write the message to the pipe
1282 *******************************/
1283   if( pipe_put( msg, type ) != 0 )
1284        logit( "et", "eqprelim:  Error sending msg to pipe.\n");
1285
1286   return;
1287}
Note: See TracBrowser for help on using the repository browser.