source: EEW/trunk/mcast2eew/EEW.cc @ 3747

Revision 3747, 13.2 KB checked in by solanki, 4 years ago (diff)

Created earthworm module for Caltech EEW

Line 
1#include "EEW.h"
2#include "eewPropertiesST.h"
3#include "Duration.h"
4#include "../eewserver/udp.h"
5#include "../eewserver/MessageBuffer.h"
6#include <iomanip>
7#include <arpa/inet.h>
8#include <netdb.h>
9
10unsigned int EEW::serverip = 0;
11bool EEW::udpsetup = false;
12
13EEW::EEW(Channel Z,Channel E,Channel N){
14
15  chanZ = Z;
16  chanE = E;
17  chanN = N;
18
19  samplerate = chanZ.samprate;
20
21  gcbrZ = NULL;
22  gcbrN = NULL;
23  gcbrE = NULL;
24 
25  picker = NULL;
26  buthfilter = NULL;
27 
28  buf = NULL;
29  pickbuf = NULL;
30  vdbuf = NULL;
31  trigger = false;
32  firsttimeE = true;
33  firsttimeN = true;
34  firsttimeZ = true;
35 
36  TC = 0.0;
37  Pd3 = 0.0;
38  Q = 0.0;
39  mag = 0.0;
40  pgv = 0.0;
41  clipped = 0;
42 
43  init();
44}
45
46void EEW::init(){
47
48  if(udpsetup==false){
49    const int  hostlen = 128;
50    char hostname[hostlen];
51
52    int udp_port = 30000+(getpid()%1000);
53    if(gethostname(hostname,hostlen)<0){
54      perror("Can't get hostname");
55      exit(-1);
56    }
57
58    udp::getInstance()->init_udp(udp_port,(char*)gethostnametoip(hostname));
59    eewPropertiesST* prop = eewPropertiesST::getInstance();
60    const char* dst = gethostnametoip((char*)prop->getServerName().c_str());
61    if(dst){
62      serverip = ntohl(inet_addr(dst));
63    }
64    else{
65      cout <<"Error: Can't find IP Address for the Server Host Name"<<endl;   
66      exit(-1);
67    }
68    udpsetup = true;
69  }
70
71  gcbrN = new GCBRTSPModule(chanN);
72  gcbrN->load("");
73
74  gcbrE = new GCBRTSPModule(chanE);
75  gcbrE->load("");
76
77  gcbrZ = new GCBRTSPModule(chanZ);
78  gcbrZ->load("");
79
80  picker = new PPickerTSPModule(chanZ);
81  picker->setEnvHandle(this);
82  picker->load("");
83 
84  buthfilter = new ButhpinFilterTSPModule(chanZ);
85  buthfilter->load("");
86
87  cout <<"SampleRate for "<<chanZ<<" is "<<samplerate<<endl;
88
89  buf = new float[samplerate*10];
90  pickbuf = new float[samplerate*10];
91  vdbuf = new struct vd[samplerate*10];
92}
93
94
95void EEW::process(Channel chn,timeval stime,int* samps,int size){
96  // cout <<"Processing "<<chn<<endl;
97  unsigned int outsize = 0;
98  eewPropertiesST* prop = eewPropertiesST::getInstance();
99  TimeStamp starttime = TimeStamp(stime);
100
101  if((double)(TimeStamp::current_time() - starttime) > 20.0){
102    return;
103  }
104
105  if(string(chn.channel) == string(chanZ.channel)){
106    checkgap(starttime,lasttimeZ,size,firsttimeZ);
107
108    gcbrZ->process(stime,size,samps,outsize,buf);
109    maintainGCBRData(zq,zmap,stime,size);
110    buthfilter->process(stime,size,buf,outsize,vdbuf); 
111    picker->process(stime,size,buf,outsize,pickbuf);
112    maintainVDQueue(vdq,stime,size);   
113  }
114  else if(string(chn.channel) == string(chanN.channel)){
115    checkgap(starttime,lasttimeN,size,firsttimeN);
116    gcbrN->process(stime,size,samps,outsize,buf);
117    maintainGCBRData(nq,nmap,stime,size);
118  }
119  else if(string(chn.channel) == string(chanE.channel)){
120    checkgap(starttime,lasttimeE,size,firsttimeE);
121    gcbrE->process(stime,size,samps,outsize,buf);
122    maintainGCBRData(eq,emap,stime,size);
123  }
124
125  //TimeStamp endtime = TimeStamp::current_time();
126  //cout <<"Processing Delay : "<<(double)(endtime - begtime)<<endl;
127}
128
129void EEW::checkgap(TimeStamp firstsamptime,TimeStamp& lastsamptime,int nsamps,bool& firsttime){
130  float dt = 1.0/samplerate;
131
132  TimeStamp temptime;
133  float offset = dt*nsamps;
134  struct timeval time_offset = {0,0};
135  time_offset.tv_sec = 0;
136  time_offset.tv_usec = offset*1000000;
137  temptime = firstsamptime + Duration(time_offset);
138
139  if(firsttime){
140    lastsamptime = temptime;
141    firsttime = false;
142  }
143  else{
144    double timediff = (double)(firstsamptime - lastsamptime);
145    //    cout <<"TimeDiff: "<<timediff<<" dt:"<<dt<<endl;
146    if(timediff > dt){
147      //gap
148      lastsamptime = temptime;
149      reset();
150      firsttime = true;
151    }
152    else{
153      lastsamptime = temptime;
154    }
155  }
156}
157
158void EEW::reset(){
159  //  cout <<"Gap Found. RESETTING EEW"<<endl;
160
161  zq.clear();
162  eq.clear();
163  nq.clear();
164
165  zmap.clear();
166  emap.clear();
167  nmap.clear();
168
169  vdq.clear();
170
171  struct timeval dummy = {0,0};
172
173  gcbrZ->restart(dummy);
174  picker->restart(dummy);
175  buthfilter->restart(dummy);
176
177  gcbrE->restart(dummy);
178  gcbrN->restart(dummy);
179}
180
181void EEW::clear(){
182  cout <<"EEW STOPPED"<<endl;
183  delete gcbrZ;
184  delete picker;
185}
186
187void EEW::maintainGCBRData(GCBRQueue& dataq,GCBRMap& datamap,timeval stime,int size){
188       float dt = (float)1.0/(samplerate*1.0);
189       
190       for(int j=0;j<size;j++){
191         float offset = dt*j;
192         struct timeval time_offset = {0,0};
193         time_offset.tv_sec = 0;
194         time_offset.tv_usec = offset*1000000;
195         
196         TimeStamp timestamp = TimeStamp(stime) + Duration(time_offset);
197         dataq.push_back(make_pair(timestamp,buf[j]));
198         if(dataq.size() > MAXQ){
199           dataq.pop_front();
200         }
201       }
202}
203
204
205void EEW::maintainVDQueue(VDQueue&,timeval stime,int size){
206       float dt = (float)1.0/(samplerate*1.0);
207       //       cout <<"In maintainVDQueue .."<<endl;
208       for(int j=0;j<size;j++){
209         float offset = dt*j;
210         struct timeval time_offset = {0,0};
211         time_offset.tv_sec = 0;
212         time_offset.tv_usec = offset*1000000;
213         TimeStamp timestamp = TimeStamp(stime) + Duration(time_offset);   
214         vdq.push_back(make_pair(timestamp,vdbuf[j]));
215       }
216
217       if(trigger){
218         // cout <<"In maintainVDQueue.. in Trigger...";
219         //pop samples while we find trigger
220         int remcount = 0;
221         while(vdq.size() > 0){
222           TimeStamp t = (*(vdq.begin())).first;
223           //cout <<"VDQ TimeStamp: "<<t<<" TrigTime: "<<trigtime<<endl;
224           if(t.seconds() == trigtime.seconds() && t.milliseconds() == trigtime.milliseconds()){
225             break;
226           }
227           else{
228             remcount++;
229             vdq.pop_front();
230             //cout <<"Removing Sample from VDQ"<<endl;
231           }
232         }
233         //cout <<" VDQ size = "<<vdq.size()<<" and removed "<<remcount<<" elements"<<endl;
234         if(vdq.size() >= samplerate*3.0){
235           //Calculate TauC/PD
236           cout <<"VDQ size = "<<vdq.size()<<" Calculate TauC/PD"<<endl;
237           calcTCPD();
238         }
239       }
240       else{
241         vdq.clear();
242       }
243}
244
245void EEW::setTriggerOn(TimeStamp timestamp){
246  trigger = true;
247  trigtime = timestamp;
248}
249
250void EEW::calcTCPD(){
251
252  trigger = false;
253
254  eewPropertiesST* prop = eewPropertiesST::getInstance();
255  Channel channel = chanZ; //Channel(prop->getNetwork().c_str(),prop->getStation().c_str(),"  ",string(string(prop->getChannelType())+"Z").c_str());
256 
257  clipped = 0;
258
259  //Get Trigger Time Samples from E and N Channels
260  float eout = findSample(eq,trigtime);
261  float nout = findSample(nq,trigtime);
262  float zout = findSample(zq,trigtime);
263  if(eout == 0.0 || nout == 0.0 || zout == 0.0){
264    double delay = TimeStamp::current_time() - TimeStamp(trigtime);
265    cout <<"ERROR: E/N/Z Channels "<<chanZ<<" DO NOT HAVE TRIGGER SAMPLES. ABORTING TauC/PD Calculation For now, After waiting "<<delay<<" seconds"<<endl;
266    cout <<"Amp for N = "<<nout<<" and E = "<<eout<<" and Z = "<<zout<<endl;
267    cout <<"Size for GCBRMaps : N = "<<nmap.size()<<" E = "<<emap.size()<<" Z = "<<zmap.size()<<endl;
268    trigger = false;
269    return;
270  }
271  //
272
273    int nsamples = samplerate * 3.0;
274    struct vd* out = new struct vd[nsamples];
275
276    for(int i=0;i<nsamples;i++){
277      out[i] = (*(vdq.begin())).second;
278      vdq.pop_front();
279    }
280   
281//     //print data
282//     cout <<"--- Z Displacement ---"<<endl;
283//     for(int i=0;i<nsamples;i++){
284//       cout <<out[i].d<<",";
285//     }
286//     cout <<endl;
287
288    //Check clipping
289    if(isClipping(out,nsamples)){
290      clipped = 1;
291      clipbegin = TimeStamp(trigtime);
292    }
293    else{
294      double lastclipdur = (double)(TimeStamp(trigtime) - clipbegin);
295      double clipwaitsec = (double)prop->getClipWaitSeconds();
296     
297      cout <<channel<< " lastclipdur:"<<lastclipdur<<" clipwaitsec:"<<clipwaitsec<<endl;
298     
299      if(lastclipdur <= clipwaitsec){
300        clipped = 1;
301      }
302    }
303   
304    TC =  calTauC(out,nsamples);
305    Pd3 = calPd3(out,nsamples);
306    delete [] out;
307
308    cout <<"Total Latency for "<<channel<<" is "<<(double)(TimeStamp::current_time() - TimeStamp(trigtime))<<" sec"<<endl;
309    cout <<"Amp for N = "<<nout<<" and E = "<<eout<<" and Z = "<<zout<<endl;
310
311
312    //Check if E,N,Z components satisfy the criteria//
313    double X = fabs(sqrt(pow(eout,2) + pow(nout,2))/zout);
314    if(X > 1.5){
315      cout <<"REJECTED "<<channel<<" Reason: Not a p-wave."<<endl;
316      cout <<"The trigger ignored for "<<channel<<" PD: "<<Pd3<<", X = "<<X<<", Amp for N = "<<nout<<" and E = "<<eout<<" and Z = "<<zout<<endl;
317      return;
318    }
319
320    Q = tauc_pd_trigger(TC,Pd3);
321    if(Q == 0){
322      cout <<"REJECTED "<<channel<<" Reason: Q = 0  Trigger Time: "<<TimeStamp(trigtime)<<" TauC = "<<TC<<" PD = "<<Pd3<<endl;
323      return;
324    }
325
326    mag = 4.218*log10(TC)+6.166;
327    pgv = pow(10,0.920*log10(Pd3)+1.642);
328
329    cout <<channel<<": TauC = "<<TC<<" and Pd3 = "<<Pd3<<" Q: "<<Q<<" Clipped: "<<clipped<<" Mag: "<<mag<<" PGV: "<<pgv<<endl;
330    sendToServer();
331}
332
333double EEW::calTauC(struct vd* data,unsigned int size){
334    double s1=0.0;
335    double s2=0.0;
336    double tauc[300]; //temp debug
337
338    for(int i=0;i<size;i++){
339        s1=s1+pow(data[i].d,2);
340        s2=s2+pow(data[i].v,2);
341        tauc[i] = 2.0*PI*sqrt(s1/s2);
342    }
343
344    double TauC = 2.0*PI*sqrt(s1/s2);
345    return TauC;
346}
347
348
349double EEW::calPd3(struct vd* data,unsigned int size){
350    double pd3 = 0.0;
351    for(int i=0;i<size;i++){
352        double temp = fabs(data[i].d);
353        if(temp > pd3)
354            pd3 = temp;
355    }
356    return pd3;
357}
358
359bool EEW::isClipping(struct vd* data, unsigned int size){
360  eewPropertiesST* prop = eewPropertiesST::getInstance();
361  float valthresh = prop->getVelocityThreshold();
362  for(int i=0;i<size;i++){
363      if(abs(data[i].v) >= 0.8){
364          return true;
365      }
366  }
367  return false;
368}
369
370int EEW::tauc_pd_trigger(double tau_c,double pd){
371
372  // Tauc-Pd trigger criterion after Boese et al. (in prep., Feb. 2008)://
373  // Earthquake Early Warning in California: One Year Real-Time Testing of
374
375  double rmin           =       1.0;            //km
376  double rmax           =       100.0;          //km
377  double min_tauc       =       0.2;
378  double max_tauc       =       8.00;   
379  double Pd_thres       =       0.0005; // cm
380  double q = 0.0;
381  double pi = 3.141592;
382
383 // Coefficients taken from Cua and Heaton (in prep.), for rock sites
384double a                =    0.89;
385double b                =   -4.3*pow(10.0,-4.0);
386double c1               =    1.11;
387double c2               =    1.11;
388double d                =   -1.44;
389double e                =   -2.60;
390double f                =    1.10;              // rms_to_max_PGV     
391double R_min            =   sqrt(rmin*rmin+9);
392double R_max            =   sqrt(rmax*rmax+9);
393
394// Uncertainties in the parameters/relations:
395 double sigma_IM        =   0.280; // Cua and Heaton (in prep.)
396 double sigma_M     =   0.385; // Wu et al., 2007: GJI
397 double sigma_PGV       =   0.326; // Wu and Kanamori, 2008: Sensors
398   
399 // Determine trigger quality Q:
400 if((tau_c<min_tauc)||(tau_c>max_tauc)){
401        return 0.0;
402 }
403 else{
404   // Estimate magnitude from tauc (Wu et al., 2007: GJI)
405   double M_est         =   4.218*log10(tau_c)+6.166; 
406   
407   // Mean values of the Tauc-Pd trigger criterion
408   double CM1         =   c1*exp(c2*(M_est-5))*(atan(M_est-5)+pi/2);
409   double Pd_min1     =   pow(10,(log10(pow(10,(a*M_est+b*(R_max+CM1)+d*log10(R_max+CM1)+e))*f) -1.642)/0.92);
410   double Pd_max1     =   pow(10,(log10(pow(10,(a*M_est+b*(R_min+CM1)+d*log10(R_min+CM1)+e))*f) -1.642)/0.92);
411
412   // Mean + std dev. values of the Tauc-Pd trigger criterion   
413   double CM2         = c1*exp(c2*(M_est-sigma_M-5))*(atan(M_est-sigma_M-5)+pi/2);
414   double CM3         = c1*exp(c2*(M_est+sigma_M-5))*(atan(M_est+sigma_M-5)+pi/2);
415   double Pd_min2     = pow(10,(log10(pow(10,(a*(M_est-sigma_M)+b*(R_max+CM2)+d*log10(R_max+CM2) +e-sigma_IM))*f)-1.642-sigma_PGV)/0.92);
416   double Pd_max2     = pow(10,(log10(pow(10,(a*(M_est+sigma_M)+b*(R_min+CM3)+d*log10(R_min+CM3) +e+sigma_IM))*f)-1.642+sigma_PGV)/0.92);
417
418   // Determine quality Q of the trigger:
419    if ((pd>=Pd_thres)&&(pd>=Pd_min1)&&(pd<=Pd_max1)){
420        q       =       1.0;
421    }
422    else if((pd>=Pd_thres)&&((pd>=Pd_min2)&&(pd<=Pd_min1)) ||((pd>=Pd_max1)&&(pd<=Pd_max2))){
423        q       =       0.5;
424    }
425    else{
426        q       =       0.0;
427    }
428  }
429 
430  return q;
431}
432
433
434void EEW::generateRandomTrigger(TimeStamp stime){
435  static TimeStamp lasttrig = stime;
436
437  cout <<"********  Trigger In "<<10 - (double)(stime - lasttrig)<<endl;
438  if((double)(stime - lasttrig) >= 10.0){
439    lasttrig = stime;
440    setTriggerOn(stime);
441  }
442}
443
444float EEW::findSample(GCBRQueue& q,TimeStamp timestamp){
445  for(GCBRQueue::iterator it=q.begin();it!=q.end();++it){
446    TimeStamp t = (*it).first;
447    if(t.seconds() == timestamp.seconds() && t.milliseconds() == timestamp.milliseconds()){
448      return (*it).second;
449    }
450  }
451  return 0.0;
452}
453
454void EEW::sendToServer(){
455  eewPropertiesST* prop = eewPropertiesST::getInstance();
456    char str[256];   
457    long sec = trigtime.seconds();
458    long usec = trigtime.micro_seconds();
459
460    sprintf(str,"%s %s %s -- %ld %ld %f %f %f %f %f %d",chanZ.network,
461                                                        chanZ.station,
462                                                        chanZ.channel,
463                                                        sec,usec,TC,Pd3,mag,pgv,Q,clipped); 
464    MessageBuffer *mbuf = new MessageBuffer();
465    mbuf->clear();
466    mbuf->append(str,strlen(str));
467   
468    try{
469      udp* udp_hnd = udp::getInstance();
470      udp_hnd->send(mbuf,serverip,prop->getServerPort());
471      cout <<"UDP Message Sent"<<endl;
472    }
473    catch(Error e){
474      cout<<"Error while sending message"<<endl;
475    }
476    delete mbuf;   
477}
478
479const char* EEW::gethostnametoip(const char* hostname){
480  if(!hostname)
481    return NULL;
482
483  struct hostent* ent = gethostbyname(hostname);
484  if(!ent)
485    return NULL;
486
487  if(ent->h_addrtype == AF_INET){
488    struct in_addr adr;
489    bcopy(ent->h_addr_list[0],(char *) &adr, sizeof(adr));
490    return inet_ntoa(adr);
491  }
492  else{
493    return NULL;
494  }
495}
Note: See TracBrowser for help on using the repository browser.