6 #include <Math/PdfFuncMathCore.h>
7 #include <Math/ProbFuncMathCore.h>
8 #include <Math/QuantFuncMathCore.h>
9 #include "UnivParamTimeConfig.h"
10 #include <tls/Atmosphere.h>
12 using namespace UnivParamTimeNS;
17 if (DetectorType < 0 || DetectorType > 2) {
18 printf(
"UnivParamTime: Wrong Detector Type %d \n", DetectorType);
27 std::string DAT = DATA_DIR;
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";
33 FILE* fp = fopen(DAT.c_str(),
"r");
37 printf(
"ERROR Reading UnivParamTime parameters\n");
42 printf(
"ERROR Reading UnivParamTime parameters\n");
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;
55 printf(
"Error reading parameters 1 %d \n", nread);
60 nread = fscanf(fp,
"%lf %lf %lf %lf %lf %lf ",
65 printf(
"Error reading parameters 1 %d \n", nread);
69 for (
int ith = 0; ith <
nParTheta; ith++) {
73 printf(
"Error reading parameters 2 %d\n", nread);
80 printf(
"Error reading parameters 3 %d \n", nread);
90 std::string DAT = DATA_DIR;
92 DAT +=
"Binomial.norm";
94 FILE* f = fopen(DAT.c_str(),
"r");
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");
122 return GetMS(DL, logE, theta, r, psi , icomp, iMS, par_stage1, par_stage2);
129 double theta_deg = theta * 180. / M_PI;
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.;
144 return GetMS(DL, logE, theta, r, psi , icomp, iMS, par_stage1, par_stage2);
150 UnivParamTime::GetMS(
double DL,
double logE,
double theta,
double r,
double psi ,
int icomp,
int ,
double* par_stage1,
double* par_stage2)
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];
157 double ms_slope = par_stage2[0];
158 double ms_psi_down = par_stage2[1];
159 double ms_psi_up = par_stage2[2];
165 double val1 = ms0 - ms1;
168 double C = (val1 - val0) / (exp(-B) - 1.0);
171 val = A + C * exp(-B * DL / 1000.);
177 val += ms_slope * (DL - DL_ref) / 1000.;
180 double ms_psi = (cos(psi) > 0. ? ms_psi_up * cos(psi) : ms_psi_down * cos(psi));
184 val += ((logE -
logE_ref) * ms_logE);
192 if (x1 == x2)
return v1;
193 return v1 + (v2 - v1) * (x - x1) / (x2 - x1);
207 int ir1 = 0, ir2 = 0;
227 int ith1 = 0, ith2 = 0;
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) };
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) };
252 double val_i[2] = {
GetMS_ir(DL, logE, theta, ir1, psi , icomp, iMS),
GetMS_ir(DL, logE, theta, ir2, psi , icomp, iMS) };
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;
287 double frac = 0., sum = 0.;
289 for (
int icomp = 0; icomp < 4; icomp++) {
290 if (fcomp[icomp] < 0.) {
294 if (fcomp[icomp] > 0. && (m[icomp] <= 0. || s[icomp] <= 0.)) {
300 if (sum == 0. || !ok)
return UNDEF;
302 for (
int icomp = 0; icomp < 4; icomp++) {
303 if (fcomp[icomp] == 0.)
continue;
304 if (ti < t0[icomp])
continue;
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);
314 double UnivParamTime::GetFraction(
double* DL,
double r ,
double logE,
double psi,
double theta,
double* fcomp,
double* t0,
double ti,
bool isCDF)
319 if (!ok)
return UNDEF;
331 double UnivParamTime::GetCDF(
double* DL,
double r ,
double logE,
double psi,
double theta,
double* fcomp,
double* t0,
double ti)
333 return GetFraction(DL, r, logE, psi, theta, fcomp, t0, ti,
true);
342 double UnivParamTime::GetPDF(
double* DL,
double r ,
double logE,
double psi,
double theta,
double* fcomp,
double* t0,
double ti)
344 return GetFraction(DL, r, logE, psi, theta, fcomp, t0, ti,
false);
351 double UnivParamTime::GetTime(
double* DL,
double r ,
double logE,
double psi,
double theta,
double* fcomp,
double* t0,
double fi)
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;
362 return GetTime(t0 , m, s, fcomp, fi);
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;
379 double Tolerance = 1.e-8;
383 double tmin = 1.e10, tmax = 0.;
384 for (
int icomp = 0; icomp < 4; icomp++) {
385 if (fcomp[icomp] == 0.)
continue;
387 double tmin_i = t0[icomp];
388 double tmax_i = t0[icomp] + exp(m[icomp] + 5.*s[icomp]);
390 if (tmin > tmin_i) tmin = tmin_i;
391 if (tmax < tmax_i) tmax = tmax_i;
393 if (tmin < 1.e-3) tmin = 1.e-3;
397 double xmin = log(tmin);
398 double xmax = log(tmax);
400 double fmin =
GetCDF(t0 , m, s, fcomp, exp(xmin));
401 double fmax =
GetCDF(t0 , m, s, fcomp, exp(xmax));
403 if (fmin >= fi)
return exp(xmin);
404 if (fmax <= fi)
return exp(xmax);
406 double x = (xmin + xmax) / 2.;
407 double step = (xmax - xmin) / 2.;
410 const int nIterMax = 1000;
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]);
428 if (iter > nIterMax)
break;
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]);
440 if (isnan(x) || isinf(x))
return 0.;
456 if (fem < 0.) fem = 0.;
457 if (fem > 1.) fem = 1.;
462 double pf = 1. + B *
pow(fem / 0.5, 2.);
463 if (pf < 1.) pf = 1.;
469 bool UseApprox,
double pf,
double& mean,
double& rms)
471 double pdf = 1.e-100;
474 double N = vemTot * pf;
475 if (isnan(N))
return pdf;
487 for (
int iq = 0; iq < 3; iq++)
488 tq[iq] =
GetTime(t0, m, s, fcomp, fq[iq]);
490 const double ndev = 1.28156;
492 if ((tq[2] - tq[1]) < (tq[1] - tq[0])) {
494 rms = (tq[1] - tq[0]) / ndev;
495 if (UseApprox) pdf = ROOT::Math::normal_pdf(ti, rms, mean);
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;
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.));
506 if (UseApprox && ti > t0_i) pdf = ROOT::Math::lognormal_pdf(ti - t0_i, m_i, s_i);
513 double fi =
GetCDF(t0, m, s, fcomp, ti);
515 double derivative = (fi -
GetCDF(t0, m, s, fcomp, ti * 0.99)) / ti / 0.01;
525 bool UseApprox,
double& mean,
double& rms)
527 double fem0 = fcomp[1] / (fcomp[0] + fcomp[1] + fcomp[2] + fcomp[3]);
529 return tQuantilePDF(t0, m, s, fcomp, vemTot, ti, f, UseApprox, pf, mean, rms);
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)
538 if (!ok)
return UNDEF;
540 double pdf =
tQuantilePDF(t0, m, s, fcomp, vemTot, ti, f, UseApprox, mean, rms);
549 double stepN = log10(40000. / 100.) / 100.;
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.);
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;
578 for (
int iq = 0; iq < 3; iq++)
587 double fq[3] = {0., 0., 0.};
595 if (N > 40000.) N = 40000.;
598 if (f * (N + 1) - 1 < 0.) N = 1. / f - 1.;
599 double ipos = f * (N + 1) - 1;
603 if (fi < 0. || fi > 1.)
return 0.;
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.;
615 double UnivParamTime::tFirstPDF(
double DL_mu,
double r,
double logE,
double psi,
double theta,
double t0_mu,
double npart,
double t)
617 double mean = 0., rms = 0.;
618 return tFirstPDF(DL_mu, r, logE, psi, theta, t0_mu, npart, t,
false, mean, rms);
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)
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);
630 if (npart <= 1.) npart = 1.;
631 double prob =
tFirstPDF(t0_mu, m_mu, s_mu, npart, t, UseApprox, mean, rms);
636 double UnivParamTime::tFirstPDF(
double t0_mu,
double m_mu,
double s_mu,
double npart,
double ti,
bool UseApprox,
double& mean,
double& rms)
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.};
652 double q1[3] = {0.1, 0.5, 0.9};
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);
661 const double ndev = 1.28156;
663 if ((t1[2] - t1[1]) < (t1[1] - t1[0])) {
665 rms = (t1[1] - t1[0]) / ndev;
666 if (UseApprox) tFirstPDF = ROOT::Math::normal_pdf(ti, rms, mean);
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;
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);
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;
708 if (iq < 0 || iq > 2)
return 0.;
710 double A[3] = {150.0, 70.0, 0.0};
711 double corr = A[iq] * NanoSecPerVEM / 200.;
725 double logE_i[3] = {19.0, 19.5, 20.0};
727 if (logE <= logE_i[0]) iE = 0;
728 else if (logE <= logE_i[1]) iE = 1;
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};
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};
743 double* A1_i, *A2_i, *B1_i, *B2_i;
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);
761 double sectheta = 1. / cos(theta);
762 double A = A1 * (sectheta - 1.) + A2;
763 double B = B1 * (sectheta - 1.) + B2;
765 if (r < 200.e2)
return 0.;
766 double corr = A + B * (r - 200.e2) / 800.e2;
782 if (iq < 0 || iq > 2)
return 0.;
783 if (AreaOverPeak < 0.)
return 0.;
786 const double RiseTimePulse = 40.;
787 if (RiseTime < RiseTimePulse) RiseTime = RiseTimePulse;
789 const double AsymptoticCorr[3] = { 7.5, 13., 17. };
791 const double A = AsymptoticCorr[iq] * (AreaOverPeak - 3.60) / (4.30 - 3.60);
792 const double B[3] = { 1.0, 1.30 , 4.6 };
794 double corr = A * (1. - exp(-B[iq] * RiseTime / 200.));
807 double secTheta = (theta > 60.*M_PI / 180. ? 2. : 1. / cos(theta));
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 } };
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. };
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 };
822 double D0_TO, D1_TO, D2_TO;
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];
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];
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];
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);
854 if (icomp == 1 || icomp == 3)
return 0.;
856 double SysPar1 = 2.65;
858 double shift = C * (1. - exp(-SysPar1 * r / 2000.e2));
static const double r_High
double QuantilePDF(double N, double fi, double f)
double TimeModelPar_Stage2[4][nParDist][nParTheta][2][nPar_Stage2]
static const double logE_Low
const int nPar_Stage2_Theta
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]
double interpol(double v1, double v2, double x1, double x2, double x)
static const int nParTheta
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]
double GetD_TO(double X, double theta, double logE, int icomp)
double GetOffsetM_r(double r, int icomp)
static const double TimeModelParTheta[nParTheta]
double tQuantilePDF(double *t0, double *m, double *s, double *fcomp, double vemTot, double ti, double f, bool UseApprox, double pf, double &mean, double &rms)
double TimeModelPar_Stage2_Theta[4][nParDist][2][nPar_Stage2][nPar_Stage2_Theta]
double pow(const double x, const unsigned int i)
static const double ms_minVal
double Binomial_q[200][99][3]
double GetCDF(double *t0, double *m, double *s, double *fcomp, double ti)
static const double theta_Low
double BinomialNorm[200][99]
static const double r_Low
double tStartCorrection(double r, double logE, double theta, bool Is8nsFADC)
static const double logE_High
static const double theta_High
double GetMS_ir(double DL, double logE, double theta, int ir, double psi, int icomp, int iMS)
const bool UseDiffusive_time[4]
double GetPoissonFactor(double fem, double f)
UnivParamTime(int DetectorType)
double tFirstPDF(double t0_mu, double m_mu, double s_mu, double npart, double t, bool UseApprox, double &mean, double &rms)
static const int nParDist
bool fUseThetaInterpolation
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)
double TimeModelPar_Stage1[4][nParDist][2][nPar_Stage1]
double tQuantileCorrection(double NanoSecPerVEM, int iq)
double GetBinomialNorm(double N, double f, double *fq)