MuonArrivalTime.h
Go to the documentation of this file.
1 #ifndef _utl_MuonArrivalTime_h_
2 #define _utl_MuonArrivalTime_h_
3 
4 #include <utl/MathConstants.h>
5 #include <utl/PhysicalConstants.h>
6 #include <utl/AugerUnits.h>
7 #include <utl/Integrator.h>
8 #include <utl/Math.h>
9 #include <utl/NormalDistribution.h>
10 #include <limits>
11 
12 // based on original code and analysis of Lorenzo Cazon
13 // rewritten and extended by Hans Dembinski
14 
15 // not available in some compiler collections
16 namespace std {
17  inline double pow(const double x, const unsigned int i) { return std::pow(x, int(i)); }
18 }
19 
20 namespace utl {
21 
24  public:
25 
27  : fTheta(0.0),
28  fR(0.0),
29  fDelta(0.0),
30  fLogLambda(0.0),
31  fLogMean(0.0),
32  fLogSigma(0.0),
33  fNorm(1.0),
34  fMean(0.0),
35  fSigma(0.0),
36  fTimePDFArg(*this),
38  fTimeCDFArg(*this),
40  fSuperArg(*this),
42  fApproxMomentArg(*this),
44  {
45  // do not change these
46  fTimePDF.SetAccuracy(1e-2);
47  fTimeCDF.SetAccuracy(1e-5);
48  fSuper.SetAccuracy(1e-5);
49  fApproxMoment.SetAccuracy(1e-2);
50  }
51 
53  void
54  SetTheta(const double theta)
55  {
56  fTheta = theta;
57  const double c = std::cos(theta);
58 
59  const double pars1[] = { 5.682, -5.524, 9.180, -8.277, 2.797 };
60  fLogMean = EvalPoly(c, 5, pars1);
61 
62  const double pars2[] = { 0.03266, 0.456, -1.084, 1.199, -0.4366 };
63  fLogSigma = EvalPoly(c, 5, pars2);
64 
65  const double pars3[] = { -0.01111, 0.2581, -0.7385, 3.362, -2.261 };
66  fLogLambda = EvalPoly(c, 5, pars3);
67  if (fLogLambda < 0.03) fLogLambda = 0.03;
68  }
69 
71  void
72  SetThetaAndDistance(const double theta, const double distance)
73  {
74  SetTheta(theta);
75  fLogMean = std::log10(distance);
76  }
77 
80  void
81  SetCoordinates(const double r, const double delta)
82  {
83  fR = r;
84  fDelta = delta;
85 
86  // compute normalisation and 1rst and 2nd moment
87  double result[4] = { 0, 0, 0, 0 };
88  fNorm = 1.0;
89  fStart = -20;
90  for (int i = fStart; i < 20; ++i)
91  {
92  double delta[4];
93  fSuper.GetIntegral(delta, i, i+1);
94  result[0] += delta[0];
95  result[1] += delta[1];
96  result[2] += delta[2];
97  result[3] += delta[3];
98  if (result[0] == 0) fStart = i+1;
99  if (delta[0] < 1e-5*result[0]) break;
100  }
101 
102  fNorm = result[0];
103  fMean = result[2]/result[1];
104  fSigma = std::sqrt(result[3]/result[1]-fMean*fMean);
105  }
106 
108  double
109  TimePDF(const double t)
110  const
111  {
112  if (t <= 0) return 0;
114  return fTimePDF.GetIntegral(0, t);
115  }
116 
118  double
119  TimeCDF(const double t)
120  const
121  {
122  if (t <= 0) return 0;
123  const double lnt = std::log(t);
124  double result = 0;
125  for (int i = fStart; i < lnt; ++i)
126  {
127  const double delta = fTimeCDF.GetIntegral(i, i+1 < lnt ? i+1 : lnt);
128  result += delta;
129  if (delta < 1e-5*result) break;
130  }
131  return result;
132  }
133 
135  double
136  FirstTimePDF(const double t, const unsigned int nmuons)
137  const
138  {
139  if (nmuons <= 1) return TimePDF(t);
140  return nmuons*std::pow(1.0 - TimeCDF(t), nmuons-1)*TimePDF(t);
141  }
142 
144  double
145  ApproximateTimePDF(const double t)
146  const
147  {
148  if (t <= 0) return 0;
149  // beware: normal distribution in log(t), not log-normal distribution!
150  return utl::NormalPDF(std::log(t),fMean,fSigma)/std::exp(fMean+0.5*fSigma*fSigma);
151  }
152 
154  double
155  ApproximateTimeCDF(const double t)
156  const
157  {
158  if (t <= 0) return 0;
159  const double z = (std::log(t)-fMean)/fSigma - fSigma;
160  return 0.5*(1.0+erf(z/kSqrt2));
161  }
162 
164  double
165  ApproximateFirstTimePDF(const double t, const unsigned int nmuons)
166  const
167  {
168  if (nmuons <= 1) return ApproximateTimePDF(t);
169  return nmuons*std::pow(1.0 - ApproximateTimeCDF(t), nmuons-1)*ApproximateTimePDF(t);
170  }
171 
172  void
173  GetApproximateMeanAndStDev(double& mean, double& stdev, const unsigned int nmuon)
174  const
175  {
176  fApproxMomentArg.fNMuon = nmuon;
177  double result[2] = { 0, 0 };
178  for (int i = fStart; i < 20; ++i)
179  {
180  double delta[2];
181  fApproxMoment.GetIntegral(delta, i, i+1);
182  result[0] += delta[0];
183  result[1] += delta[1];
184  if (delta[1] < 1e-5*result[1]) break;
185  }
186 
187  mean = result[0];
188  stdev = std::sqrt(result[1] - mean*mean);
189  }
190 
191  private:
192 
194  double
195  PDF_dNdt_G(const double t)
196  const
197  {
198  if (t <= 0) return 0.0;
199 
200  const double c = utl::kSpeedOfLight;
201  const double r = fR;
202 
203  // t is time delay after shower front (for ct << z?)
204  const double z0 = 0.5*(r*r/(c*t)-c*t);
205  const double z = z0 + fDelta;
206  if (z <= 0) return 0.0;
207 
208  const double dzdt = 0.5*(r*r/(c*t*t)+c);
209 
210  const double cosaDa = std::sqrt(1.0-r*r/(z0*z0 + r*r));
211 
212  const double lgZ = std::log10(z);
213  const double dNdz = 1.0/(z*utl::kLn10)*PDF_dNdlgZ(lgZ);
214 
215  return cosaDa*dNdz*dzdt;
216  }
217 
219  double
220  PDF_dNdt_E(const double t)
221  const
222  {
223  if (t <= 0) return 0.0;
224 
225  const double zMean = std::pow(10, fLogMean);
226  const double z0 = zMean - fDelta;
227  const double x = std::sqrt(z0*z0 + fR*fR);
228 
229  const double m2 = 0.011;
230  const double pk = 0.0002;
231  const double c = utl::kSpeedOfLight;
232 
233  const double energy = 0.5*pk*x*(1.0+std::sqrt(1.0+2.0*m2/(pk*pk*x*c*t)));
234  const double dEdt = 0.5*pk*x*1.0/std::sqrt(1.0+2.0*m2/(pk*pk*x*c*t))*m2/(pk*pk*x*c*t*t);
235 
236  return PDF_dNdE(energy, x, fR)*dEdt;
237  }
238 
240  double
241  PDF_dNdlgZ(const double logz)
242  const
243  {
244  const double f1 = (logz-fLogMean)/fLogLambda;
245  const double f2 = 0.5*(fLogSigma*fLogSigma)/(fLogLambda*fLogLambda);
246  const double f3 = (logz-fLogMean)/(utl::kSqrt2*fLogSigma);
247  const double f4 = fLogSigma/(utl::kSqrt2*fLogLambda);
248 
249  return std::exp(f1+f2)*erfc(f3+f4)/(2.0*fLogLambda);
250  }
251 
253  double
254  PDF_dNdE(const double energy, const double x, const double r)
255  const
256  {
257  const double pk=0.0002;
258  const double kappa=0.8;
259  const double lamb=1;
260  const double ptc=0.17;
261  const double gam=2.6;
262  return (1.0-r*r/(x*x))
263  *std::pow(r/x,lamb)
264  *std::pow(energy,-gam-kappa+lamb+1)
265  *std::pow(energy-pk*x,kappa)
266  *std::exp(-energy*r/(x*ptc));
267  }
268 
269  // Utiltities
270  double
271  EvalPoly(const double x, const int n, const double* pars)
272  const
273  {
274  double result = pars[n-1];
275  for (int i = 1; i < n; ++i)
276  {
277  result *= x;
278  result += pars[n-1-i];
279  }
280  return result;
281  }
282 
283  struct TimePDFArg {
285  double fT;
286 
288  : fParent(parent)
289  {}
290 
291  double
292  operator()(const double t)
293  const
294  {
295  return fParent.PDF_dNdt_E(t)*fParent.PDF_dNdt_G(fT-t)/fParent.fNorm;
296  }
297  };
298 
299  struct TimeCDFArg {
301 
303  : fParent(parent)
304  {}
305 
306  double
307  operator()(const double lnt)
308  const
309  {
310  const double t = std::exp(lnt);
311  fParent.fTimePDFArg.fT = t;
312  return t*fParent.fTimePDF.GetIntegral(0, t);
313  }
314  };
315 
316  struct SuperArg {
318 
319  SuperArg(const MuonArrivalTime& parent)
320  : fParent(parent)
321  {}
322 
323  void
324  operator()(double* result, const double lnt)
325  const
326  {
327  const double t = std::exp(lnt);
328  fParent.fTimePDFArg.fT = t;
329  const double f = fParent.fTimePDF.GetIntegral(0, t);
330 
331  result[0] = f*t; // norm of f(t) d t
332  result[1] = f; // norm of f(t) d ln(t)
333  result[2] = f*lnt; // mean of f(t) d ln(t)
334  result[3] = f*lnt*lnt; // var of f(t) d ln(t)
335  }
336  };
337 
340  unsigned int fNMuon;
341 
343  : fParent(parent)
344  {}
345 
346  void
347  operator()(double* result, const double lnt)
348  const
349  {
350  const double t = std::exp(lnt);
351  const double f = fParent.ApproximateFirstTimePDF(t, fNMuon)*t;
352 
353  result[0] = f*t;
354  result[1] = f*t*t;
355  }
356  };
357 
358  private:
359  double fTheta;
360  double fR;
361  double fDelta;
362  double fLogLambda;
363  double fLogMean;
364  double fLogSigma;
365  double fNorm;
366  double fStart;
367  double fMean;
368  double fSigma;
377  };
378 
379 }
380 
381 #endif
TimePDFArg(const MuonArrivalTime &parent)
utl::VectorIntegrator< ApproxMomentArg, 2 > fApproxMoment
return PDF_dNdE(energy, x, fR)*dEdt
utl::VectorIntegrator< SuperArg, 4 > fSuper
double operator()(const double lnt) const
Class for integration of functions with one independent parameter.
Definition: Integrator.h:72
return * erf(z/kSqrt2))
void SetThetaAndDistance(const double theta, const double distance)
setup model for given zenith angle and mean production distance
utl::Integrator< TimePDFArg > fTimePDF
double pow(const double x, const unsigned int i)
const MuonArrivalTime & fParent
return cosaDa *dNdz * dzdt
double operator()(const double t) const
double NormalPDF(const double x)
void operator()(double *result, const double lnt) const
ApproxMomentArg(const MuonArrivalTime &parent)
const MuonArrivalTime & fParent
double EvalPoly(const T &a, const double x)
Simple polynomial evaluator.
void SetTheta(const double theta)
setup of model for given zenith angle
void operator()(double *result, const double lnt) const
ApproxMomentArg fApproxMomentArg
all time delays are relative to arrival time of shower front plane
constexpr double kLn10
Definition: MathConstants.h:29
constexpr double kSqrt2
Definition: MathConstants.h:30
constexpr double kSpeedOfLight
SuperArg(const MuonArrivalTime &parent)
utl::Integrator< TimeCDFArg > fTimeCDF
return std::exp(f1+f2)*erfc(f3+f4)/(2.0 *fLogLambda)
TimeCDFArg(const MuonArrivalTime &parent)
void SetCoordinates(const double r, const double delta)
const MuonArrivalTime & fParent

, generated on Tue Sep 26 2023.