12 #include <utl/TabulatedFunction.h>
13 #include <utl/Reader.h>
14 #include <utl/ErrorLogger.h>
15 #include <utl/MathConstants.h>
16 #include <utl/Vector.h>
17 #include <utl/AxialVector.h>
18 #include <utl/AugerUnits.h>
19 #include <utl/PhysicalConstants.h>
20 #include <utl/PhysicalFunctions.h>
21 #include <utl/Transformation.h>
22 #include <utl/TabulatedFunctionErrors.h>
23 #include <utl/ReferenceEllipsoid.h>
24 #include <utl/Point.h>
25 #include <utl/StringCompare.h>
26 #include <utl/TimeStamp.h>
28 #include <atm/ProfileResult.h>
29 #include <atm/AnalyticalCherenkovModel.h>
31 #include <fwk/CentralConfig.h>
32 #include <fwk/CoordinateSystemRegistry.h>
33 #include <fwk/MagneticFieldModel.h>
34 #include <fwk/RunController.h>
36 #include <det/Detector.h>
38 #include <evt/Event.h>
39 #include <evt/Header.h>
48 const double AnalyticalCherenkovModel::fdE = 10*
MeV;
49 const double AnalyticalCherenkovModel::fjMax = 800*
MeV;
51 const double AnalyticalCherenkovModel::fNerlingMinValidShowerAge = 0.1;
52 const double AnalyticalCherenkovModel::fNerlingMaxValidShowerAge = 2.;
61 const double kAngHillas_aPar = 0.83;
62 const double kAngHillas_bPar = -0.67;
65 return kAngHillas_aPar *
pow(energyThreshold/
MeV, kAngHillas_bPar);
71 const double kAngNerling_a0 = 4.2489e-1;
72 const double kAngNerling_a1 = 5.8371e-1;
73 const double kAngNerling_a2 = -8.2373e-2;
74 return kAngNerling_a0 + kAngNerling_a1 * s + kAngNerling_a2 * s*
s;
78 const double kAngNerling_b0 = 5.5108e-2;
79 const double kAngNerling_b1 = -9.5587e-2;
80 const double kAngNerling_b2 = 5.6952e-2;
81 return kAngNerling_b0 + kAngNerling_b1 * s + kAngNerling_b2 * s*
s;
85 const double kAngNerling_thc0 = 6.2694e-1;
86 const double kAngNerling_thc1 = -6.0590e-1;
87 return kAngNerling_thc0 *
pow(energyThreshold/
MeV, kAngNerling_thc1);
91 const double kAngNerling_thcc0 = 1.0509e+1;
92 const double kAngNerling_thcc1 = -4.9644;
93 return kAngNerling_thcc0 + kAngNerling_thcc1 *
s;
109 const double showerAge,
112 const unsigned int nValues = 4;
114 { {6.058, -1.103e-3, -2.886e-3, -5.447},
115 {2.905, -3.851e-2, 1.072e-1, 1.066e+1},
116 {7.320, -3.778e-1, 7.202e-2, 7.143},
117 {-2.754, -4.242e-1, 1.084e-1, 3.344},
118 {2.620, 6.837e-2, -2.247e-2, 1.110} };
119 const double additionalC2Par = -4.294;
121 const double*
p = parArray[par];
122 const double s = showerAge;
123 const double h = height /
km;
126 return p[0] * exp(p[1] * s + p[2] * h) + p[3];
128 const double s2 = s*
s;
129 return p[0] * exp(p[1] * s2 + p[2] * h) +
130 (p[3] * s2 + additionalC2Par *
s);
138 return -exp(-x/t)*(t*cos(x)+sin(x))/(t*t+1);
145 return -exp(-x*(1./t+a))*(a*t*sin(x)+t*cos(x)+sin(x))/(t*t*(a*a+1)+2*t*a+1);
149 AnalyticalCherenkovModel::AnalyticalCherenkovModel() :
150 fArbeletcheAngularDistribution(1e6,
kPiOnTwo),
151 fShowerAgePrevious(-10)
164 CentralConfig::GetInstance()->
GetTopBranch(
"AnalyticalCherenkovModel");
168 const string param = topB.
GetChild(
"parametrization").
Get<
string>();
169 if (param ==
"eHillas")
171 else if (param ==
"eGiller")
173 else if (param ==
"eNerling")
176 ERROR(
"Parametrization not implemented");
180 const string paramAngular =
181 topB.
GetChild(
"parametrization_angular").
Get<
string>();
182 if (paramAngular ==
"eAngHillas")
184 else if (paramAngular ==
"eAngNerling")
186 else if (paramAngular ==
"eAngGiller")
188 else if (paramAngular ==
"eAngArbeletche")
191 ERROR(
"Parametrization Angular not implemented");
195 const string cherenkovDistribution =
196 topB.
GetChild(
"cherenkovDistribution").
Get<
string>();
197 if (cherenkovDistribution ==
"symmetric")
199 else if (cherenkovDistribution ==
"asymmetric")
202 ERROR(
"Unknown \"cherenkovDistribution\"");
227 const double showerAge)
235 vector<double> directCher;
236 for (
int i = 0; i < numWaves; ++i) {
238 directCher.push_back(photons[i].Y()*prob*probWl);
253 const double showerAge)
256 Detector& theDetector = Detector::GetInstance();
262 (xA.
GetZ(cs) + xB.
GetZ(cs))*0.5, cs);
263 const Vector xAxEyeDir = xEye - xA;
264 const Vector xBxEyeDir = xEye - xB;
266 double aBin =
Angle(xAxEyeDir, xBxEyeDir);
271 const double projection = shwDir*xAxEyeDir;
272 const double rp = (xA + projection*shwDir - xEye).GetMag();
273 const Vector xMeanVec = xMean - xEye;
276 const double emissAngle =
Angle(-shwDir,xMeanVec);
281 double lowAngle = emissAngle - aBin*0.5;
283 lowAngle = emissAngle*0.5;
284 const double highAngle = emissAngle + aBin*0.5;
285 aBin = highAngle-lowAngle;
288 const double atmHeightMin = dvh.
MinX();
289 const double atmHeightMax = dvh.
MaxX();
292 if (hA < atmHeightMin)
293 depthA = dvh.
Y(atmHeightMin);
294 else if (hA > atmHeightMax)
295 depthA = dvh.
Y(atmHeightMax);
299 if (hB < atmHeightMin)
300 depthB = dvh.
Y(atmHeightMin);
301 else if (hB > atmHeightMax)
302 depthB = dvh.
Y(atmHeightMax);
306 const double meanDepth = (depthA + depthB)*0.5;
321 const double dAModified =
kTwoPi*rp*rp*aBin;
323 return eTimesSine/dAModified;
330 const double showerAge,
331 const double wavelength)
334 Detector& theDetector = Detector::GetInstance();
340 (xA.
GetZ(cs) + xB.
GetZ(cs))*0.5, cs);
341 const Vector xAxEyeDir = xEye - xA;
342 const Vector xBxEyeDir = xEye - xB;
344 double aBin =
Angle(xAxEyeDir, xBxEyeDir);
349 const double projection = shwDir*xAxEyeDir;
350 const double rp = (xA + projection*shwDir - xEye).GetMag();
351 const Vector xMeanVec = xMean - xEye;
354 const double emissAngle =
Angle(-shwDir,xMeanVec);
359 double lowAngle = emissAngle - aBin*0.5;
361 lowAngle = emissAngle*0.5;
362 const double highAngle = emissAngle + aBin*0.5;
363 aBin = highAngle-lowAngle;
366 const double atmHeightMin = dvh.
MinX();
367 const double atmHeightMax = dvh.
MaxX();
388 const double meanHeight = ((hA+hB)/2.) < atmHeightMin ? atmHeightMin : ( ((hA+hB)/2.) > atmHeightMax ? atmHeightMax : ((hA+hB)/2.) );
405 const double dAModified =
kTwoPi*rp*rp*aBin;
407 return eTimesSine/dAModified;
429 const double showerAge)
443 const double distAB = (xA - xB).GetMag();
448 Detector& theDetector = Detector::GetInstance();
450 const double atmHeightMin = dvh.
MinX();
451 const double atmHeightMax = dvh.
MaxX();
454 if (hA < atmHeightMin)
455 depthA = dvh.
Y(atmHeightMin);
456 else if (hA > atmHeightMax)
457 depthA = dvh.
Y(atmHeightMax);
461 if (hB < atmHeightMin)
462 depthB = dvh.
Y(atmHeightMin);
463 else if (hB > atmHeightMax)
464 depthB = dvh.
Y(atmHeightMax);
468 const double meanDepth = (depthA + depthB)*0.5;
470 const double meanHeight = ((hA+hB)/2.) < atmHeightMin ? atmHeightMin : ( ((hA+hB)/2.) > atmHeightMax ? atmHeightMax : ((hA+hB)/2.) );
484 vector<double> nPhotons(numWaves,0);
486 for (
double energy = thresholdEnergy; energy <
fjMax; energy +=
fdE) {
488 double deltaLength = 0.;
492 deltaLength = tl1 - tl2;
496 ERROR(
"Non-existent parametrization");
500 const double eelec = energy +
fdE*0.5;
505 double maxWaveBin = 0;
506 for (
int i = 0; i < numWaves; ++i) {
510 if (
fWlRefrac && (energy < thresholdEnergyWl))
continue;
515 minWaveBin = maxWaveBin;
523 minWaveBin, maxWaveBin);
528 const double ehigh = 10.*
GeV;
531 double trackLength = 0.;
537 for (
double jj = fjMax; jj < ehigh; jj +=
fdE) {
541 ERROR(
"Non-existent parametrization");
546 double maxWaveBin = 0;
547 for (
int i = 0; i < numWaves; ++i) {
552 minWaveBin = maxWaveBin;
562 minWaveBin, maxWaveBin);
579 const double showerAge)
592 const double e0 = (showerAge < 0.4) ?
594 (44.0 - 17.0*(showerAge - 1.46)*(showerAge - 1.46))*
MeV;
597 const double trackLength =
598 pow((0.89*e0/
MeV - 1.2)/(e0/
MeV + energy/
MeV), showerAge) /
599 pow((1.0 + 1.0e-4*showerAge*energy/
MeV), 2);
612 const double a = 1.005;
613 const double b = 0.06;
614 const double c = 189.0;
616 const double cs = 0.111*showerAge + 0.134;
617 const double ds = 7.06*showerAge + 12.48;
619 const double energyCr = 80.0*
MeV;
621 const double auxExponent = -(showerAge + b*log(energy/(c*energyCr)));
623 const double dist_giller = cs*(1.0 - a*exp(-ds*energy/energyCr)) *
624 pow(1.0 + energy/energyCr, auxExponent);
626 const double trackLength = dist_giller *(
fdE/energy);
633 const double a1 = 6.42522 - 1.53183 * truncatedAge;
634 const double a2 = 168.168 - 42.1368 * truncatedAge;
641 double dist_nerling = a0 / (energy/
MeV + a1) /
pow(energy/
MeV + a2, truncatedAge);
643 const double trackLength = dist_nerling * (
fdE/
MeV);
648 ERROR(
"Non-existent parametrization");
660 const double eelec,
const double dSlant,
661 const double wl1,
const double wl2)
665 const double delta = nIndex - 1.;
666 const double alpha = 1./137.035989;
667 const double photons = (
kTwoPi*alpha) *
abs(1.0/wl1 - 1.0/wl2) *
668 (2.*delta - xme*xme/(eelec*eelec))*dSlant;
679 const double highAngle,
680 const double showerAge,
681 const double refractiveIndex)
701 const double t2 = c * t1;
710 double par[5] = {6.98169e-01, -2.86420e-01, 1.76411e-01/
deg, -2.36286e+00, -7.70755e-02/
deg};
723 ERROR(
"Non-existent parametrization");
732 const double verticalDepth,
733 const double showerAge)
744 const double energyThreshold =
749 const double elecAngle =
HillasAngle(energyThreshold);
750 const double hillasCDF = 1.- exp(-theta/elecAngle);
768 const double th_cc = c * th_c;
770 const double nerlingCDF = A*(1 - exp(-theta/th_c)) +
771 B*(1 - exp(-theta/th_cc));
774 const double nerlingNorm = A*(1 - exp(-
kPiOnTwo/th_c)) +
777 return nerlingCDF/nerlingNorm;
784 ERROR(
"Non-existent CDF parametrization");
795 static const double b11[]=
797 static const double b12[]=
799 static const double b13[]=
802 return b11[species] * theta * theta + b12[species] * theta + b13[species];
808 static const double b2 [] = { -8.4e-3, -9.3e-3};
809 return b1param(theta, species) * a + b2[species];
817 const double Fs = 0.5 * bsum;
818 const double Fa = bdiff / bsum;
820 const double binning = 10./360.;
821 const double A = binning - 3./8. * Fs;
823 const double sinphi4=(sinphi*sinphi) * (sinphi*sinphi);
825 return (1./binning) * (A + Fs * (1 + Fa*sinphi) * sinphi4);
831 return v - axis*v*axis;
845 const int neg = signbit (uXv * up);
860 Detector& det = Detector::GetInstance();
868 const double density)
const
876 double theta =
Angle(axis, v_toeye);
897 (xA.
GetZ(cs) + xB.
GetZ(cs))*0.5, cs);
898 Vector xMeanVec = xMean-xEye;
899 double altitude=xMean.
GetZ(cs);
901 const Atmosphere& atmo = det::Detector::GetInstance().GetAtmosphere();
913 static const double b11[]={ 0.00206, 0.00156};
914 static const double b12[]={ 0.0072, 0.0065};
916 const double b1=b11[species] * theta/
degree + b12[species];
923 const double sinphi)
const
925 const double binning=10./360.;
926 const double sinphi4= (sinphi*sinphi)*(sinphi*sinphi);
927 return (1./binning) * ( (binning - bp*3./8.) + bp * (1+bm*sinphi) * sinphi4 );
933 const double density)
const
942 double theta =
Angle(axis, v_toeye);
947 double bm = (fm - fp) / (fm + fp);
948 double bp = 0.5* (fm + fp);
956 const double verticalDepth,
957 const double showerAge)
968 const double energyThreshold =
973 const double elecAngle =
HillasAngle(energyThreshold);
975 const double hillasNorm = 1.- exp(-
kPiOnTwo/elecAngle);
976 return exp(-theta/elecAngle)/hillasNorm;
988 const double th_cc = c * th_c;
991 const double nerlingNorm = A*(1 - exp(-
kPiOnTwo/th_c)) +
994 return (A*exp(-theta/th_c)/th_c+B*exp(-theta/th_cc)/th_cc)/nerlingNorm;
1000 Detector::GetInstance().GetAtmosphere().EvaluateHeightVsDepth();
1001 const double height =
1002 heightVsDepth.
Y(fmin(fmax(verticalDepth, heightVsDepth.
MinX()),
1003 heightVsDepth.
MaxX()));
1006 if (theta < theta0) {
1010 return a1 * exp(-(c1 * theta + c2 * theta*theta));
1015 return a2 *
pow(theta, -alpha);
1022 ERROR(
"Non-existent PDF parametrization");
1039 const int nEnergies = 6;
1041 const double Ecut[nEnergies] = { 2.*
MeV, 1.*
MeV, 0.5*
MeV,
1044 const double p0[nEnergies] = { 1.48071e-01, 1.45098e-01,
1045 1.43458e-01, 1.42589e-01,
1046 1.42049e-01, 1.41866e-01 };
1048 const double p1[nEnergies] = { 6.22334, 6.20114,
1052 const double p2[nEnergies] = { -5.89710e-01, -5.96851e-01,
1053 -6.01298e-01, -6.03838e-01,
1054 -6.05484e-01, -6.06055e-01 };
1057 if (
fEcut > Ecut[0]) {
1064 for (
int i = 1; i < nEnergies; ++i)
1065 if (
fEcut > Ecut[i]) {
1074 p0[i1] + (p0[i2] - p0[i1])/(Ecut[i2] - Ecut[i1]) * (
fEcut - Ecut[i1]);
1076 p1[i1] + (p1[i2] - p1[i1])/(Ecut[i2] - Ecut[i1]) * (
fEcut - Ecut[i1]);
1078 p2[i1] + (p2[i2] - p2[i1])/(Ecut[i2] - Ecut[i1]) * (
fEcut - Ecut[i1]);
Branch GetTopBranch() const
double NerlingAngle(const double energyThreshold)
AxialVector Cross(const Vector &l, const Vector &r)
std::vector< double > fNerlingFactor
double fShowerAgePrevious
double CherenkovIntegral(double lowAngle, double highAngle, double meanShowerAge, double refractiveIndex) const
Calculation of the Cherenkov angle integral int(df/dtheta*sin(theta))
Top of the interface to Atmosphere information.
utl::TabulatedFunction & EvaluateCherenkovPhotons(const utl::Point &xA, const utl::Point &xB, const double showerAge) const
Calculation of Cherenkov photons produced between two points.
Parametrization fParam
Parametrization to be used in the Cherenkov light calculation.
double Angle(const double theta1, const double phi1, const double theta2, const double phi2)
double b1param(double theta, int species)
constexpr double kElectronMass
double AngularPDF(const double theta, const double verticalDepth, const double showerAge) const
double fEcut
electron energy-cutoff
double NerlingAngleFactor(const double s)
Class to hold collection (x,y) points and provide interpolation between them.
const atm::ProfileResult & EvaluatePressureVsHeight() const
Tabulated function giving Y=air pressure as a function of X=height.
bool fCorrectCherenkovAsymmetry
const atm::ProfileResult & EvaluateDensityVsHeight() const
Tabulated function giving Y=density as a function of X=height.
double fparam(double a, double theta, int species)
utl::Vector GetGeoMagneticFieldAt(const utl::Point &location)
void Init()
Init method of the model.
Arbeletche2021CherenkovAngularModel fArbeletcheAngularDistribution
static const double fjMax
double CDF(const double theta, const double showerAge, const double refractiveIndex) const
Computes the CDF of the angular distribution of Cherenkov photons.
Base class for exceptions trying to access non-existing components.
Branch GetChild(const std::string &childName) const
Get child of this Branch by child name.
utl::CoordinateSystemPtr GetSiteCoordinateSystem() const
Get the coordinate system for the site.
double pow(const double x, const unsigned int i)
utl::TabulatedFunction fCherenkovPhotons
Number of photons as function of the wavelength.
utl::Point fxAprevious
Keep reference to previous calculation, to prevent re-calculation.
double PDF(const double theta, const double showerAge, const double refractiveIndex) const
Computes the PDF of the angular distribution of Cherenkov photons.
double Y(const double x) const
Get the Y value (coordinate) for given X (ordinate)
double AngularCDF(const double theta, const double verticalDepth, const double showerAge) const
bool CorrectCherenkovAsymmetry(double age, double theta) const
utl::Vector bFieldAt(utl::Point x)
const atm::Atmosphere & GetAtmosphere() const
double fCherenkovAsymmetryMinAge
double NerlingNormB(const double s)
boost::shared_ptr< const CoordinateTransformer > CoordinateSystemPtr
Shared pointer for coordinate systems.
Class representing a document branch.
double fCherenkovAsymmetryMinA
Reference ellipsoids for UTM transformations.
double IntegralExpSinExp(const double x, const double t, const double a)
double CherenkovThreshold(const double nRef)
Calculate the electron Cherenkov threshold energy for refraction index.
double DeltaPhotons(double nIndex, double eelec, double dSlant, double wl1, double wl2) const
Calculation of Cherenkov Photons between two wavelengths.
double GetX(const CoordinateSystemPtr &coordinateSystem) const
Class describing the Atmospheric profile.
double EvaluateDirectCherenkovProbability(const utl::Point &xA, const utl::Point &xB, const utl::Point &xEye, const double showerAge) const
double abs(const SVector< n, T > &v)
double HillasAngle(const double energyThreshold)
double Integral(const double lowAngle, const double highAngle, const double showerAge, const double refractiveIndex) const
Compute the integral of PDF(theta)*sin(theta) between specified angles.
Top of the hierarchy of the detector description interface.
Triple PointToLatitudeLongitudeHeight(const Point &thePoint) const
Convert Point to Lat/Long/Height.
const atm::ProfileResult & EvaluateDepthVsHeight() const
Tabulated function giving Y=depth as a function of X=height.
constexpr double kPiOnTwo
void GetData(bool &b) const
Overloads of the GetData member template function.
constexpr double microtesla
AxialVector Normalized(const AxialVector &v)
double bparam(double a, double theta, int species)
double IntegralExpSin(const double x, const double t)
double LorentzLorentz(const double verticalDepth)
Calculate the refraction index for a given depth.
static const double fNerlingMinValidShowerAge
Limits for the shower age in the use of the Nerling parameterizations.
double GetGillerAngularParameter(const EGillerAngularParameter par, const double showerAge, const double height)
double vectorsine_oriented(const utl::Vector &u, const utl::Vector &v, const utl::Vector &up)
ParametrizationAngular fParamAngular
double GetY(const CoordinateSystemPtr &coordinateSystem) const
double MinX() const
Return the minimum value for X (ordinate) stored in the profile.
double Ciddor95(const double wl, const double temperature, const double pressure, const double vaporPressure)
Wavelength-dependent index of refraction for humid air.
double fCherenkovAsymmetryMaxA
double AsymmCorrection(double a, double theta, double sinphi) const
Asymmetry correction as local parametrisation.
double NerlingNormA(const double s)
static const double fNerlingMaxValidShowerAge
double fCherenkovAsymmetryMinAngle
double GetZ(const CoordinateSystemPtr &coordinateSystem) const
utl::TabulatedFunction & EvaluateCherenkovDirect(const utl::Point &xA, const utl::Point &xB, const utl::Point &xEye, const double showerAge) const
Calculation of probability of Cherenkov emission.
#define ERROR(message)
Macro for logging error messages.
std::vector< double > fWavelength
Wavelengths to calculate the light production.
void SetEnergyCutoff(double ecut) const
const atm::ProfileResult & EvaluateVaporPressureVsHeight() const
Tabulated function giving Y=H20 vapor pressure as a function of X=height.
double AsymmCorrectionOld(double bm, double bp, double sinphi) const
Asymmetry correction with old local parametrisation.
double fCherenkovAsymmetryMaxAge
utl::Vector perpendicular(const utl::Vector &v, const utl::Vector &axis)
const atm::ProfileResult & EvaluateTemperatureVsHeight() const
Tabulated function giving Y=temperature as a function of X=height.
double CherenkovTrackLength(double energy, double showerAge) const
Calculation of a special track length to be used in the Cherenkov light evaluation.
double MaxX() const
Return the maximum value for X (ordinate) stored in the profile.
double vectorsine(const utl::Vector &u, const utl::Vector &v)
utl::TabulatedFunction fDirectCherenkovPhotons
double fCherenkovAsymmetryMaxAngle