UnivRec.cc
Go to the documentation of this file.
1 #include "UnivRec.h"
2 
3 #include <TMath.h>
4 #include <TMatrixTSym.h>
5 #include <TMatrixDSym.h>
6 #include <TMatrixDSymEigen.h>
7 #include <TGraphErrors.h>
8 #include <TCanvas.h>
9 
10 #include <TRandom3.h>
11 
12 using namespace UnivRecNS;
13 
14 
15 //---------------------------------------------------------
16 //Electronics/GPS settings (WCD/Scintillators)
17 //---------------------------------------------------------
18 // (Upgrade) Sampling=8 [ns], 12-bit, InterGPS Accuracy 4 [ns]
19 // (Current) Sampling=25 [ns], 10-bit, InterGPS Accuracy 10 [ns]
20 //
21 //---------------------------------------------------------
22 // Saturation (WCD)
23 //---------------------------------------------------------
24 // Anode non-linearity fo the current nominal gain starts at 100 [mA], 5 [V] at 50 Ohm , 1 nC in 10 [ns]
25 // Gain=2 x 10^5 <pe>=94 -> 1 [nC]= 6.25 10^9 electrons -> 3.12e4 photo-electrons -> ~300 [vem]
26 //
27 // Electronic saturation : 5 anode [ADC] = 1 [vem]
28 // (Upgrade SDE) -> 4096/5= 800 [vem]
29 // (Current SDE) -> 1024/5= 200 [vem]
30 //
31 // But, the small PMT is now part of the baseline SDE design. Saturation should happen at total signal ~20000 [vem] ( ~2000 [vem]/8 [ns] at peak )
32 //
33 // Saturation (Total signal) : 1000/20000 [vem] Current/Upgraded SDE
34 //
35 //---------------------------------------------------------
36 // Saturation (ASCII)
37 //---------------------------------------------------------
38 // Set to electronic saturation assuming 5 anode [ADC] = 1 [vem]
39 //
40 // (Upgrade SDE) -> 4096/5 = 800 [vem]
41 // (Current SDE) -> 1024/5 = 200 [vem]
42 //
43 // For ASCII there is a shaper so the time response is matched to the one for the WCD.
44 //
45 // Saturation (Total signal) : 1500/10000 [vem] Current/Upgraded SDE
46 
47 
48 //---------------------------------------------------------
49 // Saturation (Muon detectors)
50 //---------------------------------------------------------
51 // (0-64 x 3 muons)
52 
53 //--------------------------------------
54 // Rec types
55 //--------------------------------------
56 //
57 // Station selection for Signal/Time likelihood: after Fitstage -1
58 // Gaus PDF flags : after Fitstage 1
59 //
60 //
61 //
62 // Hybrid reconstructions ( direction fixed to hybrid reconstruction )
63 // -----------------------
64 // Fitstage -1 : (logE,Xmax)=(log_FD,Xmax_FD) -> Nmu_FD (core search for station selection)
65 // Fitstage 0 : (logE,Xmax) constrained to (logE_FD,Xmax_FD) -> Nmu_FD
66 //
67 // [0] Nmu_FD
68 // [7] Nmu_FD and OffsetM_Mu (FitStage 1 and 2 also )
69 //
70 //
71 // SD reconstructions
72 // -----------------------
73 // Fitstage -1 : (Nmu,Xmax) fixed to <Nmu>(E,theta),<Xmax>(E) (core search for station selection)
74 // Fitstage 0 : (Nmu,Xmax) fixed to <Nmu>(E,theta),<Xmax>(E)
75 // Fitstage 1 : (core,logE,Nmu,direction) fixed from FitStage 0 ( Xmax/T0 guess )
76 // Fitstage 2 : Nmu=<Nmu>(E,theta,Xmax)
77 //
78 // [1] OffsetM_Mu fit Nmu=<Nmu>(logE,theta,Xmax) ( Xmax/OffsetM_mu ) free parameter
79 // [2] Rec. Stops at FitStage 0
80 // [3] Rec. Stops at FitStage 0, Nmu free in FitStage 0, ( Nmu_SD with <Xmax> ) only WCD+TopScin/WCD+MD
81 // [4] Xmax_SD fit Nmu=<Nmu>(logE,theta,Xmax)
82 // [5] Xmax_SD fit log(E)=log(E_ref) Nmu free
83 // [8] Xmax_SD fit Nmu=<Nmu>(logE,theta,-100)
84 //
85 // Photon search
86 // -----------------
87 // [6] Same as [4] but Nmu=Nmu_PhotonSearch , Xmax=Xmax_PhotonSearch
88 // (FitStage=-1/0 Signal Likelihood, FitStage=1/2 Only Time likelihood )
89 //
90 //
91 //--------------------------------------
92 // Data sets ( always 6T5 )
93 //--------------------------------------
94 // DataSet=0 SD ( 1500 [m] log(E_ADST)>18.6 [eV] , 750 [m] log(E_ADST)>17.8 [eV] )
95 // DataSet=1 Golden ( log(E_FD)>17.5 [eV] )
96 // DataSet=2 SD low energy ( 6T5 750 [m] events that are also 6T5 1500 [m] events)
97 // DataSet=3 SD high energy( log(E_ADST)>19.5 [eV] )
98 
99 //--------------------------------------
100 // Likelihood setting
101 //--------------------------------------
102 // Parameters (logE,core,direction,Xmax,T0,Nmu)
103 // WCD: : Signal/Starttime/T1/T10/T50 likelihood used
104 // Scintillators : Signal/Starttime/T1/T10/T50 likelihood used
105 // Muon detectors: Signal/Starttime/T1/T10/T50 likelihood used
106 // At least 4 stations with r<%4.0lf [m] after core search are required for the time likelihood \n",rQuantileCut[1]/1.e2);
107 
108 //-------------------------------------------------------------
109 
110 //-------------------------------------------------------------------
111 //-------------------------------------------------------------------
112 // Set flags
113 // Init Univ. Parameterizations
114 // Create atmosphere
115 //-------------------------------------------------------------------
116 //-------------------------------------------------------------------
118 {
120  for (int itype = 0; itype < 3; itype++) {
121  ftime[itype] = new UnivParamTimeNS::UnivParamTime(itype);
122  fsignal[itype] = new UnivParamNS::UnivParam(itype);
123  }
124  fcalib = NULL;
125 }
126 
127 bool UnivRec::InitRec(bool IsData, int RecType, int CalibOpt, int RecDetector /*all*/, int RecSys /*Only CalibOpt=-2*/ , int RecMixture /*Only CalibOpt=0,1*/)
128 {
129  //General
130  gRecMC = !IsData;
131  gRecType = RecType;
132  if (gRecType < 0 || gRecType > 8) {
133  printf("ERROR: Wrong [RecType] \n");
134  return false;
135  }
136 
137  gCalibOpt = CalibOpt;
138  if (gCalibOpt < -3 || gCalibOpt > 3) {
139  printf("ERROR: Wrong [CalibOpt] %d \n", gCalibOpt);
140  return false;
141  }
142 
143  if (RecDetector < 0 || RecDetector > 3) {
144  printf("Wrong [RecDetector] \n");
145  return false;
146  }
147  if (RecDetector > 0 && (gRecType == 1 || gRecType == 4 || gRecType == 5 || gRecType == 6 || gRecType == 7 || gRecType == 8)) {
148  printf("ERROR: Time model for Scintillator above below ground is not tested, you can delete this break at your own risk \n");
149  return false;
150  }
151  if (gRecType == 3 && RecDetector == 0) {
152  printf("ERROR: Nmu_SD only possible with upgrades \n");
153  return false;
154  }
155 
156  gDetectorTypeMask[0] = false;
157  gDetectorTypeMask[1] = (RecDetector == 1 || RecDetector == 3 ? false : true);
158  gDetectorTypeMask[2] = (RecDetector == 2 || RecDetector == 3 ? false : true);
159 
160  //Only CalibOpt=-2
161  gRecSys = RecSys;
162  if (CalibOpt > -2 && gRecSys != 0) {
163  printf("ERROR: Systematics only implemented for CalibOpt=-2 \n");
164  return false;
165  }
166  if (CalibOpt <= -2 && (gRecSys < 0 || gRecSys >= UnivCalibConstantsNS::nSys)) {
167  printf("ERROR: Wrong [RecSys] \n");
168  return false;
169  }
170 
171  //Only CalibOpt=0,1
172  gRecMixture = RecMixture;
173  if (CalibOpt >= 0 && (gRecMixture < 0 || gRecMixture > UnivCalibConstantsNS::nRecMixtures)) {
174  printf("ERROR: Wrong [gRecMixture] \n");
175  return false;
176  }
177 
178  if (gRecType == 6 && CalibOpt != -1)
179  printf("WARNING: Photon search without photon calib parameters \n");
180  //--
181  IsTimeRec = (gRecType == 1 || gRecType == 4 || gRecType == 5 || gRecType == 6 || gRecType == 8 || gRecType == 7 ? true : false);
182 
183  if (fcalib != NULL) delete fcalib;
185 
186  //--Set Golden rec. flag ( So FD rec. parameters are used )
187  IsGoldenRec = (gRecType == 0 || gRecType == 7 ? true : false);
188  if (IsGoldenRec && CalibOpt != -3) {
189  printf("ERROR: Wrong CalibOpt \n");
190  return false;
191  }
192 
193  //-- Only required for Bariloche framework (Initialized in a specialized routine)
194  gRecInfill = false;
195  gRecSDE_Upgrade = false;
196  gRecAoP = UNDEF;
197  gRecDataSet = (IsGoldenRec ? 1 : UNDEF);
198 
199  return true;
200 }
201 
202 
203 bool
204 #ifndef ExternalUse
205 UnivRec::InitRec_InternalFramework(bool RecInfill /*all*/, int RecDataSet, int year, std::string& FileName /*Only data*/, bool RecSDEUpgrade, int RecAoP /*Only MC */)
206 #else
207 UnivRec::InitRec_InternalFramework(bool RecInfill /*all*/, int RecDataSet, int /*year*/, std::string& /*FileName*/ /*Only data*/, bool RecSDEUpgrade, int RecAoP /*Only MC */)
208 #endif
209 {
210  gRecInfill = RecInfill;
211  if (gRecMC) {
212  gRecSDE_Upgrade = RecSDEUpgrade;
213  gRecAoP = RecAoP;
214  if (!(gRecAoP == 0 || gRecAoP == 2 || gRecAoP == 3)) {
215  printf("Wrong [RecAoP]\n");
216  return false;
217  }
218  } else {
219  gRecDataSet = RecDataSet;
220  if (!(gRecDataSet == 0 || gRecDataSet == 1 || gRecDataSet == 2 || gRecDataSet == 3)) {
221  printf("Wrong [RecDataSet]\n");
222  return false;
223  }
224 
225  if ((gRecDataSet == 0 || gRecDataSet == 2 || gRecDataSet == 3) && IsGoldenRec)
226  printf("Hybrid reconstruction on SD data not possible\n");
227  if ((gRecDataSet == 2 || gRecDataSet == 3) && gRecInfill)
228  printf("Wrong data set for Infill rec.\n");
229 
230 #ifndef ExternalUse
231  if (gRecDataSet == 0 && !gRecInfill && (year < 2004 || year > 2012)) {
232  printf("Wrong SD data set\n");
233  return false;
234  }
235  if (gRecDataSet == 0)
236  FileName = ToyUtilsNS::GetDataFileName(gRecInfill ? 1 : 0 , year);
237  else if (gRecDataSet == 1)
238  FileName = ToyUtilsNS::GetDataFileName(gRecInfill ? 3 : 2, year);
239  else if (gRecDataSet == 2)
240  FileName = ToyUtilsNS::GetDataFileName(4, year);
241  else if (gRecDataSet == 3)
242  FileName = ToyUtilsNS::GetDataFileName(5, year);
243 #endif
244  }
245 
246  return true;
247 }
248 
249 
250 
251 //---------------------------------------------------
252 //---------------------------------------------------
253 // Init/Clear event/station
254 //---------------------------------------------------
255 //---------------------------------------------------
257 {
258  station->type = UNDEF;
259  station->id = UNDEF;
260 
261  station->AreaOverPeak = -1.;
262  station->DetectorArea = UNDEF;
263  station->isSaturated = false;
264 
265  station->xg = 0.;
266  station->yg = 0.;
267  station->zg = 0.;
268 
269  station->GPSnano = 0.;
270 
271  station->r = 0.;
272  station->psi = 0.;
273  station->T0_PF = 0.;
274  for (int icomp = 0; icomp < 4; icomp++) {
275  station->DX[icomp] = 0.;
276  station->DL[icomp] = 0.;
277  station->T0_CF[icomp] = 0.;
278  }
279 
280  station->mask_quantiles = true;
281  for (int iq = 0; iq < UnivRecNS::nQ; iq++) {
282  station->UseGausPDF_quantiles[iq] = true;
283  station->quantile[iq] = UNDEF;
284  station->tquantile[0][iq] = UNDEF;
285  station->tquantile[1][iq] = UNDEF;
286  station->tq_rec[iq] = 0.;
287  station->tq_pred[iq] = 0.;
288  station->tq_rms[iq] = 0.;
289  station->tq_corr[iq] = 0.;
290  station->lnP_quantiles = 0.;
291  }
292 
293  station->UseGausPDF_start = true;
294  station->mask_starttime = true;
295  station->starttime = UNDEF;
296  station->start_rec = 0.;
297  station->start_pred = 0.;
298  station->start_rms = 0.;
299  station->start_corr = 0.;
300  station->lnP_start = 0.;
301 
302  station->density = 0.;
303  station->signalsize = 0.;
304  station->mask_signal = true;
305 }
306 
308 {
309 
310  //RecInfo
311  recinfo.id = UNDEF;
313  recinfo.iatm = UNDEF;
314 
315  recinfo.xgcore = UNDEF;
316  recinfo.ygcore = UNDEF;
319  recinfo.zgcore = UNDEF;
320 
321  recinfo.logE = UNDEF;
322  recinfo.logE_err = 0.;
323  recinfo.Xmax = UNDEF;
324  recinfo.Xmax_err = 0.;
325  recinfo.Nmu = UNDEF;
326  recinfo.Nmu_err = 0.;
327  recinfo.theta = UNDEF;
328  recinfo.azi = UNDEF;
329  recinfo.T0 = UNDEF;
330  recinfo.T0_err = 0.;
332  recinfo.logE_ref_err = 0.;
335 
337 
338  recinfo.RA = UNDEF;
339  recinfo.Dec = UNDEF;
340 
341  recinfo.nStationsMD = 0;
343  recinfo.nStationsWCD = 0;
346 
347  for (int iloop = 0; iloop < 2; iloop++)
348  recinfo.FitStatus[iloop] = -1;
349 
350  for (int iloop = 0; iloop < 3; iloop++) {
351  recinfo.lnP[iloop] = 0;
352  recinfo.seed[iloop] = 0;
353  }
354  recinfo.MinEigenVal = 0.;
355  recinfo.edm = 0.;
356 
357  recinfo.FitStage = -2;
358 
359  recinfo.AllTimesOK = false;
360  for (int i = 0; i < 2; i++) {
361  recinfo.TimeRejected[i] = 0.;
362  recinfo.TimeMaxdev[i] = 0.;
363  }
364 
365  recinfo.rHot = UNDEF;
367  recinfo.nFCNcalls = 0;
368  recinfo.IsSaturated[0] = false;
369  recinfo.IsSaturated[1] = false;
370  recinfo.IsSaturated[2] = false;
371 
372  // MC Info
373  MCinfo.im = UNDEF;
374  MCinfo.ip = UNDEF;
375  MCinfo.ie = UNDEF;
376  MCinfo.ith = UNDEF;
377  MCinfo.ish = UNDEF;
378  MCinfo.iatm = UNDEF;
379  MCinfo.xgcore = UNDEF;
380  MCinfo.ygcore = UNDEF;
381  MCinfo.zgcore = UNDEF;
382  MCinfo.theta = UNDEF;
383  MCinfo.azi = UNDEF;
384  MCinfo.logE = UNDEF;
385  MCinfo.Xmax = UNDEF;
386  MCinfo.Nmu = UNDEF;
387  MCinfo.T0 = UNDEF;
388 
389  // Auger Info
396  augerinfo.logE_SD_err = 0.;
397 
404  augerinfo.logE_FD_err = 0.;
406  augerinfo.Xmax_FD_err = 0.;
407 
408  augerinfo.isGoodSD = false;
409  augerinfo.isGoodFD = false;
410 
411  augerinfo.RA = UNDEF;
412  augerinfo.dec = UNDEF;
413 
414  // Stations
415  fstation.clear();
416 
417 
418 }
419 
420 #ifndef ExternalUse
421 
422 bool UnivRec::InitEvent(ToyShowerNS::ToyShower* fevt)
423 {
424  ClearRecEvent();
425 
426  nRecStations = 0;
427  XmaxLow = (gRecType == 6 ? 200. : low[4]);
428  XmaxHigh = high[4];
429 
430  bool okT4 = true, okEnergyCut = true, okAtm = true, okXmax = true;
431 
432  //-----------------------------------------------
433  // Set Id, Check T4, Init Random Number
434  //-----------------------------------------------
435 
436  recinfo.id = (gRecMC ? int(fevt->GetCorsikaInfo()->runnr) : fevt->GetAugerInfo()->sdid);
437  okT4 = fevt->CheckT4(gRecInfill);
438  TRandom3* rnd = new TRandom3(recinfo.id + gRecType);
439 
440  //-----------------------------------------------
441  // Load MC info
442  //-----------------------------------------------
443  if (gRecMC) {
444  ToyUtilsNS::GetShowerIndexes(recinfo.id, MCinfo.im, MCinfo.ip, MCinfo.ie, MCinfo.ith, MCinfo.ish, MCinfo.iatm);
445 
446  MCinfo.theta = fevt->GetCorsikaInfo()->theta;
447  MCinfo.azi = fevt->GetCorsikaInfo()->azi;
448 
449  float x_ref, y_ref, z_ref;
450  fevt->GetCoreMC(x_ref, y_ref, z_ref);
451  MCinfo.xgcore = x_ref;
452  MCinfo.ygcore = y_ref;
453  MCinfo.zgcore = z_ref;
454 
455  MCinfo.T0 = fevt->GetCoreT0_MC();
456 
457  MCinfo.logE = log10(fevt->GetCorsikaInfo()->E0) + 9.;
458  MCinfo.Xmax = fevt->GetCorsikaInfo()->Xmax + ToyUtilsNS::XmaxCorsikaOffset;
459 
460  int ir0 = 4 , ipsi0 = 2;
461  ToyShowerNS::SamplingArea_t* saRef = fevt->GetDenseSA(ir0, ipsi0);
462  double density = fevt->GetAtmosphere()->GetDensity(saRef->zg);
463  double sMu = saRef->Muon.vem;
464 
465  double sMuRef = fsignal[0]->GetSignal(ToyUtilsNS::rRing[ir0], MCinfo.Xmax, MCinfo.logE, MCinfo.theta, ToyUtilsNS::psiS[ipsi0],
466  density, ToyShowerNS::hgroundRef, 1.0 , 0 , MCinfo.iatm);
467  MCinfo.Nmu = sMu / sMuRef;
468 
469  }
470 
471  //-----------------------------------------------
472  //Set : Atmosphere/Ground Density
473  //-----------------------------------------------
474  if (gRecMC) {
475  GPSsec = 0;
476 
477  int imonth = fevt->GetAtmosphere()->GetCurrentAtmosphereMonth();
478  fatm->SetCurrentAtmosphere(imonth);
479  if (imonth != MCinfo.iatm) okAtm = false;
480  recinfo.iatm = imonth;
481  } else {
482  ToyShowerNS::AugerInfo_t* ainfo = fevt->GetAugerInfo();
483  if (ainfo->p == 0. || ainfo->T == 0.)
484  recinfo.AugerDensity = 1.06 * 1.e-3; // Average density
485  else {
486  double R = 286.9; // [atm][l]/[mol][K]
487  recinfo.AugerDensity = ainfo->p * 100000. / 286.9 / ainfo->T / 1.e3; // [g]/[cm3]
488  }
489  GPSsec = ainfo->GPSsec;
490 
491  unsigned int nsec = 0;
492  utl::TimeStamp time_stamp(ainfo->GPSsec, nsec);
493  int imonth = time_stamp.GetMonth();
494  fatm->SetCurrentAtmosphere(imonth);
495  recinfo.iatm = imonth;
496  }
497 
498 
499  //-----------------------------------------------
500  //Set Auger Info
501  //-----------------------------------------------
502  augerinfo.Xmax_FD_err = 20.;
503  augerinfo.logE_FD_err = log10(1.1);
504 
505  if (gRecMC) {
506  //--- Cut events with Xmax_ref below ground ( so Mean/RMS in ToyUtils is consistent )
507  if (std::isnan(MCinfo.Xmax) || std::isinf(MCinfo.Xmax) || MCinfo.Xmax <= 0.) okXmax = false;
508 
509  //--- Fluctuated values of Energy and Xmax
511  augerinfo.logE_FD = MCinfo.logE + rnd->Gaus(0., augerinfo.logE_FD_err);
512 
513  //---Fluctuated values of (theta,azi)
514  TVector3 theCR;
515  theCR.SetMagThetaPhi(1., MCinfo.theta, MCinfo.azi);
516  TVector3 rndD = theCR.Orthogonal();
517  rndD.SetMag(fabs(rnd->Gaus(0, SmearingAngle * TMath::DegToRad())));
518  rndD.Rotate(rnd->Rndm()*TMath::TwoPi(), theCR);
519  rndD = theCR + rndD;
520  theCR = rndD.Unit();
521  augerinfo.theta_FD = theCR.Theta();
522  augerinfo.azi_FD = NormalizeAngle(theCR.Phi());
523  } else {
524  ToyShowerNS::AugerInfo_t* ainfo = fevt->GetAugerInfo();
525  // SD (Observer reconstruction) core position is not saved (Do it in Offline!)
526  augerinfo.logE_SD = log10(ainfo->E_SD) + 18.;
527  augerinfo.logE_SD_err = log10(1. + ainfo->E_SD_err / ainfo->E_SD);
529  augerinfo.theta_SD = ainfo->thetaObserver;
530  augerinfo.azi_SD = ainfo->aziObserver;
531  augerinfo.isGoodSD = fevt->isGoodSD(true);
532 
533  recinfo.RA = ainfo->RA;
534  recinfo.Dec = ainfo->Dec;
535 
536  // FD
537  int EyeSel = (gRecSys > 8 ? gRecSys - 8 : UNDEF);
538 
539  float Xmax_FD, Xmax_FD_err, E_FD, E_FD_err, theta_FD, theta_FD_err, azi_FD, azi_FD_err;
540  augerinfo.isGoodFD = fevt->isGoodFD(Xmax_FD, Xmax_FD_err, E_FD, E_FD_err, theta_FD, theta_FD_err, azi_FD, azi_FD_err , true, EyeSel);
541 
542  if (augerinfo.isGoodFD) {
543  augerinfo.logE_FD = log10(E_FD) + 18.; // If Offline is using M. Tueros et al, this is correct (otherwise I have to do the parameterization of missing energy)
544  augerinfo.Xmax_FD = Xmax_FD;
545 
546  augerinfo.theta_FD = theta_FD;
547  augerinfo.azi_FD = azi_FD;
548  }
549  if (gRecDataSet == 1 || gRecType == 0) okXmax = augerinfo.isGoodFD;
550 
551  // Energy cuts for different rec
552  okEnergyCut = CheckEnergyCut(true);
553  }
554  if (gCalibOpt <= -2) {
557  }
558 
559  //-----------------------------------------------
560  // Selection
561  //-----------------------------------------------
562  if (!okT4) {
563  printf(" Event is not T4 %d \n", recinfo.id);
564  return false;
565  }
566  if (!okEnergyCut) {
567  printf(" Energy below analysis threshold %d \n", recinfo.id);
568  return false;
569  }
570  if (!okAtm) {
571  printf("Error: inconsistency in the atmospheres %d \n", recinfo.id);
572  return false;
573  }
574  if (!okXmax) {
575  printf(" Xmax not well defined %d \n", recinfo.id);
576  return false;
577  }
578  if (!gRecMC) {
579  if (!augerinfo.isGoodSD) {
580  printf("Warning: SD event not 6T5 \n");
581  return false;
582  }
583  if (!augerinfo.isGoodFD && (IsGoldenRec || gRecDataSet == 1)) {
584  printf("Error: Golden event without FD rec parameters %d \n", recinfo.id);
585  return false;
586  }
587  }
588  if (recinfo.id == 4067414) {
589  printf("Lightening event %d \n", recinfo.id);
590  return false;
591  }
592 
593  //-----------------------------------------------
594  // Set station vector
595  //-----------------------------------------------
596 
597  int nSignalStations = 0;
598  for (int idet = 0; idet < ToyUtilsNS::nDetectors; idet++)
599  for (int itype = 0; itype < 3; itype++) {
600  if (gDetectorTypeMask[itype]) continue;
601 
602  //----Station/Event trigger and selection given by WCD
603  ToyShowerNS::SamplingArea_t* sa = fevt->GetArraySA(idet);
604  if (!gRecInfill && !sa->isStandard) continue;
605  if (!sa->isAlive && sa->triggerFlag == 0) continue; // Accept all stations with trigger (even if they are thought to be dead)
606  if (sa->isAccidental && sa->triggerFlag > 0) continue;
607 
608  //---- 2012 (No T2Life) Events picked up when comparing energies with the Observer ( Warning: there might be more in 2012 )
609  if (recinfo.id == 13296659 && sa->id == 203) continue;
610  if (recinfo.id == 13769235 && sa->id == 131) continue;
611  if (recinfo.id == 8270184 && sa->id == 294) continue;
612 
613  //---- Photon search (event with an accidental muon in one station)
614  if (recinfo.id == 7728630 && sa->id == 752) continue;
615 
616  //---- Xmax SD outliers ( Xmax<500. )
617  if (recinfo.id == 648728 && sa->id == 157) continue;
618  if (recinfo.id == 1711230 && sa->id == 216) continue;
619  if (recinfo.id == 10961377 && sa->id == 438) continue;
620 
621  RecStation_t station;
622  InitRecStation(&station);
623 
624  station.type = itype;
625  station.id = (gRecMC ? idet : sa->id);
626 
627  station.DetectorArea = (itype == 2 ? nMD * MDlength* MDwidth : UNDEF);
628 
629  station.xg = sa->xg;
630  station.yg = sa->yg;
631  station.zg = sa->zg;
632 
633  station.GPSnano = sa->GPSnano;
634 
635  if (sa->triggerFlag == 0) {
636  fstation.push_back(station);
637  continue;
638  }
639 
640  bool hasTrace = true;
641 
642  //----------------
643  // T1/T2 stations
644  //----------------
645 
646  //---- Area over peak
647  if (itype < 2) {
648  if (gRecMC) { // MC
649  if (itype == 0) { //WCD
650  if (gRecAoP == 2 || gRecAoP == 3) station.AreaOverPeak = AreaOverPeak_Run[gRecAoP];
651  else station.AreaOverPeak = -1.;
652  } else //Scin
653  station.AreaOverPeak = -1.;
654  } else station.AreaOverPeak = sa->AreaOverPeak; //Auger data
655  }
656  if (station.AreaOverPeak > 5.) continue;
657 
658  //---- Traces
659  float TimeUnit = (!gRecSDE_Upgrade || itype == 2 ? 25. : 8.);
660  int nTimeBins = (!gRecSDE_Upgrade || itype == 2 ? ToyShowerNS::nFADC : ToyShowerNS::nTimeBins / 4);
661  int nWindow = (!gRecSDE_Upgrade || itype == 2 ? 1 : 3);
662  float* vemtrace;
663  double vemSat;
664  int start, end;
665 
666  if (itype == 0) {
667  vemtrace = (gRecSDE_Upgrade ? sa->vemtrace_8ns : sa->vemtrace);
669  } else if (itype == 1) {
670  vemtrace = (gRecSDE_Upgrade ? sa->vemtraceScin_8ns : sa->vemtraceScin);
672  } else {
673  vemtrace = sa->vemtraceMD;
674  vemSat = SaturationLevelMD;
675  }
676 
677  //----Avg quantiles ( only MC )
678  if (gRecMC) {
679  station.tquantile[1][0] = UNDEF;
680  if (itype == 0) {
681  station.tquantile[1][1] = sa->t10T;
682  station.tquantile[1][2] = sa->t50T;
683  station.tquantile[1][3] = sa->t90T;
684  } else if (itype == 1) {
685  station.tquantile[1][1] = sa->t10T_Scin;
686  station.tquantile[1][2] = sa->t50T_Scin;
687  station.tquantile[1][3] = sa->t90T_Scin;
688  } else if (itype == 2) {
689  station.tquantile[1][1] = sa->t10T_MD;
690  station.tquantile[1][2] = sa->t50T_MD;
691  station.tquantile[1][3] = sa->t90T_MD;
692  }
693  }
694 
695  //----Saturation/Signal
696  //Data
697  if (!gRecMC) {
698  start = sa->StartBin;
699  end = sa->EndBin;
700  station.isSaturated = sa->isSaturated;
701  station.signalsize = 0.;
702  for (int itime = start; itime < end; itime++)
703  station.signalsize += vemtrace[itime];
704  }
705  //MC
706  else {
707  start = 0;
708  end = (itype == 2 ? nTimeBins - 3 : nTimeBins) ;
709  station.isSaturated = false;
710  station.signalsize = 0.;
711 
712  int itime = start;
713  while (true) {
714  //AMIGA
715  if (itype == 2) {
716  if (vemtrace[itime] > vemSat) {
717  station.isSaturated = true;
718  vemtrace[itime] = vemSat;
719  station.signalsize += vemtrace[itime];
720  } else station.signalsize += vemtrace[itime];
721  }
722  //WCD/ASCII
723  else {
724  if (vemtrace[itime] > vemSat) {
725  station.isSaturated = true;
726  vemtrace[itime] = vemSat;
727  station.signalsize += vemSat;
728  } else station.signalsize += vemtrace[itime];
729  }
730 
731  itime++;
732  if (itime >= end) break;
733  }
734  }
735 
736  //---- Data events with no traces
737  if (!gRecMC && station.signalsize == 0. && sa->vem[0] > 0.) {
738  hasTrace = false;
739  station.signalsize = sa->vem[0];
740  station.isSaturated = sa->isSaturated;
741  }
742 
743  if (station.isSaturated) recinfo.IsSaturated[itype] = true;
744  if (itype == 0 && station.signalsize > vemSignalCut) station.mask_signal = false;
745 
746  //----Start time
747  //Data
748  if (!gRecMC) {
749  int StartTimeBin = sa->StartTimeBin;
750  station.starttime = (double(StartTimeBin) + 0.5) * TimeUnit;
751  }
752  //MC
753  else {
754  int StartTimeBin;
755  // AMIGA ( First muon )
756  if (itype == 2) {
757  for (int itime = 0; itime < nTimeBins; itime++)
758  if (vemtrace[itime] > 0.) {
759  StartTimeBin = itime;
760  break;
761  }
762  }
763  // WCD/ASCII ( Signal over a window )
764  else {
765  for (int itime = 0; itime < nTimeBins - nWindow; itime++) {
766  if (vemtrace[itime] <= (0.1 / double(nWindow))) continue;
767  double vemWindow = 0.;
768  for (int it = itime; it < itime + nWindow; it++) vemWindow += vemtrace[it];
769  if (vemWindow > 0.1) {
770  StartTimeBin = itime;
771  break;
772  }
773  }
774  }
775  station.starttime = (double(StartTimeBin) + 0.5) * TimeUnit;
776  }
777 
778  //----Quantiles
779  if (hasTrace) {
780  station.quantile[0] = 0.01 * double(int(100. / station.signalsize));
781  if (station.quantile[0] < 0.01) station.quantile[0] = 0.01;
782  station.quantile[1] = 0.100;
783  station.quantile[2] = 0.500;
784  station.quantile[3] = 0.900;
785 
786  for (int iq = 0; iq < nQ; iq++) {
787  float tq, tq_err, signal = station.signalsize;
788  ToyUtilsNS::GetTQ(&vemtrace[start], signal, end - start, TimeUnit, station.quantile[iq], tq, tq_err);
789  station.tquantile[0][iq] = tq + double(start) * TimeUnit;
790  }
791  for (int iq = 0; iq < nQ; iq++)
792  if (station.signalsize < vemTimeCut[iq] || station.isSaturated) {
793  station.quantile[iq] = UNDEF;
794  station.tquantile[0][iq] = UNDEF;
795  station.tquantile[1][iq] = UNDEF;
796  }
797 
798  } else {
799  station.quantile[0] = UNDEF;
800  station.tquantile[0][0] = UNDEF;
801  station.tquantile[1][0] = UNDEF;
802  station.quantile[1] = UNDEF;
803  station.tquantile[0][1] = UNDEF;
804  station.tquantile[1][1] = UNDEF;
805  station.quantile[2] = UNDEF;
806  station.tquantile[0][2] = UNDEF;
807  station.tquantile[1][2] = UNDEF;
808  station.quantile[3] = UNDEF;
809  station.tquantile[0][3] = UNDEF;
810  station.tquantile[1][3] = UNDEF;
811  }
812  station.quantile[3] = UNDEF;
813  station.tquantile[0][3] = UNDEF; // Disable T90
814 
815  //----
816 
817  if (UseStartTimeOnlyWhenSaturated && station.isSaturated) station.mask_starttime = false;
818  if (!UseStartTimeOnlyWhenSaturated && station.signalsize > vemStartCut) station.mask_starttime = false;
819 
820  if (station.quantile[0] != UNDEF || station.quantile[1] != UNDEF || station.quantile[2] != UNDEF || station.quantile[3] != UNDEF)
821  station.mask_quantiles = false;
822 
823 
824  //----GPS Jitter
825  if (gRecMC) {
826  double GPSjitter = rnd->Gaus(0., InterGPSAccuracy[gRecSDE_Upgrade]);
827  station.GPSnano += GPSjitter;
828  }
829  //----
830 
831  if (IsTimeRec && !hasTrace) continue;
832  double vemCut = (!IsTimeRec ? vemSignalCut : vemTimeCut[2]);
833  if (itype == 0 && station.signalsize > vemCut) recinfo.nStationsWCD++;
834  if (itype == 1 && station.signalsize > vemCut) recinfo.nStationsScin++;
835  if (itype == 2 && station.signalsize > vemCut) recinfo.nStationsMD++;
836 
837  fstation.push_back(station);
838  } // Stations
839  nRecStations = fstation.size();
840 
841  printf("Number of stations loaded: %d (%d/%d/%d) (id=%d) | log(E_SD)=%5.2lf \n", nRecStations, recinfo.nStationsWCD, recinfo.nStationsScin, recinfo.nStationsMD
843 
844  const int nMin = (!IsTimeRec ? nSignalStationsMin : nTimeStationsMin);
845  bool okStations = (recinfo.nStationsWCD >= nMin);
846  if (!okStations) {
847  printf("Not processing: Number of stations loaded %d | WCD above threshold %d \n", nRecStations, recinfo.nStationsWCD);
848  return false;
849  }
850 
851  //-----------------------------------------------
852  // Set AMIGA/ASCII mask_signal according to WCD
853  //-----------------------------------------------
854  for (int idet_i = 0; idet_i < nRecStations; idet_i++) {
855  RecStation_t* st = &fstation[idet_i];
856  if (st->type == 0) continue;
857  st->mask_signal = false;
858 
859  int idet_wcd = UNDEF;
860  for (int idet_j = 0; idet_j < nRecStations; idet_j++)
861  if (fstation[idet_j].type == 0 && fstation[idet_j].id == st->id)
862  idet_wcd = idet_j;
863 
864  if (idet_wcd == UNDEF) continue;
865  st->mask_signal = fstation[idet_wcd].mask_signal;
866  }
867 
868  //-----------------------------------------------
869  // Hot station, Height of the core position (WCD)
870  //-----------------------------------------------
871 
872  double vemMax = -1.e10;
873  for (int idet = 0; idet < nRecStations; idet++)
874  if (fstation[idet].type == 0 && fstation[idet].signalsize > vemMax) {
875  vemMax = fstation[idet].signalsize;
876  recinfo.gDetHot = idet;
877  }
879 
880 
881  return true;
882 }
883 
884 #endif
885 
886 //-----------------------------------------------
887 //-----------------------------------------------
888 // Set initial values used in the reconstruction
889 //-----------------------------------------------
890 //-----------------------------------------------
891 
893 {
894  //-----------------------------------------------
895  // Set OffsetM_Mu
896  //-----------------------------------------------
897  recinfo.OffsetM_Mu = 0.;
898  for (int itype = 0; itype < 3; itype++)
899  ftime[itype]->SetOffsetM_Mu(recinfo.OffsetM_Mu);
900 
901  //-----------------------------------------------
902  //--(Xmax,Nmu)
903  //-----------------------------------------------
904  recinfo.Xmax = 750.;
905  recinfo.Nmu = 2.;
906 
907  //-----------------------------------------------
908  // (theta,azi,core)
909  //-----------------------------------------------
910 
911  //-- SD Auger standard reconstructions
912 #ifdef ExternalUse
918 #else
919  //-- Own estimation ( needed for Bariloche MC )
920  if (!GetRecEstimate(0)) return false;
921  if (std::isnan(recinfo.theta)) return false;
922 #endif
923 
924  //-- Hybrid direction is use in all reconstruction stages
925  if (IsGoldenRec) {
928  }
929 
930  //-----------------------------------------------
931  //--Xmax ranges
932  //-----------------------------------------------
933  XmaxLow = (gRecType == 6 ? 200. : 400.);
934  XmaxHigh = 875. / cos(recinfo.theta) + 200.;
935 
936  //-----------------------------------------------
937  //--Energy
938  //-----------------------------------------------
939  double E_sum = 0., w = 0.;
940  int n_sum = 0;
941  for (int idet = 0; idet < nRecStations; idet++) {
942  RecStation_t* station = &fstation[idet];
943  if (station->type != 0) continue;
944  if (station->isSaturated) continue;
945  if (station->signalsize < vemSignalCut) continue;
946 
947  SetSPCoordinates(idet);
948  if (station->r < 600.e2 || station->r > 2500.e2) continue;
949 
950  int iatm = fatm->GetCurrentAtmosphereMonth();
951  double logEi = fsignal[0]->GetLogE(station->signalsize, station->r, recinfo.Xmax, recinfo.theta, station->psi, station->density, station->zg, recinfo.Nmu, iatm);
952  if (logEi < 18. || logEi > 20.5) continue;
953 
954  double wi = 1. / station->signalsize;
955  E_sum += (pow(10., logEi) * wi);
956  w += wi;
957  n_sum++;
958  }
959  if (n_sum > 0) recinfo.logE = log10(E_sum / w);
960  else recinfo.logE = 18.5;
961 
962 
963  recinfo.theDir_Ref.SetMagThetaPhi(1., recinfo.theta, recinfo.azi);
964 
965  //-----------------------------------------------
966  //T0
967  //-----------------------------------------------
968  SetT0FromHot(false, UNDEF);
969 
970  return true;
971 }
972 
973 //---------------------------------------------------
974 //---------------------------------------------------
975 // Shower plane coordinates
976 //---------------------------------------------------
977 //---------------------------------------------------
978 
979 float UnivRec::DistPoints(float x1, float y1, float x2, float y2)
980 {
981  return sqrtf((x2 - x1) * (x2 - x1) + (y2 - y1) * (y2 - y1));
982 }
983 
984 
985 float UnivRec::NormalizeAngle(const float angle)
986 {
987  if (angle > 2 * M_PI)
988  return angle - int(angle / 2 / M_PI) * 2 * M_PI;
989  if (angle < 0.)
990  return 2 * M_PI + angle + int(-angle / 2 / M_PI) * 2 * M_PI;
991  return angle;
992 }
993 
995 {
996  RecStation_t* station = &fstation[idet];
997 
998  //----Shower plane coordinates
999 
1000  double xg0 = station->xg - recinfo.xgcore;
1001  double yg0 = station->yg - recinfo.ygcore;
1002  double zg0 = station->zg - recinfo.zgcore;
1003 
1004  double costheta = cos(recinfo.theta);
1005  double sintheta = sin(recinfo.theta);
1006  double cosazi = cos(recinfo.azi);
1007  double sinazi = sin(recinfo.azi);
1008 
1009  double xr = xg0 * cosazi + yg0 * sinazi;
1010  double yr = -xg0 * sinazi + yg0 * cosazi;
1011  double zr = zg0;
1012 
1013  station->r = sqrt((-xr * costheta + zr * sintheta) * (-xr * costheta + zr * sintheta) + yr * yr);
1014  station->psi = NormalizeAngle(atan2(yr, xr * costheta - zr * sintheta));
1015 
1016  //----(DX.DL,T0_CF,T0_PF)
1017  station->T0_PF = fatm->GetTimePF_h(station->r, station->psi, recinfo.zgcore, recinfo.theta, station->zg);
1018  for (int icomp = 0; icomp < 4; icomp++) {
1019 
1020  double Xsignal = recinfo.Xmax + UnivParamNS::XmaxShift[icomp];
1021  double Xtime = recinfo.Xmax + UnivParamTimeNS::XmaxShift_time[icomp];
1022 
1023  station->DX[icomp] = fatm->Get_DX_DL(station->r, station->psi, Xsignal , recinfo.theta, station->zg,
1025  station->DL[icomp] = fatm->Get_DX_DL(station->r, station->psi, Xtime , recinfo.theta, station->zg,
1027 
1028 
1029  double D_TO = ftime[station->type]->GetD_TO(recinfo.Xmax, recinfo.theta, recinfo.logE, icomp);
1030  double h1 = fatm->SlantDepthToHeight(recinfo.Xmax, recinfo.theta) + D_TO * 1.e5 * cos(recinfo.theta);
1031  station->T0_CF[icomp] = fatm->GetTimeCF_h(station->r, station->psi, h1, recinfo.theta, station->zg) ;
1032  }
1033  //--- Density at height of station
1034  station->density = (gRecMC ? fatm->GetDensity(station->zg) : recinfo.AugerDensity);
1035 
1036 
1037 }
1038 
1040 {
1041  for (int idet = 0; idet < nRecStations; idet++)
1042  SetSPCoordinates(idet);
1043 }
1044 
1045 //---------------------------------------------------
1046 //---------------------------------------------------
1047 // Rec estimate (Only used if Auger Rec standard reconstruction parameters are not used as seed )
1048 //---------------------------------------------------
1049 //---------------------------------------------------
1050 
1052 {
1053  GetRecSeed(itype);
1054 
1055  //Set Rec core as the barycenter
1056  recinfo.xgcore = 0.;
1057  recinfo.ygcore = 0.;
1058 
1059  float vemsqrt = 0.;
1060  for (int idet = 0; idet < nRecStations; idet++) {
1061  RecStation_t* station = &fstation[idet];
1062  if (station->type != itype) continue;
1063 
1064  recinfo.xgcore += (station->xg * sqrt(station->signalsize));
1065  recinfo.ygcore += (station->yg * sqrt(station->signalsize));
1066  vemsqrt += sqrt(station->signalsize);
1067  }
1068 
1069  if (vemsqrt == 0.) return false;
1070  recinfo.xgcore /= vemsqrt;
1071  recinfo.ygcore /= vemsqrt;
1072 
1073 
1074  //Set Rec direction using Plane fit
1075  if (!PlaneFit(false, false, true, itype)) return false;
1076 
1077  float theta_prev = recinfo.theta;
1078  int nIter = 0;
1079  while (true) {
1081  if (!PlaneFit(true, true, true, itype)) {
1082  PlaneFit(false, false, true, itype);
1084  return true;
1085  }
1086  if (fabs(theta_prev - recinfo.theta) < 0.1 * M_PI / 180.) break;
1087  theta_prev = recinfo.theta;
1088  nIter++;
1089  if (nIter > 10) break;
1090  }
1091  return true;
1092 }
1093 
1094 
1095 bool UnivRec::PlaneFit(bool CurvCorr, bool AltitudeCorr, bool RecSeed, int itype)
1096 {
1097  std::vector<double> fX, fY, fT, fW;
1098  float speedC = AtmosphereNS::c_cmperns;
1099 
1100  //----
1101  int nSel = 0;
1102  for (int idet = 0; idet < nRecStations; idet++) {
1103  RecStation_t* station = &fstation[idet];
1104  if (station->type != itype) continue;
1105  if (RecSeed && !(idet == recinfo.seed[0] || idet == recinfo.seed[1] || idet == recinfo.seed[2])) continue;
1106  if (station->signalsize > vemSignalCut) nSel++;
1107  }
1108  if (nSel < 3) return false;
1109  //-----
1110  for (int idet = 0; idet < nRecStations; idet++) {
1111  RecStation_t* station = &fstation[idet];
1112  if (station->type != itype) continue;
1113  if (station->signalsize <= vemSignalCut) continue;
1114  if (RecSeed && !(idet == recinfo.seed[0] || idet == recinfo.seed[1] || idet == recinfo.seed[2]))
1115  continue;
1116 
1117  float tstation = station->GPSnano + station->starttime;
1118  float t50 = station->tquantile[0][2] - station->starttime;
1119  float theta = (recinfo.theta == 0. ? 38.*M_PI / 180. : recinfo.theta); //If iterating
1120  float nMuons = station->signalsize / (cos(theta) + 2.*tankh * sin(theta) / M_PI / tankr);
1121  if (nMuons < 2) continue;
1122  float TimeVariance2 = 134 + 2.4 * pow((t50 + 10.) / (nMuons + 1), 2) * nMuons / (nMuons + 2);
1123 
1124  float tcorr = 0.;
1125  if (AltitudeCorr) //Above ground-> Positive corr
1126  tcorr = (station->zg - recinfo.zgcore) * cos(recinfo.theta) / speedC;
1127  if (CurvCorr) { //Negative correction
1128  float R = (1. - cos(recinfo.theta)) * 34 + 8.; //km ( theta=0. 8 km, theta=60 25 km)
1129  R *= 1.e5; //cm
1130  float tcurv = station->r * station->r / speedC / 2 / R;
1131  tcorr -= tcurv;
1132  }
1133  tstation += tcorr;
1134 
1135  fW.push_back(1. / TimeVariance2);
1136  fX.push_back(station->xg);
1137  fY.push_back(station->yg);
1138  fT.push_back(tstation);
1139  }
1140  if (fX.size() < 3) return false;
1141  if (!PlaneFit(fX, fY, fT, fW)) return false;
1142  return true;
1143 }
1144 
1145 bool UnivRec::PlaneFit(std::vector<double> fX, std::vector<double>fY, std::vector<double>fT, std::vector<double>fW)
1146 {
1147  if (fX.size() == 0.) return false;
1148 
1149  double speedC = AtmosphereNS::c_cmperns;
1150 
1151  //---Use the weighted time center as the origin of coordinates, so T0=0
1152  double fX0 = 0., fY0 = 0., fT0 = 0.;
1153  double WSum = 0.;
1154  for (unsigned int i = 0; i < fX.size(); i++) {
1155  WSum += (fW[i]);
1156  fX0 += (fX[i] * fW[i]);
1157  fY0 += (fY[i] * fW[i]);
1158  fT0 += (fT[i] * fW[i]);
1159  }
1160  //printf("\n");
1161  for (unsigned int i = 0; i < fX.size(); i++) {
1162  fX[i] = (fX[i] - fX0 / WSum);
1163  fY[i] = (fY[i] - fY0 / WSum);
1164  fT[i] = (fT[i] - fT0 / WSum);
1165  }
1166  //------------------
1167 
1168  float Det, Det1, Det2;
1169  float b[2][2], c[2];
1170  float l, m, lerr, merr, lmerr;
1171 
1172  //----Calculates the matrix of the linear system--------------------------------
1173  b[0][0] = 0.;
1174  b[0][1] = 0.;
1175  b[1][0] = 0.;
1176  b[1][1] = 0.;
1177  c[0] = 0.;
1178  c[1] = 0.;
1179 
1180  for (unsigned int i = 0; i < fX.size(); i++) {
1181  b[0][0] += fX[i] * fX[i] * fW[i];
1182  b[0][1] += fX[i] * fY[i] * fW[i];
1183  b[1][1] += fY[i] * fY[i] * fW[i];
1184 
1185  c[0] -= (fT[i] * speedC * fX[i] * fW[i]);
1186  c[1] -= (fT[i] * speedC * fY[i] * fW[i]);
1187  }
1188  b[1][0] = b[0][1];
1189 
1190  //---Calculates the solution of the linear system using Cramer determinants-----
1191  Det = b[1][1] * b[0][0] - b[0][1] * b[1][0];
1192  Det1 = c[0] * b[1][1] - b[1][0] * c[1];
1193  Det2 = c[1] * b[0][0] - b[1][0] * c[0];
1194  l = Det1 / Det;
1195  m = Det2 / Det;
1196 
1197  float lm2;
1198  lm2 = l * l + m * m;
1199 
1200  if (lm2 > 1. || l == 0.) return false;
1201 
1202  //---Calculates the inverse of the matrix, i.e. the variance matrix-------------
1203  float deter = 0;
1204  deter = b[0][0] * b[1][1] * WSum - b[0][1] * b[1][0] * WSum;
1205 
1206  lerr = (speedC * speedC) * WSum * b[1][1] / deter;
1207  merr = (speedC * speedC) * WSum * b[0][0] / deter;
1208  lmerr = (speedC * speedC) * WSum * b[0][1] / deter;
1209 
1210  //---Calculates the angles---------------------------------------------------------
1211  float theta = asin(sqrt(l * l + m * m));
1212  float azi = atan2(m, l);
1213  float theta_err, azi_err;
1214 
1215  theta_err = cos(azi) * cos(azi) * lerr + sin(azi) * sin(azi) * merr + 2 * cos(azi) * sin(azi) * lmerr;
1216  if (theta_err > 0) theta_err = sqrt(theta_err) / cos(theta);
1217  azi_err = cos(azi) * cos(azi) * merr + sin(azi) * sin(azi) * lerr - 2 * cos(azi) * sin(azi) * lmerr ;
1218  if (azi_err > 0) azi_err = sqrt(azi_err) / sin(theta);
1219 
1220  //---Set reconstruction
1221  recinfo.theta = theta;
1222  recinfo.azi = NormalizeAngle(azi);
1223 
1224  return true;
1225 };
1226 
1227 void UnivRec::GetRecSeed(int itype)
1228 {
1229  // The triangle with the larges sum of the signal
1230 
1231  float minDistance = (!gRecInfill ? 1200.e2 : 700.e2);
1232  float maxDistance = (!gRecInfill ? 1700.e2 : 800.e2);
1233  float SizeMax = 0.;
1234 
1235  for (int i = 0; i < nRecStations; i++) {
1236  if (fstation[i].type != itype) continue;
1237  for (int j = (i + 1); j < nRecStations; j++) {
1238  if (fstation[j].type != itype) continue;
1239 
1240  float dij = DistPoints(fstation[i].xg, fstation[i].yg, fstation[j].xg, fstation[j].yg);
1241  if (dij > maxDistance || dij < minDistance) continue;
1242 
1243  for (int k = 0; k < nRecStations; k++) {
1244  if (k == i || k == j) continue;
1245  if (fstation[k].type != itype) continue;
1246 
1247  float dik = DistPoints(fstation[i].xg, fstation[i].yg, fstation[k].xg, fstation[k].yg);
1248  if (dik > maxDistance || dik < minDistance) continue;
1249  float djk = DistPoints(fstation[j].xg, fstation[j].yg, fstation[k].xg, fstation[k].yg);
1250  if (djk > maxDistance || djk < minDistance) continue;
1251 
1252  float Size = fstation[i].signalsize + fstation[j].signalsize + fstation[k].signalsize;
1253  if (Size > SizeMax) {
1254  SizeMax = Size;
1255  recinfo.seed[0] = i;
1256  recinfo.seed[1] = j;
1257  recinfo.seed[2] = k;
1258  }
1259  }//k
1260  }// j
1261  }// i
1262 
1263 }
1264 
1265 //---------------------------------------------------
1266 //---------------------------------------------------
1267 // Utilities
1268 //---------------------------------------------------
1269 //---------------------------------------------------
1270 
1271 
1272 void UnivRec::PrintRecInfo(bool PrintResiduals)
1273 {
1274  // Print debug info
1275  printf("\n");
1276  printf("---------------------------------------\n");
1277  printf(" Fit results ( FitStage = %d ) \n", recinfo.FitStage);
1278  printf("---------------------------------------\n");
1279 
1280  printf("Id=%d \n", recinfo.id);
1281  printf("theta=%5.2lf (%5.2lf) azi=%5.2lf (%5.2lf) (x,y,z)=(%5.2lf,%5.2lf,%5.2lf) (%5.2lf,%5.2lf,%5.2lf) sigma_x,sigma_y=(%5.2lf,%5.2lf) \n",
1282  recinfo.theta * 180 / M_PI, (gRecMC ? MCinfo.theta : augerinfo.theta_FD) * 180. / M_PI ,
1283  recinfo.azi * 180 / M_PI, (gRecMC ? MCinfo.azi : augerinfo.azi_FD) * 180. / M_PI ,
1284  recinfo.xgcore / 1.e2, recinfo.ygcore / 1.e2, recinfo.zgcore / 1.e2,
1286  recinfo.xgcore_err / 1.e2, recinfo.ygcore_err / 1.e2);
1287 
1288  printf("logE=%5.2lf +-%5.2lf (%5.2lf), Nmu=%5.2lf+-%5.2lf (%5.2lf) Xmax=%5.2lf +- %5.2lf (%5.2lf) \n",
1292  printf(" OffsetM_Mu=%5.2lf %5.2lf \n", recinfo.OffsetM_Mu, recinfo.OffsetM_Mu_err);
1293  printf(" T0=%5.2lf+-%5.2lf (%5.2lf) \n" , recinfo.T0, recinfo.T0_err, MCinfo.T0);
1294 
1295  printf("\n");
1296  printf(" logE_ref=%5.2lf +-%5.2lf \n", recinfo.logE_ref, recinfo.logE_ref_err);
1297  printf("\n");
1298  printf(" logE_SD=%5.2lf theta_SD=%5.2lf azi_SD=%5.2lf \n", augerinfo.logE_SD, augerinfo.theta_SD * 180. / M_PI, augerinfo.azi_SD * 180. / M_PI);
1299  printf(" logE_FD=%5.2lf Xmax_FD=%5.2lf theta_FD=%5.2lf azi_FD=%5.2lf \n", augerinfo.logE_FD, augerinfo.Xmax_FD, augerinfo.theta_FD * 180. / M_PI, augerinfo.azi_FD * 180. / M_PI);
1300 
1301  printf("\n");
1302 
1303  printf(" lnP=%5.2lf/%5.2lf/%5.2lf (%5.2lf) \n", recinfo.lnP[0], recinfo.lnP[1], recinfo.lnP[2],
1304  recinfo.lnP[0] + recinfo.lnP[1] + recinfo.lnP[2]);
1305  printf(" FitStatus=%d/%d nFCNcalls=%d Min EigenVal=%5.2lf EDM=%5.2lf IsTimeRec=%d \n", recinfo.FitStatus[0], recinfo.FitStatus[1], recinfo.nFCNcalls,
1307  if (recinfo.FitStage > 0) printf(" TimeRejected=%d (%lf) | TimeMaxDev=%d (%lf) \n", int(recinfo.TimeRejected[1]), recinfo.TimeRejected[0], int(recinfo.TimeMaxdev[1]), recinfo.TimeMaxdev[0]);
1308  else printf("\n");
1309  printf(" AllTimesOK= %d \n", recinfo.AllTimesOK);
1310  printf(" gDetHot=%d r=%5.2lf [m]\n", recinfo.gDetHot, recinfo.rHot / 1.e2);
1311  if (!gRecMC) printf(" Density %lf [g]/[cm3] \n", recinfo.AugerDensity);
1312  printf(" month=%d \n", recinfo.iatm);
1313 
1314  printf("nSignalStations=%d nTimeStations=%d \n", recinfo.nSignalStations, recinfo.nTimeStations);
1315 
1316  // Print residuals
1317  if (PrintResiduals) {
1318  for (int iloop = 0; iloop < 2; iloop++) {
1319  if (iloop == 0) printf("Signal likelihood \n");
1320  else printf("Time likelihood \n");
1321  printf("--------------------------\n");
1322 
1323  for (int idet = 0; idet < nRecStations; idet++) {
1324  RecStation* st = &fstation[idet];
1325  if (iloop == 0 && st->mask_signal) continue;
1326  if (iloop == 1 && recinfo.FitStage < 1) continue;
1327  if (iloop == 1 && st->mask_quantiles && st->mask_starttime) continue;
1328  printf("idet=%d (%d) %d | %4.0lf %4.0lf %4.0lf %4.0lf %d %d ", idet, (st->id), st->type, st->r / 1.e2, st->psi * 180. / M_PI,
1329  st->DX[0], st->DX[1], st->isSaturated, st->mask_signal);
1330 
1331  if (iloop == 0)
1332  printf(" | Rec=%5.0lf Pred=%5.0lf RMS=%5.0lf lnP=%5.2lf \n", st->signalsize, st->signalsize_pred, st->signalsize_rms, st->lnP_signal);
1333  else {
1334  printf(" %4.0lf %4.2lf| t0_cf=%3.0lf | %d %d St= %4.0lf (%4.0lf %4.0lf)| %d %d%d%d T1= %4.0lf (%4.0lf %4.0lf) T10=%4.0lf (%4.0lf %4.0lf) T50=%4.0lf (%4.0lf %4.0lf) | lnP=%3.1lf %3.1lf \n",
1335  st->signalsize, st->AreaOverPeak, st->T0_CF[0],
1337  st->start_rec + st->start_corr, st->start_pred + st->start_corr, st->start_rms,
1339  st->tq_rec[0] + st->tq_corr[0], st->tq_pred[0] + st->tq_corr[0], st->tq_rms[0],
1340  st->tq_rec[1] + st->tq_corr[1], st->tq_pred[1] + st->tq_corr[1], st->tq_rms[1],
1341  st->tq_rec[2] + st->tq_corr[2], st->tq_pred[2] + st->tq_corr[2], st->tq_rms[2],
1342  st->lnP_start, st->lnP_quantiles);
1343  }
1344  }
1345  }// Signal/Time
1346  }
1347 }
1348 
1349 #ifndef ExternalUse
1350 void UnivRec::WriteTextFile(FILE* fp)
1351 {
1352  // Print short summary to a file
1353 
1354  TVector3 theDir0, theDir;
1355  theDir0.SetMagThetaPhi(1., (gRecMC ? MCinfo.theta : augerinfo.theta_FD), (gRecMC ? MCinfo.azi : augerinfo.azi_FD));
1356  theDir.SetMagThetaPhi(1., recinfo.theta, recinfo.azi);
1357 
1358  bool okRec = IsGoodRec();
1359 
1360  double Chi2[2] = {0., 0.};
1361  int nChi2[2] = {0, 0};
1362  if (okRec) GetChi2(Chi2, nChi2);
1363 
1364 
1365  unsigned int GPSnano = 0;
1366  utl::TimeStamp time_stamp(GPSsec, GPSnano);
1367  unsigned int month = (!gRecMC ? time_stamp.GetMonth() : recinfo.iatm);
1368  unsigned int year = (!gRecMC ? time_stamp.GetYear() : UNDEF);
1369 
1370 
1371  fprintf(fp, "%d %d %d %d %d %d %lf %lf %lf %lf %lf %lf %lf %lf %lf %lf %lf %lf %lf %d %d %lf %lf %d %lf %lf %lf %lf %lf %lf %lf %lf %lf %lf %lf %lf %d %lf %d %lf %lf %d %d %d %d %lf %lf %d %d %d %lf %lf \n",
1377  recinfo.OffsetM_Mu, okRec, month ,
1381  recinfo.azi, MCinfo.azi,
1382  theDir0.Angle(theDir),
1384  recinfo.lnP[0], recinfo.FitStatus[0],
1385  recinfo.lnP[1], recinfo.FitStatus[1],
1386  Chi2[0], Chi2[1],
1387  nChi2[0], nChi2[1],
1392 }
1393 #endif
1394 bool UnivRec::RWRecinfo(FILE* fp, bool WriteStations, bool readFlag)
1395 {
1396  if (fp == NULL) return false;
1397  if (readFlag && feof(fp)) return false;
1398 
1399  if (!readFlag) {
1400  fwrite(&gRecType, 1, sizeof(int), fp);
1401  fwrite(&gRecMC, 1, sizeof(bool), fp);
1402  fwrite(&gRecInfill, 1, sizeof(bool), fp);
1403  fwrite(&gRecSDE_Upgrade, 1, sizeof(bool), fp);
1404  fwrite(&gRecAoP, 1, sizeof(int), fp);
1405  int DataSet_Sys = (gRecMC ? UNDEF : gRecDataSet + gRecSys * 10);
1406  fwrite(&DataSet_Sys, 1, sizeof(int), fp);
1407  fwrite(&gRecMixture, 1, sizeof(int), fp);
1408  fwrite(&gCalibOpt, 1, sizeof(int), fp);
1409  for (int itype = 0; itype < 3; itype++)
1410  fwrite(&gDetectorTypeMask[itype], 1, sizeof(bool), fp);
1411 
1412  fwrite(&recinfo, 1, sizeof(RecInfo_t), fp);
1413  fwrite(&MCinfo, 1, sizeof(MCInfo_t), fp);
1414  fwrite(&augerinfo, 1, sizeof(AugerRecInfo_t), fp);
1415  if (!gRecMC) fwrite(&GPSsec, 1, sizeof(unsigned int), fp);
1416 
1417  int nDet = 0;
1418  if (!WriteStations)
1419  fwrite(&nDet, 1, sizeof(int), fp);
1420  else {
1421  for (int idet = 0; idet < nRecStations; idet++)
1422  if (fstation[idet].signalsize > 0.) nDet++;
1423  fwrite(&nDet, 1, sizeof(int), fp);
1424  for (int idet = 0; idet < nRecStations; idet++)
1425  if (fstation[idet].signalsize > 0.)
1426  fwrite(&fstation[idet], 1, sizeof(RecStation_t), fp);
1427  }
1428  } else {
1429  [[maybe_unused]]int nread = 0; // unused. LN.
1430  nread += fread(&gRecType, 1, sizeof(int), fp);
1431  IsGoldenRec = (gRecType == 0 || gRecType == 7);
1432  if (feof(fp)) return false;
1433  nread += fread(&gRecMC, 1, sizeof(bool), fp);
1434  nread += fread(&gRecInfill, 1, sizeof(bool), fp);
1435  nread += fread(&gRecSDE_Upgrade, 1, sizeof(bool), fp);
1436  nread += fread(&gRecAoP, 1, sizeof(int), fp);
1437  int DataSet_Sys;
1438  nread += fread(&DataSet_Sys, 1, sizeof(int), fp);
1439  gRecDataSet = (gRecMC ? UNDEF : DataSet_Sys % 10);
1440  gRecSys = (gRecMC ? 0 : DataSet_Sys / 10);
1441  if (!gRecMC && (gRecDataSet < 0 || gRecDataSet > 3 || gRecSys < 0 || gRecSys > UnivCalibConstantsNS::nSys))
1442  return false;
1443 
1444  nread += fread(&gRecMixture, 1, sizeof(int), fp);
1445  nread += fread(&gCalibOpt, 1, sizeof(int), fp);
1446 
1447  for (int itype = 0; itype < 3; itype++)
1448  nread += fread(&gDetectorTypeMask[itype], 1, sizeof(bool), fp);
1449 
1450  nread += fread(&recinfo, sizeof(RecInfo_t), 1, fp);
1451  nread += fread(&MCinfo, sizeof(MCInfo_t), 1, fp);
1452  nread += fread(&augerinfo, sizeof(AugerRecInfo_t), 1, fp);
1453  if (!gRecMC) nread += fread(&GPSsec, sizeof(unsigned int), 1, fp);
1454 
1455  nRecStations = 0;
1456  nread += fread(&nRecStations, sizeof(int), 1, fp);
1457  if (feof(fp)) return false;
1458  fstation.clear();
1459 
1460  if (nRecStations > 0) {
1461  for (int idet = 0; idet < nRecStations; idet++) {
1462  RecStation_t station;
1463  nread += fread(&station, 1, sizeof(RecStation_t), fp);
1464  fstation.push_back(station);
1465  }
1466  }
1467 
1468  //---
1469  IsTimeRec = (gRecType == 1 || gRecType == 4 || gRecType == 5 || gRecType == 6 || gRecType == 7 || gRecType == 8 ? true : false);
1470 
1471  if (fcalib != NULL) delete fcalib;
1473 
1476 
1477  double vemMax = -1.e10;
1478  for (int idet = 0; idet < nRecStations; idet++)
1479  if (fstation[idet].type == 0 && fstation[idet].signalsize > vemMax) {
1480  vemMax = fstation[idet].signalsize;
1481  recinfo.gDetHot = idet;
1482  }
1483 
1484  //----
1485  }
1486  return true;
1487 }
1488 
1489 void UnivRec::GetChi2(double* Chi2, int* nChi2)
1490 {
1491  for (int i = 0; i < 2; i++) {
1492  Chi2[i] = 0.;
1493  nChi2[i] = 0;
1494  }
1495  for (int idet = 0; idet < nRecStations; idet++) {
1496  RecStation_t* st = &fstation[idet];
1497  if (!st->mask_signal && !st->isSaturated) {
1498  Chi2[0] += pow((st->signalsize_pred - st->signalsize) / st->signalsize_rms, 2.);
1499  nChi2[0] += 1;
1500  }
1501 
1502  if (!st->mask_starttime && st->start_pred != 0. && st->start_rec != 0. && st->start_rms != 0.) {
1503  Chi2[1] += pow((st->start_pred - st->start_rec) / st->start_rms, 2.);
1504  nChi2[1] += 1;
1505  }
1506 
1507 
1508  if (!st->mask_quantiles) {
1509  for (int iq = 0; iq < nQ; iq++) {
1510  if (st->quantile[iq] == UNDEF) continue;
1511  if (st->tq_rms[iq] == 0. || st->tq_pred[iq] == 0. || st->tq_rec[iq] == 0.) continue;
1512  Chi2[1] += pow((st->tq_pred[iq] - st->tq_rec[iq]) / st->tq_rms[iq], 2.);
1513  nChi2[1] += 1;
1514  }
1515  }
1516  }
1517 }
1518 
1519 
1520 void UnivRec::GetResiduals(std::vector<double>& mean, std::vector<double>& rms, std::vector<double>& rec, int optY, std::vector<double>& fx, int optX)
1521 {
1522  GetResiduals(mean, rms, rec, optY, fx, optX, false);
1523 }
1524 
1525 void UnivRec::GetResiduals(std::vector<double>& mean, std::vector<double>& rms, std::vector<double>& rec, int optY, std::vector<double>& fx, int optX , bool OnlyNotSaturated)
1526 {
1527  // opt=0,1,2,3,4 Signal/Start time/T1/T10/T50
1528  if (optY < 0 || optY > 4) return;
1529  if (optX < 0 || optX > 2) return;
1530  mean.clear();
1531  rms.clear();
1532  rec.clear();
1533  fx.clear();
1534 
1535  for (int idet = 0; idet < nRecStations; idet++) {
1536  RecStation_t* st = &fstation[idet];
1537 
1538 
1539  if (OnlyNotSaturated && st->isSaturated) continue;
1540  if (optY == 0 && (st->mask_signal || st->isSaturated)) continue;
1541  if (optY == 1 && st->mask_starttime) continue;
1542  if (optY > 1 && (st->mask_quantiles || st->quantile[optY - 2] == UNDEF)) continue;
1543 
1544  double x_i;
1545  if (optX == 0) x_i = st->r;
1546  else if (optX == 1) x_i = st->AreaOverPeak;
1547 
1548 
1549  if (optY == 0) {
1550  mean.push_back(st->signalsize_pred);
1551  rms.push_back(st->signalsize_rms);
1552  rec.push_back(st->signalsize);
1553  fx.push_back(x_i);
1554  } else if (optY == 1) {
1555  mean.push_back(st->start_pred);
1556  rms.push_back(st->start_rms);
1557  rec.push_back(st->start_rec);
1558  fx.push_back(x_i);
1559  } else {
1560  mean.push_back(st->tq_pred[optY - 2]);
1561  rms.push_back(st->tq_rms[optY - 2]);
1562  rec.push_back(st->tq_rec[optY - 2]);
1563  fx.push_back(x_i);
1564  }
1565  }
1566 }
1567 
1568 void UnivRec::GetMeanRMS_AoP(double& mean, double& rms)
1569 {
1570  mean = 0.;
1571  rms = 0.;
1572  double nStations = 0.;
1573  for (int idet = 0; idet < nRecStations; idet++) {
1574  RecStation_t* st = &fstation[idet];
1575  if (st->mask_quantiles) continue;
1576 
1577  mean += (st->AreaOverPeak);
1578  rms += pow(st->AreaOverPeak, 2.);
1579  nStations += 1.;
1580  }
1581  if (nStations < 2) {
1582  mean = 0.;
1583  rms = 0.;
1584  return;
1585  }
1586  mean /= nStations;
1587  rms = sqrt(nStations / (nStations - 1) * (rms / nStations - mean * mean));
1588 }
1589 
1590 bool UnivRec::ScanRange(int iparX, int iparY, std::vector<double> par, std::vector<int> parStatus, double* rangeX, double* rangeY, double* d, double RotAngle, double errDef, double& edm)
1591 {
1592  double InitStep = 2.0;
1593  return ScanRange(iparX, iparY, par, parStatus, rangeX, rangeY, d, RotAngle, errDef, InitStep, edm);
1594 }
1595 
1596 bool UnivRec::ScanRange(int iparX, int iparY, std::vector<double> par, std::vector<int> parStatus, double* rangeX, double* rangeY, double* d, double RotAngle, double errDef, double InitStep, double& edm)
1597 {
1598  // Note: iside refers to positive increment after the coordinates are rotated.
1599 
1600  std::vector<bool> isFixed;
1601  for (unsigned int ipar = 0; ipar < par.size(); ipar++)
1602  isFixed.push_back(parStatus[ipar] < 2 ? false : true);
1603 
1604  edm = 0.;
1605  bool okX = (iparX >= 0 && iparX < int(par.size()));
1606  bool okY = (iparY >= 0 && iparY < int(par.size()));
1607  if (okX) okX = !isFixed[iparX];
1608  if (okY) okY = !isFixed[iparY];
1609  if (!okX && !okY) return false;
1610 
1611  if (okX && okY && iparX == iparY) okY = false;
1612  if (!okX) RotAngle = M_PI / 2.;
1613  if (!okY) RotAngle = 0.;
1614 
1615  const int niter_max = (InitStep < 1. ? 500 : 100);
1616 
1617  double lnP_max = GetLikelihood(par, parStatus);
1618  double val_max[2] = { (okX ? par[iparX] : UNDEF) , (okY ? par[iparY] : UNDEF) };
1619  bool ok_range = true;
1620 
1621  double lowX = UNDEF, highX = UNDEF;
1622  if (okX) {
1623  lowX = low[iparX] / unit[iparX];
1624  highX = high[iparX] / unit[iparX];
1625  if (iparX == 4) {
1626  lowX = XmaxLow / unit[iparX];
1627  highX = XmaxHigh / unit[iparX];
1628  }
1629  if (iparX == 5) {
1630  lowX = (val_max[0] + lowX);
1631  highX = (val_max[0] + highX);
1632  }
1633  }
1634  double lowY = UNDEF, highY = UNDEF;
1635  if (okY) {
1636  lowY = low[iparY] / unit[iparY];
1637  highY = high[iparY] / unit[iparY];
1638  if (iparY == 4) {
1639  lowY = XmaxLow / unit[iparY];
1640  highY = XmaxHigh / unit[iparY];
1641  }
1642  if (iparY == 5) {
1643  lowY = (val_max[1] + lowY);
1644  highY = (val_max[1] + highY);
1645  }
1646  }
1647 
1648  for (int iside = 0; iside < 2; iside++) {
1649  double sign = (iside == 0 ? -1. : 1.);
1650  double t_iter = 0., lnP_iter = 0., step = InitStep;
1651  int niter = 0;
1652 
1653  while (true) {
1654  t_iter += (sign * step);
1655  if (okX) par[iparX] = val_max[0] + cos(RotAngle) * t_iter;
1656  if (okY) par[iparY] = val_max[1] + sin(RotAngle) * t_iter;
1657  lnP_iter = GetLikelihood(par, parStatus);
1658 
1659  if (UnivRecNS::debug > 1) {
1660  printf(" ipar=(%d,%d) iside=%d iter=%d t=%5.4lf step=%5.4lf lnP=%lf (%lf %lf) ", iparX, iparY, iside, niter, t_iter, step, lnP_iter, lnP_max, errDef);
1661  if (okX) printf(" parX=%lf (%lf) ", par[iparX]*unit[iparX], val_max[0]*unit[iparX]);
1662  if (okY) printf(" parY=%lf (%lf) ", par[iparY]*unit[iparY], val_max[0]*unit[iparY]);
1663  printf("\n");
1664  }
1665 
1666  //----------
1667  if (lnP_iter > lnP_max) edm = lnP_iter - lnP_max;
1668 
1669  //----------
1670  if ((okX && (par[iparX] < lowX || par[iparX] > highX)) ||
1671  (okY && (par[iparY] < lowY || par[iparY] > highY)) || niter > niter_max) {
1672  ok_range = false;
1673  break;
1674  }
1675 
1676  //----------
1677  if (lnP_iter < (lnP_max - errDef)) {
1678  if ((lnP_max - errDef) - lnP_iter < 0.01) break;
1679  else {
1680  t_iter -= (sign * step);
1681  step /= 2.;
1682  }
1683  }
1684  //----------
1685  niter++;
1686  }
1687 
1688  if (!ok_range) break;
1689 
1690  //--Interpolate
1691 
1692  double t_i[2] = { t_iter - sign * step , t_iter };
1693  double lnP_i[2] = { 0., lnP_iter};
1694 
1695  if (okX) par[iparX] = val_max[0] + cos(RotAngle) * t_i[0];
1696  if (okY) par[iparY] = val_max[1] + sin(RotAngle) * t_i[0];
1697 
1698  lnP_i[0] = GetLikelihood(par, parStatus);
1699 
1700  double t = (t_i[1] - t_i[0]) * (lnP_max - errDef - lnP_i[0]) / (lnP_i[1] - lnP_i[0]) + t_i[0];
1701  if (okX) rangeX[iside] = val_max[0] + cos(RotAngle) * t;
1702  if (okY) rangeY[iside] = val_max[1] + sin(RotAngle) * t;
1703  d[iside] = t;
1704 
1705  //--
1706  if (UnivRecNS::debug > 1) {
1707 
1708  printf(" ipar=(%d,%d) iside=%d niter=%d lnP=%lf %lf (%lf) RotAngle=%4.2lf ", iparX, iparY, iside, niter, lnP_i[0], lnP_i[1], lnP_max, RotAngle * 180. / M_PI);
1709  if (okX) printf(" parX=%lf (%lf) ", rangeX[iside]*unit[iparX], val_max[0]*unit[iparX]);
1710  if (okY) printf(" parY=%lf (%lf) ", rangeY[iside]*unit[iparY], val_max[1]*unit[iparY]);
1711 
1712  if (okX) par[iparX] = rangeX[iside];
1713  if (okY) par[iparY] = rangeY[iside];
1714  printf(" | d=%5.2lf %lf \n", d[iside], lnP_max - GetLikelihood(par, parStatus));
1715  }
1716  }
1717 
1718  // Set ranges to low/high if failed
1719  if (!ok_range) {
1720  if (okX) {
1721  rangeX[0] = lowX;
1722  rangeX[1] = highX;
1723  }
1724  if (okY) {
1725  rangeY[0] = lowY;
1726  rangeY[1] = highY;
1727  }
1728  }
1729 
1730  // Restore
1731  if (okX) par[iparX] = val_max[0];
1732  if (okY) par[iparY] = val_max[1];
1733  GetLikelihood(par, parStatus);
1734 
1735  bool ok_minima = (edm < edm_tolerance);
1736 
1737  return ok_range && ok_minima;
1738 }
1739 
1740 
1741 void UnivRec::ScanLikelihood(int iparX, int iparY, int N, std::vector<std::pair<double, double> >& parXY, std::vector<double>& lnP,
1742  std::pair<double, double>& parXY_min, double& lnP_min)
1743 {
1744  parXY.clear();
1745  lnP.clear();
1746 
1747  std::vector<double> par, epar;
1748  std::vector<int> parStatus;
1749  std::vector<bool> isFixed, hasLimits;
1750  InitFCNParameters(par, epar, parStatus, hasLimits);
1751  for (unsigned int ipar = 0; ipar < par.size(); ipar++)
1752  isFixed.push_back(parStatus[ipar] < 2 ? false : true);
1753 
1754  bool okX = (iparX >= 0 && iparX < int(par.size()));
1755  if (okX) okX = !isFixed[iparX];
1756  bool okY = (iparY >= 0 && iparY < int(par.size()));
1757  if (okY) okY = !isFixed[iparY];
1758  if (!okX && !okY) return;
1759 
1760  double range[2][2] = { {1.e10, -1.e10}, {1.e10, -1.e10} }; // [ix/iy][min/max]
1761  double dum[2], edm;
1762  double step[2] = {0., 0.};
1763  unsigned int NX = 1, NY = 1;
1764 
1765  if (okX && okY) {
1766  for (int irot = 0; irot < 8; irot++) {
1767  double RotAngle = M_PI / 8.*double(irot);
1768  double rangeX[2], rangeY[2];
1769  ScanRange(iparX, iparY, par, parStatus, rangeX, rangeY, dum, RotAngle, 6., edm);
1770  for (int iside = 0; iside < 2; iside++) {
1771  if (okX && rangeX[iside] < range[0][0]) range[0][0] = rangeX[iside];
1772  if (okX && rangeX[iside] > range[0][1]) range[0][1] = rangeX[iside];
1773  if (okY && rangeY[iside] < range[1][0]) range[1][0] = rangeY[iside];
1774  if (okY && rangeY[iside] > range[1][1]) range[1][1] = rangeY[iside];
1775  }
1776  }
1777  } else ScanRange(iparX, iparY, par, parStatus, range[0], range[1], dum, (okX ? 0. : M_PI / 2.) , 6., edm);
1778 
1779 
1780  if (UnivRecNS::debug > 1)
1781  printf("rangeX=(%5.2lf %5.2lf ) rangeY=(%5.2lf,%5.2lf ) \n", range[0][0]*unit[iparX], range[0][1]*unit[iparX], range[1][0]*unit[iparY], range[1][1]*unit[iparY]);
1782 
1783  if (okX) {
1784  step[0] = (range[0][1] - range[0][0]) / double(N);
1785  NX = N;
1786  }
1787  if (okY) {
1788  step[1] = (range[1][1] - range[1][0]) / double(N);
1789  NY = N;
1790  }
1791 
1792  for (unsigned int ix = 0; ix < NX; ix++)
1793  for (unsigned int iy = 0; iy < NY; iy++) {
1794  std::vector<double> par_i;
1795  for (unsigned int ipar = 0; ipar < par.size(); ipar++) par_i.push_back(par[ipar]);
1796  std::pair<double, double> parXY_i;
1797  if (okX) {
1798  parXY_i.first = range[0][0] + double(ix) * step[0];
1799  par_i[iparX] = parXY_i.first;
1800  parXY_i.first *= unit[iparX];
1801  } else parXY_i.first = 0.;
1802 
1803  if (okY) {
1804  parXY_i.second = range[1][0] + double(iy) * step[1];
1805  par_i[iparY] = parXY_i.second;
1806  parXY_i.second *= unit[iparY];
1807  } else parXY_i.second = 0.;
1808  double lnP_i = GetLikelihood(par_i, parStatus);
1809 
1810  parXY.push_back(parXY_i);
1811  lnP.push_back(lnP_i);
1812  }
1813 
1814  lnP_min = GetLikelihood(par, parStatus); // Restore the internal values for the minimum and recalculate the likelihood
1815 
1816  if (okX)
1817  parXY_min.first = par[iparX] * unit[iparX];
1818  if (okY)
1819  parXY_min.second = par[iparY] * unit[iparY];
1820 }
1821 
1822 
1823 bool
1825 {
1826  return IsGoodRec(true);
1827 }
1828 
1829 
1830 bool
1831 #ifndef ExternalUse
1832 UnivRec::IsGoodRec(bool CutBadYears)
1833 #else
1834 UnivRec::IsGoodRec(bool /*CutBadYears*/)
1835 #endif
1836 {
1837 #ifndef ExternalUse
1838  if (!gRecMC && CutBadYears && gRecDataSet == 1) {
1839  unsigned int GPSnano = 0;
1840  utl::TimeStamp time(GPSsec, GPSnano);
1841  if (time.GetYear() < 2008) return false;
1842  }
1843 #endif
1844  //-----
1845  bool okRec;
1846  if (!IsTimeRec)
1847  okRec = (recinfo.FitStatus[0] == 3 && recinfo.FitStage == 0);
1848  else {
1849  bool okQuality = (recinfo.Xmax_err < 200. && (gRecType == 6 ? true : recinfo.TimeMaxdev[0] < 4.0));
1850  bool okMinimum = (recinfo.FitStatus[1] >= 2 && recinfo.MinEigenVal > -0.5);
1851  okRec = (recinfo.FitStatus[0] == 3 && recinfo.FitStage == 2 && recinfo.AllTimesOK && okMinimum && okQuality);
1852  }
1853  //---
1854 
1855  if (!okRec && UnivRecNS::debug > 2) {
1856 
1857  printf("sdid=%d ok=%d Status=%d/%d FitStage=%d EDM=%5.3lf MinEigenVal=%5.3lf AlltimesOK=%d theta=%5.2f (%5.2lf %5.2lf) logE=%5.2lf (%5.2lf %5.2lf) Xmax=%5.2lf+-%5.2lf (%5.2lf %5.2lf ) Nmu=%5.2lf nStations=%d/%d\n",
1858  recinfo.id, okRec, recinfo.FitStatus[0], recinfo.FitStatus[1], recinfo.FitStage,
1859  recinfo.edm, recinfo.MinEigenVal,
1860  recinfo.AllTimesOK,
1861  recinfo.theta * 180. / M_PI, MCinfo.theta * 180. / M_PI, augerinfo.theta_FD * 180. / M_PI,
1862  recinfo.logE, MCinfo.logE, augerinfo.logE_FD,
1863  recinfo.Xmax, recinfo.Xmax_err, MCinfo.Xmax, augerinfo.Xmax_FD,
1864  recinfo.Nmu, recinfo.nSignalStations, recinfo.nTimeStations);
1865 
1866  }
1867  return okRec;
1868 }
1869 
1870 
1871 
1872 bool UnivRec::CheckEnergyCut(bool PrintOut)
1873 {
1874  if (gRecMC) return true;
1875 
1876  double logE = (gRecDataSet == 1 ? augerinfo.logE_FD : augerinfo.logE_SD);
1877  double logE_Thresh = 18.60;
1878  if (!IsTimeRec || gRecInfill) logE_Thresh = 17.00;
1879  else if (gRecType == 1) logE_Thresh = 19.10;
1880  else if (gRecSys > 0) logE_Thresh = 19.00;
1881 
1882  if (logE < logE_Thresh) {
1883  if (PrintOut) printf("%d Event not selected : logE=%5.2lf \n", recinfo.id, logE);
1884  return false;
1885  }
1886  return true;
1887 }
1888 
1889 
1890 //---------------------------------------------------
1891 //---------------------------------------------------
1892 // Time Likelihood
1893 //---------------------------------------------------
1894 //---------------------------------------------------
1896 {
1897  return GetTimeLikelihood(false);
1898 }
1899 
1900 double UnivRec::GetTimeLikelihood(bool UseAvgQuantiles)
1901 {
1902  recinfo.TimeMaxdev[0] = -1.e10;
1903  recinfo.TimeMaxdev[1] = UNDEF;
1904  recinfo.AllTimesOK = true;
1905  recinfo.nTimeStations = 0;
1906  recinfo.lnP[0] = 0.;
1907 
1908 
1909  for (int idet = 0; idet < nRecStations; idet++) {
1910 
1911  RecStation_t* st = &fstation[idet];
1912  for (int iq = 0; iq < nQ; iq++) {
1913  st->tq_rec[iq] = UNDEF;
1914  st->tq_pred[iq] = UNDEF;
1915  st->tq_rms[iq] = UNDEF;
1916  st->tq_corr[iq] = 0.;
1917  st->lnP_quantiles = 0.;
1918 
1919  st->start_rec = UNDEF;
1920  st->start_pred = UNDEF;
1921  st->start_rms = UNDEF;
1922  st->start_corr = 0.;
1923  st->lnP_start = 0.;
1924  }
1925  int type = st->type;
1926  if (st->mask_starttime && st->mask_quantiles) continue;
1928 
1929  //------------------------------
1930  //
1931  //------------------------------
1932 
1933  if (!Check_DX_DL(st)) {
1934  st->lnP_quantiles = lnP_inf;
1935  st->lnP_start = lnP_inf;
1936  recinfo.AllTimesOK = false;
1937  recinfo.lnP[0] += (st->lnP_start + st->lnP_quantiles);
1938  continue;
1939  }
1940 
1941  double vemTot_p = 0., fcomp[4];
1942  for (int icomp = 0; icomp < 4; icomp++) {
1943  fcomp[icomp] = fsignal[type]->GetSignal(st->r, st->DX, recinfo.logE, recinfo.theta, st->psi,
1944  st->density, st->zg, recinfo.Nmu, icomp);
1945  vemTot_p += fcomp[icomp];
1946  }
1947  for (int icomp = 0; icomp < 4; icomp++) fcomp[icomp] /= vemTot_p;
1948 
1949 
1950 
1951  //---------------
1952  // Start time
1953  //---------------
1954 
1956  st->start_rec = (st->GPSnano + st->starttime - st->start_corr) - (recinfo.T0 + st->T0_PF);
1957 
1958  double UnitPerMuon = 0;
1959  if (st->type == 0)
1960  UnitPerMuon = 1. / (cos(recinfo.theta) + 2.*tankh * sin(recinfo.theta) / M_PI / tankr);
1961  else if (st->type == 1)
1962  UnitPerMuon = 1. / cos(recinfo.theta);
1963  else if (st->type == 2)
1964  UnitPerMuon = 1.;
1965  double nmuDetector = fcomp[0] * st->signalsize / UnitPerMuon;
1966  if (nmuDetector <= 1.)
1967  nmuDetector = 1.;
1968  double P_extreme = ftime[type]->tFirstPDF(st->DL[0], st->r, recinfo.logE, st->psi, recinfo.theta, st->T0_CF[0], nmuDetector, st->start_rec
1969  , false, st->start_pred, st->start_rms);
1970  double Accuracy = (st->type == 2 ? StartAccuracyAMIGA : StartAccuracy[gRecSDE_Upgrade]);
1971  st->start_rms = sqrt(pow(st->start_rms, 2.) + pow(Accuracy, 2.) + pow(InterGPSAccuracy[gRecSDE_Upgrade], 2.));
1972 
1973  if (!st->mask_starttime) {
1974  double dev = (st->start_rec - st->start_pred) / st->start_rms;
1975  if (st->UseGausPDF_start)
1976  st->lnP_start += (-pow(dev, 2.) / 2. + log(1. / sqrt(2.*M_PI) / st->start_rms));
1977  else if (P_extreme < exp(lnP_inf))
1978  st->lnP_start += lnP_inf;
1979  else
1980  st->lnP_start += log(P_extreme);
1981 
1982  if (fabs(dev) > recinfo.TimeMaxdev[0]) {
1983  recinfo.TimeMaxdev[0] = fabs(dev);
1984  recinfo.TimeMaxdev[1] = idet;
1985  }
1986  if (!st->UseGausPDF_start && (st->start_rec < st->T0_CF[0] || P_extreme < exp(lnP_inf)))
1987  recinfo.AllTimesOK = false;
1988  }
1989 
1990  //---------------
1991  // T1/T10/T50/T90
1992  //---------------
1993  for (int iq = 0; iq < nQ; iq++) {
1994  if (st->quantile[iq] == UNDEF)
1995  continue;
1996  double tq = (UseAvgQuantiles ? st->tquantile[1][iq] : st->tquantile[0][iq]);
1997  if (tq == UNDEF)
1998  continue;
1999  st->tq_rec[iq] = (st->GPSnano + tq) - (recinfo.T0 + st->T0_PF);
2000  }
2001 
2002  // Corrections are applied to the reconstructed quantiles since it is not possible to change the binomial probability accordingly
2003  // The predicted quantiles for large signals are used.
2004 
2005  double RiseTime = ftime[type]->GetTime(st->DL, st->r, recinfo.logE, st->psi, recinfo.theta, fcomp, st->T0_CF, 0.50) -
2006  ftime[type]->GetTime(st->DL, st->r, recinfo.logE, st->psi, recinfo.theta, fcomp, st->T0_CF, 0.10);
2007 
2008  for (int iq = 0; iq < nQ; iq++) {
2009  if (st->quantile[iq] == UNDEF)
2010  continue;
2011 
2012  //Area Over Peak
2013  double corrAoP = ftime[type]->tQuantileCorrection_AoP(RiseTime, iq, st->AreaOverPeak);
2014  st->tq_rec[iq] -= corrAoP;
2015 
2016  //Quantile corrections ( Pulse effects+Small signal shifts)
2017  double NanoSecPerVEM = RiseTime / st->signalsize / 0.4;
2018  double corr = ftime[type]->tQuantileCorrection(NanoSecPerVEM, iq);
2019  if (!UseAvgQuantiles)
2020  st->tq_rec[iq] -= corr;
2021 
2022  st->tq_corr[iq] = corrAoP + corr;
2023  }
2024  //------------------------------------
2025  //------------------------------------
2026 
2027  for (int iq = 0; iq < nQ; iq++) {
2028  if (st->quantile[iq] == UNDEF) continue;
2029 
2030  double signalsize = (UseAvgQuantiles ? 1.e4 : st->signalsize);
2031  double P_binom = ftime[type]->tQuantilePDF(st->DL, st->r , recinfo.logE, st->psi, recinfo.theta, fcomp, st->T0_CF, signalsize,
2032  st->tq_rec[iq], st->quantile[iq] , false, st->tq_pred[iq], st->tq_rms[iq]);
2033  st->tq_rms[iq] = sqrt(pow(st->tq_rms[iq], 2.) + pow(ParameterizationRMSLimit, 2.) + pow(InterGPSAccuracy[gRecSDE_Upgrade], 2.));
2034 
2035  if (!st->mask_quantiles) {
2036  double dev = (st->tq_rec[iq] - st->tq_pred[iq]) / st->tq_rms[iq];
2037  if (st->UseGausPDF_quantiles[iq]) st->lnP_quantiles += (-pow(dev, 2.) / 2. + log(1. / sqrt(2.*M_PI) / st->tq_rms[iq]));
2038  else if (P_binom < exp(lnP_inf)) st->lnP_quantiles += lnP_inf;
2039  else st->lnP_quantiles += log(P_binom);
2040 
2041  if (fabs(dev) > recinfo.TimeMaxdev[0]) {
2042  recinfo.TimeMaxdev[0] = fabs(dev);
2043  recinfo.TimeMaxdev[1] = idet;
2044  }
2045  if (!st->UseGausPDF_quantiles[iq] && (st->tq_rec[iq] < st->T0_CF[0] || P_binom < exp(lnP_inf))) recinfo.AllTimesOK = false;
2046  }
2047  }//iq
2048  recinfo.lnP[0] += (st->lnP_start + st->lnP_quantiles);
2049  }
2050  return recinfo.lnP[0];
2051 }
2052 
2053 
2054 //---------------------------------------------------
2055 //---------------------------------------------------
2056 // Signal Likelihood
2057 //---------------------------------------------------
2058 //---------------------------------------------------
2059 
2061 {
2063  recinfo.lnP[1] = 0.;
2064 
2065  for (int idet = 0; idet < nRecStations; idet++) {
2066  RecStation_t* st = &fstation[idet];
2067  int type = st->type;
2068  if (st->mask_signal) continue;
2070 
2071  if (!Check_DX_DL(st)) {
2072  st->lnP_signal = lnP_inf;
2073  recinfo.lnP[1] += (st->lnP_signal);
2074  continue;
2075  }
2076 
2077  double Rec = st->signalsize;
2078  double Pred = fsignal[type]->GetSignal(st->r, st->DX, recinfo.logE, recinfo.theta, st->psi, st->density, st->zg, recinfo.Nmu, -1);
2079  if (st->type == 2) Pred *= (st->DetectorArea / nMD / MDlength / MDwidth);
2080 
2081  double RMS_sh = 0.02 * Pred;
2082  double rms = sqrt(Pred + RMS_sh * RMS_sh);
2083 
2084  st->signalsize_pred = Pred;
2085  st->signalsize_rms = rms;
2086 
2087  //-------------------------
2088  double lnP = 0.;
2089 
2090  //stations saturated
2091  if (st->isSaturated) {
2092  double dev = (Rec - Pred) / 2. / rms;
2093  double Pi = TMath::Erfc(dev) / 2.;
2094  if (Pi > exp(lnP_inf)) lnP = log(Pi);
2095  else lnP = lnP_inf;
2096 
2097  }
2098  // Stations with signal: Approx. gaussian
2099  else if (Rec > 20) {
2100  if (rms == 0.) lnP = lnP_inf;
2101  else lnP = -pow((Rec - Pred) / rms, 2.) / 2. + log(1. / sqrt(2.*M_PI) / rms);
2102  }
2103  // Stations with signal: Poisson distrib.
2104  else if (Rec > 0) {
2105  double part = double(int(Rec + 0.5));
2106  double Pi = TMath::Poisson(part, Pred);
2107  if (Pi < exp(lnP_inf) || std::isnan(Pi) || std::isinf(Pi)) lnP = lnP_inf;
2108  else lnP = log(Pi);
2109  }
2110  // Silent stations
2111  else {
2112  double Pi = 0.;
2113  for (int i = 0; i < 3; i++) Pi += TMath::Poisson(double(i), Pred);
2114  if (Pi < exp(lnP_inf)) lnP = lnP_inf;
2115  else lnP = log(Pi);
2116  }
2117 
2118  if (!st->mask_signal) {
2119  st->lnP_signal = lnP;
2120  recinfo.lnP[1] += lnP;
2121  } else
2122  st->lnP_signal = 0.;
2123  }
2124  return recinfo.lnP[1];
2125 }
2126 
2127 
2128 //---------------------------------------------------
2129 //---------------------------------------------------
2130 //
2131 //---------------------------------------------------
2132 //---------------------------------------------------
2133 
2135 {
2136  for (int icomp = 0; icomp < 4; icomp++) {
2137  if (!UnivParamNS::UseDiffusive[icomp] && st->DX[icomp] <= 0.) return false;
2138  if (!UnivParamTimeNS::UseDiffusive_time[icomp] && st->DL[icomp] <= 0.) return false;
2139  double DX0 = fsignal[st->type]->RFunc(st->r, icomp, 5);
2140  if (st->DX[icomp] <= DX0) return false;
2141  }
2142  return true;
2143 }
2144 
2145 bool UnivRec::SetFitStage(int FitStage)
2146 {
2147  bool ok = true;
2148 
2149  // Good Signal reconstruction
2150  if (FitStage == 1)
2151  ok = (recinfo.FitStage == 0 && recinfo.FitStatus[0] == 3 && IsTimeRec);
2152  // Set PDF flags
2153  else if (FitStage == 2) {
2154  ok = (recinfo.FitStage == 1 && IsTimeRec);
2155  if (ok) SetOptPDF();
2156  }
2157  if (ok) recinfo.FitStage = FitStage;
2158 
2159  return ok;
2160 }
2161 
2163 {
2164  //-----------------
2165  //------Signal ( WCD )
2166  //-----------------
2167  const double vemCut = vemSignalCut;
2168 
2169  for (int idet = 0; idet < nRecStations; idet++) {
2170  RecStation_t* st = &fstation[idet];
2171  int type = st->type;
2172  if (type != 0) continue;
2173 
2174  if (!Check_DX_DL(st)) {
2175  st->mask_signal = true;
2176  st->mask_quantiles = true;
2177  st->mask_starttime = true;
2178  continue;
2179  }
2180 
2181  if (st->r > rSignalCut[1] || st->r < rSignalCut[0]) {
2182  st->mask_signal = true;
2183  continue;
2184  }
2185 
2186  double Pred = fsignal[type]->GetSignal(st->r, st->DX , recinfo.logE, recinfo.theta, st->psi, st->density, st->zg, recinfo.Nmu, -1);
2187  if (Pred < vemCut) {
2188  st->mask_signal = true;
2189  continue;
2190  }
2191 
2192  st->mask_signal = false;
2193  }
2194 
2195  //-----------------
2196  //------Signal ( ASCII/AMIGA )
2197  //-----------------
2198  for (int idet_i = 0; idet_i < nRecStations; idet_i++) {
2199  RecStation_t* st = &fstation[idet_i];
2200  if (st->type == 0) continue;
2201  st->mask_signal = false;
2202 
2203  int idet_wcd = UNDEF;
2204  for (int idet_j = 0; idet_j < nRecStations; idet_j++)
2205  if (fstation[idet_j].type == 0 && fstation[idet_j].id == st->id)
2206  idet_wcd = idet_j;
2207 
2208  if (idet_wcd == UNDEF) continue;
2209  st->mask_signal = fstation[idet_wcd].mask_signal;
2210  }
2211 
2212  //-----------------
2213  //------Time
2214  //-----------------
2215  for (int idet = 0; idet < nRecStations; idet++) {
2216  RecStation_t* st = &fstation[idet];
2217 
2218  if (!st->mask_quantiles && (st->r > rQuantileCut[1] || st->r < rQuantileCut[0]))
2219  st->mask_quantiles = true;
2220 
2221  if (!st->mask_starttime && (st->r > rStartCut[1] || st->r < rStartCut[0]))
2222  st->mask_starttime = true;
2223  }
2224 
2225  return TimeSignalOK();
2226 }
2227 
2228 //----------------------------------------------------------
2229 // -Chi2 on WCD signals
2230 // -Minimum number of stations positions in TimeLikelihood
2231 //----------------------------------------------------------
2233 {
2234  //Chi2 (WCD only)
2235  //---------
2236  double Chi2 = 0., nChi2 = 0.;
2237  for (int idet = 0; idet < nRecStations; idet++) {
2238  RecStation_t* st = &fstation[idet];
2239  if (st->mask_signal) continue;
2240  if (st->type != 0) continue;
2241 
2242  int type = st->type;
2243 
2244  if (!Check_DX_DL(st)) {
2245  st->mask_signal = true;
2246  st->mask_quantiles = true;
2247  st->mask_starttime = true;
2248  continue;
2249  }
2250 
2251  double Pred = fsignal[type]->GetSignal(st->r, st->DX, recinfo.logE, recinfo.theta, st->psi, st->density, st->zg, recinfo.Nmu, -1);
2252 
2253  if (!st->isSaturated) {
2254  Chi2 += (pow(Pred - st->signalsize, 2.) / Pred);
2255  nChi2 += 1.;
2256  }
2257  }
2258  if (Chi2 / double(nChi2) > 100.) return false;
2259 
2260  // Minimum number of WCD in time/signal likelihood
2261  //---------
2262  int nTimeStations = 0, nSignalStations = 0;
2263  for (int idet = 0; idet < nRecStations; idet++) {
2264  RecStation_t* st = &fstation[idet];
2265  if (st->type != 0) continue;
2266  if (!st->mask_starttime || !st->mask_quantiles) nTimeStations++;
2267  if (!st->mask_signal && st->signalsize > 0.) nSignalStations++;
2268  }
2269 
2270  if (IsTimeRec && nTimeStations < nTimeStationsMin) return false;
2271  if (nSignalStations < nSignalStationsMin) return false;
2272 
2273  return true;
2274 }
2275 
2276 
2278 {
2279 
2283 
2284  int idet_max = int(recinfo.TimeMaxdev[1]);
2285  fstation[idet_max].mask_quantiles = true;
2286  fstation[idet_max].mask_starttime = true;
2287  fstation[idet_max].mask_signal = true;
2288 
2289  if (debug == 1) printf("Rejecting station : %d %d \n", fstation[idet_max].id, idet_max);
2290  return true;
2291  }
2292  return false;
2293 }
2294 
2296 {
2297  for (int idet = 0; idet < nRecStations; idet++) {
2298  RecStation_t* st = &fstation[idet];
2299  if (!st->mask_starttime) {
2300  double Accuracy = (st->type == 2 ? StartAccuracyAMIGA : StartAccuracy[gRecSDE_Upgrade]);
2301  double rms_model = sqrt(pow(st->start_rms, 2.) - pow(Accuracy, 2.) - pow(InterGPSAccuracy[gRecSDE_Upgrade], 2.));
2302  st->UseGausPDF_start = (rms_model < sqrt(pow(Accuracy, 2.) + pow(InterGPSAccuracy[gRecSDE_Upgrade], 2.)) ? true : false);
2303  if (st->start_rec < -3 * st->start_rms) st->UseGausPDF_start = true;
2304  }
2305  if (st->mask_quantiles) continue;
2306 
2307  for (int iq = 0; iq < nQ; iq++) {
2308  if (st->quantile[iq] == UNDEF) continue;
2309 
2310  double rms_model = sqrt(pow(st->tq_rms[iq], 2.) - pow(ParameterizationRMSLimit, 2.) - pow(InterGPSAccuracy[gRecSDE_Upgrade], 2.));
2311  st->UseGausPDF_quantiles[iq] = (rms_model < sqrt(pow(ParameterizationRMSLimit, 2.) + pow(InterGPSAccuracy[gRecSDE_Upgrade], 2.)) ? true : false);
2312  if (st->tq_rec[iq] < 0.) st->UseGausPDF_quantiles[iq] = true;
2313  }
2314  }
2315 }
2316 
2317 
2318 //---------------------------------------------------
2319 //---------------------------------------------------
2320 //
2321 //---------------------------------------------------
2322 //---------------------------------------------------
2323 
2324 
2325 // Load the current guess of the reconstructed parameters into the par array for a new minimization
2326 // (l,m) are initialized to 0, since after every minimization the direction is centered around the reconstructed one.
2327 
2328 // status=0 Free
2329 // 1 Constrained
2330 // 2 Fixed to current value in recinfo
2331 // 3 Fixed to a value that is set in GetLikelihood routine (it can depend on other parameters)
2332 
2333 int UnivRec::InitFCNParameters(std::vector<double>& par , std::vector<double>& epar, std::vector<int>& status , std::vector<bool>& hasLimits)
2334 {
2335  par.clear();
2336  epar.clear();
2337  status.clear();
2338  hasLimits.clear();
2339 
2340 
2341  // Fill par status
2342  //-----------------
2343  //----
2344  if (recinfo.FitStage == -1) {
2345  // logE Nmu Xmax T0 l m OffsetM_Mu
2346  const int status_golden[npar] = { 0, 0, 3, 0, 3, 3, 2, 2, 3 };
2347  const int status_sd[npar] = { 0, 0, 0, (gRecType == 3 ? 0 : 3), 3, 3, 2, 2, 3 };
2348  for (unsigned int ipar = 0; ipar < npar; ipar++) {
2349  if (IsGoldenRec) status.push_back(status_golden[ipar]);
2350  else status.push_back(status_sd[ipar]);
2351  }
2352  }
2353  //----
2354  if (recinfo.FitStage == 0) {
2355  // logE Nmu Xmax T0 l m OffsetM_Mu
2356  const int status_golden[npar] = { 0, 0, 1, 0, 1, 3, 2, 2, 3 };
2357  const int status_sd[npar] = { 0, 0, 0, (gRecType == 3 ? 0 : 3), 3, 3, 2, 2, 3 };
2358 
2359  for (unsigned int ipar = 0; ipar < npar; ipar++) {
2360  if (IsGoldenRec) status.push_back(status_golden[ipar]);
2361  else status.push_back(status_sd[ipar]);
2362  }
2363  }
2364  //----
2365  if (recinfo.FitStage == 1) {
2366  // logE Nmu Xmax T0 l m OffsetM_Mu
2367  const int status_xmax[npar] = { 2, 2, 2, 2, (gRecType == 7 ? 2 : 0), 0, 2, 2, (gRecType == 7 ? 0 : 3) };
2368  for (unsigned int ipar = 0; ipar < npar; ipar++) status.push_back(status_xmax[ipar]);
2369  }
2370  //----
2371  if (recinfo.FitStage == 2) {
2372  // logE Nmu Xmax T0 l m OffsetM_Mu
2373  const int status_xmax[npar] = { 0, 0, (gRecType == 5 ? 2 : 0), (gRecType == 5 ? 0 : (gRecType == 3 ? 0 : 3)), 0, 0, 0 , 0, (gRecType == 1 ? 0 : 3) };
2374  const int status_OffsetM_mu_FD[npar] = { 2, 2, 2, 2, 2, 0, 2 , 2, 0 };
2375  const int status_photon[npar] = { 2, 2, 2, 3, 0, 0, 0 , 0, 3 };
2376  for (unsigned int ipar = 0; ipar < npar; ipar++) {
2377  if (gRecType == 6) status.push_back(status_photon[ipar]);
2378  else if (gRecType == 7) status.push_back(status_OffsetM_mu_FD[ipar]);
2379  else status.push_back(status_xmax[ipar]);
2380  }
2381  }
2382 
2383  // Set Init values
2384  //--------------------------
2385 
2386  double T0_relative;
2389  T0_relative = (st->GPSnano + st->starttime) - (st->T0_PF + recinfo.T0);
2390  double val_i[npar] = { recinfo.xgcore - fstation[recinfo.gDetHot].xg, recinfo.ygcore - fstation[recinfo.gDetHot].yg,
2391  recinfo.logE, recinfo.Nmu, recinfo.Xmax, T0_relative , 0., 0., recinfo.OffsetM_Mu
2392  };
2393 
2394 
2395 
2396  // Fill Limits,Init values
2397  //--------------------------
2398  for (unsigned int ipar = 0; ipar < npar; ipar++) {
2399  par.push_back((status[ipar] == 3 ? 0. : val_i[ipar] / unit[ipar]));
2400  if (status[ipar] == 0 || status[ipar] == 1) {
2401  epar.push_back(1.);
2402  hasLimits.push_back((ipar == 3 || ipar == 4 || ipar == 8 ? true : false)); // Xmax/Nmu/OffsetM_Mu
2403  } else {
2404  epar.push_back(0.);
2405  hasLimits.push_back(false);
2406  }
2407  }
2408  return par.size();
2409 }
2410 
2411 
2412 //Save Minimization results
2413 void UnivRec::SaveFCNParameters(std::vector<double> par, std::vector<int> status)
2414 {
2415  //-- Recalculate
2416  GetLikelihood(par, status);
2417 
2418  //-- Hottest station distance / T0 from hot
2420 
2421  //-- Calculate parameter errors
2422  std::vector<double> epar;
2423  for (unsigned int i = 0; i < par.size(); i++) epar.push_back(0.);
2424  if (recinfo.FitStage == 0) recinfo.FitStatus[0] = GetErrors(par, epar, status);
2425  if (recinfo.FitStage == 2) recinfo.FitStatus[1] = GetErrors(par, epar, status);
2426 
2427  //-- Save errors in internal coordinates
2428  if (status[0] < 2) recinfo.xgcore_err = epar[0] * unit[0];
2429  if (status[1] < 2) recinfo.ygcore_err = epar[1] * unit[1];
2430  if (status[2] < 2) recinfo.logE_err = epar[2] * unit[2];
2431  if (status[3] < 2) recinfo.Nmu_err = epar[3] * unit[3];
2432  if (status[4] < 2) recinfo.Xmax_err = epar[4] * unit[4];
2433  if (status[5] < 2) recinfo.T0_err = epar[5] * unit[5];
2434  if (status[8] < 2) recinfo.OffsetM_Mu_err = epar[8] * unit[8];
2435 
2436  //-- Save energy estimated in FitStage 0
2437  if (recinfo.FitStage == 0) {
2442  }
2443 
2444  //-- Update direction
2445  recinfo.theDir_Ref.SetMagThetaPhi(1., recinfo.theta, recinfo.azi);
2446 
2447 }
2448 
2449 
2450 //---------------------------------------------------
2451 //---------------------------------------------------
2452 //
2453 //---------------------------------------------------
2454 //---------------------------------------------------
2455 
2456 
2457 void UnivRec::Unrotate(double l_p, double m_p, double& theta, double& azi)
2458 {
2459 
2460  double theta_p = asin(sqrt(l_p * l_p + m_p * m_p));
2461  double azi_p = NormalizeAngle(atan2(m_p, l_p));
2462 
2463  TVector3 theDir_p;
2464  theDir_p.SetMagThetaPhi(1., theta_p, azi_p);
2465  theDir_p.RotateY(recinfo.theDir_Ref.Theta());
2466  theDir_p.RotateZ(recinfo.theDir_Ref.Phi());
2467 
2468  theta = theDir_p.Theta();
2469  azi = NormalizeAngle(theDir_p.Phi());
2470 }
2471 
2472 
2473 void
2474 UnivRec::SetT0FromHot(bool UseT0_relative, double T0_relative)
2475 {
2477  RecStation_t* const st = &fstation[recinfo.gDetHot];
2478 
2479  for (int itype = 0; itype < 3; ++itype)
2480  ftime[itype]->SetOffsetM_Mu(recinfo.OffsetM_Mu);
2481 
2482  if (UseT0_relative)
2483  recinfo.T0 = (st->GPSnano + st->starttime) - (st->T0_PF + T0_relative);
2484  else {
2485  //---Expected signal
2486  double vemTot_p = 0., fcomp[4];
2487  for (int icomp = 0; icomp < 4; icomp++) {
2488  fcomp[icomp] = fsignal[st->type]->GetSignal(st->r, st->DX, recinfo.logE, recinfo.theta, st->psi, st->density, st->zg, recinfo.Nmu, icomp);
2489  vemTot_p += fcomp[icomp];
2490  }
2491  for (int icomp = 0; icomp < 4; icomp++)
2492  fcomp[icomp] /= vemTot_p;
2493 
2494  // Start time
2495  double UnitPerMuon = 0;
2496  if (st->type == 0)
2497  UnitPerMuon = 1. / (cos(recinfo.theta) + 2.*tankh * sin(recinfo.theta) / M_PI / tankr);
2498  else if (st->type == 1)
2499  UnitPerMuon = 1. / cos(recinfo.theta);
2500  else if (st->type == 2)
2501  UnitPerMuon = 1.;
2502  double nmuDetector = fcomp[0] * st->signalsize / UnitPerMuon;
2503  if (nmuDetector <= 1.)
2504  nmuDetector = 1.;
2505  double pred = 0, rms = 0;
2506  double corr = ftime[st->type]->tStartCorrection(st->r, recinfo.logE, recinfo.theta, gRecSDE_Upgrade);
2507  /*double P_extreme =*/ ftime[st->type]->tFirstPDF(st->DL[0], st->r, recinfo.logE, st->psi, recinfo.theta, st->T0_CF[0], nmuDetector, -1., false, pred, rms);
2508  recinfo.T0 = (st->GPSnano + st->starttime) - (st->T0_PF + pred + corr);
2509  }
2510 }
2511 
2512 
2513 // Those parameters that are fixed use the values stored in recinfo except the exceptions found below.
2514 double UnivRec::GetLikelihood(std::vector<double> par, std::vector<int> status)
2515 {
2516  if (par.size() != npar) {
2517  printf("ERROR (GetLikelihood): par size %ld\n", par.size());
2518  exit(1);
2519  }
2520  for (unsigned int ipar = 0; ipar < npar; ++ipar)
2521  if (std::isnan(par[ipar]) || std::isinf(par[ipar])) {
2522  printf("ERROR (GetLikelihood): par %d ->%lf \n", ipar, par[ipar]);
2523  return lnP_inf * 4 * nRecStations;
2524  }
2525  recinfo.nFCNcalls++;
2526 
2527  //-- Transform parameters
2528  if (status[6] < 2 && status[7] < 2)
2529  Unrotate(par[6]*unit[6], par[7]*unit[7], recinfo.theta, recinfo.azi);
2530 
2531  if (status[0] < 2) recinfo.xgcore = par[0] * unit[0] + fstation[recinfo.gDetHot].xg;
2532  if (status[1] < 2) recinfo.ygcore = par[1] * unit[1] + fstation[recinfo.gDetHot].yg;
2533 
2534  if (status[2] < 2) recinfo.logE = par[2] * unit[2];
2535  else if (status[2] == 3) {
2536  if (gRecType == 5 && recinfo.FitStage > 0) recinfo.logE = recinfo.logE_ref;
2538  else {
2539  printf("ERROR (GetLikelihood): setting energy \n");
2540  exit(1);
2541  }
2542  }
2543 
2544  if (status[4] < 2) recinfo.Xmax = par[4] * unit[4];
2545  else if (status[4] == 3) {
2546  if (gRecType == 0 || gRecType == 7) recinfo.Xmax = augerinfo.Xmax_FD;
2548  }
2549 
2550  if (status[3] < 2) recinfo.Nmu = par[3] * unit[3];
2551  else if (status[3] == 3) {
2552  double Xmax = (gRecType == 4 || gRecType == 1 ? recinfo.Xmax : -100.);
2554  }
2555 
2556  if (status[8] < 2) recinfo.OffsetM_Mu = par[8] * unit[8];
2557  else if (status[8] == 3) recinfo.OffsetM_Mu = fcalib->GetOffsetM_Mu(recinfo.logE, recinfo.theta, recinfo.Xmax);
2558 
2559  for (int itype = 0; itype < 3; itype++)
2560  ftime[itype]->SetOffsetM_Mu(recinfo.OffsetM_Mu);
2561 
2562  if (status[5] < 2) SetT0FromHot(true, par[5]*unit[5]);
2563  else if (status[5] == 3) SetT0FromHot(false, UNDEF);
2564 
2565  //-- Set coordinates,DX,T0_CF,T0_PF
2567 
2568  recinfo.lnP[2] = 0.;
2569 
2570  // Golden hybrid constrains
2571  //--------------------------
2572 
2573  //--- Energy constrain
2574  if (status[2] == 1) {
2575  if (!IsGoldenRec) {
2576  printf("ERROR (GetLikelihood): constraining energy \n");
2577  exit(1);
2578  }
2579  double rec = recinfo.logE;
2580  double mean = augerinfo.logE_FD, rms = augerinfo.logE_FD_err;
2581  double lnP_Energy = (-pow((mean - rec) / rms, 2.) / 2. + log(1. / sqrt(2.*M_PI) / rms));
2582  recinfo.lnP[2] += lnP_Energy;
2583  }
2584 
2585  //--- Xmax constrain
2586  if (status[4] == 1) {
2587  if (!IsGoldenRec) {
2588  printf("ERROR (GetLikelihood): constraining Xmax \n");
2589  exit(1);
2590  }
2591  double rec = recinfo.Xmax;
2592  double mean = augerinfo.Xmax_FD, rms = augerinfo.Xmax_FD_err;
2593  double lnP_Xmax = (-pow((mean - rec) / rms, 2.) / 2. + log(1. / sqrt(2.*M_PI) / rms));
2594  recinfo.lnP[2] += lnP_Xmax;
2595  }
2596 
2597  //--- Nmu constrain
2598  if (status[3] == 1) {
2599  double rec = recinfo.Nmu / fcalib->GetMeanNmu(recinfo.logE, recinfo.theta, -100.);
2600  double mean = 1., rms = 0.2;
2601  double lnP_Nmu = (-pow((mean - rec) / rms, 2.) / 2. + log(1. / sqrt(2.*M_PI) / rms));
2602  recinfo.lnP[2] += lnP_Nmu;
2603  }
2604 
2605  //--- Signal/Time Likelihood
2606  double lnP = 0.;
2607  lnP = recinfo.lnP[2];
2608 
2609  if ((gRecType == 6 || gRecType == 7) && recinfo.FitStage > 0) recinfo.lnP[1] = 0.;
2610  else lnP += GetSignalLikelihood();
2611 
2612  if (recinfo.FitStage > 0) lnP += GetTimeLikelihood();
2613 
2614  /*
2615  printf(" %5.2lf %5.2lf %5.2lf %5.2lf %5.2lf %5.2lf %5.2lf %5.2lf | lnP=%5.2lf | %d \n",recinfo.xgcore/1.e2,recinfo.ygcore/1.e2,recinfo.logE,recinfo.Nmu,
2616  recinfo.Xmax, recinfo.T0, recinfo.theta*180./M_PI, recinfo.azi*180./M_PI
2617  ,lnP,status[6]);
2618  */
2619 
2620  if (std::isnan(lnP) || std::isinf(lnP)) {
2621  printf("ERROR (GetLikelihood): lnP=%lf %lf %lf | %lf \n", recinfo.lnP[0], recinfo.lnP[1], recinfo.lnP[2], lnP);
2622  return lnP_inf * 4 * nRecStations;
2623  }
2624 
2625  return lnP;
2626 }
2627 
2628 // Covariance Matrix
2629 int UnivRec::GetErrors(std::vector<double> par, std::vector<double>& epar , std::vector<int> parStatus)
2630 {
2631  // If F=-log(L) is quadratic F=F_0+0.5 (t/d)^2, the second derivative is 1/d^2
2632  //
2633 
2634  int nFCNcalls_start = recinfo.nFCNcalls;
2635 
2636  bool ok_range = true;
2637 
2638  std::vector<bool> isFixed;
2639  for (unsigned int ipar = 0; ipar < par.size(); ipar++)
2640  isFixed.push_back(parStatus[ipar] < 2 ? false : true);
2641 
2642  int ndim = 0;
2643  for (unsigned int ipar = 0; ipar < par.size(); ipar++)
2644  if (!isFixed[ipar]) ndim++;
2645 
2646  // Save Error guess 1D likelihood scan ( Step is decreased to guarantee at least a good minimum in all 1D scan )
2647  //----------------------------------------------
2648  if (debug > 0) printf("1D scan of parameter errors \n\n");
2649  double errDef_i[npar] = { 0.5, 1.20, 1.35, 2.40, 3.00, 3.60, 4.20 , 4.75, 5.30 };
2650  for (unsigned int i = 0; i < par.size(); i++) {
2651  if (isFixed[i]) continue;
2652  double rangeX[2], rangeY[2];
2653  double d[2], edm;
2654  bool ok = ScanRange(i, UNDEF, par, parStatus, rangeX, rangeY, d , 0. , errDef_i[ndim - 1], edm);
2655  if (!ok) ok_range = false;
2656  epar[i] = (fabs(d[0]) + fabs(d[1])) / 2.;
2657  if (debug > 0) printf(" ipar=%d %lf (%lf,%lf) edm=%5.2lf ok=%d \n", i, par[i]*unit[i], (par[i] + d[0])*unit[i], (par[i] + d[1])*unit[i], edm, ok);
2658  }
2659  if (!ok_range) return 1;
2660 
2661  // Calculate d_side[i][j]
2662  //----------------------------------------------
2663  double errDef = 1.0;
2664  if (debug > 0) printf("\n\n2D scan of parameter errors \n\n");
2665  recinfo.edm = 0.;
2666  double d_side[par.size()][par.size()][2];
2667  for (unsigned int i = 0; i < par.size(); i++)
2668  for (unsigned int j = 0; j <= i; j++) {
2669  double range_i[2], range_j[2];
2670  if (isFixed[i] || isFixed[j]) {
2671  d_side[i][j][0] = 0.;
2672  d_side[i][j][1] = 0.;
2673  continue;
2674  }
2675  double edm;
2676  bool ok = ScanRange(i, j, par, parStatus, range_i, range_j, d_side[i][j] , (i == j ? 0. : M_PI / 4.) , errDef, edm);
2677  if (!ok) ok_range = false;
2678  if (edm > 0. && edm > recinfo.edm) recinfo.edm = edm;
2679  if (UnivRecNS::debug > 0) {
2680  printf("(i,j)=(%d,%d) ok=%d d=(%lf,%lf) ", i, j, ok, d_side[i][j][0], d_side[i][j][1]);
2681  if (i == j) printf(" (%lf,%lf) \n", (par[i] + d_side[i][i][0])*unit[i], (par[i] + d_side[i][i][1])*unit[i]);
2682  else printf("\n");
2683  if (edm > 0.) printf("Warning %lf \n", edm);
2684  }
2685  }
2686  if (!ok_range) return 1;
2687 
2688  // Approximate d[i][j] as the left/right average
2689  //----------------------------------------------
2690  double d[par.size()][par.size()];
2691  for (unsigned int i = 0; i < par.size(); i++)
2692  for (unsigned int j = 0; j < par.size(); j++) {
2693  if (j <= i) d[i][j] = (fabs(d_side[i][j][0]) + fabs(d_side[i][j][1])) / 2.;
2694  else d[i][j] = (fabs(d_side[j][i][0]) + fabs(d_side[j][i][1])) / 2.;
2695  d[i][j] /= sqrt(errDef * 2.);
2696  if (isFixed[i] || isFixed[j]) continue;
2697  }
2698 
2699  // Covariance matrix
2700  //---------------------
2701 
2702  TMatrixDSym G(ndim);
2703 
2704  int ir = 0;
2705  for (unsigned int i = 0; i < par.size(); i++) {
2706  if (isFixed[i]) continue;
2707  int ic = 0;
2708  for (unsigned int j = 0; j < par.size(); j++) {
2709  if (isFixed[j]) continue;
2710  if (i == j) TMatrixDRow(G, ir)[ic] = 1. / d[i][j] / d[i][j];
2711  else TMatrixDRow(G, ir)[ic] = 1. / d[i][j] / d[i][j] - 1. / d[i][i] / d[i][i] / 2. - 1. / d[j][j] / d[j][j] / 2. ;
2712  ic++;
2713  }
2714  ir++;
2715  }
2716 
2717  // Eigen value analysis
2718  //---------------------
2719  const TMatrixDSymEigen eigen(G);
2720 
2721  TVectorD eigenVal = eigen.GetEigenValues();
2722  double MaxEigenVal = -1.e10, MinEigenVal = 1.e10;
2723  for (int i = 0; i < ndim; i++) {
2724  if (eigenVal[i] < MinEigenVal) MinEigenVal = eigenVal[i];
2725  if (eigenVal[i] > MaxEigenVal) MaxEigenVal = eigenVal[i];
2726  }
2727  recinfo.MinEigenVal = MinEigenVal;
2728  if (UnivRecNS::debug > 0)
2729  printf(" Max/Min eigen value %5.2lf %5.2lf \n", MaxEigenVal, MinEigenVal);
2730 
2731  if (MinEigenVal <= 0.) return 2;
2732 
2733  // Error calculation
2734  //-------------------------------
2735 
2736  TMatrixD ErrMatrix = G;
2737  ErrMatrix.Invert();
2738 
2739  bool ok_errors = true;
2740  for (int i = 0; i < ndim; i++)
2741  if (TMatrixDRow(ErrMatrix, i)[i] < 0.) ok_errors = false;
2742  if (!ok_errors) return 2;
2743 
2744  if (UnivRecNS::debug > 0)
2745  printf(" \n\n Errors : ");
2746  int ii = 0;
2747  for (unsigned int ipar = 0; ipar < par.size(); ipar++) {
2748  if (isFixed[ipar]) epar[ipar] = 0.;
2749  else {
2750  epar[ipar] = sqrt(TMatrixDRow(ErrMatrix, ii)[ii]);
2751  ii++;
2752  }
2753  if (UnivRecNS::debug > 0)
2754  printf(" %5.2lf %5.2lf %5.2lf (%5.2lf) | ", epar[ipar]*unit[ipar], d_side[ipar][ipar][0]*unit[ipar], d_side[ipar][ipar][1]*unit[ipar], epar[ipar]);
2755  }
2756  if (UnivRecNS::debug > 0) printf("\n");
2757 
2758 
2759  // Print
2760  //--------------------------
2761  if (UnivRecNS::debug > 0) {
2762  std::string MatrixName[2] = { " Covariance Matrix", "Error Matrix"};
2763  for (int iloop = 0; iloop < 2; iloop++) {
2764  printf("%s \n", MatrixName[iloop].c_str());
2765  printf("-----------------------------\n");
2766  for (int ir = 0; ir < ndim; ir++) {
2767  for (int ic = 0; ic < ndim; ic++) {
2768  double val = 0.;
2769  if (iloop == 0) val = TMatrixDRow(G, ir)[ic];
2770  if (iloop == 1) val = TMatrixDRow(ErrMatrix, ir)[ic];
2771  printf(" %5.2lf ", val);
2772  }
2773  printf("\n");
2774  }
2775  printf("\n");
2776  }
2777  printf(" FCN calls calculating errors %d Ok=%d \n", ok_range, recinfo.nFCNcalls - nFCNcalls_start);
2778  }
2779 
2780  return 3;
2781 
2782 }
2783 
2784 
2785 
2786 
2787 
2788 
2789 
2790 
2791 
bool SetFitStage(int FitStage)
Definition: UnivRec.cc:2145
UnivParamTimeNS::UnivParamTime * ftime[nDetectorType]
Definition: UnivRec.h:347
float NormalizeAngle(const float angle)
Definition: UnivRec.cc:985
bool ScanRange(int iparX, int iparY, std::vector< double > par, std::vector< int > parStatus, double *rangeX, double *rangeY, double *d, double RotAngle, double errDef, double InitStep, double &edm)
Definition: UnivRec.cc:1596
RecInfo_t recinfo
Definition: UnivRec.h:326
double tquantile[2][nQ]
Definition: UnivRec.h:216
static const int nSys
double quantile[nQ]
Definition: UnivRec.h:216
const bool UseDiffusive[4]
Definition: UnivParam.h:35
bool IsSaturated[nDetectorType]
Definition: UnivRec.h:166
UnivCalibConstantsNS::UnivCalibConstants * fcalib
Definition: UnivRec.h:345
double tq_rec[nQ]
Definition: UnivRec.h:217
double GetLikelihood(std::vector< double > par, std::vector< int > status)
Definition: UnivRec.cc:2514
void InitRecStation(RecStation *station)
Definition: UnivRec.cc:256
double GetMeanNmu(double logE, double theta)
float Get_DX_DL(float r, float psi, float SlantDepth, float theta, float hground, bool UseDL, bool IsDiffusive)
const int debug
Definition: UnivRec.h:29
double tq_pred[nQ]
Definition: UnivRec.h:217
const double ParameterizationRMSLimit
Definition: UnivRec.h:84
AugerRecInfo_t augerinfo
Definition: UnivRec.h:327
const double vemStartCut
Definition: UnivRec.h:94
double tq_rms[nQ]
Definition: UnivRec.h:217
double GetSignalLikelihood()
Definition: UnivRec.cc:2060
void Unrotate(double l_p, double m_p, double &theta, double &azi)
Definition: UnivRec.cc:2457
const double vemTimeCut[nQ]
Definition: UnivRec.h:97
UnivParamNS::UnivParam * fsignal[nDetectorType]
Definition: UnivRec.h:346
double GetD_TO(double X, double theta, double logE, int icomp)
void GetResiduals(std::vector< double > &mean, std::vector< double > &rms, std::vector< double > &rec, int optY, std::vector< double > &fx, int optX, bool OnlyNotSaturated)
Definition: UnivRec.cc:1525
int InitFCNParameters(std::vector< double > &par, std::vector< double > &epar, std::vector< int > &status, std::vector< bool > &hasLimits)
Definition: UnivRec.cc:2333
void PrintRecInfo(bool PrintResiduals)
Definition: UnivRec.cc:1272
const bool XmaxShift_time[4]
Definition: UnivParamTime.h:23
bool GetRecEstimate(int itype)
Definition: UnivRec.cc:1051
const unsigned int npar
Definition: UnivRec.h:75
double tQuantilePDF(double *t0, double *m, double *s, double *fcomp, double vemTot, double ti, double f, bool UseApprox, double pf, double &mean, double &rms)
bool ok(bool okay)
Definition: testlib.cc:89
double pow(const double x, const unsigned int i)
int exit
Definition: dump1090.h:237
void Chi2(int &, double *const , double &value, double *const par, const int)
const double AreaOverPeak_Run[nAoP]
Definition: UnivRec.h:57
unsigned int GPSsec
Definition: UnivRec.h:342
const double rStartCut[2]
Definition: UnivRec.h:93
double GetSignal(double r, double XmaxEdep, double logE, double theta, double psi, double rhoGround, double hGround, double Nmu, int icomp0, int iatm)
Definition: UnivParam.cc:202
float GetTimeCF_h(float r, float psi, float h1, float theta, float hground)
const double high[npar]
Definition: UnivRec.h:78
A TimeStamp holds GPS second and nanosecond for some event.
Definition: TimeStamp.h:110
static const int nRecMixtures
double OffsetM_Mu_err
Definition: UnivRec.h:140
const double MDwidth
Definition: UnivRec.h:49
bool UseGausPDF_quantiles[nQ]
Definition: UnivRec.h:218
AtmosphereNS::Atmosphere * fatm
Definition: UnivRec.h:348
void SetAllSPCoordinates()
Definition: UnivRec.cc:1039
double ygcore_err
Definition: UnivRec.h:123
const bool XmaxShift[4]
Definition: UnivParam.h:34
void ClearRecEvent()
Definition: UnivRec.cc:307
const double rSignalCut[2]
Definition: UnivRec.h:100
void GetRecSeed(int itype)
Definition: UnivRec.cc:1227
float DistPoints(float x1, float y1, float x2, float y2)
Definition: UnivRec.cc:979
MCInfo_t MCinfo
Definition: UnivRec.h:328
const double SaturationLevelMD
Definition: UnivRec.h:64
const double SmearingAngle
Definition: UnivRec.h:58
bool RWRecinfo(FILE *fp, bool RWStations, bool readFlag)
Definition: UnivRec.cc:1394
void SetSPCoordinates(int idet)
Definition: UnivRec.cc:994
const int nTimeStationsMin
Definition: UnivRec.h:108
void ScanLikelihood(int iparX, int iparY, int N, std::vector< std::pair< double, double > > &parXY, std::vector< double > &lnP, std::pair< double, double > &parXY_min, double &lnP_min)
Definition: UnivRec.cc:1741
double TimeMaxdev[2]
Definition: UnivRec.h:160
double GetTimeLikelihood()
Definition: UnivRec.cc:1895
double tStartCorrection(double r, double logE, double theta, bool Is8nsFADC)
void SaveFCNParameters(std::vector< double > par, std::vector< int > status)
Definition: UnivRec.cc:2413
bool gRecSDE_Upgrade
Definition: UnivRec.h:332
const double SaturationLevelVEM_WCD[2]
Definition: UnivRec.h:61
double signalsize_pred
Definition: UnivRec.h:229
double theta_ref
Definition: UnivRec.h:138
bool Check_DX_DL(RecStation *)
Definition: UnivRec.cc:2134
bool InitRec_InternalFramework(bool RecInfill, int RecDataSet, int year, std::string &FileName, bool RecSDEUpgrade, int RecAoP)
Definition: UnivRec.cc:207
const double nMD
Definition: UnivRec.h:47
std::vector< RecStation_t > fstation
Definition: UnivRec.h:324
void SetT0FromHot(bool UseT0_relative, double T0_relative)
Definition: UnivRec.cc:2474
const double StartAccuracyAMIGA
Definition: UnivRec.h:86
const double StartAccuracy[2]
Definition: UnivRec.h:85
int GetErrors(std::vector< double > par, std::vector< double > &epar, std::vector< int > parStatus)
Definition: UnivRec.cc:2629
double TimeRejected[2]
Definition: UnivRec.h:159
if(dataRoot)
Definition: XXMLManager.h:1003
double RFunc(double r, int icomp, int iparDX)
Definition: UnivParam.cc:87
const bool UseDL[4]
Definition: UnivParam.h:36
double GetLogE(double vem, double r, double XmaxEdep, double theta, double psi, double rhoGround, double hGround, double Nmu, int iatm)
Definition: UnivParam.cc:267
void GetChi2(double *Chi2, int *nChi2)
Definition: UnivRec.cc:1489
void GetMeanRMS_AoP(double &mean, double &rms)
Definition: UnivRec.cc:1568
const bool UseDiffusive_time[4]
Definition: UnivParamTime.h:24
const double edm_tolerance
Definition: UnivRec.h:81
const double unit[npar]
Definition: UnivRec.h:76
const bool UseStartTimeOnlyWhenSaturated
Definition: UnivRec.h:92
static const double fXmaxSys_Auger[nSys]
const double low[npar]
Definition: UnivRec.h:77
bool gDetectorTypeMask[nDetectorType]
Definition: UnivRec.h:335
const double rQuantileCut[2]
Definition: UnivRec.h:96
rtlsdr_dev_t * dev
Definition: dump1090.h:243
double AugerDensity
Definition: UnivRec.h:119
float GetTimePF_h(float r, float psi, float hStart, float theta, float hground)
const int nSignalStationsMin
Definition: UnivRec.h:109
double tFirstPDF(double t0_mu, double m_mu, double s_mu, double npart, double t, bool UseApprox, double &mean, double &rms)
#define UNDEF
Definition: UnivRec.h:24
double OffsetM_Mu
Definition: UnivRec.h:140
const double vemSignalCut
Definition: UnivRec.h:101
bool InitRec(bool IsData, int RecType, int CalibOpt, int RecDetector, int RecSys, int RecMixture)
Definition: UnivRec.cc:127
static std::vector< int > parStatus
bool RejectTimeOutliers()
Definition: UnivRec.cc:2277
int FitStatus[2]
Definition: UnivRec.h:144
bool InitRecParameters()
Definition: UnivRec.cc:892
double lnP[3]
Definition: UnivRec.h:147
const double tankh
Definition: UnivRec.h:38
double GetTime(double *DL, double r, double logE, double psi, double theta, double *fcomp, double *t0, double fi)
double logE_ref_err
Definition: UnivRec.h:137
bool PlaneFit(bool CurvCorr, bool AltitudeCorr, bool RecSeed, int itype)
Definition: UnivRec.cc:1095
const double InterGPSAccuracy[2]
Definition: UnivRec.h:83
double tQuantileCorrection_AoP(double RiseTime, int iq, double AoP)
constexpr double m
Definition: AugerUnits.h:121
bool StationSelection()
Definition: UnivRec.cc:2162
TVector3 theDir_Ref
Definition: UnivRec.h:153
void WriteTextFile(FILE *fp)
double tq_corr[nQ]
Definition: UnivRec.h:217
double tQuantileCorrection(double NanoSecPerVEM, int iq)
static const double fEnergySys_Auger[nSys]
double xgcore_err
Definition: UnivRec.h:122
const int nQ
Definition: UnivRec.h:70
const double MDlength
Definition: UnivRec.h:48
const double tankr
Definition: UnivRec.h:39
const double lnP_inf
Definition: UnivRec.h:71
const double SaturationLevelVEM_Scin[2]
Definition: UnivRec.h:62
const double year
Definition: GalacticUnits.h:22
bool CheckEnergyCut(bool PrintOut)
Definition: UnivRec.cc:1872
const bool UseDL_time[4]
Definition: UnivParamTime.h:25

, generated on Tue Sep 26 2023.