UnivParamTime.cc
Go to the documentation of this file.
1 #include <stdio.h>
2 #include <stdlib.h>
3 #include <fstream>
4 
5 #include "UnivParamTime.h"
6 #include <Math/PdfFuncMathCore.h>
7 #include <Math/ProbFuncMathCore.h>
8 #include <Math/QuantFuncMathCore.h>
9 #include "UnivParamTimeConfig.h"
10 #include <tls/Atmosphere.h>
11 
12 using namespace UnivParamTimeNS;
13 
15 {
16 
17  if (DetectorType < 0 || DetectorType > 2) {
18  printf("UnivParamTime: Wrong Detector Type %d \n", DetectorType);
19  exit(1);
20  }
21  fDetectorType = DetectorType;
22  fOffsetM_Mu = 0.;
23  fUseThetaInterpolation = false;
24 
25  // Read (m,s) table
26  {
27  std::string DAT = DATA_DIR; // from UnivParamTimeConfig.h
28  DAT += "/";
29  if (DetectorType == 0) DAT += "TimeModel-WCD.dat";
30  else if (DetectorType == 1) DAT += "TimeModel-Scin.dat";
31  else if (DetectorType == 2) DAT += "TimeModel-MD.dat";
32 
33  FILE* fp = fopen(DAT.c_str(), "r");
34 
35  int ok = fscanf(fp, "%d %d %d %d %lf %lf ", &ith_min, &ith_max, &ir_min, &ir_max, &logE_ref, &Xmax_ref);
36  if (ok != 6) {
37  printf("ERROR Reading UnivParamTime parameters\n");
38  exit(1);
39  }
40  if (ir_min < 0 || ir_min >= nParDist || ir_min > ir_max || ir_max < 0 || ir_max >= nParDist ||
41  ith_min < 0 || ith_min >= nParTheta || ith_min > ith_max || ith_max < 0 || ith_max >= nParTheta) {
42  printf("ERROR Reading UnivParamTime parameters\n");
43  exit(1);
44  }
45 
46 
47  for (int icomp = 0; icomp < 4; icomp++)
48  for (int iMS = 0; iMS < 2; iMS++)
49  for (int ir = 0; ir < nParDist; ir++) {
50  if (icomp > 0 && DetectorType == 2) continue;
51 
52  int nread = fscanf(fp, "%lf %lf %lf %lf ", &TimeModelPar_Stage1[icomp][ir][iMS][0], &TimeModelPar_Stage1[icomp][ir][iMS][1],
53  &TimeModelPar_Stage1[icomp][ir][iMS][2], &TimeModelPar_Stage1[icomp][ir][iMS][3]);
54  if (nread != nPar_Stage1) {
55  printf("Error reading parameters 1 %d \n", nread);
56  exit(1);
57  }
58 
59 
60  nread = fscanf(fp, "%lf %lf %lf %lf %lf %lf ",
61  &TimeModelPar_Stage2_Theta[icomp][ir][iMS][0][0], &TimeModelPar_Stage2_Theta[icomp][ir][iMS][0][1],
62  &TimeModelPar_Stage2_Theta[icomp][ir][iMS][1][0], &TimeModelPar_Stage2_Theta[icomp][ir][iMS][1][1],
63  &TimeModelPar_Stage2_Theta[icomp][ir][iMS][2][0], &TimeModelPar_Stage2_Theta[icomp][ir][iMS][2][1]);
64  if (nread != (nPar_Stage2 * nPar_Stage2_Theta)) {
65  printf("Error reading parameters 1 %d \n", nread);
66  exit(1);
67  }
68 
69  for (int ith = 0; ith < nParTheta; ith++) {
70  int nread = fscanf(fp, "%lf %lf %lf ", &TimeModelPar_Stage2[icomp][ir][ith][iMS][0], &TimeModelPar_Stage2[icomp][ir][ith][iMS][1],
71  &TimeModelPar_Stage2[icomp][ir][ith][iMS][2]);
72  if (nread != nPar_Stage2) {
73  printf("Error reading parameters 2 %d\n", nread);
74  exit(1);
75  }
76 
77  nread = fscanf(fp, "%lf %lf %lf ", &eTimeModelPar_Stage2[icomp][ir][ith][iMS][0], &eTimeModelPar_Stage2[icomp][ir][ith][iMS][1],
78  &eTimeModelPar_Stage2[icomp][ir][ith][iMS][2]);
79  if (nread != nPar_Stage2) {
80  printf("Error reading parameters 3 %d \n", nread);
81  exit(1);
82  }
83  }
84  }
85  fclose(fp);
86  }
87 
88  // Read Binomial normalization
89  {
90  std::string DAT = DATA_DIR; // from UnivParamTimeConfig.h
91  DAT += "/";
92  DAT += "Binomial.norm";
93 
94  FILE* f = fopen(DAT.c_str(), "r");
95  int iN, ifrac;
96  double N, frac, val;
97  double fq[3] = {0., 0., 0.};
98  while (fscanf(f, "%d %d %lf %lf %lf %lf %lf %lf", &iN, &ifrac, &N, &frac, &val, &fq[0], &fq[1], &fq[2]) != EOF) {
99  if (iN < 0 || iN > 199 || ifrac < 0 || ifrac > 98) {
100  printf("Error reading Binomial coefficients \n");
101  exit(1);
102  }
103  BinomialNorm[iN][ifrac] = val;
104  Binomial_q[iN][ifrac][0] = fq[0];
105  Binomial_q[iN][ifrac][1] = fq[1];
106  Binomial_q[iN][ifrac][2] = fq[2];
107  }
108  fclose(f);
109  }
110 }
111 
112 
113 
114 double UnivParamTime::GetMS_ir_ith(double DL, double logE, int ith, int ir, double psi , int icomp, int iMS)
115 {
116  double r = TimeModelParDist[ir];
117  double theta = TimeModelParTheta[ith];
118 
119  double* par_stage1 = TimeModelPar_Stage1[icomp][ir][iMS];
120  double* par_stage2 = TimeModelPar_Stage2[icomp][ir][ith][iMS];
121 
122  return GetMS(DL, logE, theta, r, psi , icomp, iMS, par_stage1, par_stage2);
123 }
124 
125 
126 double UnivParamTime::GetMS_ir(double DL, double logE, double theta, int ir, double psi , int icomp, int iMS)
127 {
128  double r = TimeModelParDist[ir];
129  double theta_deg = theta * 180. / M_PI;
130  if (theta_deg < theta_Low) theta_deg = theta_Low ;
131  if (theta_deg > theta_High) theta_deg = theta_High;
132 
133  double* par_stage1 = TimeModelPar_Stage1[icomp][ir][iMS];
134  double par_stage2[nPar_Stage2];
135 
136  for (int ipar = 0; ipar < nPar_Stage2; ipar++) {
137  double A = TimeModelPar_Stage2_Theta[icomp][ir][iMS][ipar][0];
138  double B = TimeModelPar_Stage2_Theta[icomp][ir][iMS][ipar][1];
139 
140  if (ipar > 0) par_stage2[ipar] = sin(theta_deg * M_PI / 180. / B) * A;
141  else par_stage2[ipar] = A + (B - A) * theta_deg / 60.;
142  }
143 
144  return GetMS(DL, logE, theta, r, psi , icomp, iMS, par_stage1, par_stage2);
145 
146 }
147 
148 
149 double
150 UnivParamTime::GetMS(double DL, double logE, double theta, double r, double psi , int icomp, int /*iMS*/, double* par_stage1, double* par_stage2)
151 {
152  double ms0 = par_stage1[0];
153  double ms1 = par_stage1[1];
154  double ms2 = par_stage1[2];
155  double ms_logE = par_stage1[3];
156 
157  double ms_slope = par_stage2[0];
158  double ms_psi_down = par_stage2[1];
159  double ms_psi_up = par_stage2[2];
160 
161  // DL dependence at Xmax=Xmax_ref using psi=90 [deg] and different zenith angles
162  double val;
163 
164  double val0 = ms0;
165  double val1 = ms0 - ms1;
166  double B = ms2;
167 
168  double C = (val1 - val0) / (exp(-B) - 1.0);
169  double A = val0 - C;
170 
171  val = A + C * exp(-B * DL / 1000.);
172 
173  // Local modification of the DL dependence for psi=90 [deg]
175  double DL_ref = fatm.Get_DX_DL(r, psi, Xmax_ref , theta, AtmosphereNS::hGroundRef,
176  UnivParamTimeNS::UseDL_time[icomp], UnivParamTimeNS::UseDiffusive_time[icomp]); //Avg over the 12 atmospheres
177  val += ms_slope * (DL - DL_ref) / 1000.;
178 
179  // Psi modulation
180  double ms_psi = (cos(psi) > 0. ? ms_psi_up * cos(psi) : ms_psi_down * cos(psi));
181  val += ms_psi;
182 
183  //Energy depedence
184  val += ((logE - logE_ref) * ms_logE);
185 
186  return val;
187 }
188 
189 
190 double UnivParamTime::interpol(double v1, double v2, double x1, double x2, double x)
191 {
192  if (x1 == x2) return v1;
193  return v1 + (v2 - v1) * (x - x1) / (x2 - x1);
194 }
195 
196 
197 double UnivParamTime::GetMS(double DL, double logE, double theta, double r, double psi , int icomp, int iMS)
198 {
199  if (r < r_Low) r = r_Low;
200  if (r > r_High) r = r_High;
201  if (logE < logE_Low) logE = logE_Low;
202  if (logE > logE_High) logE = logE_High;
203 
204  double val = 0.;
205 
206  //--------
207  int ir1 = 0, ir2 = 0;
208  int ir_max_c = ir_max;
209  if (fUseThetaInterpolation && (icomp == 1 || icomp == 3) && theta > 55.*M_PI / 180. && ir_max >= 5) ir_max_c = 5; // WARNING : exception
210 
211  if (r >= TimeModelParDist[ir_max_c]) {
212  ir1 = ir_max_c - 1;
213  ir2 = ir_max_c;
214  } else if (r <= TimeModelParDist[ir_min + 1]) {
215  ir1 = ir_min;
216  ir2 = ir_min + 1;
217  } else {
218  ir1 = ir_min;
219  while (r > TimeModelParDist[ir2]) ir2++;
220  ir1 = ir2 - 1;
221  }
222 
223  //-------------------------------
224  //--- Interpolation in (r,theta)
225  //-------------------------------
227  int ith1 = 0, ith2 = 0;
228  if (theta >= TimeModelParTheta[ith_max]) {
229  ith1 = ith_max - 1;
230  ith2 = ith_max;
231  } else if (r <= TimeModelParTheta[ith_min + 1]) {
232  ith1 = ith_min;
233  ith2 = ith_min + 1;
234  } else {
235  ith1 = ith_min;
236  while (theta > TimeModelParTheta[ith2]) ith2++;
237  ith1 = ith2 - 1;
238  }
239 
240  double val_ith1[2] = { GetMS_ir_ith(DL, logE, ith1, ir1, psi , icomp, iMS), GetMS_ir_ith(DL, logE, ith1, ir2, psi , icomp, iMS) };
241  double val0 = interpol(val_ith1[0], val_ith1[1], TimeModelParDist[ir1], TimeModelParDist[ir2], r);
242 
243  double val_ith2[2] = { GetMS_ir_ith(DL, logE, ith2, ir1, psi , icomp, iMS), GetMS_ir_ith(DL, logE, ith2, ir2, psi , icomp, iMS) };
244  double val1 = interpol(val_ith2[0], val_ith2[1], TimeModelParDist[ir1], TimeModelParDist[ir2], r);
245 
246  val = interpol(val0, val1, sin(TimeModelParTheta[ith1]), sin(TimeModelParTheta[ith2]), sin(theta));
247  }
248  //-------------------------------
249  //--- Interpolation in r
250  //-------------------------------
251  else {
252  double val_i[2] = { GetMS_ir(DL, logE, theta, ir1, psi , icomp, iMS), GetMS_ir(DL, logE, theta, ir2, psi , icomp, iMS) };
253  val = interpol(val_i[0], val_i[1], TimeModelParDist[ir1], TimeModelParDist[ir2], r);
254  }
255 
256 
257  //--- Offset in <m> for Muon/Em Muon component
258  if (iMS == 0) val += GetOffsetM_r(r, icomp);
259 
260  if (val < ms_minVal) val = ms_minVal;
261 
262  return val;
263 
264 }
265 
266 
267 bool UnivParamTime::GetShapeParameters(double* DL, double r, double logE, double psi, double theta, double* m, double* s)
268 {
269  for (int iMS = 0; iMS < 2; iMS++)
270  for (int icomp = 0; icomp < 4; icomp++) {
271  double val = GetMS(DL[icomp], logE, theta, r , psi, icomp, iMS);
272  if (iMS == 0) m[icomp] = val;
273  else s[icomp] = val;
274  }
275  return true;
276 }
277 
278 
279 
280 //------------------------------------------------------------------
281 //---- CDF/PDF
282 //------------------------------------------------------------------
283 
284 
285 double UnivParamTime::GetFraction(double* t0, double* m, double* s, double* fcomp, double ti, bool isCDF)
286 {
287  double frac = 0., sum = 0.;
288  bool ok = true;
289  for (int icomp = 0; icomp < 4; icomp++) {
290  if (fcomp[icomp] < 0.) {
291  ok = false;
292  continue;
293  }
294  if (fcomp[icomp] > 0. && (m[icomp] <= 0. || s[icomp] <= 0.)) {
295  ok = false;
296  continue;
297  }
298  sum += fcomp[icomp];
299  }
300  if (sum == 0. || !ok) return UNDEF;
301 
302  for (int icomp = 0; icomp < 4; icomp++) {
303  if (fcomp[icomp] == 0.) continue;
304  if (ti < t0[icomp]) continue;
305 
306  double frac_i;
307  if (isCDF) frac_i = ROOT::Math::lognormal_cdf(ti - t0[icomp], m[icomp], s[icomp]) * (fcomp[icomp] / sum);
308  else frac_i = ROOT::Math::lognormal_pdf(ti - t0[icomp], m[icomp], s[icomp]) * (fcomp[icomp] / sum);
309  frac += frac_i;
310  }
311  return frac;
312 }
313 
314 double UnivParamTime::GetFraction(double* DL, double r , double logE, double psi, double theta, double* fcomp, double* t0, double ti, bool isCDF)
315 {
316 
317  double m[4], s[4];
318  bool ok = GetShapeParameters(DL, r, logE, psi, theta, m, s);
319  if (!ok) return UNDEF;
320 
321  return GetFraction(t0 , m, s, fcomp, ti, isCDF);
322 }
323 
324 //-------
325 
326 double UnivParamTime::GetCDF(double* t0, double* m, double* s, double* fcomp, double ti)
327 {
328  return GetFraction(t0, m, s, fcomp, ti, true);
329 }
330 
331 double UnivParamTime::GetCDF(double* DL, double r , double logE, double psi, double theta, double* fcomp, double* t0, double ti)
332 {
333  return GetFraction(DL, r, logE, psi, theta, fcomp, t0, ti, true);
334 }
335 
336 //-------
337 
338 double UnivParamTime::GetPDF(double* t0, double* m, double* s, double* fcomp, double ti)
339 {
340  return GetFraction(t0, m, s, fcomp, ti, false);
341 }
342 double UnivParamTime::GetPDF(double* DL, double r , double logE, double psi, double theta, double* fcomp, double* t0, double ti)
343 {
344  return GetFraction(DL, r, logE, psi, theta, fcomp, t0, ti, false);
345 }
346 
347 //------------------------------------------------------------------
348 //---- Time quantiles
349 //------------------------------------------------------------------
350 
351 double UnivParamTime::GetTime(double* DL, double r , double logE, double psi, double theta, double* fcomp, double* t0, double fi)
352 {
353  double m[4], s[4];
354 
355  bool ok = true;
356  for (int icomp = 0; icomp < 4; icomp++)
357  if (isnan(DL[icomp]) || isinf(DL[icomp]) || isnan(fcomp[icomp]) || isinf(fcomp[icomp]) || isnan(t0[icomp]) || isinf(t0[icomp]) || isnan(fi)) ok = false;
358  if (!ok) return 0.;
359  ok = GetShapeParameters(DL, r, logE, psi, theta, m, s);
360  if (!ok) return 0.;
361 
362  return GetTime(t0 , m, s, fcomp, fi);
363 }
364 
365 
366 double UnivParamTime::GetTime(double* t0, double* m, double* s, double* fcomp, double fi)
367 {
368  // NOTE: the standard algorithm would be to increase in one direction with a fixed step and once the
369  // we are over the desire fraction, go back and decrease the step and continue upwards.
370  // However, as it is it seems to be faster
371 
372  bool ok = true;
373  for (int icomp = 0; icomp < 4; icomp++)
374  if (isnan(t0[icomp]) || isinf(t0[icomp]) || isnan(m[icomp]) || isinf(m[icomp]) || isnan(s[icomp]) || isinf(s[icomp]) || isnan(fi)
375  || isnan(fcomp[icomp]) || isinf(fcomp[icomp]) || fi < 0 || fi > 1.) ok = false;
376  if (!ok) return 0.;
377 
378 
379  double Tolerance = 1.e-8;
380 
381  //----
382 
383  double tmin = 1.e10, tmax = 0.;
384  for (int icomp = 0; icomp < 4; icomp++) {
385  if (fcomp[icomp] == 0.) continue;
386 
387  double tmin_i = t0[icomp];
388  double tmax_i = t0[icomp] + exp(m[icomp] + 5.*s[icomp]);
389 
390  if (tmin > tmin_i) tmin = tmin_i;
391  if (tmax < tmax_i) tmax = tmax_i;
392  }
393  if (tmin < 1.e-3) tmin = 1.e-3;
394 
395  //-----
396 
397  double xmin = log(tmin);
398  double xmax = log(tmax);
399 
400  double fmin = GetCDF(t0 , m, s, fcomp, exp(xmin));
401  double fmax = GetCDF(t0 , m, s, fcomp, exp(xmax));
402 
403  if (fmin >= fi) return exp(xmin);
404  if (fmax <= fi) return exp(xmax);
405 
406  double x = (xmin + xmax) / 2.;
407  double step = (xmax - xmin) / 2.;
408  double sign = 1.;
409  int iter = 0;
410  const int nIterMax = 1000;
411  while (true) {
412  double frac = GetCDF(t0 , m, s, fcomp, exp(x));
413  if (fabs(frac - fi) < Tolerance) {
414  double a[2] = {x, x + sign * step};
415  double b[2] = {frac, GetCDF(t0 , m, s, fcomp, exp(x + sign * step))};
416  x = a[0] + (a[1] - a[0]) / (b[1] - b[0]) * (fi - b[0]);
417  break;
418  }
419  step /= 2.;
420  if (frac > fi) {
421  sign = -1.;
422  x -= step;
423  } else {
424  sign = 1.;
425  x += step;
426  }
427  iter++;
428  if (iter > nIterMax) break;
429  }
430 
431  if (iter > nIterMax) {
432  printf("ERROR: time quantile could not be calculated tq=%lf fi=%lf (%lf) | %lf %lf \n", exp(x), fi, GetCDF(t0 , m, s, fcomp, exp(x)), fmin, fmax);
433  printf(" t0=(%lf,%lf,%lf,%lf) m=(%lf,%lf,%lf,%lf) s=(%lf,%lf,%lf,%lf) fcomp=(%lf,%lf,%lf,%lf) \n",
434  t0[0], t0[1], t0[2], t0[3],
435  m[0], m[1], m[2], m[3],
436  s[0], s[1], s[2], s[3],
437  fcomp[0], fcomp[1], fcomp[2], fcomp[3]);
438  return 0.;
439  }
440  if (isnan(x) || isinf(x)) return 0.;
441 
442  return exp(x);
443 }
444 
445 
446 //------------------------------------------------------------------
447 //---- Time quantile PDF
448 // Use f=0.01,0.02,...0.99
449 // The model is only valid for integer (npart,N)
450 //------------------------------------------------------------------
451 
452 double UnivParamTime::GetPoissonFactor(double fem, double f)
453 {
454  if (fDetectorType == 2) return 1.;
455 
456  if (fem < 0.) fem = 0.;
457  if (fem > 1.) fem = 1.;
458 
459  // double A = 0.15;
460  double B = 0.93;
461  B = 1. + (f - 0.5);
462  double pf = 1. + B * pow(fem / 0.5, 2.);
463  if (pf < 1.) pf = 1.;
464 
465  return pf;
466 }
467 
468 double UnivParamTime::tQuantilePDF(double* t0, double* m, double* s, double* fcomp, double vemTot, double ti, double f,
469  bool UseApprox, double pf, double& mean, double& rms)
470 {
471  double pdf = 1.e-100;
472  mean = UNDEF;
473  rms = UNDEF;
474  double N = vemTot * pf;
475  if (isnan(N)) return pdf;
476 
477  //----------------------------------------------------------------
478  // Approximation (so mean/rms can be calculated)
479  //----------------------------------------------------------------
480 
481  // Quantiles of P(fi)
482  double fq[3];
483  QuantilePDF(N , -100. , f, fq);
484 
485  // Quantiles of P(ti)
486  double tq[3];
487  for (int iq = 0; iq < 3; iq++)
488  tq[iq] = GetTime(t0, m, s, fcomp, fq[iq]);
489 
490  const double ndev = 1.28156;
491  // Normal approximation
492  if ((tq[2] - tq[1]) < (tq[1] - tq[0])) {
493  mean = tq[1];
494  rms = (tq[1] - tq[0]) / ndev;
495  if (UseApprox) pdf = ROOT::Math::normal_pdf(ti, rms, mean);
496  }
497  // Log normal
498  else {
499  double t0_i = tq[1] - (tq[2] - tq[1]) * (tq[1] - tq[0]) / (tq[2] + tq[0] - 2.*tq[1]);
500  double m_i = log(tq[1] - t0_i);
501  double s_i = (log(tq[1] - t0_i) - log(tq[0] - t0_i)) / ndev;
502 
503  mean = exp(m_i + s_i * s_i / 2.) + t0_i;
504  rms = sqrt(exp(s_i * s_i + 2.*m_i) * (exp(s_i * s_i) - 1.));
505 
506  if (UseApprox && ti > t0_i) pdf = ROOT::Math::lognormal_pdf(ti - t0_i, m_i, s_i);
507  }
508 
509  //----------------------------------------------------------------
510  //
511  //----------------------------------------------------------------
512  if (!UseApprox) {
513  double fi = GetCDF(t0, m, s, fcomp, ti);
514  if (fi > 0.) {
515  double derivative = (fi - GetCDF(t0, m, s, fcomp, ti * 0.99)) / ti / 0.01;
516  pdf = QuantilePDF(N, fi, f);
517  pdf *= derivative;
518  }
519  }
520 
521  return pdf;
522 }
523 
524 double UnivParamTime::tQuantilePDF(double* t0, double* m, double* s, double* fcomp, double vemTot, double ti, double f,
525  bool UseApprox, double& mean, double& rms)
526 {
527  double fem0 = fcomp[1] / (fcomp[0] + fcomp[1] + fcomp[2] + fcomp[3]);
528  double pf = GetPoissonFactor(fem0, f);
529  return tQuantilePDF(t0, m, s, fcomp, vemTot, ti, f, UseApprox, pf, mean, rms);
530 }
531 
532 double UnivParamTime::tQuantilePDF(double* DL, double r, double logE, double psi, double theta, double* fcomp, double* t0, double vemTot, double ti, double f,
533  bool UseApprox, double& mean, double& rms)
534 {
535  mean = 0., rms = 0.;
536  double m[4], s[4];
537  bool ok = GetShapeParameters(DL, r, logE, psi, theta, m, s);
538  if (!ok) return UNDEF;
539 
540  double pdf = tQuantilePDF(t0, m, s, fcomp, vemTot, ti, f, UseApprox, mean, rms);
541  return pdf;
542 }
543 
544 
545 //----------------------------------------
546 
547 double UnivParamTime::GetBinomialNorm(double N, double f , double* fq)
548 {
549  double stepN = log10(40000. / 100.) / 100.;
550 
551 
552  // iN=0,......,98 | 99,....., 199
553  // N=1,......,99 | 100, , 40000
554  double N1, N2;
555  int iN;
556  if (N < 99.5) {
557  iN = int(N) - 1;
558  if (iN < 0) iN = 0;
559  N1 = double(iN + 1);
560  N2 = double(iN + 2);
561  } else {
562  iN = int(log10(N / 100.) / stepN + 0.5);
563  if (iN > 99) iN = 99;
564  N1 = pow(10., double(iN) * stepN + 2.);
565  N2 = pow(10., double(iN + 1) * stepN + 2.);
566  iN += 99;
567  }
568 
569 
570  // (ifrac)
571  f = double(int(f * 100)) / 100.;
572  double stepFrac = 0.01;
573  int ifrac = int((f - stepFrac) / stepFrac + 0.5);
574  if (ifrac < 0) ifrac = 0;
575  if (ifrac > 98) ifrac = 98;
576 
577  double norm = interpol(BinomialNorm[iN][ifrac], BinomialNorm[iN + 1][ifrac], N1, N2, N);
578  for (int iq = 0; iq < 3; iq++)
579  fq[iq] = interpol(Binomial_q[iN][ifrac][iq], Binomial_q[iN + 1][ifrac][iq], N1, N2, N);
580 
581  return norm;
582 }
583 
584 
585 double UnivParamTime::QuantilePDF(double N , double fi, double f)
586 {
587  double fq[3] = {0., 0., 0.};
588  return QuantilePDF(N, fi, f, fq);
589 }
590 
591 
592 double UnivParamTime::QuantilePDF(double N , double fi, double f, double* fq)
593 {
594  // Do not extrapolate
595  if (N > 40000.) N = 40000.;
596 
597  // Change N if ipos<0 so <f> is reproduced.
598  if (f * (N + 1) - 1 < 0.) N = 1. / f - 1.;
599  double ipos = f * (N + 1) - 1;
600 
601  double norm = GetBinomialNorm(N, f, fq);
602 
603  if (fi < 0. || fi > 1.) return 0.;
604 
605  double logval = (N - ipos - 1) * log((1. - fi) / (1. - f)) + (ipos) * log(fi / f);
606  double val = logval - log(norm);
607  if (val < -100.) val = -100.;
608  return exp(val);
609 }
610 
611 //------------------------------------------------------------------
612 //---- PDF of first particle time
613 //------------------------------------------------------------------
614 
615 double UnivParamTime::tFirstPDF(double DL_mu, double r, double logE, double psi, double theta, double t0_mu, double npart, double t)
616 {
617  double mean = 0., rms = 0.;
618  return tFirstPDF(DL_mu, r, logE, psi, theta, t0_mu, npart, t, false, mean, rms);
619 }
620 
621 double UnivParamTime::tFirstPDF(double DL_mu, double r, double logE, double psi, double theta, double t0_mu, double npart, double t,
622  bool UseApprox, double& mean, double& rms)
623 {
624  mean = 0., rms = 0.;
625 
626  int icomp = 0;
627  double m_mu = GetMS(DL_mu, logE, theta, r , psi, icomp, 0);
628  double s_mu = GetMS(DL_mu, logE, theta, r, psi, icomp, 1);
629 
630  if (npart <= 1.) npart = 1.;
631  double prob = tFirstPDF(t0_mu, m_mu, s_mu, npart, t, UseApprox, mean, rms);
632 
633  return prob;
634 }
635 
636 double UnivParamTime::tFirstPDF(double t0_mu, double m_mu, double s_mu, double npart, double ti, bool UseApprox, double& mean, double& rms)
637 {
638  double t0[4] = {t0_mu, 0., 0., 0.};
639  double m[4] = {m_mu, 0., 0., 0.};
640  double s[4] = {s_mu, 0., 0., 0.};
641  double fcomp[4] = {1., 0., 0., 0.};
642 
643  double tFirstPDF = 1.e-100;
644  mean = UNDEF;
645  rms = UNDEF;
646 
647  //----------------------------------------------------------------
648  // Approximation (so mean/rms can be calculated)
649  //----------------------------------------------------------------
650 
651  //-----
652  double q1[3] = {0.1, 0.5, 0.9};
653  double t1[3];
654  for (int i = 0; i < 3; i++) {
655  double q = 1. - pow(1. - q1[i], 1. / npart);
656  t1[i] = GetTime(t0, m, s, fcomp, q);
657  }
658 
659  //-----
660 
661  const double ndev = 1.28156;
662  // Normal
663  if ((t1[2] - t1[1]) < (t1[1] - t1[0])) {
664  mean = t1[1];
665  rms = (t1[1] - t1[0]) / ndev;
666  if (UseApprox) tFirstPDF = ROOT::Math::normal_pdf(ti, rms, mean);
667  }
668  // Log normal
669  else {
670  double t0_i = t1[1] - (t1[2] - t1[1]) * (t1[1] - t1[0]) / (t1[2] + t1[0] - 2.*t1[1]);
671  double m_i = log(t1[1] - t0_i);
672  double s_i = (log(t1[1] - t0_i) - log(t1[0] - t0_i)) / ndev;
673 
674  mean = exp(m_i + s_i * s_i / 2.) + t0_i;
675  rms = sqrt(exp(s_i * s_i + 2.*m_i) * (exp(s_i * s_i) - 1.));
676  if (UseApprox && ti > t0_i) tFirstPDF = ROOT::Math::lognormal_pdf(ti - t0_i, m_i, s_i);
677  }
678 
679 
680  //----------------------------------------------------------------
681  //
682  //----------------------------------------------------------------
683  if (!UseApprox && ti > t0[0]) {
684  double cdf = GetCDF(t0, m, s, fcomp, ti);
685  double pdf = GetPDF(t0, m, s, fcomp, ti);
686  tFirstPDF = npart * pow((1 - cdf), npart - 1) * pdf;
687  }
688 
689  return tFirstPDF;
690 
691 }
692 
693 
694 //---------------------------------------------------------------------------------------------------------------------------------
695 //---------------------------------------------------------------------------------------------------------------------------------
696 //---------------------------------------------------------------------------------------------------------------------------------
697 //
698 // [iq] = [0] T1vem [1] T10 [2] T50
699 //
700 
701 //----- Corrections due failure of : (a) Log normal ansatz (b) Time variance model shifts (c) Discrete pulse effects
702 //---- This quantity must be substracted to the reconstructed quantile
703 // From MultiShower/time-corrections.cc
704 // [NanoSecPerVEM] = (T50-T10)/vem/0.4 [ns]/[vem]
705 double UnivParamTime::tQuantileCorrection(double NanoSecPerVEM, int iq)
706 {
707  if (fDetectorType == 2) return 0.;
708  if (iq < 0 || iq > 2) return 0.;
709 
710  double A[3] = {150.0, 70.0, 0.0};
711  double corr = A[iq] * NanoSecPerVEM / 200.;
712 
713  return corr;
714 }
715 
716 //---------------------------------------------------------------------------------------------------------------------------------
717 //---- This quantity should be substracted to the reconstructed start time
718 // Valid only r<1000 [m].
719 // From MultiShower/time-corrections.cc
720 //---------------------------------------------------------------------------------------------------------------------------------
721 
722 double UnivParamTime::tStartCorrection(double r, double logE, double theta, bool Is8nsFADC)
723 {
724  if (fDetectorType == 2) return 0.;
725  double logE_i[3] = {19.0, 19.5, 20.0};
726  int iE;
727  if (logE <= logE_i[0]) iE = 0;
728  else if (logE <= logE_i[1]) iE = 1;
729  else iE = 1;
730 
731  double A1_25ns[3] = { 0.00, 0.00, 0.00};
732  double B1_25ns[3] = {34.65, 29.17, 21.78};
733  double A2_25ns[3] = { 0.00, 0.00, 0.00};
734  double B2_25ns[3] = { -41.13, -33.07, -26.58};
735 
736 
737  double A1_8ns[3] = { 0.00, 0.00, 0.00};
738  double B1_8ns[3] = {41.03, 30.93, 23.21};
739  double A2_8ns[3] = { 0.00, 0.00, 0.00};
740  double B2_8ns[3] = { -48.71, -38.09, -30.47};
741 
742 
743  double* A1_i, *A2_i, *B1_i, *B2_i;
744  if (Is8nsFADC) {
745  A1_i = A1_8ns;
746  A2_i = A2_8ns;
747  B1_i = B1_8ns;
748  B2_i = B2_8ns;
749  } else {
750  A1_i = A1_25ns;
751  A2_i = A2_25ns;
752  B1_i = B1_25ns;
753  B2_i = B2_25ns;
754  }
755 
756  double A1 = interpol(A1_i[iE], A1_i[iE + 1], logE_i[iE], logE_i[iE + 1], logE);
757  double B1 = interpol(B1_i[iE], B1_i[iE + 1], logE_i[iE], logE_i[iE + 1], logE);
758  double A2 = interpol(A2_i[iE], A2_i[iE + 1], logE_i[iE], logE_i[iE + 1], logE);
759  double B2 = interpol(B2_i[iE], B2_i[iE + 1], logE_i[iE], logE_i[iE + 1], logE);
760 
761  double sectheta = 1. / cos(theta);
762  double A = A1 * (sectheta - 1.) + A2;
763  double B = B1 * (sectheta - 1.) + B2;
764 
765  if (r < 200.e2) return 0.;
766  double corr = A + B * (r - 200.e2) / 800.e2;
767  return corr;
768 }
769 
770 
771 //---------------------------------------------------------------------------------------------------------------------------------
772 //---- This quantity should be substracted to the reconstructed quantile to get the expected value for AreaOverPeak=3.60
773 //---------------------------------------------------------------------------------------------------------------------------------
774 //
775 // [iq] = [0] T1vem [1] T10 [2] T50
776 // [tq]
777 //
778 // From MultiShower/time-corrections.cc
779 
780 double UnivParamTime::tQuantileCorrection_AoP(double RiseTime, int iq, double AreaOverPeak)
781 {
782  if (iq < 0 || iq > 2) return 0.;
783  if (AreaOverPeak < 0.) return 0.;
784  if (fDetectorType > 0) return 0.; // Not implemented
785 
786  const double RiseTimePulse = 40.;
787  if (RiseTime < RiseTimePulse) RiseTime = RiseTimePulse;
788 
789  const double AsymptoticCorr[3] = { 7.5, 13., 17. };
790 
791  const double A = AsymptoticCorr[iq] * (AreaOverPeak - 3.60) / (4.30 - 3.60);
792  const double B[3] = { 1.0, 1.30 , 4.6 };
793 
794  double corr = A * (1. - exp(-B[iq] * RiseTime / 200.));
795  return corr;
796 }
797 
798 
799 //---------------------------------------------------------------------------------------------------------------------------------
800 //---- D_TO (proton QGSJet II) r=800 [m] psi=90 [deg] Convolved with the detector response
801 //---------------------------------------------------------------------------------------------------------------------------------
802 
803 double UnivParamTime::GetD_TO(double X, double theta, double logE, int icomp)
804 {
805  if (fDetectorType == 2 && icomp > 0) return UNDEF;
806 
807  double secTheta = (theta > 60.*M_PI / 180. ? 2. : 1. / cos(theta));
808 
809  const double D0_TO_Par_WCD[4][3] = { { 27.16 , 36.33 , 0.00 } , { 27.01 , -3.59 , 0.00 } , { 29.54 , 34.38 , 0.00 } , { 18.42 , -5.34 , 0.00 } };
810  const double D0_TO_Par_Scin[4][3] = { { 17.79 , 33.85 , 0.00 } , { 17.95 , -11.00 , 0.00 } , { 23.48 , 19.71 , 0.00 } , { 19.07 , -12.06 , 0.00 } };
811  const double D0_TO_Par_MD[4][3] = { { 85.40 , 46.60 , 0.00 } , { 0.00 , 0.00 , 0.00 } , { 0.00 , 0.00 , 0.00 } , { 0.00 , 0.00 , 0.00 } };
812 
813 
814  const double D1_TO_Par_WCD[4] = { 309.14, -4.56, 280.30 , -1.68 };
815  const double D1_TO_Par_Scin[4] = { 338.33 , 1.98, 707.64 , 1.39 };
816  const double D1_TO_Par_MD[4] = { 181.82 , 0., 0., 0. };
817 
818  const double D2_TO_Par_WCD[4] = { 3.58, -0.07 , 5.73, 1.75 };
819  const double D2_TO_Par_Scin[4] = { 2.13 , -1.34 , 2.17 , 2.56 };
820  const double D2_TO_Par_MD[4] = { 25.65 , 0.00 , 0.00 , 0.00 };
821 
822  double D0_TO, D1_TO, D2_TO;
823  if (fDetectorType == 0) {
824  D0_TO = D0_TO_Par_WCD[icomp][0] + D0_TO_Par_WCD[icomp][1] * (secTheta - 1.) + D0_TO_Par_WCD[icomp][2] * pow(secTheta - 1, 2.);
825  D1_TO = D1_TO_Par_WCD[icomp];
826  D2_TO = D2_TO_Par_WCD[icomp];
827  } else if (fDetectorType == 1) {
828  D0_TO = D0_TO_Par_Scin[icomp][0] + D0_TO_Par_Scin[icomp][1] * (secTheta - 1.) + D0_TO_Par_Scin[icomp][2] * pow(secTheta - 1, 2.);
829  D1_TO = D1_TO_Par_Scin[icomp];
830  D2_TO = D2_TO_Par_Scin[icomp];
831  } else if (fDetectorType == 2) {
832  D0_TO = D0_TO_Par_MD[icomp][0] + D0_TO_Par_MD[icomp][1] * (secTheta - 1.) + D0_TO_Par_MD[icomp][2] * pow(secTheta - 1, 2.);
833  D1_TO = D1_TO_Par_MD[icomp];
834  D2_TO = D2_TO_Par_MD[icomp];
835  } else return UNDEF;
836 
837  double X0 = 750.;
838  double D_TO;
839  if (icomp == 1 || icomp == 3) D_TO = D0_TO + (X - X0) / 200.*D1_TO + D2_TO * (logE - 19.);
840  else D_TO = (D0_TO + D2_TO * (logE - 19.)) * exp(-(X - X0) / D1_TO);
841 
842 
843 
844  return D_TO;
845 }
846 
847 //---------------------------------------------------------------------------------------------------------------------------------
848 //----
849 //---------------------------------------------------------------------------------------------------------------------------------
850 
851 double UnivParamTime::GetOffsetM_r(double r, int icomp)
852 {
853  if (fDetectorType == 2) return 0.;
854  if (icomp == 1 || icomp == 3) return 0.;
855 
856  double SysPar1 = 2.65;
857  double C = fOffsetM_Mu / (1. - exp(-SysPar1));
858  double shift = C * (1. - exp(-SysPar1 * r / 2000.e2));
859 
860  return shift;
861 }
862 
863 
864 
static const double r_High
Definition: UnivParamTime.h:45
double QuantilePDF(double N, double fi, double f)
double TimeModelPar_Stage2[4][nParDist][nParTheta][2][nPar_Stage2]
Definition: UnivParamTime.h:70
static const double logE_Low
Definition: UnivParamTime.h:43
const int nPar_Stage2_Theta
Definition: UnivParamTime.h:35
bool GetShapeParameters(double *DL, double r, double logE, double psi, double theta, double *m, double *s)
double GetMS(double DL, double logE, double theta, double r, double psi, int icomp, int iMS, double *par_stage1, double *par_stage2)
static const double TimeModelParDist[nParDist]
Definition: UnivParamTime.h:31
double interpol(double v1, double v2, double x1, double x2, double x)
static const int nParTheta
Definition: UnivParamTime.h:32
double GetMS_ir_ith(double DL, double logE, int ith, int ir, double psi, int icomp, int iMS)
float Get_DX_DL(float r, float psi, float SlantDepth, float theta, float hground, bool UseDL, bool IsDiffusive)
double eTimeModelPar_Stage2[4][nParDist][nParTheta][2][nPar_Stage2]
Definition: UnivParamTime.h:70
double GetD_TO(double X, double theta, double logE, int icomp)
double GetOffsetM_r(double r, int icomp)
static const double TimeModelParTheta[nParTheta]
Definition: UnivParamTime.h:33
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 TimeModelPar_Stage2_Theta[4][nParDist][2][nPar_Stage2][nPar_Stage2_Theta]
Definition: UnivParamTime.h:71
double pow(const double x, const unsigned int i)
static const double ms_minVal
Definition: UnivParamTime.h:46
int exit
Definition: dump1090.h:237
double Binomial_q[200][99][3]
Definition: UnivParamTime.h:74
double GetCDF(double *t0, double *m, double *s, double *fcomp, double ti)
const int nPar_Stage2
Definition: UnivParamTime.h:35
static const double theta_Low
Definition: UnivParamTime.h:42
constexpr double s
Definition: AugerUnits.h:163
static const double r_Low
Definition: UnivParamTime.h:44
double tStartCorrection(double r, double logE, double theta, bool Is8nsFADC)
static const double logE_High
Definition: UnivParamTime.h:43
static const double theta_High
Definition: UnivParamTime.h:42
double GetMS_ir(double DL, double logE, double theta, int ir, double psi, int icomp, int iMS)
const bool UseDiffusive_time[4]
Definition: UnivParamTime.h:24
const int nPar_Stage1
Definition: UnivParamTime.h:35
double GetPoissonFactor(double fem, double f)
double norm(utl::Vector x)
UnivParamTime(int DetectorType)
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
static const int nParDist
Definition: UnivParamTime.h:30
double GetPDF(double *t0, double *m, double *s, double *fcomp, double ti)
double GetTime(double *DL, double r, double logE, double psi, double theta, double *fcomp, double *t0, double fi)
double GetFraction(double *t0, double *m, double *s, double *fcomp, double ti, bool isCDF)
double tQuantileCorrection_AoP(double RiseTime, int iq, double AoP)
constexpr double m
Definition: AugerUnits.h:121
double TimeModelPar_Stage1[4][nParDist][2][nPar_Stage1]
Definition: UnivParamTime.h:68
double tQuantileCorrection(double NanoSecPerVEM, int iq)
const double ndev
Definition: UnivParamTime.h:38
double GetBinomialNorm(double N, double f, double *fq)
const bool UseDL_time[4]
Definition: UnivParamTime.h:25

, generated on Tue Sep 26 2023.