9 #include <utl/ErrorLogger.h>
10 #include <utl/AugerUnits.h>
11 #include <utl/MathConstants.h>
12 #include <utl/PhysicalConstants.h>
13 #include <utl/PhysicalFunctions.h>
36 return pow(x / xMax, xMax) * exp(xMax - x);
42 const double xMax,
const double nMax,
50 (xMax - x0) / lambda);
53 namespace RefractionIndex {
64 const double n02 =
Sqr(n0);
65 const double dx = verticalDepth * (n02 - 1) / (n02 + 2) / x0;
67 return sqrt((1 + 2 * dx) / (1 - dx));
72 const double densityAtSeaLevel,
73 const double refractiveIndexAtSeaLevel)
75 return 1 + (refractiveIndexAtSeaLevel - 1) * density / densityAtSeaLevel;
79 Ciddor95(
const double wl,
const double temperature,
80 const double pressure,
const double vaporPressure)
85 const double tempK = temperature /
kelvin;
86 const double presPa = pressure /
pascal;
90 const double fpt = 1.00062 + 3.14e-8 * presPa + 5.6e-7 * tempC * tempC;
91 const double xV = fpt * vaporPressure / pressure;
100 const double rAS = 1e-8 * (5792105 / (238.0185 - invWl2) +
101 167917 / (57.362 - invWl2));
102 const double rAXS = rAS * (1 + 5.34e-7 * (xCO2 - 450));
105 const double rVS = 1.022e-8 * (
106 295.235 + invWl2 * (2.6422 + invWl2 * (-0.03238 + invWl2 * 0.004028)));
107 constexpr
double rhoVS = 0.00985938;
110 constexpr
double pa = 101325;
111 constexpr
double Ta = 288.15;
112 constexpr
double Za = 0.9995922115;
113 constexpr
double rhoAXS = pa * Ma / (Za * R * Ta);
116 const double pOnT = presPa / tempK;
118 1 - pOnT * (1.58123e-6 + tempC * (-2.9311e-8 + 1.1043e-10 * tempC) +
119 xV * ((5.707e-6 - 2.051e-8*tempC) + (1.9898e-4 - 2.376e-6*tempC)*xV))
120 + pOnT * pOnT * (1.93e-11 - 0.765e-8 * xV * xV);
123 const double rhoV = xV * presPa * Mv / (Zm * R * tempK);
124 const double rhoA = (1 - xV) * presPa * Ma / (Zm * R * tempK);
126 return 1 + (rhoA / rhoAXS) * rAXS + (rhoV / rhoVS) * rVS;
135 double vaporPressure = 0;
136 const double T = temperature /
kelvin;
139 constexpr
double k1 = 1.16705214528e+03;
140 constexpr
double k2 = -7.24213167032e+05;
141 constexpr
double k3 = -1.70738469401e+01;
142 constexpr
double k4 = 1.20208247025e+04;
143 constexpr
double k5 = -3.23255503223e+06;
144 constexpr
double k6 = 1.49151086135e+01;
145 constexpr
double k7 = -4.82326573616e+03;
146 constexpr
double k8 = 4.05113405421e+05;
147 constexpr
double k9 = -2.38555575678e-01;
148 constexpr
double k10 = 6.50175348448e+02;
150 const double O = T + k9 / (T - k10);
151 const double O2 = O*O;
152 const double A = O2 + k1 * O + k2;
153 const double B = k3 * O2 + k4 * O + k5;
154 const double C = k6 * O2 + k7 * O + k8;
155 const double X = -B +
sqrt(B*B - 4*A*C);
157 vaporPressure = 1e6 *
pow(2*C/X, 4) *
pascal;
159 const double A = -13.928169;
160 const double B = 34.7078238;
161 const double O = T / 273.16;
163 A * (1 -
pow(O, -1.5)) + B * (1 -
pow(O, -1.25));
165 vaporPressure = 611.657 * exp(Y) *
pascal;
168 return vaporPressure;
177 const double exponent = 1 / 5.25588;
187 const double p_crit = 10;
188 if (correctedPressure < p_crit) {
189 const double dp = pressure - correctedPressure;
190 correctedPressure = pressure - dp * pressure / (p_crit + dp);
193 const double rm = 272.5 * temperature *
194 pow(correctedPressure/pressure, exponent) / correctedPressure;
212 constexpr
double maxMeVCut = 3*
MeV;
214 if (enCut > maxMeVCut) {
216 warn <<
"enCut " << enCut/
MeV <<
" is larger than " << maxMeVCut/
MeV <<
" MeV";
221 return 1 - 0.045*enCut/
MeV;
238 constexpr
double p[] = { 3.90883, 1.05301, 9.91717, 2.41715, 0.13180 };
243 const double eDep = p[0]/
pow(p[1] + age, p[2]) + p[3] + p[4]*age;
245 return eDep / scaleFactor *
MeV/(
g/
cm2);
259 const double determinant =
260 + a[0][0] * (a[1][1] * a[2][2] - a[1][2] * a[2][1])
261 - a[0][1] * (a[1][0] * a[2][2] - a[1][2] * a[2][0])
262 + a[0][2] * (a[1][0] * a[2][1] - a[1][1] * a[2][0]);
264 const double small = 1e-30;
265 if (fabs(determinant) < small)
267 ERROR(
"Invert3x3: Error-matrix singular");
273 b[0][0] = a[1][1] * a[2][2] - a[1][2] * a[2][1];
274 b[1][0] = a[1][2] * a[2][0] - a[2][2] * a[1][0];
275 b[2][0] = a[1][0] * a[2][1] - a[1][1] * a[2][0];
277 b[0][1] = a[0][2] * a[2][1] - a[2][2] * a[0][1];
278 b[1][1] = a[0][0] * a[2][2] - a[2][0] * a[0][2];
279 b[2][1] = a[0][1] * a[2][0] - a[0][0] * a[2][1];
281 b[0][2] = a[0][1] * a[1][2] - a[1][1] * a[0][2];
282 b[1][2] = a[0][2] * a[1][0] - a[1][2] * a[0][0];
283 b[2][2] = a[0][0] * a[1][1] - a[0][1] * a[1][0];
285 const double iDet = 1 / determinant;
286 for (
int i = 0; i < 3; ++i)
287 for (
int j = 0; j < 3; ++j)
288 a[i][j] = iDet * b[i][j];
311 Solve3x3(
const double y[3],
double a[3][3],
double x[3])
315 for (
int i = 0; i < 3; ++i)
316 x[i] = a[i][0] * y[0] + a[i][1] * y[1] + a[i][2] * y[2];
325 double& xMax,
double& yMax)
330 const unsigned int nX = x.size();
332 if (nX != y.size() || nX < 5)
335 unsigned int iMax = 0;
336 double tempYMax = y[iMax];
338 for (
unsigned int i = 1; i < nX; ++i) {
339 if (y[i] > tempYMax) {
345 if (iMax < 2 || iMax > nX - 2) {
346 ERROR(
"QuadraticMaximumInterpolation - Error: Maximum not confined!");
350 const double yin[3] = {y[iMax - 1], y[iMax], y[iMax + 1]};
352 const double meanAroundMax = (yin[0] + yin[1] + yin[2]) / 3;
353 const double threshold = 2;
355 if (yin[1]/meanAroundMax > threshold || yin[0] < 0 || yin[2] < 0) {
356 ERROR(
"QuadraticMaximumInterpolation - Error: Interpolation unreliable due to spike in data!");
361 const double xin[3] = {x[iMax - 1], x[iMax], x[iMax + 1]};
363 m[0][0] =
Sqr(xin[0]);
366 m[1][0] =
Sqr(xin[1]);
369 m[2][0] =
Sqr(xin[2]);
378 xMax = -a[1] / (2 * a[0]);
379 yMax = (a[0] * xMax + a[1]) * xMax + a[2];
381 ERROR(
"QuadraticMaximumInterpolation - Error: no maximum found ...");
393 const double cosTheta,
const double signal)
401 const double detResolution = 0.023*signal;
402 return sqrt(
Sqr(shFluctuations) +
Sqr(detResolution));
405 ERROR(
"You should specify a SignalVariance model!");
415 return 0.34 + 0.46 / cosTheta;
418 constexpr
double a = 0.865;
419 constexpr
double b = 0.593;
420 const double factor = a*(1 + b*(1/cosTheta - 1.22));
424 ERROR(
"You should specify a SignalVariance model!");
433 return exp(-
Sqr(x/width));
439 const double lgExpectedSignal,
const double sin2Theta)
441 if (totdMoPSEnabled) {
444 const double n =
EvalPoly({0.091, -0.252}, sin2Theta);
445 constexpr
double sigma = 0.097;
446 const double mu =
EvalPoly({0.261, 0.174}, sin2Theta);
447 const double x0 =
EvalPoly({0.173, 0.170, -0.246}, sin2Theta);
448 constexpr
double delta = 0.225;
450 const double sigmoid =
Fermi(x0, lgExpectedSignal, delta);
451 return gauss + sigmoid;
455 const double n =
EvalPoly({0.163, -0.404}, sin2Theta);
456 constexpr
double sigma = 0.124;
457 const double mu =
EvalPoly({0.148, 0.294}, sin2Theta);
458 const double x0 =
EvalPoly({-0.012, 0.252, -0.148}, sin2Theta);
459 constexpr
double delta = 0.214;
461 const double sigmoid =
Fermi(x0, lgExpectedSignal, delta);
462 return gauss + sigmoid;
472 const double cosTheta,
const double signal)
480 constexpr
double baseFluctuations = 0.04;
481 return sqrt(
Sqr(shFluctuations) +
Sqr(baseFluctuations));
484 ERROR(
"You should specify a SignalVariance model!");
495 constexpr
double a = 1.398;
496 constexpr
double b = 0.210;
497 const double factor = a*(1 + b*(1/cosTheta - 1.22));
502 constexpr
double a = 1.449;
503 constexpr
double b = 0.175;
504 const double factor = a*(1 + b*(1/cosTheta - 1.22));
508 ERROR(
"You should specify a SignalVariance model!");
515 namespace InvisibleEnergy {
521 constexpr
double kQ2Sib[] = { 1.016, 1.012 };
533 constexpr
double kData[] = { 0.179, 0.947, 1.95, 4, 0.846, -0.265, 0.489, -0.441 };
539 constexpr
double min = 0.01*
EeV;
540 constexpr
double max = 1000*
EeV;
541 return std::min(
std::max(min, energy), max);
549 switch (interaction) {
554 switch (composition) {
557 case eData:
return 1;
561 ERROR(
"You should specify a valid interaction and composition!");
569 switch (composition) {
575 ERROR(
"You should specify a valid composition!");
591 const double cosTheta)
599 if (intMod ==
eDATA) {
608 constexpr
double th0 = 66*
degree;
609 const double cth = cosTheta - cos(th0);
610 const double eCal = energyEeV;
611 const double logECal = log10(energyEeV);
612 const double a = p[0];
613 const double b = p[1];
614 const double eCalA = p[2];
615 const double logECalA = log10(p[2]);
616 const double k = p[3];
617 const double bExt = p[4];
618 const double fTheta = 1 + cth*(p[5] + cth*(p[6] + cth*p[7]));
619 const double eInvH = a *
pow(eCal, b);
620 const double eInvL = a *
pow(eCalA, b) *
pow(eCal / eCalA, bExt);
621 const double fTanh = 0.5 * (1 + tanh(k*(logECal - logECalA)));
622 const double factor = 1 + (fTheta / eCal) * (eInvL + fTanh * (eInvH - eInvL));
627 return 1 / (mf * (p[0] - p[1] *
pow(energyEeV, -p[2])));
645 const double cosTheta)
650 const double ep2 =
pow(energyLim/
EeV, -p[2]);
651 const double energyEeV = energyLim/
EeV;
653 if (intMod ==
eDATA) {
662 constexpr
double th0 = 66*
degree;
663 const double cth = cosTheta - cos(th0);
664 const double eCal = energyEeV;
665 const double logECal = log10(energyEeV);
666 const double a = p[0];
667 const double b = p[1];
668 const double eCalA = p[2];
669 const double logECalA = log10(p[2]);
670 const double k = p[3];
671 const double bExt = p[4];
672 const double fTheta = 1 + cth*(p[5] + cth*(p[6] + cth*p[7]));
673 const double eInvH = a *
pow(eCal, b);
674 const double eInvL = a *
pow(eCalA, b) *
pow(eCal / eCalA, bExt);
675 const double fTanh = 0.5 * (1 + tanh(k*(logECal - logECalA)));
676 const double fCosh =
Sqr(cosh(k*(logECal - logECalA)));
677 const double dFactor =
678 fTheta / (eCal * energyLim) *
679 ((bExt - 1)*eInvL + fTanh*(((b - 1)*eInvH) - ((bExt - 1)*eInvL)) + (0.5/log(10))*k/fCosh * (eInvH - eInvL));
684 return -ep2 * p[1] * p[2] / (energyLim * mf *
Sqr(p[0] - p[1]*ep2));
712 const double lgETot = log10(eTot);
715 constexpr
double pp0 = 1.20836e6;
716 constexpr
double pp1 = -6.42338;
717 const double uncert1 = eTot * pp0 *
pow(lgETot, pp1);
724 constexpr
double c0 = 1.558;
725 constexpr
double c1 = -0.0797843;
726 constexpr
double c2 = 0.00237286;
727 const double fbeta =
max(0., c0 + lgETot*(c1 + c2*lgETot));
730 constexpr
double p0 = 1.52404;
731 constexpr
double p1 = 2.06276e2;
732 constexpr
double p2 = -2.19605e2;
734 const double lgFeTot = log10(
max(0.9*1e17, eTot)) / 18;
735 const double var_lnA = p0 *
pow(lgFeTot, p1 + p2*lgFeTot);
736 const double sqrt_var_lnA =
sqrt(var_lnA);
738 const double uncert2 = (eTot - eCal) * (1 - fbeta) * sqrt_var_lnA;
740 const double uncertsquare = (
Sqr(uncert1/eTot) +
Sqr(uncert2/eTot)) *
Sqr(eTot);
748 namespace XmaxParam {
751 Mean(
const double energy,
const double massNumber,
754 const double lgE = log10(energy /
utl::eV) - 19;
755 const double lnA = log(massNumber);
763 x0 = 815.87 *
g /
cm2;
764 d = 57.873 *
g /
cm2;
765 xi = -0.3035 *
g /
cm2;
766 delta = 0.7963 *
g /
cm2;
768 x0 = 806.04 *
g /
cm2;
769 d = 56.295 *
g /
cm2;
770 xi = 0.3463 *
g /
cm2;
771 delta = 1.0442 *
g /
cm2;
773 x0 = 790.15 *
g /
cm2;
774 d = 54.191 *
g /
cm2;
775 xi = -0.4170 *
g /
cm2;
776 delta = 0.6927 *
g /
cm2;
779 "Invalid hadronic interaction model requested. "
780 "Implemented are Sibyll2.3d, EPOS-LHC and QGSJETII-04");
783 const double meanXmaxP = x0 + d * lgE;
784 const double factorEnergy = xi - d / log(10) + delta * lgE ;
785 return meanXmaxP + factorEnergy *
lnA;
792 const double lgE = log10(energy /
utl::eV) - 19;
793 const double lnA = log(massNumber);
824 "Invalid hadronic interaction model requested. "
825 "Implemented are Sibyll2.3d, EPOS-LHC and QGSJETII-04");
828 double sigmaP2 = p0 + p1 * lgE + p2 *
pow(lgE, 2);
829 double a = a0 + a1 * lgE;
831 return sqrt(sigmaP2 * (1 + a * lnA + b *
pow(lnA, 2)));
837 namespace GumbelXmax {
840 Mu(
const double energy,
const double massNumber,
843 const double lgE = log10(energy /
utl::eV) - 19;
844 const double lnA = log(massNumber);
851 p0 = 785.852 + lnA * (-15.5994 - 1.06906 *
lnA);
852 p1 = 60.5929 + lnA * (-0.786014 + 0.200728 *
lnA);
853 p2 = -0.689462 + lnA * (-0.294794 - 0.0399432 *
lnA);
855 p0 = 775.457 + lnA * (-10.3991 - 1.75261 *
lnA);
856 p1 = 58.5306 + lnA * (-0.827668 + 0.231144 *
lnA);
857 p2 = -1.40781 + lnA * (0.225624 - 0.10008 *
lnA);
859 p0 = 758.65 + lnA * (-12.3571 - 1.24539 *
lnA);
860 p1 = 56.5943 + lnA * (-1.01244 + 0.228689 *
lnA);
861 p2 = -0.534683 + lnA * (-0.17284 - 0.019159 *
lnA);
864 "Invalid hadronic interaction model requested. "
865 "Implemented are Sibyll2.3d, EPOS-LHC and QGSJETII-04");
868 const double mu = p0 + lgE * (p1 + p2 * lgE);
873 Sigma(
const double energy,
const double massNumber,
876 const double lgE = log10(energy /
utl::eV) - 19;
877 const double lnA = log(massNumber);
882 p0 = 41.0345 + lnA * (-2.17329 - 0.306202 *
lnA);
883 p1 = -0.309466 + lnA * (-1.1649 + 0.225445 *
lnA);
885 p0 = 32.2632 + lnA * (3.94252 - 0.864421 *
lnA);
886 p1 = 1.27601 + lnA * (-1.81337 + 0.231914 *
lnA);
888 p0 = 35.4234 + lnA * (6.75921 - 1.46182 *
lnA);
889 p1 = -0.796042 + lnA * (0.201762 - 0.0142452 *
lnA);
892 "Invalid hadronic interaction model requested. "
893 "Implemented are Sibyll2.3d, EPOS-LHC and QGSJETII-04");
896 const double sigma = p0 + lgE * p1;
897 return sigma *
g/
cm2;
902 Lambda(
const double energy,
const double massNumber,
905 const double lgE = log10(energy /
utl::eV) - 19;
906 const double lnA = log(massNumber);
911 p0 = 0.799493 + lnA * (0.235235 + 0.00856884 *
lnA);
912 p1 = 0.0632135 + lnA * (-0.0012847 + 0.000330525 *
lnA);
914 p0 = 0.641093 + lnA * (0.219762 + 0.171124 *
lnA);
915 p1 = 0.0726131 + lnA * (0.0353188 - 0.0131158 *
lnA);
917 p0 = 0.671545 + lnA * (0.373902 + 0.075325 *
lnA);
918 p1 = 0.0304335 + lnA * (0.0473985 - 0.000564531 *
lnA);
921 "Invalid hadronic interaction model requested. "
922 "Implemented are Sibyll2.3d, EPOS-LHC and QGSJETII-04");
925 const double lambda = p0 + lgE * p1;
926 return lambda *
g/
cm2;
937 return (((5.151*age - 28.925)*age + 60.056)*age - 56.718)*age + 22.331;
946 return (-1.039*age + 2.251)*age + 0.676;
955 return 1-
pow(1 + a*rStar, -b);
964 return (
pow(1 - fraction, -1/b) - 1) /
a;
973 return b * a *
pow(1 + a*rStar, -b - 1);
double StandardDeviation(const std::vector< double > &v, const double mean)
double Factor(const double energyEM, const EInteractionModel intMod, const ECompositionModel compMod, const double cosTheta)
invisible energy factor, finv=Etot/Eem, given Eem. CosTheta only needed when using data driven estima...
constexpr double kQGSJetMixed[]
double InverseGoraCDF(const double fraction, const double age)
constexpr T Sqr(const T &x)
double GoraCDF(const double rStar, const double age)
double GladstoneDale(const double density, const double densityAtSeaLevel, const double refractiveIndexAtSeaLevel)
Calculate the refraction index for a given density.
constexpr double kDryAirMolarMass
double ElectronsAboveCut(double enCut)
Fraction of electrons above energy cutoff enCut (in MeV) at age = 1.
double ModelFactor(const EInteractionModel interaction, const ECompositionModel composition)
constexpr double kRadiationLength
double FactorDerivative(const double energyEM, const EInteractionModel intMod, const ECompositionModel compMod, const double cosTheta)
derivative of invisible energy factor dfinv/dEem given Eem. CosTheta only needed when using data driv...
Base class for exceptions arising because configuration data are not valid.
constexpr double kRefractiveIndexSeaLevel
double GoraAParameter(const double age)
parameter a of D. Gora et al., Astropart. Phys. 24 (2006), 484
constexpr double kOverburdenSeaLevel
constexpr double kQGSJetProton[]
double pow(const double x, const unsigned int i)
bool Solve3x3(const double y[3], double a[3][3], double x[3])
constexpr double micrometer
double Fermi(const double x)
double MoliereRadius(double temperature, double pressure, const double cosTheta)
The Moliere Radius (2 radiation length above obs-level, GAP-1998-002)
double EvalPoly(const T &a, const double x)
Simple polynomial evaluator.
constexpr double fraction
double SaturationVaporPressure(const double temperature)
Evaluate the saturation vapor pressure over ice or water.
bool Invert3x3(double a[3][3])
#define WARNING(message)
Macro for logging warning messages.
double Sigma(const double energy, const double massNumber, const HadronicInteractionModel hadModel)
constexpr double kQGSJetIron[]
constexpr double kH2OMolarMass
double GaisserHillas(const double x, const double x0, const double xMax, const double nMax, const double lambda)
Calculate the Gaisser-Hillas function.
double LorentzLorentz(const double verticalDepth)
Calculate the refraction index for a given depth.
double GoraBParameter(const double age)
parameter b of D. Gora et al., Astropart. Phys. 24 (2006), 484
double GoraPDF(const double rStar, const double age)
double lnA(const double Rmu, const double Xmax, const double lgE, const bool realEvent)
constexpr double kQ2Sib[]
double SignalUncertainty(const ESignalVarianceModel model, const double cosTheta, const double signal)
double Ciddor95(const double wl, const double temperature, const double pressure, const double vaporPressure)
Wavelength-dependent index of refraction for humid air.
constexpr double kMolarGasConstant
double TriggerProbability(const bool totdMoPSEnabled, const double lgExpectedSignal, const double sin2Theta)
const double * FitParameters(const ECompositionModel composition)
double ModeGauss(const double x, const double width)
double EnergyDeposit(const double age, const double enCut)
Parametrization for the average energy deposit per particle.
double SignalUncertaintyFactor(const ESignalVarianceModel model, const double cosTheta)
double Mean(const std::vector< double > &v)
constexpr double kCO2AirFraction
double Lambda(const double energy, const double massNumber, const HadronicInteractionModel hadModel)
double EnergyLimits(const double energy)
constexpr double kH2OFreezingPoint
#define ERROR(message)
Macro for logging error messages.
double FactorVariance(const double eCal, const double eTot)
constexpr double perMillion
double Mu(const double energy, const double massNumber, const HadronicInteractionModel hadModel)
constexpr double millibar
bool QuadraticMaximumInterpolation(const std::vector< double > &x, const std::vector< double > &y, double &xMax, double &yMax)
double NormalizedGaisserHillas(const double x, const double xMax)