MuonTimeModel.cc
Go to the documentation of this file.
1 #include "MuonTimeModel.h"
2 
3 #include <utl/RandomEngine.h>
4 #include <utl/TabulatedFunction.h>
5 #include <utl/RandomSamplerFromPDF.h>
6 #include <utl/PhysicalConstants.h>
7 #include <utl/PhysicalFunctions.h>
8 #include <utl/Math.h>
9 
10 #include <iostream>
11 #include <iomanip>
12 
13 using namespace utl;
14 using namespace std;
15 
16 
17 /* Model Constants */
18 /* todo
19  - add many comments (especially to constants)
20  - only use meaningfull names or variables/functins
21 */
22 const double MuonTimeModel::fgM2 = 0.011;
23 const double MuonTimeModel::fgPk = 0.0002;
24 const double MuonTimeModel::fgKappa = 0.8;
25 const double MuonTimeModel::fgLambda = 1;
26 const double MuonTimeModel::fgQ = 0.17;
27 const double MuonTimeModel::fgGamma = 2.6;
28 
29 
31  const double theta,
32  const double logE,
33  const int primary,
34  const bool flagAngularFactorDa_in) :
35  fRandomEngine(randomEngine),
36  fTheta(theta),
37  fCosTheta(cos(theta)),
38  fLogE(logE),
39  fPrimary(primary),
40  flagAngularFactorDa(flagAngularFactorDa_in),
41  flagDecayFactor(false),
42  fGRDGeometricalLogtDist(0),
43  fGRDKinematicalLogtDist(0),
44  fGeometricalLogtDist(0),
45  fKinematicalLogtDist(0),
46  fLogzDist(0)
47 {
48  flagUserdNdlogz = false;
49 
52 }
53 
54 
56  const double theta,
57  const TabulatedFunction* LogzDist,
58  const bool flagAngularFactorDa_in,
59  const bool flagDecayFactor_in) :
60  fRandomEngine(randomEngine),
61  fTheta(theta),
62  fCosTheta(cos(theta)),
63  flagAngularFactorDa(flagAngularFactorDa_in),
64  flagDecayFactor(flagDecayFactor_in),
65  fGRDGeometricalLogtDist(0),
66  fGRDKinematicalLogtDist(0),
67  fGeometricalLogtDist(0),
68  fKinematicalLogtDist(0),
69  fLogzDist(new TabulatedFunction(*LogzDist))
70 {
71  flagUserdNdlogz = true;
72 
73  double sumXW = 0;
74  double sumW = 0;
75  for (unsigned int iBin = 0; iBin < fLogzDist->GetNPoints(); ++iBin) {
76  sumXW += (*fLogzDist)[iBin].Y() * (*fLogzDist)[iBin].X();
77  sumW += (*fLogzDist)[iBin].Y();
78  }
79  fzMean = pow(10, sumXW/sumW);
80 
82 }
83 
84 
85 void
87 {
88  fNLogSteps = 1000;
89  fLogt_e_up = 5; // 3.23;
90  fLogt_e_low = -6;
91  fR = 1000;
92  fZeta = 0;
93 }
94 
95 
97 {
100  delete fGeometricalLogtDist;
101  delete fKinematicalLogtDist;
102  delete fLogzDist;
103 }
104 
105 
106 void
108 {
109  cout.setf(ios_base::fixed);
110  cout << "\n"
111  "*******************************\n"
112  "* MODEL CONSTANTS *\n"
113  "*******************************\n"
114  "* pk "
115  << setw(5) << setprecision(2)
116  << fgPk*1000 << " GeV/km *\n"
117  "* kappa "
118  << setw(5) << setprecision(1)
119  << fgKappa << " *\n"
120  "* lambda "
121  << setw(5) << setprecision(1)
122  << fgLambda << " *\n"
123  "* gamma "
124  << setw(5) << setprecision(1)
125  << fgGamma << " *\n"
126  "* ptc or Q "
127  << setw(5) << setprecision(2)
128  << fgQ << " GeV *\n"
129  "*******************************\n"
130  "\n"
131  "*******************************\n"
132  "* SHOWER CONSTANTS *\n"
133  "*******************************\n"
134  "* fTheta "
135  << setw(5) << setprecision(1)
136  << fTheta/deg << " deg *\n"
137  "*******************************\n"
138  "\n"
139  "*******************************\n"
140  "* dN/d log10(z/m) *\n"
141  "*******************************\n";
142  if (!flagUserdNdlogz) {
143  const double cosTheta = cos(fTheta);
144  cout << "* logMean /m "
145  << setw(5) << setprecision(3)
146  << GetParametricLogMean(cosTheta, fLogE, fPrimary)
147  << " *\n"
148  "* logSigma /m "
149  << setw(5) << setprecision(3)
150  << GetParametricLogSigma(cosTheta, fLogE, fPrimary)
151  << " *\n"
152  "* logLambda /m "
153  << setw(5) << setprecision(3)
154  << GetParametricLogLambda(cosTheta, fLogE, fPrimary)
155  << " *\n";
156  } else {
157  cout << "* User Defined function *\n"
158  "* logMean /m "
159  << setw(5) << setprecision(3) << log10(fzMean) << " *\n";
160  }
161  cout << "*******************************\n";
163  cout << "* D(a)=1 *\n";
164  else
165  cout << "* D(a)=cos(a)+Delta/L *\n";
166  cout << "*******************************\n"
167  "\n"
168  "*******************************\n"
169  "* COORDINATES *\n"
170  "*******************************\n"
171  "*fR "
172  << setw(10) << setprecision(1)
173  << fR << " m *\n"
174  "* fZeta "
175  << setw(5) << setprecision(1)
176  << fZeta/deg << " deg *\n"
177  "*******************************" << endl;
178 }
179 
180 
182 //This function was not in the original model
183 //It was added to be able to use the PRODUCTION DISTRIBUTION h(z)
184 //instead of the PRODUCTION DISTRIBUTION at ground dN/dz
185 //depends on the flagDecayFactor
186 double
188 {
189  if (flagDecayFactor)
190  return pow(Z*Z + fR*fR, 0.5*(1 - fgGamma));
191  else
192  return 1;
193 }
195 
196 
197 double
198 MuonTimeModel::cosaDa(const double Z)
199 {
200  if (Z < 0)
201  return 0; // muons back!?
202  const double L = L_Z(Z);
203  const double cosa2 = 1 - (fR*fR) / (L*L);
204 
206  return sqrt(cosa2);
207  return cosa2 + fDelta/L*sqrt(cosa2);
208 }
209 
210 
211 double
212 MuonTimeModel::Z_t(const double t)
213 {
214  return 0.5*(fR*fR/(kSpeedOfLight*t) - kSpeedOfLight*t);
215 }
216 
217 
218 double
219 MuonTimeModel::dZdt(const double t)
220 {
221  return 0.5*(fR*fR/(kSpeedOfLight*t*t) + kSpeedOfLight);
222 }
223 
224 
225 double
226 MuonTimeModel::dNdlogz(const double logz)
227 {
228  if (flagUserdNdlogz) {
229  if (logz < fLogzDist->XFront() ||
230  logz > fLogzDist->XBack()-1)
231  return 0;
232  return fLogzDist->Y(logz);
233  }
234 
235  const double logSigma = GetParametricLogSigma(fCosTheta, fLogE, fPrimary);
236  const double logLambda = GetParametricLogLambda(fCosTheta, fLogE, fPrimary);
237  const double logMean = GetParametricLogMean(fCosTheta, fLogE, fPrimary);
238 
239  if (logLambda <= 0) {
240  const double e = (logz - logMean) / logSigma;
241  static double sqrt2pi = 2.50662827463100024;
242  return exp(-0.5*e*e) / (logSigma*sqrt2pi);
243  }
244 
245  const double norm = 1;
246  const double s2 = sqrt(2.);
247 
248  const double f1 = (logz - logMean) / logLambda;
249  const double f2 = 0.5 * (logSigma*logSigma) / (logLambda*logLambda);
250  const double f3 = (logz - logMean) / (s2*logSigma);
251  const double f4 = logSigma / (s2*logLambda);
252 
253  return norm * exp(f1 + f2) * ErrFC(f3 + f4) / (2*logLambda);
254 }
255 
256 
257 double
258 MuonTimeModel::dNdz(const double z)
259 {
260  if (z < 0)
261  return 0;
262  return 1 / (z*log(10.)) * dNdlogz(log10(z));
263 }
264 
265 
266 double
267 MuonTimeModel::g_t(const double t)
268 {
269  const double Z = Z_t(t);
270  if (t <= 0)
271  return 0;
272  return DecayFactor_Z(Z) * cosaDa(Z) * dNdz(Z+fDelta) * dZdt(t);
273  //dZdt = dzdt
274 }
275 
276 
277 double
278 MuonTimeModel::g_logt(const double logt)
279 {
280  const double t = pow(10, logt);
281  return t * log(10.) * g_t(t);
282 }
283 
284 
288 
289 double
290 MuonTimeModel::E(const double t, const double x)
291 {
292  return 0.5 * fgPk * x * (1 + sqrt(1 + 2*fgM2/(fgPk*fgPk*x*kSpeedOfLight*t)));
293 }
294 
295 
296 double
297 MuonTimeModel::dEdt(const double t, const double x)
298 {
299  const double pk2 = fgPk * fgPk;
300  return 0.5 * fgPk * x /
301  sqrt(1 + 2*fgM2 / (pk2 * x * kSpeedOfLight * t)) *
302  fgM2 /
303  (pk2 * x * kSpeedOfLight * t*t);
304 }
305 
306 
307 double
308 MuonTimeModel::dNdE(const double E, const double x)
309 {
310  if (E < fgPk*x || x <= 0 || fR >= x)
311  return 0;
312 
313  return (1 - fR*fR/(x*x)) * pow(fR/x, fgLambda) *
314  pow(E, -fgGamma - fgKappa + fgLambda + 1) *
315  pow(E - fgPk*x, fgKappa) *
316  exp(-E*fR/(x*fgQ));
317 }
318 
319 
320 double
321 MuonTimeModel::dNdlogE(const double logE, const double x)
322 {
323  const double E = pow(10, logE);
324  return E * log(10.) * dNdE(E, x);
325 }
326 
327 
328 double
329 MuonTimeModel::e_t(const double t)
330 {
331  if (t <= 0)
332  return 0;
333 
334  const double x = L_Z(fzMean - fDelta);
335  return dNdE(E(t, x), x) * dEdt(t, x);
336 }
337 
338 
339 double
340 MuonTimeModel::e_logt(const double logt)
341 {
342  const double t = pow(10, logt);
343  return t * log(10.) * e_t(t);
344 }
345 
346 
347 void
349  const double zeta)
350 {
351  fR = r;
352  fZeta = zeta;
353  fDelta = fR * cos(fZeta) * tan(fTheta);
354  UpdateModel();
355 }
356 
357 
358 void
360  const double zeta,
361  const double delta)
362 {
363  fR = r;
364  fZeta = zeta;
365  fDelta = delta;
366  UpdateModel();
367 }
368 
369 
370 void
372 {
373  const double LZ = (fzMean - fDelta);
374 
375  logt_g_up = log10(8000*(sqrt(fR*fR + LZ*LZ) - LZ));
376  logt_g_low = log10(0.2*(sqrt(fR*fR + LZ*LZ) - LZ));
377 
380 
381  delete fGeometricalLogtDist;
383  delete fKinematicalLogtDist;
385 
386  for (int i = 0; i < fNLogSteps; ++i) {
387 
388  const double logtg = logt_g_low + logstep_g*i;
389  const double logte = fLogt_e_low + logstep_e*i;
390 
391  fGeometricalLogtDist->PushBack(logtg, g_logt(logtg));
392  fKinematicalLogtDist->PushBack(logte, e_logt(logte));
393 
394  }
395 
396  //------------------------
397 
401 
405 }
406 
407 
408 double
409 MuonTimeModel::GetFirstTime(const int n/*=1*/)
410 {
411  double t_first = 1e25;
412  for (int i = 0; i < n; ++i) {
413 
414  const double t_i =
417 
418  if (t_i < t_first)
419  t_first = t_i;
420  }
421 
422  return t_first - fDelta/kSpeedOfLight;
423 }
424 
425 
426 double
427 MuonTimeModel::GetTimes(const int n, double* const at)
428 {
429  double t_first = 1e25;
430  for (int i = 0; i < n; ++i) {
431 
432  const double t_i =
435 
436  at[i] = t_i - fDelta/kSpeedOfLight;
437  if (t_i < t_first)
438  t_first = t_i;
439  }
440 
441  return t_first - fDelta/kSpeedOfLight;
442 }
443 
444 
445 double
446 MuonTimeModel::GetMeanTime(const int n/*=1*/)
447 {
448  double t_mean = 0;
449  for (int i = 0; i < n; ++i) {
450 
451  t_mean +=
454 
455  }
456  return t_mean/n - fDelta/kSpeedOfLight;
457 }
458 
459 
460 void
462  double& t_mean,
463  const int n/*=1*/)
464 {
465  t_mean = 0;
466  t_first = 1e25;
467  for (int i = 0; i < n; ++i) {
468 
469  const double t_i =
472 
473  if (t_i < t_first)
474  t_first = t_i;
475 
476  t_mean += t_i;
477  }
478 
479  t_first -= fDelta / kSpeedOfLight;
480  t_mean = t_mean/n - fDelta/kSpeedOfLight;
481 }
482 
483 
484 double
485 MuonTimeModel::GetLastTime(const int n/*=1*/)
486 {
487  double t_last = 0;
488  for (int i = 0; i <n; ++i) {
489 
490  const double t_i =
493 
494  if (t_i > t_last)
495  t_last = t_i;
496 
497  }
498  return t_last - fDelta/kSpeedOfLight;
499 }
500 
501 
502 void
504  double& rms_t1,
505  const int n/*=1*/,
506  const int stats/*=1000*/)
507 {
508  double t1sum = 0;
509  double t1sum2 = 0;
510 
511  for (int i = 0; i < stats; ++i) {
512  const double t1 = GetFirstTime(n);
513  t1sum += t1;
514  t1sum2 += t1*t1;
515  }
516 
517  mean_t1 = t1sum / stats;
518  rms_t1 = sqrt(t1sum2/stats - mean_t1*mean_t1);
519 }
520 
521 
522 double
524 {
525  return fDelta / kSpeedOfLight;
526 }
527 
528 
529 
530 double
532 {
533  const int n = 850;
534  const double tmin = 0;
535  double tmax = 1700;
536 
537  if (t < tmax)
538  tmax = t;
539 
540  const double h = (tmax - tmin) / n;
541  double sum = 0;
542  double t_i = tmin + 0.5*h;
543 
544  for (int i = 0; i < n; ++i) {
545  sum += g_t(t - t_i) * e_t(t_i);
546  t_i += h;
547  }
548 
549  return sum * h;
550 }
551 
552 
553 double
554 MuonTimeModel::TotaldNdlogt(const double logt)
555 {
556  const double t = pow(10, logt);
557  return t * log(10.) * TotaldNdt(t);
558 }
559 
560 
561 /**************************************************
562  *
563  * Returns the incomplete gamma function P (a, x)
564  * evaluated by its series representation as gamser.
565  * Also returns ln G(a) as gln.
566  *
567  * taken from Numerical Recipes in C
568  *
569  ***************************************************/
570 
571 const int kITMAX = 100; // max iterations
572 const double kEPS = 3e-7; // relative accuracy
573 const double kFPMIN = 1e-30; // Number near the smallest representable floating-point number.
574 
575 
576 void
577 MuonTimeModel::gser(double& gamser, const double a, const double x, double& gln)
578 {
579  gln = LogGamma(a);
580 
581  if (x <= 0) {
582  if (x < 0)
583  cerr << "x less than 0 in routine gser" << endl;
584  gamser = 0;
585  } else {
586  double ap = a;
587  double del = 1 / a;
588  double sum = del;
589  for (int n = 1; n <= kITMAX; ++n) {
590  ++ap;
591  del *= x/ap;
592  sum += del;
593  if (fabs(del) < fabs(sum)*kEPS) {
594  gamser = sum * exp(-x + a*log(x) - gln);
595  return;
596  }
597  }
598  cerr << "a too large, ITMAX too small in routine gser" << endl;
599  }
600 }
601 
602 
603 /**************************************************
604  *
605  * Returns the incomplete gamma function Q(a, x)
606  * evaluated by its continued fraction represen-
607  * tation as gammcf. Also returns ln (a) as gln.
608  *
609  * taken from Numerical Recipes in C
610  *
611  ***************************************************/
612 void
613 MuonTimeModel::gcf(double& gammcf, const double a, const double x, double& gln)
614 {
615  gln = LogGamma(a);
616  //gammln(a); // Set up for evaluating continued fraction
617 
618  double b = x + 1 - a; // by modified Lentz's method (ยง5.2)
619  double c = 1. / kFPMIN; // with b0 = 0.
620  double d = 1 / b;
621  double h = d; // Iterate to convergence.
622 
623  int i;
624  for (i = 1; i <= kITMAX; ++i) {
625  const double an = i * (a - i);
626  b += 2;
627  d = an*d + b;
628  if (fabs(d) < kFPMIN)
629  d = kFPMIN;
630  c = b + an/c;
631  if (fabs(c) < kFPMIN)
632  c = kFPMIN;
633  d = 1 / d;
634  const double del = d*c;
635  h *= del;
636  if (fabs(del - 1) < kEPS)
637  break;
638  }
639  if (i > kITMAX)
640  cerr << "a too large, ITMAX too small in gcf" << endl;
641 
642  gammcf = exp(-x + a*log(x) - gln) * h; // Put factors in front.
643 }
644 
645 
646 /**************************************************
647  *
648  * Returns the incomplete gamma function P (a, x).
649  *
650  * taken from Numerical Recipes in C
651  *
652  ***************************************************/
653 double
654 MuonTimeModel::GammaP(double a, double x)
655 {
656  if (x < 0 || a <= 0)
657  cerr << "gammp: Invalid arguments in x,a="
658  << x << ' ' << a << endl;
659 
660  double g;
661  double gln;
662  if (x < a+1) { // Use the series representation.
663  gser(g, a, x, gln);
664  return g;
665  } else { // Use the continued fraction representation
666  gcf(g, a, x, gln);
667  return 1 - g; // and take its complement.
668  }
669 }
670 
671 
672 /**************************************************
673  *
674  * Returns the incomplete gamma function Q(a, x) 1 - P (a, x).
675  *
676  * taken from Numerical Recipes in C
677  *
678  ***************************************************/
679 double
680 MuonTimeModel::GammaQ(const double a, const double x)
681 {
682  if (x < 0 || a <= 0)
683  cerr << "Invalid arguments in routine gammq" << endl;
684 
685  double g;
686  double gln;
687  if (x < a+1) { // Use the series representation
688  gser(g, a, x, gln);
689  return 1 - g; // and take its complement.
690  } else { // Use the continued fraction representation.
691  gcf(g, a, x, gln);
692  return g;
693  }
694 }
695 
696 
697 double
698 MuonTimeModel::ErrF(const double x)
699 {
700  return x < 0 ? -GammaP(0.5, x*x) : GammaP(0.5, x*x);
701 }
702 
703 
704 double
705 MuonTimeModel::ErrFC(const double x)
706 {
707  return x < 0 ? 1 + GammaP(0.5, x*x) : GammaQ(0.5, x*x);
708 }
utl::TabulatedFunction * fLogzDist
unsigned int GetNPoints() const
static const double fgKappa
void GetFirstAndMeanTime(double &t_first, double &t_mean, const int n=1)
double dNdz(const double z)
double e_logt(const double logt)
static double ErrF(const double)
utl::VRandomSampler * fGRDKinematicalLogtDist
ArrayConstReference XBack() const
read-only reference to back of array of X
double dZdt(double t)
RandomEngineType & GetEngine()
Definition: RandomEngine.h:32
double GetParametricLogLambda(const double cosTheta, const double, const int) const
static void gcf(double &, const double, const double, double &)
Class to hold collection (x,y) points and provide interpolation between them.
double GetParametricLogSigma(const double cosTheta, const double, const int) const
Definition: MuonTimeModel.h:96
static const double fgLambda
double dEdt(double t, double x)
MuonTimeModel(utl::RandomEngine &randomEngine, const double theta=0, const double logE=19, const int primary=1, const bool flagAngularFactorDa_in=true)
double dNdE(double E, double x)
void PushBack(const double x, const double y)
const int kITMAX
double pow(const double x, const unsigned int i)
double shoot(HepEngine &engine) const
Method to shoot random values using a given engine by-passing the static generator.
utl::VRandomSampler * fGRDGeometricalLogtDist
utl::RandomEngine & fRandomEngine
double GetMeanTime(const int n=1)
const double kEPS
constexpr double deg
Definition: AugerUnits.h:140
double GetLastTime(const int n=1)
const double kFPMIN
double LogGamma(const double x)
double dNdlogz(double logz)
static const double fgGamma
static double ErrFC(const double x)
double g_logt(const double logt)
double GetParametricLogMean(const double cosTheta, const double, const int) const
Definition: MuonTimeModel.h:83
Wraps the random number engine used to generate distributions.
Definition: RandomEngine.h:27
static double GammaQ(const double, const double)
constexpr double g
Definition: AugerUnits.h:200
double GetFirstTime(const int n=1)
double cosaDa(double z)
double g_t(double t)
utl::TabulatedFunction * fKinematicalLogtDist
utl::TabulatedFunction * fGeometricalLogtDist
double TotaldNdt(const double t)
static const double fgQ
double L_Z(const double z) const
Definition: MuonTimeModel.h:58
static const double fgM2
double Z_t(double t)
double e_t(double t)
constexpr double kSpeedOfLight
double TotaldNdlogt(const double logt)
double norm(utl::Vector x)
static const double fgPk
double dNdlogE(double logE, double x)
double GetTimes(const int n, double *const at)
void GetMeanAndRMSOfFirstTime(double &mean_t1, double &rms_t1, const int n=1, const int stats=1000)
static void gser(double &, const double, const double, double &)
double Y(const double x) const
Get or interpolate the Y value that corresponds to parameter x.
double E(double t, double x)
int stats
Definition: dump1090.h:293
static double GammaP(const double, const double)
double DecayFactor_Z(double Z)
void SetCoordinates(const double r, const double zeta)

, generated on Tue Sep 26 2023.