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

Revision 3772, 14.5 KB checked in by solanki, 4 years ago (diff)

Added earthworm support

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