Logo coherent WaveBurst  
Library Reference Guide
Logo
CWB_Plugin_Linear_Bilinear_Regression_Rank.C
Go to the documentation of this file.
1 /*
2 # Copyright (C) 2019 Gabriele Vedovato
3 #
4 # This program is free software: you can redistribute it and/or modify
5 # it under the terms of the GNU General Public License as published by
6 # the Free Software Foundation, either version 3 of the License, or
7 # (at your option) any later version.
8 #
9 # This program is distributed in the hope that it will be useful,
10 # but WITHOUT ANY WARRANTY; without even the implied warranty of
11 # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
12 # GNU General Public License for more details.
13 #
14 # You should have received a copy of the GNU General Public License
15 # along with this program. If not, see <https://www.gnu.org/licenses/>.
16 */
17 
18 
19 #define XIFO 4
20 
21 #pragma GCC system_header
22 
23 #include "cwb.hh"
24 #include "config.hh"
25 #include "network.hh"
26 #include "wavearray.hh"
27 #include "TString.h"
28 #include "TObjArray.h"
29 #include "TObjString.h"
30 #include "TRandom.h"
31 #include "TComplex.h"
32 #include "TMath.h"
33 #include "TSystem.h"
34 #include "mdc.hh"
35 #include "WDM.hh"
36 #include "regression.hh"
37 #include "frame.hh"
38 #include "watplot.hh"
39 #include "Biorthogonal.hh"
40 #include <fstream>
41 #include <vector>
42 
43 #define NCH 1000
44 
45 using namespace CWB;
46 
47 void
49 //!REGRESSION
50 // Plugin for linear/bilinear ranking analysis for one detector
51 
52  cout << endl;
53  cout << "-----> CWB_Plugin_Linear_Bilinear_Regression_Rank.C : " << ifo.Data() << endl;
54  cout << endl;
55 
56  //---------------------------------------------------------------------
57  // MAIN REGRESSION RANK
58  //---------------------------------------------------------------------
59 
60  bool SAVE_TREE = false; // if true then results are saved to tree
61  bool SAVE_ASCII = false; // if true then results are saved to ascii file
62 
63  TString REGRESSION_RANK = "LINEAR"; // regression rank [LINEAR/BILINEAR]
64  int CUT_LOW_FREQ = 32; // if > 0 the data in [0:CUT_LOW_FREQ] are set to 0
65 
66  //---------------------------------------------------------------------
67  // REGRESSION PARAMETERS
68  //---------------------------------------------------------------------
69 
70  TString FRLIST_WITNESS = ""; // list of witness frame files
71  TString CHLIST_LINEAR = ""; // list of channel names used for linear regression
72  TString CHLIST_WITNESS = ""; // list of channel names used for regression rank
73 
74  TString CHNAME_LINEAR = ""; // channel name used to made the bilinear channels
75 
76  int RESAMPLING_INDEX = 11; // resample target/witness channels to pow(2,RESAMPLING_INDEX)
77 
78  double WFLOW = 0; // lower frequency used to made the bilinear channels
79  double WFHIGH = 10; // high frequency used to made the bilinear channels
80 
81  //---------------------------------------------------------------------
82  // REGRESSION PARAMETERS
83  //---------------------------------------------------------------------
84 
85  double LAYER_WIDTH = 1.0; // frequency layer resolution used in the regression analysis
86  double fPOWERLINE = 60.0; // powerline frequency (Hz)
87  int lPOWERLINE = 1; // low power line harmonic (lPOWERLINE*fPOWERLINE)
88  int hPOWERLINE = 3; // high power line harmonic (hPOWERLINE*fPOWERLINE)
89  double FWIDTH = 5; // frequency width used by regression
90 
91  // PARAMETERS FOR LINEAR REGRESSION
92 
93  int L_NFILTER = 5; // half-size length of a unit filter (setFilter)
94  double L_APPLY_THRESHOLD = 0.2; // threshold used in apply
95  double L_SOLVE_THRESHOLD = 0.0; // eigenvalue threshold (solve)
96  double L_SOLVE_NEIGEN_PER_LAYER = 0; // number of selected eigenvalues (solve)
97  char L_SOLVE_REGULATOR = 'h'; // regulator (solve)
98 
99  // PARAMETERS FOR BILINEAR REGRESSION
100 
101  int B_NFILTER = 5; // half-size length of a unit filter (setFilter)
102  double B_APPLY_THRESHOLD = 0.2; // threshold used in apply
103  double B_SOLVE_THRESHOLD = 0.0; // eigenvalue threshold (solve)
104  double B_SOLVE_NEIGEN_PER_LAYER = 0; // number of selected eigenvalues (solve)
105  char B_SOLVE_REGULATOR = 'h'; // regulator (solve)
106 
107  // ---------------------------------
108  // read plugin config
109  // ---------------------------------
110 
111  cfg->configPlugin.Exec();
112 
113  IMPORT(bool,SAVE_TREE)
114  IMPORT(bool,SAVE_ASCII)
115 
116  IMPORT(TString,REGRESSION_RANK)
117  IMPORT(int,CUT_LOW_FREQ)
118  IMPORT(int,RESAMPLING_INDEX)
119  IMPORT(double,WFLOW)
120  IMPORT(double,WFHIGH)
121 
122  IMPORT(TString,FRLIST_WITNESS)
123  IMPORT(TString,CHLIST_LINEAR)
124  IMPORT(TString,CHLIST_WITNESS)
125  IMPORT(TString,CHNAME_LINEAR)
126 
127  if(FRLIST_WITNESS=="") {cout << "Error : witness frames list not defined" << endl;gSystem->Exit(1);}
128  if(CHLIST_LINEAR=="") {cout << "Error : linear witness channels list not defined" << endl;gSystem->Exit(1);}
129  if(CHLIST_WITNESS=="") {cout << "Error : witness channels list not defined" << endl;gSystem->Exit(1);}
130  if(CHNAME_LINEAR=="") {cout << "Error : main linear witness channel list not defined" << endl;gSystem->Exit(1);}
131 
132  IMPORT(double,LAYER_WIDTH)
133  IMPORT(double,fPOWERLINE)
134  IMPORT(int,lPOWERLINE)
135  IMPORT(int,hPOWERLINE)
136  IMPORT(double,FWIDTH)
137 
138  IMPORT(int,L_NFILTER)
139  IMPORT(double,L_APPLY_THRESHOLD)
140  IMPORT(double,L_SOLVE_THRESHOLD)
141  IMPORT(double,L_SOLVE_NEIGEN_PER_LAYER)
142  IMPORT(char,L_SOLVE_REGULATOR)
143 
144  IMPORT(int,B_NFILTER)
145  IMPORT(double,B_APPLY_THRESHOLD)
146  IMPORT(double,B_SOLVE_THRESHOLD)
147  IMPORT(double,B_SOLVE_NEIGEN_PER_LAYER)
148  IMPORT(char,B_SOLVE_REGULATOR)
149 
150  REGRESSION_RANK.ToUpper();
151  if(REGRESSION_RANK!="LINEAR" && REGRESSION_RANK!="BILINEAR") {
152  cout << "Error : REGRESSION_RANK not defined [LINEAR/BILINEAR]" << endl;
153  gSystem->Exit(1);
154  }
155 
156  if(type==CWB_PLUGIN_DATA_MDC) {
157 
158  int rank[4] = {50,30,10,1};
159 
160  int nCH=0;
161  std::vector<std::string> CHN;
162  std::vector<std::string>* pCHN=&CHN;
163  double CHC[4][NCH];
164 
165  // get ifo index
166  int xIFO =0;
167  for(int n=0;n<cfg->nIFO;n++) if(ifo==cfg->ifo[n]) {xIFO=n;break;}
168 
169  int runID = net->nRun;
170  char flabel[512];
171  int Tb=x->start();
172  int dT=x->size()/x->rate();
173  sprintf(flabel,"%d_%d_%s_job%d",int(Tb),int(dT),cfg->data_label,runID);
174 
175  Biorthogonal<double> Bio(512);
176  WSeries<double> wB(Bio);
177  WSeries<double> wT;
179  int size=0;
180 
181  // target channel
182  int level=x->getLevel();
183  x->Inverse(-1);
184  wavearray<double> xx(x->size());
185  xx.start(x->start());
186  xx.rate(x->rate());
187  for(int i=0;i<x->size();i++) xx.data[i]=x->data[i];
188 
189  if(CUT_LOW_FREQ>0) {
190  // set range [0-CUT_LOW_FREQ]Hz to 0 (remove large dynamics at low frequency)
191  int SR = int(xx.rate());
192  int mm = 0;
193  while (((SR % 2) == 0) && SR > 2*CUT_LOW_FREQ) {SR /= 2;mm++;}
194  wB.Forward(xx,mm);
195  for(int i=0;i<1;i++) {wB.getLayer(xx,i);xx=0;wB.putLayer(xx,i);}
196  wB.Inverse();
197  wB.getLayer(xx,0);
198  cout << "Set Frequency Range [0:" << SR/2 << "] = 0" << endl;
199  }
200 
201  // resample target to pow(2,RESAMPLING_INDEX) Hz
202  int sr = int(xx.rate());
203  int nn = 0;
204  while (((sr % 2) == 0) && sr > (1<<RESAMPLING_INDEX)) {sr /= 2;nn++;}
205  wB.Forward(xx,nn);
206  wB.getLayer(xx,0);
207 
208  int rrlevel=xx.rate()/(2*LAYER_WIDTH);
209  WDM<double> WD(rrlevel, 2*rrlevel, 6, 12);
210  double scratch = WD.m_H/xx.rate();
211  if(scratch>cfg->segEdge+0.001) {
212  cout << endl;
213  cout << "Regression Plugin : Error - filter scratch must be <= cwb scratch!!!" << endl;
214  cout << "filter scratch : " << scratch << " sec" << endl;
215  cout << "cwb scratch : " << cfg->segEdge << " sec" << endl;
216  gSystem->Exit(1);
217  }
218 
219  regression rr;
220 
221  // --------------------------------------------------------------
222  // LINEAR RANKING
223  // --------------------------------------------------------------
224 
225  cout << "CWB_PLUGIN_DATA_MDC : Apply Linear Regression ..." << endl;
226 
227  frame frl(FRLIST_WITNESS,"","README",true);
229  wl.start(x->start()); wl.stop(x->stop());
230  wT.Forward(xx,WD);
231 
232  if(REGRESSION_RANK=="LINEAR") {
233  cout << "CWB_PLUGIN_DATA_MDC : Apply Linear Regression Rank ..." << endl;
234 
235  // open witness channel list
236  ifstream ifl;
237  ifl.open(CHLIST_WITNESS.Data(),ios::in);
238  if (!ifl.good()) {cout << "Error Opening File : " << CHLIST_WITNESS.Data() << endl;gSystem->Exit(1);}
239 
240  char witness[1024];
241  cout << endl;
242 
243  char ofname[256];
244  sprintf(ofname,"%s/linear_regression_rank_%s_%s.txt",cfg->output_dir,ifo.Data(),flabel);
245  cout << "write results to " << ofname << endl;
246  ofstream out;
247  if(SAVE_ASCII) {
248  out.open(ofname);
249  if (!out.good()) {cout << "Error Opening File : " << ofname << endl;gSystem->Exit(1);}
250  }
251  nCH=0;
252  char fstring[512];
253  while(true) {
254  ifl >> witness;
255  if (!ifl.good()) break;
256  if(witness[0]=='#') continue;
257  //cout << "read witness channel : \t" << witness << endl;
258  frl.setChName(witness);
259  frl.setSRIndex(RESAMPLING_INDEX);
260  frl >> wl;
261  size = rr.add(wT,"target");
262  if(size==0) {cout << "Regression Plugin - empty target channel" << endl;gSystem->Exit(1);}
263  rr.mask(0,0.,xx.rate()/2.);
264  for(int n=lPOWERLINE;n<=hPOWERLINE;n++) {double f=n*fPOWERLINE;rr.unmask(0,f-FWIDTH,f+FWIDTH);}
265  size = rr.add(wl,witness);
266  if(size>0) {
267  rr.setFilter(L_NFILTER);
268  rr.setMatrix(cfg->segEdge,1.);
269  rr.solve(L_SOLVE_THRESHOLD,L_SOLVE_NEIGEN_PER_LAYER,L_SOLVE_REGULATOR);
270  rr.apply(L_APPLY_THRESHOLD);
271 
272  for(int n=0;n<4;n++) {
273  e[n] = rr.rank(rank[n],0);
274  CHC[n][nCH]=e[n][0];
275  }
276  } else {
277  for(int n=0;n<4;n++) {
278  CHC[n][nCH]=-1;
279  }
280  }
281  CHN.push_back(witness);
282  sprintf(fstring,"%3d %35s %10.5f %9.4f %8.3f %7.2f",
283  nCH,witness,CHC[0][nCH],CHC[1][nCH],CHC[2][nCH],CHC[3][nCH]);
284  cout << fstring << endl;
285  if(SAVE_ASCII) out << fstring << endl;out.flush();
286  nCH++;
287  }
288  cout << endl;
289  ifl.close();
290  if(SAVE_ASCII) out.close();
291  } else {
292 
293  // open linear channel list
294  ifstream ifl;
295  ifl.open(CHLIST_LINEAR.Data(),ios::in);
296  if (!ifl.good()) {cout << "Error Opening File : " << CHLIST_LINEAR.Data() << endl;gSystem->Exit(1);}
297 
298  char linear[1024];
299  cout << endl;
300 
301  size = rr.add(wT,"target");
302  if(size==0) {cout << "Regression Plugin - empty target channel" << endl;gSystem->Exit(1);}
303  rr.mask(0,0.,xx.rate()/2.);
304  for(int n=lPOWERLINE;n<=hPOWERLINE;n++) {double f=n*fPOWERLINE;rr.unmask(0,f-FWIDTH,f+FWIDTH);}
305  while(true) {
306  ifl >> linear;
307  if (!ifl.good()) break;
308  if(linear[0]=='#') continue;
309  cout << "read linear channel : \t" << linear << endl;
310  frl.setChName(linear);
311  frl.setSRIndex(RESAMPLING_INDEX);
312  frl >> wl;
313  rr.add(wl,linear);
314  }
315  cout << endl;
316  ifl.close();
317  rr.setFilter(L_NFILTER);
318  rr.setMatrix(cfg->segEdge,1.);
319  rr.solve(L_SOLVE_THRESHOLD,L_SOLVE_NEIGEN_PER_LAYER,L_SOLVE_REGULATOR);
320  rr.apply(L_APPLY_THRESHOLD);
321  }
322  wl.resize(0);
323 
324  // --------------------------------------------------------------
325  // BILINEAR RANKING
326  // --------------------------------------------------------------
327 
328  if(REGRESSION_RANK=="BILINEAR") {
329 
330  cout << "CWB_PLUGIN_DATA_MDC : Apply Bilinear Regression Rank ..." << endl;
331 
332  char ofname[256];
333  sprintf(ofname,"%s/bilinear_regression_rank_%s_%s.txt",cfg->output_dir,ifo.Data(),flabel);
334  cout << "write results to " << ofname << endl;
335  ofstream out;
336  if(SAVE_ASCII) {
337  out.open(ofname);
338  if (!out.good()) {cout << "Error Opening File : " << ofname << endl;gSystem->Exit(1);}
339  }
341  wT.Forward(yy,WD);
342 
343  // open main linear frame list
345  ml.start(x->start()); ml.stop(x->stop());
346  frame frb(FRLIST_WITNESS,"","README",true);
347 
348  // open witness channel list
349  ifstream iwb;
350  iwb.open(CHLIST_WITNESS.Data(),ios::in);
351  if (!iwb.good()) {cout << "Error Opening File : " << CHLIST_WITNESS.Data() << endl;gSystem->Exit(2);}
352 
353  char fstring[512];
354  char witness[1024];
356  wb.start(x->start()); wb.stop(x->stop());
357  cout << endl;
358  nCH=0;
359  while(true) {
360  iwb >> witness;
361  if (!iwb.good()) break;
362  //cout << "read witness channel : \t" << witness << endl;
363  if(witness[0]=='#') continue;
364  frb.setChName(witness);
365  frb.setSRIndex(RESAMPLING_INDEX);
366  frb >> wb;
367 
368  rr.clear();
369  size=rr.add(wT,"target");
370  if(size==0) {cout << "Regression Plugin - empty target channel" << endl;gSystem->Exit(1);}
371  rr.mask(0,0.,yy.rate()/2.);
372  for(int n=lPOWERLINE;n<=hPOWERLINE;n++) {double f=n*fPOWERLINE;rr.unmask(0,f-FWIDTH,f+FWIDTH);}
373 
374  // add main linear channel for bicoherence removal
375  //cout << endl;
376  //cout << "read main linear channel : \t" << CHNAME_LINEAR.Data() << endl << endl;
377  frb.setChName(CHNAME_LINEAR);
378  frb.setSRIndex(RESAMPLING_INDEX);
379  frb >> ml;
380  size=rr.add(ml,const_cast<char*>(CHNAME_LINEAR.Data()));
381  if(size==0) {cout << "Regression Plugin - empty main linear channel" << endl;gSystem->Exit(1);}
382 
383  if(rr.add(wb,witness,WFLOW,WFHIGH)) {
384  rr.add(1,2,"biwitness");
385  rr.mask(1); rr.mask(2);
386 
387  rr.setFilter(B_NFILTER);
388  rr.setMatrix(cfg->segEdge,1.);
389  rr.solve(B_SOLVE_THRESHOLD,B_SOLVE_NEIGEN_PER_LAYER,B_SOLVE_REGULATOR);
390  rr.apply(B_APPLY_THRESHOLD);
391 
392  for(int n=0;n<4;n++) {
393  e[n] = rr.rank(rank[n],0);
394  CHC[n][nCH]=e[n][0];
395  }
396  } else {
397  for(int n=0;n<4;n++) {
398  CHC[n][nCH]=-1;
399  }
400  }
401  CHN.push_back(witness);
402  nCH++;
403  sprintf(fstring,"%3d %35s %10.5f %9.4f %8.3f %7.2f",
404  nCH,witness,CHC[0][nCH],CHC[1][nCH],CHC[2][nCH],CHC[3][nCH]);
405  cout << fstring << endl;
406  if(SAVE_ASCII) out << fstring << endl;out.flush();
407  }
408  iwb.close();
409  if(SAVE_ASCII) out.close();
410  cout << endl;
411 
412  ml.resize(0);
413  wb.resize(0);
414  }
415 
416  if(SAVE_TREE) {
417  // save data to root
418  char outFile[512];
419  if(REGRESSION_RANK=="LINEAR") {
420  sprintf(outFile,"%s/linear_regression_rank_%s_%s.root",cfg->output_dir,ifo.Data(),flabel);
421  } else {
422  sprintf(outFile,"%s/bilinear_regression_rank_%s_%s.root",cfg->output_dir,ifo.Data(),flabel);
423  }
424  cout << "write results to " << outFile << endl;
425 
426  TFile* ofile = new TFile(outFile,"RECREATE");
427  cfg->Write("config"); // write config object
428  //cfg->configPlugin.Write("configPlugin"); // write configPlugin object
429 
430  TTree rrtree("regression","regression");
431  double igps=x->start();
432  double start=x->start();
433  double stop=x->stop();
434  char sifo[256];sprintf(sifo,"%s",ifo.Data());
435  rrtree.Branch("run",&runID,"run/I");
436  rrtree.Branch("gps",&igps,"gps/D");
437  rrtree.Branch("start",&start,"start/D");
438  rrtree.Branch("stop",&stop,"stop/D");
439  rrtree.Branch("sifo",sifo,"sifo/C");
440  rrtree.Branch("ifo",&xIFO,"ifo/I");
441  rrtree.Branch("nch",&nCH,"nch/I");
442  rrtree.Branch("chc50",CHC[0],"chc[nch]/D");
443  rrtree.Branch("chc30",CHC[1],"chc[nch]/D");
444  rrtree.Branch("chc10",CHC[2],"chc[nch]/D");
445  rrtree.Branch("chc01",CHC[3],"chc[nch]/D");
446  rrtree.Branch("chn",&pCHN);
447 
448  rrtree.Fill();
449  rrtree.Write();
450  ofile->Close();
451  }
452 
453  // end job - clean temporary files
454  if(ifo==cfg->ifo[xIFO]) {
455  cout << "remove temporary file ..." << endl;
456  TString jname = jfile->GetPath();
457  jname.ReplaceAll(":/","");
458  cout << jname.Data() << endl;
459  gSystem->Exec(TString("rm "+jname).Data());
460  cout << "end job" << endl;
461  gSystem->Exit(0);
462  }
463  }
464 
465  return;
466 }
char ofile[1024]
CWB::config * cfg
void setMatrix(double edge=0., double f=1.)
Definition: regression.cc:425
TMacro configPlugin
Definition: config.hh:362
Definition: ced.hh:42
virtual void rate(double r)
Definition: wavearray.hh:141
int n
Definition: cwb_net.C:28
TString("c")
size_t nRun
Definition: network.hh:572
ofstream out
Definition: cwb_merge.C:214
cout<< endl;cout<< "ts size = "<< ts.size()<< " ts rate = "<< ts.rate()<< endl;tf.Forward(ts, wdm);int levels=tf.getLevel();cout<< "tf size = "<< tf.size()<< endl;double dF=tf.resolution();double dT=1./(2 *dF);cout<< "rate(hz) : "<< RATE<< "\ layers : "<< nLAYERS<< "\ dF(hz) : "<< dF<< "\ dT(ms) : "<< dT *1000.<< endl;int itime=TIME_PIXEL_INDEX;int ifreq=FREQ_PIXEL_INDEX;int index=(levels+1) *itime+ifreq;double time=itime *dT;double freq=(ifreq >0) ? ifreq *dF :dF/4;cout<< endl;cout<< "PIXEL TIME = "<< time<< " sec "<< endl;cout<< "PIXEL FREQ = "<< freq<< " Hz "<< endl;cout<< endl;wavearray< double > x
wavearray< double > rank
Definition: Regression_H1.C:80
Long_t size
size_t add(WSeries< double > &target, char *name, double fL=0., double fH=0.)
Definition: regression.cc:91
virtual void start(double s)
Definition: wavearray.hh:137
i drho i
cout<< "SNR "<< xsnr<< endl;wavearray< double > f
Definition: ComputeSNR.C:75
char ifo[NIFO_MAX][8]
network ** net
NOISE_MDC_SIMULATION.
void setChName(TString chName)
Definition: frame.hh:120
double segEdge
Definition: config.hh:164
virtual size_t size() const
Definition: wavearray.hh:145
wavearray< double > rank(int nbins=0, double fL=0., double fH=0.)
Definition: regression.cc:825
int getLevel()
Definition: wseries.hh:109
jfile
Definition: cwb_job_obj.C:43
wavearray< double > xx
Definition: TestFrame1.C:11
#define IMPORT(TYPE, VAR)
Definition: cwb.hh:69
i() int(T_cor *100))
char output_dir[1024]
Definition: config.hh:318
void apply(double threshold=0., char c='a')
Definition: regression.cc:709
int getLayer(wavearray< DataType_t > &w, double n)
param: n - layer number
Definition: wseries.cc:193
void CWB_Plugin(TFile *jfile, CWB::config *cfg, network *net, WSeries< double > *x, TString ifo, int type)
COHERENCE.
void solve(double th, int nE=0, char c='s')
Definition: regression.cc:610
size_t setFilter(size_t)
Definition: regression.cc:276
void setSRIndex(int srIndex)
Definition: frame.hh:114
wavearray< double > getClean()
Definition: regression.hh:135
double e
wavearray< double > yy
Definition: TestFrame5.C:12
void clear()
Definition: regression.hh:160
double Tb
ifstream in
virtual void stop(double s)
Definition: wavearray.hh:139
char ifo[NIFO_MAX][8]
Definition: config.hh:124
void Forward(int n=-1)
param: wavelet - n is number of steps (-1 means full decomposition)
Definition: wseries.cc:246
void unmask(int n, double flow=0., double fhigh=0.)
Definition: regression.cc:339
#define FRLIST_WITNESS
Definition: RegressionL1.C:2
void mask(int n, double flow=0., double fhigh=0.)
Definition: regression.cc:321
sprintf(tfres,"(1/%g)x(%g) (sec)x(Hz)", 2 *df, df)
int nIFO
Definition: config.hh:120
DataType_t * data
Definition: wavearray.hh:319
TString jname
double dT
Definition: testWDM_5.C:12
char data_label[1024]
Definition: config.hh:332
virtual void resize(unsigned int)
Definition: wavearray.cc:463
void Inverse(int n=-1)
param: n - number of steps (-1 means full reconstruction)
Definition: wseries.cc:291
void putLayer(wavearray< DataType_t > &, double n)
param: n - layer number
Definition: wseries.cc:219
int m_H
Definition: Wavelet.hh:121