PhysicalFunctions.cc
Go to the documentation of this file.
1 
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>
14 
15 using namespace std;
16 using namespace utl;
17 
18 
19 // For some reason, CLHEP SystemOfUnits.h #defines pascal to hep_pascal,
20 // putting it in the global namespace and screwing up our own definition of
21 // pascal from AugerUnits.h. It appears the CLHEP units are being pulled in
22 // via the geometry package. The following line undoes the CLHEP sabotage.
23 #undef pascal
24 
25 
26 namespace utl {
27 
32  inline
33  double
34  NormalizedGaisserHillas(const double x, const double xMax)
35  {
36  return pow(x / xMax, xMax) * exp(xMax - x);
37  }
38 
39 
40  double
41  GaisserHillas(const double x, const double x0,
42  const double xMax, const double nMax,
43  const double lambda)
44  {
45  if (x < x0)
46  return 0;
47 
48  return nMax *
49  NormalizedGaisserHillas((x - x0) / lambda,
50  (xMax - x0) / lambda);
51  }
52 
53  namespace RefractionIndex {
54 
55  double
56  LorentzLorentz(const double verticalDepth)
57  {
58  const double n0 = kRefractiveIndexSeaLevel;
59  const double x0 = kOverburdenSeaLevel;
60 
61  // Where the Lorentz-Lorenz relation is assumed:
62  // (n^2 - 1) / (n^2 + 2) = constant*density
63 
64  const double n02 = Sqr(n0);
65  const double dx = verticalDepth * (n02 - 1) / (n02 + 2) / x0;
66 
67  return sqrt((1 + 2 * dx) / (1 - dx));
68  }
69 
70  double
71  GladstoneDale(const double density,
72  const double densityAtSeaLevel/* = kAirDensitySeaLevel*/,
73  const double refractiveIndexAtSeaLevel/* = kRefractiveIndexSeaLevel*/)
74  {
75  return 1 + (refractiveIndexAtSeaLevel - 1) * density / densityAtSeaLevel;
76  }
77 
78  double
79  Ciddor95(const double wl, const double temperature,
80  const double pressure, const double vaporPressure)
81  {
82  // Refraction index: P. Ciddor, Appl Opt 35 (1996) 1566-1573
83  const double invWl2 = pow(wl / micrometer, -2);
84  const double tempC = temperature - kH2OFreezingPoint;
85  const double tempK = temperature / kelvin;
86  const double presPa = pressure / pascal;
87  constexpr double R = kMolarGasConstant / (joule / (mole * kelvin));
88 
89  // Calculate the enhancement factor and mole fraction (xV) of water vapor
90  const double fpt = 1.00062 + 3.14e-8 * presPa + 5.6e-7 * tempC * tempC;
91  const double xV = fpt * vaporPressure / pressure;
92  constexpr double Mv = kH2OMolarMass / (kg / mole);
93 
94  // Molar mass of dry air [kg/mol] with a CO2 concentration of xCO2 [ppm]
95  constexpr double xCO2 = kCO2AirFraction / perMillion;
96  constexpr double Ma = kDryAirMolarMass / (kg/mole) + 1.2011e-8 * (xCO2 - 400);
97 
98  // Calculate the component indices of refraction as r = 1e-8 * (n-1).
99  // Standard dry air index (15 C, 101.325 kPa, 450 ppm CO2 or xCO2 ppm)
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));
103 
104  // Standard index and density of pure water vapor (xV = 1) at 20 C, 1333 Pa
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;
108 
109  // Compressibility and density of dry air
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);
114 
115  // Compressibility of moist air
116  const double pOnT = presPa / tempK;
117  const double Zm =
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);
121 
122  // Density of water vapor and moist air
123  const double rhoV = xV * presPa * Mv / (Zm * R * tempK);
124  const double rhoA = (1 - xV) * presPa * Ma / (Zm * R * tempK);
125 
126  return 1 + (rhoA / rhoAXS) * rAXS + (rhoV / rhoVS) * rVS;
127  }
128  }
129 
130  double
131  SaturationVaporPressure(const double temperature)
132  {
133  // Use the expression due to P.H. Huang, Proc. Third Int. Symp. Humidity
134  // and Moisture 1 (1998) 69-76 (see also http://emtoolbox.nist.gov).
135  double vaporPressure = 0;
136  const double T = temperature / kelvin;
137 
138  if (T >= 273.15) {
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;
149 
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);
156 
157  vaporPressure = 1e6 * pow(2*C/X, 4) * pascal;
158  } else {
159  const double A = -13.928169;
160  const double B = 34.7078238;
161  const double O = T / 273.16;
162  const double Y =
163  A * (1 - pow(O, -1.5)) + B * (1 - pow(O, -1.25));
164 
165  vaporPressure = 611.657 * exp(Y) * pascal;
166  }
167 
168  return vaporPressure;
169  }
170 
171 
172  double
173  MoliereRadius(double temperature, double pressure, const double cosTheta)
174  {
175 //#warning MoliereRadius() does not work for inclined events
176 //#warning MoliereRadius() should use density from Atmosphere
177  const double exponent = 1 / 5.25588;
178 
179  double correctedPressure = pressure - kgEarth * 2 * kRadiationLength * cosTheta;
180 
181  temperature /= kelvin;
182  pressure /= millibar;
183  correctedPressure /= millibar;
184 
185  // for security. High in the atmosphere, low pressure
186  // linear asymptotic behaviour to zero
187  const double p_crit = 10; // [millibar]
188  if (correctedPressure < p_crit) {
189  const double dp = pressure - correctedPressure;
190  correctedPressure = pressure - dp * pressure / (p_crit + dp); // should never get zero
191  }
192 
193  const double rm = 272.5 * temperature *
194  pow(correctedPressure/pressure, exponent) / correctedPressure;
195 
196  return rm * meter;
197  }
198 
199 
209  double
210  ElectronsAboveCut(double enCut)
211  {
212  constexpr double maxMeVCut = 3*MeV; // maximum extrapolation
213 
214  if (enCut > maxMeVCut) {
215  ostringstream warn;
216  warn << "enCut " << enCut/MeV << " is larger than " << maxMeVCut/MeV << " MeV";
217  WARNING(warn);
218  enCut = maxMeVCut;
219  }
220 
221  return 1 - 0.045*enCut/MeV;
222  }
223 
224 
234  double
235  EnergyDeposit(const double age, const double enCut)
236  {
237  // parameters at 1 MeV
238  constexpr double p[] = { 3.90883, 1.05301, 9.91717, 2.41715, 0.13180 };
239 
240  // limit to reasonable ranges
241  const double scaleFactor = ElectronsAboveCut(enCut) / ElectronsAboveCut(1*MeV);
242 
243  const double eDep = p[0]/pow(p[1] + age, p[2]) + p[3] + p[4]*age;
244 
245  return eDep / scaleFactor * MeV/(g/cm2);
246  }
247 
248 
249  /****************************************************
250  *
251  * inversion of 3-by-3 matrix A
252  *
253  * (returns false if matrix singular)
254  *
255  ****************************************************/
256  bool
257  Invert3x3(double a[3][3])
258  {
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]);
263 
264  const double small = 1e-30;
265  if (fabs(determinant) < small)
266  {
267  ERROR("Invert3x3: Error-matrix singular");
268  return false;
269  }
270 
271  double b[3][3];
272 
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];
276 
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];
280 
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];
284 
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];
289 
290  return true;
291  }
292 
293 
294  /****************************************************
295  *
296  * solves linear system
297  *
298  * / y[0] \ / A[0][0] A[0][1] A[0][2] \ / x[0] \
299  * | y[1] | = | A[1][0] A[1][1] A[1][2] | * | x[1] |
300  * \ y[2] / \ A[2][0] A[2][1] A[2][2] / \ x[2] /
301  *
302  *
303  * Input: y[3] and A[3][3]
304  * Output: returns true when succeded (i.e. A is not singular)
305  * A is overwritten with its inverse
306  *
307  * M. Unger 12/1/05
308  *
309  *****************************************************/
310  bool
311  Solve3x3(const double y[3], double a[3][3], double x[3])
312  {
313  if (Invert3x3(a))
314  {
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];
317  return true;
318  }
319  return false;
320  }
321 
322 
323  bool
324  QuadraticMaximumInterpolation(const std::vector<double>& x, const std::vector<double>& y,
325  double& xMax, double& yMax)
326  {
327  yMax = 0;
328  xMax = 0;
329 
330  const unsigned int nX = x.size();
331 
332  if (nX != y.size() || nX < 5)
333  return false;
334 
335  unsigned int iMax = 0;
336  double tempYMax = y[iMax];
337 
338  for (unsigned int i = 1; i < nX; ++i) {
339  if (y[i] > tempYMax) {
340  iMax = i;
341  tempYMax = y[i];
342  }
343  }
344 
345  if (iMax < 2 || iMax > nX - 2) {
346  ERROR("QuadraticMaximumInterpolation - Error: Maximum not confined!");
347  return false;
348  }
349 
350  const double yin[3] = {y[iMax - 1], y[iMax], y[iMax + 1]};
351 
352  const double meanAroundMax = (yin[0] + yin[1] + yin[2]) / 3;
353  const double threshold = 2;
354 
355  if (yin[1]/meanAroundMax > threshold || yin[0] < 0 || yin[2] < 0) {
356  ERROR("QuadraticMaximumInterpolation - Error: Interpolation unreliable due to spike in data!");
357  return false;
358  }
359 
360  // quadratic "fit" around maximum to get yMax and Xmax
361  const double xin[3] = {x[iMax - 1], x[iMax], x[iMax + 1]};
362  double m[3][3];
363  m[0][0] = Sqr(xin[0]);
364  m[0][1] = xin[0];
365  m[0][2] = 1;
366  m[1][0] = Sqr(xin[1]);
367  m[1][1] = xin[1];
368  m[1][2] = 1;
369  m[2][0] = Sqr(xin[2]);
370  m[2][1] = xin[2];
371  m[2][2] = 1;
372 
373  double a[3];
374 
375  Solve3x3(yin, m, a);
376 
377  if (a[0] <= 0) {
378  xMax = -a[1] / (2 * a[0]);
379  yMax = (a[0] * xMax + a[1]) * xMax + a[2];
380  } else {
381  ERROR("QuadraticMaximumInterpolation - Error: no maximum found ...");
382  return false;
383  }
384 
385  return true;
386  }
387 
388 
389  namespace wcd {
390 
391  double
393  const double cosTheta, const double signal)
394  {
395  switch (model) {
396  case eGAP2012_012:
397  return SignalUncertaintyFactor(model, cosTheta) * sqrt(signal);
398  case eGAP2014_035:
399  {
400  const double shFluctuations = SignalUncertaintyFactor(model, cosTheta) * sqrt(signal);
401  const double detResolution = 0.023*signal;
402  return sqrt(Sqr(shFluctuations) + Sqr(detResolution));
403  }
404  }
405  ERROR("You should specify a SignalVariance model!");
406  return 0;
407  }
408 
409 
410  double
411  SignalUncertaintyFactor(const ESignalVarianceModel model, const double cosTheta)
412  {
413  switch (model) {
414  case eGAP2012_012:
415  return 0.34 + 0.46 / cosTheta;
416  case eGAP2014_035:
417  {
418  constexpr double a = 0.865;
419  constexpr double b = 0.593;
420  const double factor = a*(1 + b*(1/cosTheta - 1.22));
421  return factor;
422  }
423  }
424  ERROR("You should specify a SignalVariance model!");
425  return 0;
426  }
427 
428 
429  inline
430  double
431  ModeGauss(const double x, const double width)
432  {
433  return exp(-Sqr(x/width));
434  }
435 
436 
437  double
438  TriggerProbability(const bool totdMoPSEnabled,
439  const double lgExpectedSignal, const double sin2Theta)
440  {
441  if (totdMoPSEnabled) {
442  // suitable for the new triggers, calculated using doublet stations in infill array
443  // see GAP-2018-017
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;
449  const double gauss = n * ModeGauss(lgExpectedSignal - mu, sigma);
450  const double sigmoid = Fermi(x0, lgExpectedSignal, delta);
451  return gauss + sigmoid;
452  }
453 
454  // based on a study using the new triggers in the regular array
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;
460  const double gauss = n * ModeGauss(lgExpectedSignal - mu, sigma);
461  const double sigmoid = Fermi(x0, lgExpectedSignal, delta);
462  return gauss + sigmoid;
463  }
464 
465  }
466 
467 
468  namespace ssd {
469 
470  double
472  const double cosTheta, const double signal)
473  {
474  switch (model) {
475  case eGAP2018_025:
476  return SignalUncertaintyFactor(model, cosTheta) * sqrt(signal);
477  case eGAP2019_000:
478  {
479  const double shFluctuations = SignalUncertaintyFactor(model, cosTheta) * sqrt(signal);
480  constexpr double baseFluctuations = 0.04;
481  return sqrt(Sqr(shFluctuations) + Sqr(baseFluctuations));
482  }
483  }
484  ERROR("You should specify a SignalVariance model!");
485  return 0;
486  }
487 
488 
489  double
490  SignalUncertaintyFactor(const ESignalVarianceModel model, const double cosTheta)
491  {
492  switch (model) {
493  case eGAP2018_025:
494  {
495  constexpr double a = 1.398;
496  constexpr double b = 0.210;
497  const double factor = a*(1 + b*(1/cosTheta - 1.22));
498  return factor;
499  }
500  case eGAP2019_000:
501  {
502  constexpr double a = 1.449;
503  constexpr double b = 0.175;
504  const double factor = a*(1 + b*(1/cosTheta - 1.22));
505  return factor;
506  }
507  }
508  ERROR("You should specify a SignalVariance model!");
509  return 0;
510  }
511 
512  }
513 
514 
515  namespace InvisibleEnergy {
516 
517  constexpr double kQGSJetProton[] = { 0.958, 0.048, 0.162 };
518  constexpr double kQGSJetIron[] = { 0.977, 0.109, 0.130 };
519  constexpr double kQGSJetMixed[] = { 0.967, 0.078, 0.140 };
520 
521  constexpr double kQ2Sib[] = { 1.016, 1.012 };
522 
523  //constexpr double kData[] = { 1, 1.9065e-01, 8.9624e-01 };
524 
525  // ICRC 2013
526  //constexpr double kData[] = { 1, 1.7425e-01, 9.1445e-01 };
527 
528  // ICRC 2017
529  //constexpr double kData[] = {1, 0.1633, 0.9463, 0.8475, 0.957, 1.67};
530 
531  // PRD Paper
532  // a b EcalA K bextr f1 f2 f3
533  constexpr double kData[] = { 0.179, 0.947, 1.95, 4, 0.846, -0.265, 0.489, -0.441 };
534 
535 
536  double
537  EnergyLimits(const double energy)
538  {
539  constexpr double min = 0.01*EeV;
540  constexpr double max = 1000*EeV;
541  return std::min(std::max(min, energy), max);
542  }
543 
544 
545  double
546  ModelFactor(const EInteractionModel interaction,
547  const ECompositionModel composition)
548  {
549  switch (interaction) {
550  case eQGSJET01:
551  case eDATA:
552  return 1;
553  case eSIBYLL21:
554  switch (composition) {
555  case eProton: return kQ2Sib[0];
556  case eIron: return kQ2Sib[1];
557  case eData: return 1;
558  case eMixedComposition: return 0.5*(kQ2Sib[0] + kQ2Sib[1]);
559  }
560  }
561  ERROR("You should specify a valid interaction and composition!");
562  return 0;
563  }
564 
565 
566  const double*
567  FitParameters(const ECompositionModel composition)
568  {
569  switch (composition) {
570  case eData: return kData;
571  case eProton: return kQGSJetProton;
572  case eIron: return kQGSJetIron;
573  case eMixedComposition: return kQGSJetMixed;
574  }
575  ERROR("You should specify a valid composition!");
576  return nullptr;
577  }
578 
579 
587  double
588  Factor(const double energyEM,
589  const EInteractionModel intMod,
590  const ECompositionModel compMod,
591  const double cosTheta)
592  {
593  const double energyEeV = InvisibleEnergy::EnergyLimits(energyEM) / EeV;
594 
595  const double mf = InvisibleEnergy::ModelFactor(intMod, compMod);
596 
597  const double* const p = InvisibleEnergy::FitParameters(compMod);
598 
599  if (intMod == eDATA) {
600  //const double factor = mf * (p[0] + p[1] * pow(energyEeV, p[2]-1));
601 
602  // ICRC 2017
603  //if (energyEeV > p[5])
604  // return mf * (p[0] + p[1] * pow(energyEeV, p[2]-1) * p[4]);
605  //else (becouse the previous returns!)
606  //return mf * (p[0] + p[1] * pow(p[5], p[2]) * pow(energyEeV/p[5], p[3]-1) /p[5] * p[4]);
607 
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));
623 
624  return factor;
625  }
626 
627  return 1 / (mf * (p[0] - p[1] * pow(energyEeV, -p[2])));
628  }
629 
630 
641  double
642  FactorDerivative(const double energyEM,
643  const EInteractionModel intMod,
644  const ECompositionModel compMod,
645  const double cosTheta)
646  {
647  const double energyLim = InvisibleEnergy::EnergyLimits(energyEM);
648  const double mf = InvisibleEnergy::ModelFactor(intMod, compMod);
649  const double* const p = InvisibleEnergy::FitParameters(compMod);
650  const double ep2 = pow(energyLim/EeV, -p[2]);
651  const double energyEeV = energyLim/EeV;
652 
653  if (intMod == eDATA) {
654  //const double dfdE = (p[2] - 1) * p[1] * pow(energyLim/EeV, p[2]-1)/energyLim;
655 
656  // ICRC 2017
657  //if (energyLim/EeV > p[5])
658  // return (p[2] - 1) * p[1] * pow(energyLim/EeV, p[2]-1) * p[4] / energyLim;
659 
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));
680 
681  return dFactor;
682  }
683 
684  return -ep2 * p[1] * p[2] / (energyLim * mf * Sqr(p[0] - p[1]*ep2));
685  }
686 
687 
688  // ICRC 2013
695  /*double
696  FactorVariance(const double eTot)
697  {
698  const double p0 = 1.66299e+06;
699  const double p1 = -6.35739e+00;
700  const double uncert = eTot * p0 * pow(log10(eTot), p1);
701  return Sqr(uncert);
702  }*/
703 
704 
705  // ICRC 2019
709  double
710  FactorVariance(const double eCal, const double eTot)
711  {
712  const double lgETot = log10(eTot);
713  // Matias Tueros QGSJET0III p/Fe (50%/50%) composition
714  // shower-to-shower fluctuations
715  constexpr double pp0 = 1.20836e6;
716  constexpr double pp1 = -6.42338;
717  const double uncert1 = eTot * pp0 * pow(lgETot, pp1); // dEinv_1
718 
719  // get the uncertainty due to the mixed composition
720  // Einv ~ A^(1-beta)
721  // dEinv = Einv (1-beta) sqrt( Var(ln(A) )
722 
723  // beta from Conex EPOSLHC (from Einv Fe/p)
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));
728 
729  // lnA variance - EPOSLHC ICRC 2017 v2 - function from Michael U.
730  constexpr double p0 = 1.52404;
731  constexpr double p1 = 2.06276e2;
732  constexpr double p2 = -2.19605e2;
733  // not extrapolate below 0.9*1e17
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);
737 
738  const double uncert2 = (eTot - eCal) * (1 - fbeta) * sqrt_var_lnA; // dEinv_2
739 
740  const double uncertsquare = (Sqr(uncert1/eTot) + Sqr(uncert2/eTot)) * Sqr(eTot);
741 
742  return uncertsquare;
743  }
744 
745  }
746 
747 
748  namespace XmaxParam {
749 
750  double
751  Mean(const double energy, const double massNumber,
752  const HadronicInteractionModel hadModel)
753  {
754  const double lgE = log10(energy / utl::eV) - 19;
755  const double lnA = log(massNumber);
756 
757  double x0 = 0;
758  double d = 0;
759  double xi = 0;
760  double delta = 0;
761 
762  if (hadModel == HadronicInteractionModel::eSibyll23d) {
763  x0 = 815.87 * g / cm2;
764  d = 57.873 * g / cm2;
765  xi = -0.3035 * g / cm2;
766  delta = 0.7963 * g / cm2;
767  } else if (hadModel == HadronicInteractionModel::eEPOSLHC) {
768  x0 = 806.04 * g / cm2;
769  d = 56.295 * g / cm2;
770  xi = 0.3463 * g / cm2;
771  delta = 1.0442 * g / cm2;
772  } else if (hadModel == HadronicInteractionModel::eQGSJETII04) {
773  x0 = 790.15 * g / cm2;
774  d = 54.191 * g / cm2;
775  xi = -0.4170 * g / cm2;
776  delta = 0.6927 * g / cm2;
777  } else {
779  "Invalid hadronic interaction model requested. "
780  "Implemented are Sibyll2.3d, EPOS-LHC and QGSJETII-04");
781  }
782 
783  const double meanXmaxP = x0 + d * lgE;
784  const double factorEnergy = xi - d / log(10) + delta * lgE ;
785  return meanXmaxP + factorEnergy * lnA;
786  }
787 
788  double
789  StandardDeviation(const double energy, const double massNumber,
790  const HadronicInteractionModel hadModel)
791  {
792  const double lgE = log10(energy / utl::eV) - 19;
793  const double lnA = log(massNumber);
794  double p0 = 0;
795  double p1 = 0;
796  double p2 = 0;
797  double a0 = 0;
798  double a1 = 0;
799  double b = 0;
800 
801  if (hadModel == HadronicInteractionModel::eSibyll23d) {
802  p0 = 3.727e3 * g * g / cm2 / cm2;
803  p1 = -4.838e2 * g * g / cm2 / cm2;
804  p2 = 1.325e2 * g * g / cm2 / cm2;
805  a0 = -4.055e-1;
806  a1 = -2.536e-4;
807  b = 4.749e-2;
808  } else if (hadModel == HadronicInteractionModel::eEPOSLHC) {
809  p0 = 3.269e3 * g * g / cm2 / cm2;
810  p1 = -3.053e2 * g * g / cm2 / cm2;
811  p2 = 1.239e2 * g * g / cm2 / cm2;
812  a0 = -4.605e-1;
813  a1 = -4.751e-4;
814  b = 5.838e-2;
815  } else if (hadModel == HadronicInteractionModel::eQGSJETII04) {
816  p0 = 3.688e3 * g * g / cm2 / cm2;
817  p1 = -4.279e2 * g * g / cm2 / cm2;
818  p2 = 5.096e1 * g * g / cm2 / cm2;
819  a0 = -3.939e-1;
820  a1 = 1.314e-3;
821  b = 4.512e-2;
822  } else {
824  "Invalid hadronic interaction model requested. "
825  "Implemented are Sibyll2.3d, EPOS-LHC and QGSJETII-04");
826  }
827 
828  double sigmaP2 = p0 + p1 * lgE + p2 * pow(lgE, 2);
829  double a = a0 + a1 * lgE;
830 
831  return sqrt(sigmaP2 * (1 + a * lnA + b * pow(lnA, 2)));
832  }
833 
834  }
835 
836 
837  namespace GumbelXmax {
838 
839  double
840  Mu(const double energy, const double massNumber,
841  const HadronicInteractionModel hadModel)
842  {
843  const double lgE = log10(energy / utl::eV) - 19;
844  const double lnA = log(massNumber);
845  double p0 = 0;
846  double p1 = 0;
847  double p2 = 0;
848 
849 
850  if (hadModel == HadronicInteractionModel::eSibyll23d) {
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);
854  } else if (hadModel == HadronicInteractionModel::eEPOSLHC) {
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);
858  } else if (hadModel == HadronicInteractionModel::eQGSJETII04) {
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);
862  } else {
864  "Invalid hadronic interaction model requested. "
865  "Implemented are Sibyll2.3d, EPOS-LHC and QGSJETII-04");
866  }
867 
868  const double mu = p0 + lgE * (p1 + p2 * lgE);
869  return mu * g/cm2;
870  }
871 
872  double
873  Sigma(const double energy, const double massNumber,
874  const HadronicInteractionModel hadModel)
875  {
876  const double lgE = log10(energy / utl::eV) - 19;
877  const double lnA = log(massNumber);
878  double p0 = 0;
879  double p1 = 0;
880 
881  if (hadModel == HadronicInteractionModel::eSibyll23d) {
882  p0 = 41.0345 + lnA * (-2.17329 - 0.306202 * lnA);
883  p1 = -0.309466 + lnA * (-1.1649 + 0.225445 * lnA);
884  } else if (hadModel == HadronicInteractionModel::eEPOSLHC) {
885  p0 = 32.2632 + lnA * (3.94252 - 0.864421 * lnA);
886  p1 = 1.27601 + lnA * (-1.81337 + 0.231914 * lnA);
887  } else if (hadModel == HadronicInteractionModel::eQGSJETII04) {
888  p0 = 35.4234 + lnA * (6.75921 - 1.46182 * lnA);
889  p1 = -0.796042 + lnA * (0.201762 - 0.0142452 * lnA);
890  } else {
892  "Invalid hadronic interaction model requested. "
893  "Implemented are Sibyll2.3d, EPOS-LHC and QGSJETII-04");
894  }
895 
896  const double sigma = p0 + lgE * p1;
897  return sigma * g/cm2;
898  }
899 
900 
901  double
902  Lambda(const double energy, const double massNumber,
903  const HadronicInteractionModel hadModel)
904  {
905  const double lgE = log10(energy / utl::eV) - 19;
906  const double lnA = log(massNumber);
907  double p0 = 0;
908  double p1 = 0;
909 
910  if (hadModel == HadronicInteractionModel::eSibyll23d) {
911  p0 = 0.799493 + lnA * (0.235235 + 0.00856884 * lnA);
912  p1 = 0.0632135 + lnA * (-0.0012847 + 0.000330525 * lnA);
913  } else if (hadModel == HadronicInteractionModel::eEPOSLHC) {
914  p0 = 0.641093 + lnA * (0.219762 + 0.171124 * lnA);
915  p1 = 0.0726131 + lnA * (0.0353188 - 0.0131158 * lnA);
916  } else if (hadModel == HadronicInteractionModel::eQGSJETII04) {
917  p0 = 0.671545 + lnA * (0.373902 + 0.075325 * lnA);
918  p1 = 0.0304335 + lnA * (0.0473985 - 0.000564531 * lnA);
919  } else {
921  "Invalid hadronic interaction model requested. "
922  "Implemented are Sibyll2.3d, EPOS-LHC and QGSJETII-04");
923  }
924 
925  const double lambda = p0 + lgE * p1;
926  return lambda * g/cm2;
927  }
928 
929  }
930 
931 
933  inline
934  double
935  GoraAParameter(const double age)
936  {
937  return (((5.151*age - 28.925)*age + 60.056)*age - 56.718)*age + 22.331;
938  }
939 
940 
942  inline
943  double
944  GoraBParameter(const double age)
945  {
946  return (-1.039*age + 2.251)*age + 0.676;
947  }
948 
949 
950  double
951  GoraCDF(const double rStar, const double age)
952  {
953  const double a = GoraAParameter(age);
954  const double b = GoraBParameter(age);
955  return 1- pow(1 + a*rStar, -b);
956  }
957 
958 
959  double
960  InverseGoraCDF(const double fraction, const double age)
961  {
962  const double a = GoraAParameter(age);
963  const double b = GoraBParameter(age);
964  return (pow(1 - fraction, -1/b) - 1) / a;
965  }
966 
967 
968  double
969  GoraPDF(const double rStar, const double age)
970  {
971  const double a = GoraAParameter(age);
972  const double b = GoraBParameter(age);
973  return b * a * pow(1 + a*rStar, -b - 1);
974  }
975 
976 }
double StandardDeviation(const std::vector< double > &v, const double mean)
Definition: Functions.cc:26
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 eV
Definition: AugerUnits.h:185
constexpr double kQGSJetMixed[]
double InverseGoraCDF(const double fraction, const double age)
const double degree
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
const double meter
Definition: GalacticUnits.h:29
HadronicInteractionModel
constexpr double kQGSJetProton[]
double pow(const double x, const unsigned int i)
const double EeV
Definition: GalacticUnits.h:34
constexpr double kgEarth
bool Solve3x3(const double y[3], double a[3][3], double x[3])
constexpr double MeV
Definition: AugerUnits.h:184
constexpr double micrometer
Definition: AugerUnits.h:101
#define max(a, b)
const double gauss
Definition: GalacticUnits.h:41
double Fermi(const double x)
constexpr double mole
Definition: AugerUnits.h:262
constexpr double pascal
Definition: AugerUnits.h:212
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
Definition: AugerUnits.h:281
double SaturationVaporPressure(const double temperature)
Evaluate the saturation vapor pressure over ice or water.
constexpr double g
Definition: AugerUnits.h:200
bool Invert3x3(double a[3][3])
#define WARNING(message)
Macro for logging warning messages.
Definition: ErrorLogger.h:163
double Sigma(const double energy, const double massNumber, const HadronicInteractionModel hadModel)
constexpr double kelvin
Definition: AugerUnits.h:259
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.
constexpr double joule
Definition: AugerUnits.h:181
constexpr double kData[]
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)
Definition: Functions.cc:505
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)
Definition: Functions.h:31
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.
Definition: ErrorLogger.h:165
constexpr double m
Definition: AugerUnits.h:121
double FactorVariance(const double eCal, const double eTot)
constexpr double perMillion
Definition: AugerUnits.h:286
double Mu(const double energy, const double massNumber, const HadronicInteractionModel hadModel)
constexpr double millibar
Definition: AugerUnits.h:214
bool QuadraticMaximumInterpolation(const std::vector< double > &x, const std::vector< double > &y, double &xMax, double &yMax)
double NormalizedGaisserHillas(const double x, const double xMax)
constexpr double kg
Definition: AugerUnits.h:199
constexpr double cm2
Definition: AugerUnits.h:118

, generated on Tue Sep 26 2023.