Jpp
 All Classes Namespaces Files Functions Variables Typedefs Enumerations Enumerator Friends Macros Pages
JPDF.hh
Go to the documentation of this file.
1 #ifndef __JPHYSICS__JPDF__
2 #define __JPHYSICS__JPDF__
3 
4 #include <vector>
5 #include <algorithm>
6 #include <cmath>
7 #include <limits>
8 
9 #include "JLang/JCC.hh"
10 #include "JLang/JException.hh"
11 #include "JTools/JConstants.hh"
12 #include "JTools/JQuadrature.hh"
14 #include "JPhysics/JDispersion.hh"
15 #include "JPhysics/JAbstractPMT.hh"
17 #include "JPhysics/JPDFToolkit.hh"
18 #include "JPhysics/JPDFTypes.hh"
19 #include "JGeometry3D/JVector3D.hh"
20 
21 
22 /**
23  * \author mdejong
24  */
25 
26 namespace JPHYSICS {}
27 namespace JPP { using namespace JPHYSICS; }
28 
29 namespace JPHYSICS {
30 
31  using JTOOLS::PI;
32  using JLANG::JException;
33 
34  /**
35  * Radius of optical module [m].
36  *
37  * This parameter is used to implement shadowing of the PMT by the optical module.
38  */
39  static double MODULE_RADIUS_M = 0.25;
40 
41 
42  /**
43  * Low level interface for the calculation of the Probability Density Functions (PDFs) of
44  * the arrival time of Cherenkov light from a muon or an EM-shower on a photo-multiplier tube (PMT).
45  * The calculation of the PDF covers direct light light and single-scattered light.
46  * The direct light is attenuated by absorption and any form of light scattering.\n
47  * The attenuation length is defined as:
48  \f[
49  \frac{1}{\lambda_{att}} ~\equiv~ \frac{1}{\lambda_{abs}} + \frac{1}{\lambda_{s}}
50  \f]
51  * where
52  \f$\lambda_{abs}\f$ and
53  \f$\lambda_{s}\f$
54  refer to the absorption and scattering length, respectively.\n
55  * The scattered light is attenuated by absorption and light scattering weighed with the scattering angle \f$\theta_{s}\f$.
56  * The attenuation length is in this case defined as:
57  \f[
58  \frac{1}{\lambda_{att}} ~\equiv~ \frac{1}{\lambda_{abs}} + \frac{1-\left<\cos\theta_s\right>}{\lambda_{s}}
59  \f]
60  *
61  * The PDFs of a muon are evaluated as a function of:
62  * - distance of closest approach of the muon to the PMT, and
63  * - orientation of the PMT (zenith and azimuth angle).
64  *
65  * The PDFs of an EM-shower are evaluated as a function of:
66  * - distance between the EM-shower and the PMT,
67  * - cosine angle EM-shower direction and EM-shower - PMT position, and
68  * - orientation of the PMT (zenith and azimuth angle).
69  *
70  * The intensity of light from an EM-shower is assumed to be proportional to the energy of the shower.\n
71  * For a given energy of the EM-shower, the longitudinal profile of the EM-shower is taken into account.
72  *
73  * The coordinate system is defined such that z-axis corresponds to the muon trajectory (EM-shower).\n
74  * The orientation of the PMT (i.e. zenith and azimuth angle) are defined following a rotation around the z-axis,
75  * such that the PMT is located in the x-z plane.
76  *
77  * Schematics of the PDF of direct light from a muon:
78  *
79  \f{center}\setlength{\unitlength}{0.7cm}\begin{picture}(8,12)
80 
81  \put( 1.0, 0.5){\vector(0,1){9}}
82  \put( 1.0,10.0){\makebox(0,0){$z$}}
83  \put( 1.0, 0.0){\makebox(0,0){muon}}
84 
85  \put( 1.0, 8.0){\line(1,0){6}}
86  \put( 4.0, 8.5){\makebox(0,0)[c]{$R$}}
87 
88  \multiput( 1.0, 2.0)(0.5, 0.5){12}{\qbezier(0.0,0.0)(-0.1,0.35)(0.25,0.25)\qbezier(0.25,0.25)(0.6,0.15)(0.5,0.5)}
89  \put( 4.5, 4.5){\makebox(0,0)[l]{photon}}
90 
91  \put( 1.0, 2.0){\circle*{0.2}}
92  \put( 0.5, 2.0){\makebox(0,0)[r]{$(0,0,z,t_{0})$}}
93 
94  \put( 1.0, 8.0){\circle*{0.2}}
95  \put( 0.5, 8.0){\makebox(0,0)[r]{$(0,0,0)$}}
96 
97  \put( 7.0, 8.0){\circle*{0.2}}
98  \put( 7.0, 9.0){\makebox(0,0)[c]{PMT}}
99  \put( 7.5, 8.0){\makebox(0,0)[l]{$(R,0,0,t_{1})$}}
100 
101  \put( 1.1, 2.1){
102  \put(0.0,1.00){\vector(-1,0){0.1}}
103  \qbezier(0.0,1.0)(0.25,1.0)(0.5,0.75)
104  \put(0.5,0.75){\vector(1,-1){0.1}}
105  \put(0.4,1.5){\makebox(0,0){$\theta_{c}$}}
106  }
107 
108  \end{picture}
109  \f}
110  *
111  * For the PDF of a muon, the time is defined such that \f$t ~=~ 0\f$
112  * refers to the time when the muon passes through the point at minimal approach to the PMT
113  * (i.e. position \f$(0,0,0)\f$ in the above figure).
114  *
115  * The delay for the Cherenkov cone to actually pass through the PMT is defined as
116  \f[
117  \Delta t ~\equiv~ R \tan(\theta_{c}) / c
118  \f]
119  * where \f$\tan(\theta_{c})\f$ is given by method JTOOLS::getTanThetaC.
120  *
121  * Given a measured hit time, \f$t_{hit}\f$, the PDF should be probed at \f$(t_{hit} - t_1)\f$,
122  * where \f$t_1\f$ is given by:
123  *
124  \f[
125  ct_1 = ct_0 - z + R \tan(\theta_{c})
126  \f]
127  *
128  * In this, \f$t_0\f$ refers to the time the muon passes through point \f$(0,0,z)\f$.
129  *
130  * Schematics of single scattered light from a muon:
131  *
132  \f{center}\setlength{\unitlength}{0.7cm}\begin{picture}(8,12)
133 
134  \put( 1.0, 0.5){\vector(0,1){9}}
135  \put( 1.0,10.0){\makebox(0,0){$z$}}
136  \put( 1.0, 0.0){\makebox(0,0){muon}}
137 
138  \put( 1.0, 8.0){\line(1,0){2}}
139  \put( 2.0, 8.5){\makebox(0,0)[c]{$R$}}
140 
141  \multiput( 1.0, 2.0)( 0.5, 0.5){8}{\qbezier(0.0,0.0)(-0.1,0.35)( 0.25,0.25)\qbezier( 0.25,0.25)( 0.6,0.15)( 0.5,0.5)}
142  \multiput( 5.0, 6.0)(-0.5, 0.5){4}{\qbezier(0.0,0.0)(+0.1,0.35)(-0.25,0.25)\qbezier(-0.25,0.25)(-0.6,0.15)(-0.5,0.5)}
143 
144  \put( 5.0, 6.0){\circle*{0.2}}
145 
146  \put( 3.5, 3.5){\makebox(0,0)[c]{$\bar{u}$}}
147  \put( 5.0, 7.0){\makebox(0,0)[c]{$\bar{v}$}}
148 
149  \put( 1.0, 2.0){\circle*{0.2}}
150  \put( 0.5, 2.0){\makebox(0,0)[r]{$(0,0,z,t_0)$}}
151 
152  \put( 1.0, 8.0){\circle*{0.2}}
153  \put( 0.5, 8.0){\makebox(0,0)[r]{$(0,0,0)$}}
154 
155  \put( 3.0, 8.0){\circle*{0.2}}
156  \put( 3.0, 9.0){\makebox(0,0)[c]{PMT}}
157  \put( 3.5, 8.0){\makebox(0,0)[l]{$(R,0,0,t_1)$}}
158 
159  \end{picture}
160  \f}
161  *
162  * In this,
163  *
164  \f{math}{
165  \bar{u} ~\equiv~ u ~ \hat{u}
166  ~\equiv~ u \left(\begin{array}{c} \sin(\theta_{0}) \cos(\phi_{0}) \\ \sin(\theta_{0}) \sin(\phi_{0}) \\ \cos(\theta_{0})\end{array}\right)
167  \textrm{ and }
168  \bar{v} ~\equiv~ v ~ \hat{v}
169  ~\equiv~ v \left(\begin{array}{c} \sin(\theta_{1}) \cos(\phi_{1}) \\ \sin(\theta_{1}) \sin(\phi_{1}) \\ \cos(\theta_{1})\end{array}\right)
170  \f}
171  *
172  * The vectors \f$\bar{u}\f$ and \f$\bar{v}\f$ are subject to the following constraint:
173  \f{math}{
174  \begin{array}{ccccccc}
175 
176  \begin{array}{c}
177  \mathrm{start}\\
178  \mathrm{point}
179  \end{array}
180 
181  &&
182 
183  \begin{array}{c}
184  \mathrm{before}\\
185  \mathrm{scattering}
186  \end{array}
187 
188  &&
189 
190  \begin{array}{c}
191  \mathrm{after}\\
192  \mathrm{scattering}
193  \end{array}
194 
195  &&
196 
197  \mathrm{PMT}
198 
199  \\
200  \\
201 
202  \left(\begin{array}{c} 0 \\ 0 \\ z \end{array}\right)
203  & + &
204  u \left(\begin{array}{c} \sin(\theta_{0}) \cos(\phi_{0}) \\ \sin(\theta_{0}) \sin(\phi_{0}) \\ \cos(\theta_{0})\end{array}\right)
205  & + &
206  v \left(\begin{array}{c} \sin(\theta_{1}) \cos(\phi_{1}) \\ \sin(\theta_{1}) \sin(\phi_{1}) \\ \cos(\theta_{1})\end{array}\right)
207  & = &
208  \left(\begin{array}{c} R \\ 0 \\ 0 \end{array}\right)
209  \end{array}
210  * \f}
211  *
212  * Note that an expression for the cosine of the scattering angle, \f$\cos(\theta_s) ~\equiv~ \hat{u} \cdot \hat{v}\f$,
213  * can directly be obtained by multiplying the left hand side and the right hand side with \f$\hat{u}\f$:
214  *
215  \f[
216  \cos\theta_s = \frac{R\sin\theta_0\cos\phi_0 - z\cos\theta_0 - u}{v}
217  \f]
218  *
219  *
220  * The arrival time of the single scattered light can be expressed as:
221  *
222  \f[
223  ct_1 = ct_0 + n (u + v)
224  \f]
225  *
226  * where \f$n\f$ is the index of refraction.
227  *
228  * Schematics of direct light from a EM-shower:
229  *
230  \f{center}\setlength{\unitlength}{0.7cm}\begin{picture}(8,12)
231 
232  \put( 1.0, 2.0){\vector(0,1){1}}
233  \put( 1.0, 3.5){\multiput(0,0)(0,0.5){12}{\line(0,1){0.2}}}
234  \put( 1.0,10.0){\makebox(0,0){$z$}}
235  \put( 1.0, 1.0){\makebox(0,0){EM-shower}}
236 
237  \put( 1.0, 8.0){\line(1,0){6}}
238  \put( 4.0, 8.5){\makebox(0,0)[c]{$R$}}
239 
240  \multiput( 1.0, 2.0)(0.5, 0.5){12}{\qbezier(0.0,0.0)(-0.1,0.35)(0.25,0.25)\qbezier(0.25,0.25)(0.6,0.15)(0.5,0.5)}
241  \put( 4.5, 4.5){\makebox(0,0)[l]{photon}}
242 
243  \put( 1.0, 2.0){\circle*{0.2}}
244  \put( 0.5, 2.0){\makebox(0,0)[r]{$(0,0,z,t_0)$}}
245 
246  \put( 1.0, 8.0){\circle*{0.2}}
247  \put( 0.5, 8.0){\makebox(0,0)[r]{$(0,0,0)$}}
248 
249  \put( 7.0, 8.0){\circle*{0.2}}
250  \put( 7.0, 9.0){\makebox(0,0)[c]{PMT}}
251  \put( 7.5, 8.0){\makebox(0,0)[l]{$(R,0,0,t_1)$}}
252 
253  \put( 1.1, 2.1){
254  \put(0.0,1.00){\vector(-1,0){0.1}}
255  \qbezier(0.0,1.0)(0.25,1.0)(0.5,0.75)
256  \put(0.5,0.75){\vector(1,-1){0.1}}
257  \put(0.4,1.5){\makebox(0,0){$\theta_0$}}
258  }
259 
260  \end{picture}
261  \f}
262  *
263  * Note that the emission angle \f$\theta_0\f$ is in general not equal to the Cherenkov angle \f$\theta_c\f$.\n
264  * For an EM-shower, the arrival time of the light can be expressed as:
265  *
266  \f[
267  ct_1 = ct_0 + n D
268  \f]
269  *
270  * where \f$D\f$ is the total distance traveled by the photon from its emission point to the PMT,
271  * including possible scattering.
272  *
273  * For the computation of the various integrals, it is assumed that the index of refraction
274  * decreases monotonously as a function of the wavelength of the light.
275  */
276  class JPDF :
277  public JTOOLS::JGaussLegendre,
278  public virtual JDispersionInterface,
279  public virtual JAbstractPMT,
280  public virtual JAbstractMedium
281  {
282 
284 
285  public:
286  /**
287  * Constructor.
288  *
289  * \param Wmin minimal wavelength for integration [nm]
290  * \param Wmax maximal wavelength for integration [nm]
291  * \param numberOfPoints number of points for integration
292  * \param epsilon precision of points for integration
293  */
294  JPDF(const double Wmin,
295  const double Wmax,
296  const int numberOfPoints = 20,
297  const double epsilon = 1e-12) :
298  JTOOLS::JGaussLegendre(numberOfPoints,epsilon),
299  wmin(Wmin),
300  wmax(Wmax)
301  {
302  // phi integration points
303 
304  const double dx = PI / numberOfPoints;
305 
306  for (double x = 0.5*dx; x < PI; x += dx) {
307  phd.push_back(element_type(cos(x),sin(x)));
308  }
309  }
310 
311 
312  /**
313  * Virtual destructor.
314  */
315  virtual ~JPDF()
316  {}
317 
318 
319  /**
320  * Number of Cherenkov photons per unit track length
321  *
322  * \return number of photons per unit track length [m^-1]
323  */
324  double getNumberOfPhotons() const
325  {
326  double value = 0.0;
327 
328  const double xmin = 1.0 / wmax;
329  const double xmax = 1.0 / wmin;
330 
331  for (const_iterator i = begin(); i != end(); ++i) {
332 
333  const double x = 0.5 * (xmax + xmin) + i->getX() * 0.5 * (xmax - xmin);
334  const double dx = i->getY() * 0.5 * (xmax - xmin);
335 
336  const double w = 1.0 / x;
337  const double dw = dx * w*w;
338 
339  const double n = getIndexOfRefractionPhase(w);
340 
341  value += cherenkov(w,n) * dw;
342  }
343 
344  return value;
345  }
346 
347 
348  /**
349  * Number of photo-electrons from direct Cherenkov light from muon.
350  *
351  * \param R_m distance between muon and PMT [m]
352  * \param theta zenith angle orientation PMT [rad]
353  * \param phi azimuth angle orientation PMT [rad]
354  * \return P [npe]
355  */
356  double getDirectLightFromMuon(const double R_m,
357  const double theta,
358  const double phi) const
359  {
360  using namespace JTOOLS;
361 
362  double value = 0;
363 
364  const double R = std::max(R_m, getRmin());
365  const double A = getPhotocathodeArea();
366 
367  const double px = sin(theta)*cos(phi);
368  const double pz = cos(theta);
369 
370  for (const_iterator m = begin(); m != end(); ++m) {
371 
372  const double w = 0.5 * (wmax + wmin) + m->getX() * 0.5 * (wmax - wmin);
373  const double dw = m->getY() * 0.5 * (wmax - wmin);
374 
375  const double n = getIndexOfRefractionPhase(w);
376 
377  const double l_abs = getAbsorptionLength(w);
378  const double ls = getScatteringLength(w);
379 
380  const double npe = cherenkov(w,n) * dw * getQE(w);
381 
382  const double ct0 = 1.0 / n;
383  const double st0 = sqrt((1.0 + ct0)*(1.0 - ct0));
384 
385  const double d = R / st0; // distance traveled by photon
386  const double ct = st0*px + ct0*pz; // cosine angle of incidence on PMT
387 
388  const double U = getAngularAcceptance(ct); // PMT angular acceptance
389  const double V = exp(-d/l_abs) * exp(-d/ls); // absorption & scattering
390  const double W = A / (2.0*PI*R*st0); // solid angle
391 
392  value += npe * U * V * W;
393  }
394 
395  return value;
396  }
397 
398 
399  /**
400  * Probability density function for direct light from muon.
401  *
402  * \param R_m distance between muon and PMT [m]
403  * \param theta zenith angle orientation PMT [rad]
404  * \param phi azimuth angle orientation PMT [rad]
405  * \param t_ns time difference relative to direct Cherenkov light [ns]
406  * \return dP/dt [npe/ns]
407  */
408  double getDirectLightFromMuon(const double R_m,
409  const double theta,
410  const double phi,
411  const double t_ns) const
412  {
413  using namespace JTOOLS;
414 
415  static const int N = 100; // maximal number of iterations
416  static const double eps = 1.0e-6; // precision index of refraction
417 
418  const double R = std::max(R_m, getRmin());
419  const double t = R * getTanThetaC() / C + t_ns; // time [ns]
420  const double a = C*t/R; // target value
421  const double A = getPhotocathodeArea();
422 
423  const double px = sin(theta)*cos(phi);
424  const double pz = cos(theta);
425 
426  // check validity range for index of refraction
427 
428  for (double buffer[] = { wmin, wmax, 0.0 }, *p = buffer; *p != 0.0; ++p) {
429 
430  const double n = getIndexOfRefractionPhase(*p);
431  const double ng = getIndexOfRefractionGroup(*p);
432 
433  const double ct0 = 1.0 / n;
434  const double st0 = sqrt((1.0 + ct0)*(1.0 - ct0));
435 
436  const double b = (ng - ct0) / st0; // running value
437 
438  if (*p == wmin && b < a) { return 0.0; }
439  if (*p == wmax && b > a) { return 0.0; }
440  }
441 
442 
443  double umin = wmin;
444  double umax = wmax;
445 
446  for (int i = 0; i != N; ++i) { // binary search for wavelength
447 
448  const double w = 0.5 * (umin + umax);
449 
450  const double n = getIndexOfRefractionPhase(w);
451  const double ng = getIndexOfRefractionGroup(w);
452 
453  const double ct0 = 1.0 / n;
454  const double st0 = sqrt((1.0 + ct0)*(1.0 - ct0));
455 
456  const double b = (ng - ct0) / st0; // running value
457 
458  if (fabs(b-a) < a*eps) {
459 
460  const double np = getDispersionPhase(w);
461  const double ngp = getDispersionGroup(w);
462 
463  const double l_abs = getAbsorptionLength(w);
464  const double ls = getScatteringLength(w);
465 
466  const double d = R / st0; // distance traveled by photon
467  const double ct = st0*px + ct0*pz; // cosine angle of incidence on PMT
468 
469  const double i3 = ct0*ct0*ct0 / (st0*st0*st0);
470 
471  const double U = getAngularAcceptance(ct); // PMT angular acceptance
472  const double V = exp(-d/l_abs - d/ls); // absorption & scattering
473  const double W = A / (2.0*PI*R*st0); // solid angle
474 
475  const double Ja = R * (ngp/st0 + np*(n-ng)*i3) / C; // dt/dlambda
476 
477  return cherenkov(w,n) * getQE(w) * U * V * W / fabs(Ja);
478  }
479 
480  if (b > a)
481  umin = w;
482  else
483  umax = w;
484  }
485 
486  return 0.0;
487  }
488 
489 
490  /**
491  * Probability density function for scattered light from muon.
492  *
493  * \param R_m distance between muon and PMT [m]
494  * \param theta zenith angle orientation PMT [rad]
495  * \param phi azimuth angle orientation PMT [rad]
496  * \param t_ns time difference relative to direct Cherenkov light [ns]
497  * \return dP/dt [npe/ns]
498  */
499  double getScatteredLightFromMuon(const double R_m,
500  const double theta,
501  const double phi,
502  const double t_ns) const
503  {
504  using namespace JTOOLS;
505 
506  static const double eps = 1.0e-10;
507 
508  double value = 0;
509 
510  const double R = std::max(R_m, getRmin());
511  const double t = R * getTanThetaC() / C + t_ns; // time [ns]
512  const double A = getPhotocathodeArea();
513 
514  const double px = sin(theta)*cos(phi);
515  const double py = sin(theta)*sin(phi);
516  const double pz = cos(theta);
517 
518  const double n0 = getIndexOfRefractionGroup(wmax);
519  const double n1 = getIndexOfRefractionGroup(wmin);
520  const double ni = sqrt(R*R + C*t*C*t) / R; // maximal index of refraction
521 
522  if (n0 >= ni) return value;
523 
524  const double nj = std::min(ni,n1);
525 
526  double w = wmax;
527 
528  for (const_iterator i = begin(); i != end(); ++i) {
529 
530  const double ng = 0.5 * (nj + n0) + i->getX() * 0.5 * (nj - n0);
531  const double dn = i->getY() * 0.5 * (nj - n0);
532 
533  w = getWavelength(ng, w, 1.0e-5);
534 
535  const double dw = dn / fabs(getDispersionGroup(w));
536 
537  const double n = getIndexOfRefractionPhase(w);
538 
539  const double l_abs = getAbsorptionLength(w);
540  const double ls = getScatteringLength(w);
541 
542  const double npe = cherenkov(w,n) * dw * getQE(w);
543 
544  if (npe <= 0) { continue; }
545 
546  const double Jc = 1.0 / ls; // dN/dx
547 
548  const double ct0 = 1.0 / n; // photon direction before scattering
549  const double st0 = sqrt((1.0 + ct0)*(1.0 - ct0));
550 
551  JRoot rz(R, ng, t); // square root
552 
553  if (!rz.is_valid) { continue; }
554 
555  const double zmin = rz.first;
556  const double zmax = rz.second;
557 
558  const double zap = 1.0 / l_abs;
559 
560  const double xmin = exp(zap*zmax);
561  const double xmax = exp(zap*zmin);
562 
563  for (const_iterator j = begin(); j != end(); ++j) {
564 
565  const double x = 0.5 * (xmax + xmin) + j->getX() * 0.5 * (xmax - xmin);
566  const double dx = j->getY() * 0.5 * (xmax - xmin);
567 
568  const double z = log(x) / zap;
569  const double dz = -dx / (zap*x);
570 
571  const double D = sqrt(z*z + R*R);
572  const double cd = -z / D;
573  const double sd = R / D;
574 
575  const double d = (C*t - z) / ng; // photon path
576 
577  //const double V = exp(-d/l_abs); // absorption
578 
579  const double cta = cd*ct0 + sd*st0;
580  const double dca = d - 0.5*(d+D)*(d-D) / (d - D*cta);
581  const double tip = -log(D*D/(dca*dca) + eps) / PI;
582 
583  const double ymin = exp(tip*PI);
584  const double ymax = 1.0;
585 
586  for (const_iterator k = begin(); k != end(); ++k) {
587 
588  const double y = 0.5 * (ymax + ymin) + k->getX() * 0.5 * (ymax - ymin);
589  const double dy = k->getY() * 0.5 * (ymax - ymin);
590 
591  const double phi = log(y) / tip;
592  const double dp = -dy / (tip*y);
593 
594  const double cp0 = cos(phi);
595  const double sp0 = sin(phi);
596 
597  const double u = (R*R + z*z - d*d) / (2*R*st0*cp0 - 2*z*ct0 - 2*d);
598  const double v = d - u;
599 
600  if (u <= 0) { continue; }
601  if (v <= 0) { continue; }
602 
603  const double vi = 1.0 / v;
604  const double cts = (R*st0*cp0 - z*ct0 - u)*vi; // cosine scattering angle
605 
606  const double V = exp(-d*getInverseAttenuationLength(l_abs, ls, cts));
607 
608  if (cts < 0.0 && v * sqrt((1.0 + cts) * (1.0 - cts)) < MODULE_RADIUS_M) { continue; }
609 
610  const double vx = R - u*st0*cp0;
611  const double vy = - u*st0*sp0;
612  const double vz = -z - u*ct0;
613 
614  const double ct[] = { // cosine angle of incidence on PMT
615  (vx*px + vy*py + vz*pz) * vi,
616  (vx*px - vy*py + vz*pz) * vi
617  };
618 
619  const double U =
620  getAngularAcceptance(ct[0]) +
621  getAngularAcceptance(ct[1]); // PMT angular acceptance
622  const double W = std::min(A*vi*vi, 2.0*PI); // solid angle
623 
624  const double Ja = getScatteringProbability(cts); // d^2P/dcos/dphi
625  const double Jd = ng * (1.0 - cts) / C; // dt/du
626 
627  value += (npe * dz * dp / (2*PI)) * U * V * W * Ja * Jc / fabs(Jd);
628  }
629  }
630  }
631 
632  return value;
633  }
634 
635 
636  /**
637  * Probability density function for direct light from EM-showers.
638  *
639  * \param R_m distance between muon and PMT [m]
640  * \param theta zenith angle orientation PMT [rad]
641  * \param phi azimuth angle orientation PMT [rad]
642  * \param t_ns time difference relative to direct Cherenkov light [ns]
643  * \return dP/dt [npe/ns/GeV]
644  */
645  double getDirectLightFromEMshowers(const double R_m,
646  const double theta,
647  const double phi,
648  const double t_ns) const
649  {
650  using namespace JTOOLS;
651 
652  double value = 0;
653 
654  const double R = std::max(R_m, getRmin());
655  const double t = R * getTanThetaC() / C + t_ns; // time [ns]
656  const double A = getPhotocathodeArea();
657  const double D = 2.0*sqrt(A/PI);
658 
659  const double px = sin(theta)*cos(phi);
660  //const double py = sin(theta)*sin(phi);
661  const double pz = cos(theta);
662 
663  const double n0 = getIndexOfRefractionGroup(wmax);
664  const double n1 = getIndexOfRefractionGroup(wmin);
665  const double ni = sqrt(R*R + C*t*C*t) / R; // maximal index of refraction
666 
667  if (n0 >= ni) return value;
668 
669  const double nj = std::min(n1, ni);
670 
671  double w = wmax;
672 
673  for (const_iterator i = begin(); i != end(); ++i) {
674 
675  const double ng = 0.5 * (nj + n0) + i->getX() * 0.5 * (nj - n0);
676  const double dn = i->getY() * 0.5 * (nj - n0);
677 
678  w = getWavelength(ng, w, 1.0e-5);
679 
680  const double dw = dn / fabs(getDispersionGroup(w));
681 
682  const double n = getIndexOfRefractionPhase(w);
683 
684  const double l_abs = getAbsorptionLength(w);
685  const double ls = getScatteringLength(w);
686 
687  const double npe = cherenkov(w,n) * dw * getQE(w);
688 
689  JRoot rz(R, ng, t); // square root
690 
691  if (!rz.is_valid) { continue; }
692 
693  for (int j = 0; j != 2; ++j) {
694 
695  const double z = rz[j];
696 
697  if (C*t <= z) continue;
698 
699  const double d = sqrt(z*z + R*R); // distance traveled by photon
700 
701  const double ct0 = -z / d;
702  const double st0 = R / d;
703 
704  const double dz = D / st0; // average track length
705 
706  const double ct = st0*px + ct0*pz; // cosine angle of incidence on PMT
707 
708  const double U = getAngularAcceptance(ct); // PMT angular acceptance
709  const double V = exp(-d/l_abs - d/ls); // absorption & scattering
710  const double W = A/(d*d); // solid angle
711 
712  const double Ja = geant(n,ct0); // d^2N/dcos/dphi
713  const double Jd = (1.0 - ng*ct0) / C; // d t/ dz
714  const double Je = ng*st0*st0*st0 / (R*C); // d^2t/(dz)^2
715 
716  value += gWater() * npe * U * V * W * Ja / (fabs(Jd) + 0.5*Je*dz);
717  }
718  }
719 
720  return value;
721  }
722 
723 
724  /**
725  * Probability density function for scattered light from EM-showers.
726  *
727  * \param R_m distance between muon and PMT [m]
728  * \param theta zenith angle orientation PMT [rad]
729  * \param phi azimuth angle orientation PMT [rad]
730  * \param t_ns time difference relative to direct Cherenkov light [ns]
731  * \return dP/dt [npe/ns/GeV]
732  */
733  double getScatteredLightFromEMshowers(const double R_m,
734  const double theta,
735  const double phi,
736  const double t_ns) const
737  {
738  using namespace JTOOLS;
739 
740  double value = 0;
741 
742  const double R = std::max(R_m, getRmin());
743  const double t = R * getTanThetaC() / C + t_ns; // time [ns]
744  const double A = getPhotocathodeArea();
745 
746  const double px = sin(theta)*cos(phi);
747  const double py = sin(theta)*sin(phi);
748  const double pz = cos(theta);
749 
750  const double n0 = getIndexOfRefractionGroup(wmax);
751  const double n1 = getIndexOfRefractionGroup(wmin);
752  const double ni = sqrt(R*R + C*t*C*t) / R; // maximal index of refraction
753 
754  if (n0 >= ni) return value;
755 
756  const double nj = std::min(ni,n1);
757 
758  double w = wmax;
759 
760  for (const_iterator i = begin(); i != end(); ++i) {
761 
762  const double ng = 0.5 * (nj + n0) + i->getX() * 0.5 * (nj - n0);
763  const double dn = i->getY() * 0.5 * (nj - n0);
764 
765  w = getWavelength(ng, w, 1.0e-5);
766 
767  const double dw = dn / fabs(getDispersionGroup(w));
768 
769  const double n = getIndexOfRefractionPhase(w);
770 
771  const double l_abs = getAbsorptionLength(w);
772  const double ls = getScatteringLength(w);
773 
774  const double npe = cherenkov(w,n) * dw * getQE(w);
775 
776  if (npe <= 0) { continue; }
777 
778  const double Jc = 1.0 / ls; // dN/dx
779 
780  JRoot rz(R, ng, t); // square root
781 
782  if (!rz.is_valid) { continue; }
783 
784  const double zmin = rz.first;
785  const double zmax = rz.second;
786 
787  const double zap = 1.0 / l_abs;
788 
789  const double xmin = exp(zap*zmax);
790  const double xmax = exp(zap*zmin);
791 
792  for (const_iterator j = begin(); j != end(); ++j) {
793 
794  const double x = 0.5 * (xmax + xmin) + j->getX() * 0.5 * (xmax - xmin);
795  const double dx = j->getY() * 0.5 * (xmax - xmin);
796 
797  const double z = log(x) / zap;
798  const double dz = -dx / (zap*x);
799 
800  const double D = sqrt(z*z + R*R);
801  const double cd = -z / D;
802  const double sd = R / D;
803 
804  const double qx = cd*px + 0 - sd*pz;
805  const double qy = 1*py;
806  const double qz = sd*px + 0 + cd*pz;
807 
808  const double d = (C*t - z) / ng; // photon path
809 
810  //const double V = exp(-d/l_abs); // absorption
811 
812  const double ds = 2.0 / (size() + 1);
813 
814  for (double sb = 0.5*ds; sb < 1.0 - 0.25*ds; sb += ds) {
815 
816  for (int buffer[] = { -1, +1, 0}, *k = buffer; *k != 0; ++k) {
817 
818  const double cb = (*k) * sqrt((1.0 + sb)*(1.0 - sb));
819  const double dcb = (*k) * ds*sb/cb;
820 
821  const double v = 0.5 * (d + D) * (d - D) / (d - D*cb);
822  const double u = d - v;
823 
824  if (u <= 0) { continue; }
825  if (v <= 0) { continue; }
826 
827  const double cts = (D*cb - v) / u; // cosine scattering angle
828 
829  const double V = exp(-d*getInverseAttenuationLength(l_abs, ls, cts));
830 
831  if (cts < 0.0 && v * sqrt((1.0 + cts) * (1.0 - cts)) < MODULE_RADIUS_M) { continue; }
832 
833  const double W = std::min(A/(v*v), 2.0*PI); // solid angle
834  const double Ja = getScatteringProbability(cts); // d^2P/dcos/dphi
835  const double Jd = ng * (1.0 - cts) / C; // dt/du
836 
837  const double ca = (D - v*cb) / u;
838  const double sa = v*sb / u;
839 
840  const double dp = PI / phd.size();
841  const double dom = dcb*dp * v*v / (u*u);
842 
843  for (const_iterator l = phd.begin(); l != phd.end(); ++l) {
844 
845  const double cp = l->getX();
846  const double sp = l->getY();
847 
848  const double ct0 = cd*ca - sd*sa*cp;
849 
850  const double vx = sb*cp * qx;
851  const double vy = sb*sp * qy;
852  const double vz = cb * qz;
853 
854  const double U =
855  getAngularAcceptance(vx + vy + vz) +
856  getAngularAcceptance(vx - vy + vz); // PMT angular acceptance
857 
858  const double Jb = geant(n,ct0); // d^2N/dcos/dphi
859 
860  value += dom * gWater() * npe * dz * U * V * W * Ja * Jb * Jc / fabs(Jd);
861  }
862  }
863  }
864  }
865  }
866 
867  return value;
868  }
869 
870 
871  /**
872  * Probability density function for scattered light from muon.
873  *
874  * \param D_m distance between track segment and PMT [m]
875  * \param cd cosine angle muon direction and track segment - PMT position
876  * \param theta zenith angle orientation PMT [rad]
877  * \param phi azimuth angle orientation PMT [rad]
878  * \param t_ns time difference relative to direct Cherenkov light [ns]
879  * \return d^2P/dt/dx [npe/ns/m]
880  */
881  double getScatteredLightFromMuon(const double D_m,
882  const double cd,
883  const double theta,
884  const double phi,
885  const double t_ns) const
886  {
887  using namespace JTOOLS;
888 
889  static const double eps = 1.0e-10;
890 
891  double value = 0;
892 
893  const double sd = sqrt((1.0 + cd)*(1.0 - cd));
894  const double D = std::max(D_m, getRmin());
895  const double R = sd * D; // minimal distance of approach [m]
896  const double Z = -cd * D; // photon emission point
897  const double L = D;
898  const double t = D * getIndexOfRefraction() / C + t_ns; // time [ns]
899  const double A = getPhotocathodeArea();
900 
901  const double px = sin(theta)*cos(phi);
902  const double py = sin(theta)*sin(phi);
903  const double pz = cos(theta);
904 
905  const double n0 = getIndexOfRefractionGroup(wmax);
906  const double n1 = getIndexOfRefractionGroup(wmin);
907 
908  const double ni = C*t / L; // maximal index of refraction
909 
910  if (n0 >= ni) {
911  return value;
912  }
913 
914  const double nj = std::min(ni,n1);
915 
916  double w = wmax;
917 
918  for (const_iterator i = begin(); i != end(); ++i) {
919 
920  const double ng = 0.5 * (nj + n0) + i->getX() * 0.5 * (nj - n0);
921  const double dn = i->getY() * 0.5 * (nj - n0);
922 
923  w = getWavelength(ng, w, 1.0e-5);
924 
925  const double dw = dn / fabs(getDispersionGroup(w));
926 
927  const double n = getIndexOfRefractionPhase(w);
928 
929  const double l_abs = getAbsorptionLength(w);
930  const double ls = getScatteringLength(w);
931 
932  const double npe = cherenkov(w,n) * dw * getQE(w);
933 
934  if (npe <= 0) { continue; }
935 
936  const double Jc = 1.0 / ls; // dN/dx
937 
938  const double ct0 = 1.0 / n; // photon direction before scattering
939  const double st0 = sqrt((1.0 + ct0)*(1.0 - ct0));
940 
941  const double d = C*t / ng; // photon path
942 
943  //const double V = exp(-d/l_abs); // absorption
944 
945  const double cta = cd*ct0 + sd*st0;
946  const double dca = d - 0.5*(d+L)*(d-L) / (d - L*cta);
947  const double tip = -log(L*L/(dca*dca) + eps) / PI;
948 
949  const double ymin = exp(tip*PI);
950  const double ymax = 1.0;
951 
952  for (const_iterator j = begin(); j != end(); ++j) {
953 
954  const double y = 0.5 * (ymax + ymin) + j->getX() * 0.5 * (ymax - ymin);
955  const double dy = j->getY() * 0.5 * (ymax - ymin);
956 
957  const double phi = log(y) / tip;
958  const double dp = -dy / (tip*y);
959 
960  const double cp0 = cos(phi);
961  const double sp0 = sin(phi);
962 
963  const double u = (R*R + Z*Z - d*d) / (2*R*st0*cp0 - 2*Z*ct0 - 2*d);
964  const double v = d - u;
965 
966  if (u <= 0) { continue; }
967  if (v <= 0) { continue; }
968 
969  const double vi = 1.0 / v;
970  const double cts = (R*st0*cp0 - Z*ct0 - u)*vi; // cosine scattering angle
971 
972  const double V = exp(-d*getInverseAttenuationLength(l_abs, ls, cts));
973 
974  if (cts < 0.0 && v * sqrt((1.0 + cts) * (1.0 - cts)) < MODULE_RADIUS_M) { continue; }
975 
976  const double vx = R - u*st0*cp0;
977  const double vy = - u*st0*sp0;
978  const double vz = -Z - u*ct0;
979 
980  const double ct[] = { // cosine angle of incidence on PMT
981  (vx*px + vy*py + vz*pz) * vi,
982  (vx*px - vy*py + vz*pz) * vi
983  };
984 
985  const double U =
986  getAngularAcceptance(ct[0]) +
987  getAngularAcceptance(ct[1]); // PMT angular acceptance
988  const double W = std::min(A*vi*vi, 2.0*PI); // solid angle
989 
990  const double Ja = getScatteringProbability(cts); // d^2P/dcos/dphi
991  const double Jd = ng * (1.0 - cts) / C; // dt/du
992 
993  value += (npe * dp / (2*PI)) * U * V * W * Ja * Jc / fabs(Jd);
994  }
995  }
996 
997  return value;
998  }
999 
1000 
1001  /**
1002  * Probability density function for direct light from EM-shower.
1003  *
1004  * \param D_m distance between EM-shower and PMT [m]
1005  * \param cd cosine angle EM-shower direction and EM-shower - PMT position
1006  * \param theta zenith angle orientation PMT [rad]
1007  * \param phi azimuth angle orientation PMT [rad]
1008  * \param t_ns time difference relative to direct Cherenkov light [ns]
1009  * \return d^2P/dt/dE [npe/ns/GeV]
1010  */
1011  double getDirectLightFromEMshower(const double D_m,
1012  const double cd,
1013  const double theta,
1014  const double phi,
1015  const double t_ns) const
1016  {
1017  using namespace JTOOLS;
1018 
1019  const double ct0 = cd;
1020  const double st0 = sqrt((1.0 + ct0)*(1.0 - ct0));
1021 
1022  const double D = std::max(D_m, getRmin());
1023  const double t = D * getIndexOfRefraction() / C + t_ns; // time [ns]
1024  const double A = getPhotocathodeArea();
1025 
1026  const double px = sin(theta)*cos(phi);
1027  const double pz = cos(theta);
1028 
1029  const double n0 = getIndexOfRefractionGroup(wmax);
1030  const double n1 = getIndexOfRefractionGroup(wmin);
1031  const double ng = C*t/D; // index of refraction
1032 
1033  if (n0 >= ng) { return 0.0; }
1034  if (n1 <= ng) { return 0.0; }
1035 
1036  const double w = getWavelength(ng);
1037  const double n = getIndexOfRefractionPhase(w);
1038 
1039  const double l_abs = getAbsorptionLength(w);
1040  const double ls = getScatteringLength(w);
1041 
1042  const double npe = cherenkov(w,n) * getQE(w);
1043 
1044  const double ct = st0*px + ct0*pz; // cosine angle of incidence on PMT
1045 
1046  const double U = getAngularAcceptance(ct); // PMT angular acceptance
1047  const double V = exp(-D/l_abs - D/ls); // absorption & scattering
1048  const double W = A/(D*D); // solid angle
1049 
1050  const double ngp = getDispersionGroup(w);
1051 
1052  const double Ja = D * ngp / C; // dt/dlambda
1053  const double Jb = geant(n,ct0); // d^2N/dcos/dphi
1054 
1055  return npe * geanc() * U * V * W * Jb / fabs(Ja);
1056  }
1057 
1058 
1059  /**
1060  * Probability density function for scattered light from EM-shower.
1061  *
1062  * \param D_m distance between EM-shower and PMT [m]
1063  * \param cd cosine angle EM-shower direction and EM-shower - PMT position
1064  * \param theta zenith angle orientation PMT [rad]
1065  * \param phi azimuth angle orientation PMT [rad]
1066  * \param t_ns time difference relative to direct Cherenkov light [ns]
1067  * \return d^2P/dt/dE [npe/ns/GeV]
1068  */
1069  double getScatteredLightFromEMshower(const double D_m,
1070  const double cd,
1071  const double theta,
1072  const double phi,
1073  const double t_ns) const
1074  {
1075  using namespace JTOOLS;
1076 
1077  double value = 0;
1078 
1079  const double sd = sqrt((1.0 + cd)*(1.0 - cd));
1080  const double D = std::max(D_m, getRmin());
1081  const double L = D;
1082  const double t = D * getIndexOfRefraction() / C + t_ns; // time [ns]
1083 
1084  const double A = getPhotocathodeArea();
1085 
1086  const double px = sin(theta)*cos(phi);
1087  const double py = sin(theta)*sin(phi);
1088  const double pz = cos(theta);
1089 
1090  const double qx = cd*px + 0 - sd*pz;
1091  const double qy = 1*py;
1092  const double qz = sd*px + 0 + cd*pz;
1093 
1094  const double n0 = getIndexOfRefractionGroup(wmax);
1095  const double n1 = getIndexOfRefractionGroup(wmin);
1096 
1097  const double ni = C*t / L; // maximal index of refraction
1098 
1099  if (n0 >= ni) {
1100  return value;
1101  }
1102 
1103  const double nj = std::min(ni,n1);
1104 
1105  double w = wmax;
1106 
1107  for (const_iterator i = begin(); i != end(); ++i) {
1108 
1109  const double ng = 0.5 * (nj + n0) + i->getX() * 0.5 * (nj - n0);
1110  const double dn = i->getY() * 0.5 * (nj - n0);
1111 
1112  w = getWavelength(ng, w, 1.0e-5);
1113 
1114  const double dw = dn / fabs(getDispersionGroup(w));
1115 
1116  const double n = getIndexOfRefractionPhase(w);
1117 
1118  const double l_abs = getAbsorptionLength(w);
1119  const double ls = getScatteringLength(w);
1120 
1121  const double npe = cherenkov(w,n) * dw * getQE(w);
1122 
1123  if (npe <= 0) { continue; }
1124 
1125  const double Jc = 1.0 / ls; // dN/dx
1126 
1127  const double d = C*t / ng; // photon path
1128 
1129  //const double V = exp(-d/l_abs); // absorption
1130 
1131  const double ds = 2.0 / (size() + 1);
1132 
1133  for (double sb = 0.5*ds; sb < 1.0 - 0.25*ds; sb += ds) {
1134 
1135  for (int buffer[] = { -1, +1, 0}, *k = buffer; *k != 0; ++k) {
1136 
1137  const double cb = (*k) * sqrt((1.0 + sb)*(1.0 - sb));
1138  const double dcb = (*k) * ds*sb/cb;
1139 
1140  const double v = 0.5 * (d + L) * (d - L) / (d - L*cb);
1141  const double u = d - v;
1142 
1143  if (u <= 0) { continue; }
1144  if (v <= 0) { continue; }
1145 
1146  const double cts = (L*cb - v) / u; // cosine scattering angle
1147 
1148  const double V = exp(-d*getInverseAttenuationLength(l_abs, ls, cts));
1149 
1150  if (cts < 0.0 && v * sqrt((1.0 + cts) * (1.0 - cts)) < MODULE_RADIUS_M) { continue; }
1151 
1152  const double W = std::min(A/(v*v), 2.0*PI); // solid angle
1153  const double Ja = getScatteringProbability(cts); // d^2P/dcos/dphi
1154  const double Jd = ng * (1.0 - cts) / C; // dt/du
1155 
1156  const double ca = (L - v*cb) / u;
1157  const double sa = v*sb / u;
1158 
1159  const double dp = PI / phd.size();
1160  const double dom = dcb*dp * v*v / (u*u);
1161  const double dos = sqrt(dom);
1162 
1163  for (const_iterator l = phd.begin(); l != phd.end(); ++l) {
1164 
1165  const double cp = l->getX();
1166  const double sp = l->getY();
1167 
1168  const double ct0 = cd*ca - sd*sa*cp;
1169 
1170  const double vx = -sb*cp * qx;
1171  const double vy = -sb*sp * qy;
1172  const double vz = cb * qz;
1173 
1174  const double U =
1175  getAngularAcceptance(vx + vy + vz) +
1176  getAngularAcceptance(vx - vy + vz); // PMT angular acceptance
1177 
1178  //const double Jb = geant(n,ct0); // d^2N/dcos/dphi
1179 
1180  //value += npe * geanc() * dom * U * V * W * Ja * Jb * Jc / fabs(Jd);
1181 
1182  const double Jb = geant(n,
1183  ct0 - 0.5*dos,
1184  ct0 + 0.5*dos); // dN/dphi
1185 
1186  value += npe * geanc() * dos * U * V * W * Ja * Jb * Jc / fabs(Jd);
1187  }
1188  }
1189  }
1190  }
1191 
1192  return value;
1193  }
1194 
1195 
1196  /**
1197  * Probability density function for direct light from EM-shower.
1198  *
1199  * \param E EM-shower energy [GeV]
1200  * \param D_m distance between EM-shower and PMT [m]
1201  * \param cd cosine angle EM-shower direction and EM-shower - PMT position
1202  * \param theta zenith angle orientation PMT [rad]
1203  * \param phi azimuth angle orientation PMT [rad]
1204  * \param t_ns time difference relative to direct Cherenkov light [ns]
1205  * \return dP/dt [npe/ns]
1206  */
1207  double getDirectLightFromEMshower(const double E,
1208  const double D_m,
1209  const double cd,
1210  const double theta,
1211  const double phi,
1212  const double t_ns) const
1213  {
1214  using namespace JTOOLS;
1215 
1216  double value = 0;
1217 
1218  const double sd = sqrt((1.0 + cd)*(1.0 - cd));
1219  const double D = std::max(D_m, getRmin());
1220  const double R = D * sd; // minimal distance of approach [m]
1221  const double Z = -D * cd;
1222  const double t = D * getIndexOfRefraction() / C + t_ns; // time [ns]
1223 
1224  const double n0 = getIndexOfRefractionGroup(wmax);
1225  const double n1 = getIndexOfRefractionGroup(wmin);
1226 
1227  double zmin = 0.0; // minimal shower length [m]
1228  double zmax = geanz.getLength(E, 1.0); // maximal shower length [m]
1229 
1230  const double d = sqrt((Z+zmax)*(Z+zmax) + R*R);
1231 
1232  if (C*t > std::max(n1*D, zmax + n1*d)) {
1233  return value;
1234  }
1235 
1236  if (C*t < n0*D) {
1237 
1238  JRoot rz(R, n0, t + Z/C); // square root
1239 
1240  if (!rz.is_valid) {
1241  return value;
1242  }
1243 
1244  if (rz.second > Z) { zmin = rz.second - Z; }
1245  if (rz.first > Z) { zmin = rz.first - Z; }
1246  }
1247 
1248  if (C*t > n1*D) {
1249 
1250  JRoot rz(R, n1, t + Z/C); // square root
1251 
1252  if (!rz.is_valid) {
1253  return value;
1254  }
1255 
1256  if (rz.second > Z) { zmin = rz.second - Z; }
1257  if (rz.first > Z) { zmin = rz.first - Z; }
1258  }
1259 
1260  if (C*t < zmax + n0*d) {
1261 
1262  JRoot rz(R, n0, t + Z/C); // square root
1263 
1264  if (!rz.is_valid) {
1265  return value;
1266  }
1267 
1268  if (rz.first > Z) { zmax = rz.first - Z; }
1269  if (rz.second > Z) { zmax = rz.second - Z; }
1270  }
1271 
1272  if (zmin < 0.0) {
1273  zmin = 0.0;
1274  }
1275 
1276  if (zmax > zmin) {
1277 
1278  const double ymin = geanz.getIntegral(E, zmin);
1279  const double ymax = geanz.getIntegral(E, zmax);
1280  const double dy = (ymax - ymin) / size();
1281 
1282  if (dy > 2*std::numeric_limits<double>::epsilon()) {
1283 
1284  for (double y = ymin + 0.5*dy; y < ymax; y += dy) {
1285 
1286  const double z = Z + geanz.getLength(E, y);
1287  const double d = sqrt(R*R + z*z);
1288  const double t1 = t + (Z - z) / C - d * getIndexOfRefraction() / C;
1289 
1290  value += dy * E * getDirectLightFromEMshower(d, -z/d, theta, phi, t1);
1291  }
1292 
1293  }
1294  }
1295 
1296  return value;
1297  }
1298 
1299 
1300  /**
1301  * Probability density function for scattered light from EM-shower.
1302  *
1303  * \param E EM-shower energy [GeV]
1304  * \param D_m distance between EM-shower and PMT [m]
1305  * \param cd cosine angle EM-shower direction and EM-shower - PMT position
1306  * \param theta zenith angle orientation PMT [rad]
1307  * \param phi azimuth angle orientation PMT [rad]
1308  * \param t_ns time difference relative to direct Cherenkov light [ns]
1309  * \return dP/dt [npe/ns]
1310  */
1311  double getScatteredLightFromEMshower(const double E,
1312  const double D_m,
1313  const double cd,
1314  const double theta,
1315  const double phi,
1316  const double t_ns) const
1317  {
1318  using namespace JTOOLS;
1319 
1320  double value = 0;
1321 
1322  const double sd = sqrt((1.0 + cd)*(1.0 - cd));
1323  const double D = std::max(D_m, getRmin());
1324  const double R = D * sd; // minimal distance of approach [m]
1325  const double Z = -D * cd;
1326  const double t = D * getIndexOfRefraction() / C + t_ns; // time [ns]
1327 
1328  const double n0 = getIndexOfRefractionGroup(wmax);
1329 
1330  double zmin = 0.0; // minimal shower length [m]
1331  double zmax = geanz.getLength(E, 1.0); // maximal shower length [m]
1332 
1333  const double d = sqrt((Z+zmax)*(Z+zmax) + R*R);
1334 
1335  if (C*t < n0*D) {
1336 
1337  JRoot rz(R, n0, t + Z/C); // square root
1338 
1339  if (!rz.is_valid) {
1340  return value;
1341  }
1342 
1343  if (rz.second > Z) { zmin = rz.second - Z; }
1344  if (rz.first > Z) { zmin = rz.first - Z; }
1345  }
1346 
1347  if (C*t < zmax + n0*d) {
1348 
1349  JRoot rz(R, n0, t + Z/C); // square root
1350 
1351  if (!rz.is_valid) {
1352  return value;
1353  }
1354 
1355  if (rz.first > Z) { zmax = rz.first - Z; }
1356  if (rz.second > Z) { zmax = rz.second - Z; }
1357  }
1358 
1359  const double ymin = geanz.getIntegral(E, zmin);
1360  const double ymax = geanz.getIntegral(E, zmax);
1361  const double dy = (ymax - ymin) / size();
1362 
1363  if (dy > 2*std::numeric_limits<double>::epsilon()) {
1364 
1365  for (double y = ymin + 0.5*dy; y < ymax; y += dy) {
1366 
1367  const double z = Z + geanz.getLength(E, y);
1368  const double d = sqrt(R*R + z*z);
1369  const double t1 = t + (Z - z) / C - d * getIndexOfRefraction() / C;
1370 
1371  value += dy * E * getScatteredLightFromEMshower(d, -z/d, theta, phi, t1);
1372  }
1373  }
1374 
1375  return value;
1376  }
1377 
1378 
1379  /**
1380  * Probability density function for direct light from delta-rays.
1381  *
1382  * \param R_m distance between muon and PMT [m]
1383  * \param theta zenith angle orientation PMT [rad]
1384  * \param phi azimuth angle orientation PMT [rad]
1385  * \param t_ns time difference relative to direct Cherenkov light [ns]
1386  * \return d^2P/dt/dE [npe/ns x m/GeV]
1387  */
1388  double getDirectLightFromDeltaRays(const double R_m,
1389  const double theta,
1390  const double phi,
1391  const double t_ns) const
1392  {
1393  using namespace JTOOLS;
1394 
1395  double value = 0;
1396 
1397  const double R = std::max(R_m, getRmin());
1398  const double t = R * getTanThetaC() / C + t_ns; // time [ns]
1399  const double A = getPhotocathodeArea();
1400  const double D = 2.0*sqrt(A/PI);
1401 
1402  const double px = sin(theta)*cos(phi);
1403  const double pz = cos(theta);
1404 
1405  const double n0 = getIndexOfRefractionGroup(wmax);
1406  const double n1 = getIndexOfRefractionGroup(wmin);
1407  const double ni = sqrt(R*R + C*t*C*t) / R; // maximal index of refraction
1408 
1409  if (n0 >= ni) return value;
1410 
1411  const double nj = std::min(n1, ni);
1412 
1413  double w = wmax;
1414 
1415  for (const_iterator i = begin(); i != end(); ++i) {
1416 
1417  const double ng = 0.5 * (nj + n0) + i->getX() * 0.5 * (nj - n0);
1418  const double dn = i->getY() * 0.5 * (nj - n0);
1419 
1420  w = getWavelength(ng, w, 1.0e-5);
1421 
1422  const double dw = dn / fabs(getDispersionGroup(w));
1423 
1424  const double n = getIndexOfRefractionPhase(w);
1425 
1426  const double l_abs = getAbsorptionLength(w);
1427  const double ls = getScatteringLength(w);
1428 
1429  const double npe = cherenkov(w,n) * dw * getQE(w);
1430 
1431  JRoot rz(R, ng, t); // square root
1432 
1433  if (!rz.is_valid) { continue; }
1434 
1435  for (int j = 0; j != 2; ++j) {
1436 
1437  const double z = rz[j];
1438 
1439  if (C*t <= z) continue;
1440 
1441  const double d = sqrt(z*z + R*R); // distance traveled by photon
1442 
1443  const double ct0 = -z / d;
1444  const double st0 = R / d;
1445 
1446  const double dz = D / st0; // average track length
1447  const double ct = st0*px + ct0*pz; // cosine angle of incidence on PMT
1448 
1449  const double U = getAngularAcceptance(ct); // PMT angular acceptance
1450  const double V = exp(-d/l_abs - d/ls); // absorption & scattering
1451  const double W = A/(d*d); // solid angle
1452 
1453  const double Ja = 1.0/(4*PI); // d^2N/dcos/dphi
1454  const double Jd = (1.0 - ng*ct0) / C; // d t/ dz
1455  const double Je = ng*st0*st0*st0 / (R*C); // d^2t/(dz)^2
1456 
1457  value += npe * geanc() * U * V * W * Ja / (fabs(Jd) + 0.5*Je*dz);
1458  }
1459  }
1460 
1461  return value;
1462  }
1463 
1464 
1465  /**
1466  * Probability density function for direct light from delta-rays.
1467  *
1468  * \param R_m distance between muon and PMT [m]
1469  * \param theta zenith angle orientation PMT [rad]
1470  * \param phi azimuth angle orientation PMT [rad]
1471  * \param t_ns time difference relative to direct Cherenkov light [ns]
1472  * \return d^2P/dt/dx [npe/ns x m/GeV]
1473  */
1474  double getScatteredLightFromDeltaRays(const double R_m,
1475  const double theta,
1476  const double phi,
1477  const double t_ns) const
1478  {
1479  using namespace JTOOLS;
1480 
1481  double value = 0;
1482 
1483  const double R = std::max(R_m, getRmin());
1484  const double t = R * getTanThetaC() / C + t_ns; // time [ns]
1485  const double A = getPhotocathodeArea();
1486 
1487  const double px = sin(theta)*cos(phi);
1488  const double py = sin(theta)*sin(phi);
1489  const double pz = cos(theta);
1490 
1491  const double n0 = getIndexOfRefractionGroup(wmax);
1492  const double n1 = getIndexOfRefractionGroup(wmin);
1493  const double ni = sqrt(R*R + C*t*C*t) / R; // maximal index of refraction
1494 
1495  if (n0 >= ni) return value;
1496 
1497  const double nj = std::min(ni,n1);
1498 
1499  double w = wmax;
1500 
1501  for (const_iterator i = begin(); i != end(); ++i) {
1502 
1503  const double ng = 0.5 * (nj + n0) + i->getX() * 0.5 * (nj - n0);
1504  const double dn = i->getY() * 0.5 * (nj - n0);
1505 
1506  w = getWavelength(ng, w, 1.0e-5);
1507 
1508  const double dw = dn / fabs(getDispersionGroup(w));
1509 
1510  const double n = getIndexOfRefractionPhase(w);
1511 
1512  const double l_abs = getAbsorptionLength(w);
1513  const double ls = getScatteringLength(w);
1514 
1515  const double npe = cherenkov(w,n) * dw * getQE(w);
1516 
1517  if (npe <= 0) { continue; }
1518 
1519  const double Jc = 1.0 / ls; // dN/dx
1520 
1521  JRoot rz(R, ng, t); // square root
1522 
1523  if (!rz.is_valid) { continue; }
1524 
1525  const double zmin = rz.first;
1526  const double zmax = rz.second;
1527 
1528  const double zap = 1.0 / l_abs;
1529 
1530  const double xmin = exp(zap*zmax);
1531  const double xmax = exp(zap*zmin);
1532 
1533  for (const_iterator j = begin(); j != end(); ++j) {
1534 
1535  const double x = 0.5 * (xmax + xmin) + j->getX() * 0.5 * (xmax - xmin);
1536  const double dx = j->getY() * 0.5 * (xmax - xmin);
1537 
1538  const double z = log(x) / zap;
1539  const double dz = -dx / (zap*x);
1540 
1541  const double D = sqrt(z*z + R*R);
1542  const double cd = -z / D;
1543  const double sd = R / D;
1544 
1545  const double qx = cd*px + 0 - sd*pz;
1546  const double qy = 1*py;
1547  const double qz = sd*px + 0 + cd*pz;
1548 
1549  const double d = (C*t - z) / ng; // photon path
1550 
1551  //const double V = exp(-d/l_abs); // absorption
1552 
1553  const double ds = 2.0 / (size() + 1);
1554 
1555  for (double sb = 0.5*ds; sb < 1.0 - 0.25*ds; sb += ds) {
1556 
1557  for (int buffer[] = { -1, +1, 0}, *k = buffer; *k != 0; ++k) {
1558 
1559  const double cb = (*k) * sqrt((1.0 + sb)*(1.0 - sb));
1560  const double dcb = (*k) * ds*sb/cb;
1561 
1562  const double v = 0.5 * (d + D) * (d - D) / (d - D*cb);
1563  const double u = d - v;
1564 
1565  if (u <= 0) { continue; }
1566  if (v <= 0) { continue; }
1567 
1568  const double cts = (D*cb - v) / u; // cosine scattering angle
1569 
1570  const double V = exp(-d*getInverseAttenuationLength(l_abs, ls, cts));
1571 
1572  if (cts < 0.0 && v * sqrt((1.0 + cts) * (1.0 - cts)) < MODULE_RADIUS_M) { continue; }
1573 
1574  const double W = std::min(A/(v*v), 2.0*PI); // solid angle
1575  const double Ja = getScatteringProbability(cts); // d^2P/dcos/dphi
1576  const double Jd = ng * (1.0 - cts) / C; // dt/du
1577 
1578  const double dp = PI / phd.size();
1579  const double dom = dcb*dp * v*v / (u*u);
1580 
1581  for (const_iterator l = phd.begin(); l != phd.end(); ++l) {
1582 
1583  const double cp = l->getX();
1584  const double sp = l->getY();
1585 
1586  const double vx = sb*cp * qx;
1587  const double vy = sb*sp * qy;
1588  const double vz = cb * qz;
1589 
1590  const double U =
1591  getAngularAcceptance(vx + vy + vz) +
1592  getAngularAcceptance(vx - vy + vz); // PMT angular acceptance
1593 
1594  const double Jb = 1.0/(4*PI); // d^2N/dcos/dphi
1595 
1596  value += dom * npe * geanc() * dz * U * V * W * Ja * Jb * Jc / fabs(Jd);
1597  }
1598  }
1599  }
1600  }
1601  }
1602 
1603  return value;
1604  }
1605 
1606 
1607  /**
1608  * Probability density function for light from muon.
1609  *
1610  * \param type PDF type
1611  * \param E_GeV muon energy [GeV]
1612  * \param R_m distance between muon and PMT [m]
1613  * \param theta zenith angle orientation PMT [rad]
1614  * \param phi azimuth angle orientation PMT [rad]
1615  * \param t_ns time difference relative to direct Cherenkov light [ns]
1616  * \return d^2P/dt/dx [npe/ns]
1617  */
1618  double getLightFromMuon(const int type,
1619  const double E_GeV,
1620  const double R_m,
1621  const double theta,
1622  const double phi,
1623  const double t_ns) const
1624  {
1625  switch (type) {
1626 
1628  return getDirectLightFromMuon (R_m, theta, phi, t_ns);
1629 
1631  return getScatteredLightFromMuon (R_m, theta, phi, t_ns);
1632 
1634  return getDirectLightFromEMshowers (R_m, theta, phi, t_ns) * E_GeV;
1635 
1637  return getScatteredLightFromEMshowers(R_m, theta, phi, t_ns) * E_GeV;
1638 
1640  return getDirectLightFromDeltaRays (R_m, theta, phi, t_ns) * getDeltaRaysFromMuon(E_GeV);
1641 
1643  return getScatteredLightFromDeltaRays(R_m, theta, phi, t_ns) * getDeltaRaysFromMuon(E_GeV);
1644 
1645  default:
1646  return 0.0;
1647  }
1648  }
1649 
1650 
1651  /**
1652  * Probability density function for light from muon.
1653  *
1654  * \param E_GeV muon energy [GeV]
1655  * \param R_m distance between muon and PMT [m]
1656  * \param theta zenith angle orientation PMT [rad]
1657  * \param phi azimuth angle orientation PMT [rad]
1658  * \param t_ns time difference relative to direct Cherenkov light [ns]
1659  * \return d^2P/dt/dx [npe/ns]
1660  */
1661  double getLightFromMuon(const double E_GeV,
1662  const double R_m,
1663  const double theta,
1664  const double phi,
1665  const double t_ns) const
1666  {
1667  return (getDirectLightFromMuon (R_m, theta, phi, t_ns) +
1668  getScatteredLightFromMuon (R_m, theta, phi, t_ns) +
1669  getDirectLightFromEMshowers (R_m, theta, phi, t_ns) * E_GeV +
1670  getScatteredLightFromEMshowers(R_m, theta, phi, t_ns) * E_GeV +
1671  getDirectLightFromDeltaRays (R_m, theta, phi, t_ns) * getDeltaRaysFromMuon(E_GeV) +
1672  getScatteredLightFromDeltaRays(R_m, theta, phi, t_ns) * getDeltaRaysFromMuon(E_GeV));
1673  }
1674 
1675 
1676  /**
1677  * Probability density function for light from EM-shower.
1678  *
1679  * \param type PDF type
1680  * \param D_m distance between EM-shower and PMT [m]
1681  * \param cd cosine angle EM-shower direction and EM-shower - PMT position
1682  * \param theta zenith angle orientation PMT [rad]
1683  * \param phi azimuth angle orientation PMT [rad]
1684  * \param t_ns time difference relative to direct Cherenkov light [ns]
1685  * \return d^2P/dt/dE [npe/ns/GeV]
1686  */
1687  double getLightFromEMshower(const int type,
1688  const double D_m,
1689  const double cd,
1690  const double theta,
1691  const double phi,
1692  const double t_ns) const
1693  {
1694  switch (type) {
1695 
1697  return getDirectLightFromEMshower (D_m, cd, theta, phi, t_ns);
1698 
1700  return getScatteredLightFromEMshower(D_m, cd, theta, phi, t_ns);
1701 
1702  default:
1703  return 0.0;
1704  }
1705  }
1706 
1707 
1708  /**
1709  * Probability density function for light from EM-shower.
1710  *
1711  * \param D_m distance between EM-shower and PMT [m]
1712  * \param cd cosine angle EM-shower direction and EM-shower - PMT position
1713  * \param theta zenith angle orientation PMT [rad]
1714  * \param phi azimuth angle orientation PMT [rad]
1715  * \param t_ns time difference relative to direct Cherenkov light [ns]
1716  * \return d^2P/dt/dE [npe/ns/GeV]
1717  */
1718  double getLightFromEMshower(const double D_m,
1719  const double cd,
1720  const double theta,
1721  const double phi,
1722  const double t_ns) const
1723  {
1724  return (getDirectLightFromEMshower (D_m, cd, theta, phi, t_ns) +
1725  getScatteredLightFromEMshower(D_m, cd, theta, phi, t_ns));
1726  }
1727 
1728 
1729  /**
1730  * Probability density function for light from EM-shower.
1731  *
1732  * \param E_GeV EM-shower energy [GeV]
1733  * \param type PDF type
1734  * \param D_m distance between EM-shower and PMT [m]
1735  * \param cd cosine angle EM-shower direction and EM-shower - PMT position
1736  * \param theta zenith angle orientation PMT [rad]
1737  * \param phi azimuth angle orientation PMT [rad]
1738  * \param t_ns time difference relative to direct Cherenkov light [ns]
1739  * \return d^2P/dt/dE [npe/ns/GeV]
1740  */
1741  double getLightFromEMshower(const int type,
1742  const double E_GeV,
1743  const double D_m,
1744  const double cd,
1745  const double theta,
1746  const double phi,
1747  const double t_ns) const
1748  {
1749  switch (type) {
1750 
1752  return getDirectLightFromEMshower (E_GeV, D_m, cd, theta, phi, t_ns);
1753 
1755  return getScatteredLightFromEMshower(E_GeV, D_m, cd, theta, phi, t_ns);
1756 
1757  default:
1758  return 0.0;
1759  }
1760  }
1761 
1762 
1763  /**
1764  * Probability density function for light from EM-shower.
1765  *
1766  * \param E_GeV EM-shower energy [GeV]
1767  * \param D_m distance between EM-shower and PMT [m]
1768  * \param cd cosine angle EM-shower direction and EM-shower - PMT position
1769  * \param theta zenith angle orientation PMT [rad]
1770  * \param phi azimuth angle orientation PMT [rad]
1771  * \param t_ns time difference relative to direct Cherenkov light [ns]
1772  * \return d^2P/dt/dE [npe/ns/GeV]
1773  */
1774  double getLightFromEMshower(const double E_GeV,
1775  const double D_m,
1776  const double cd,
1777  const double theta,
1778  const double phi,
1779  const double t_ns) const
1780  {
1781  return (getDirectLightFromEMshower (E_GeV, D_m, cd, theta, phi, t_ns) +
1782  getScatteredLightFromEMshower(E_GeV, D_m, cd, theta, phi, t_ns));
1783  }
1784 
1785 
1786  /**
1787  * Auxiliary class to find solution(s) to \f$z\f$ of the square root expression:
1788  \f{eqnarray*}
1789  ct(z=0) & = & z + n \sqrt(z^2 + R^2)
1790  \f}
1791  * where \f$n = 1/\cos(\theta_{c})\f$ is the index of refraction.
1792  */
1793  class JRoot {
1794  public:
1795  /**
1796  * Determine solution(s) of quadratic equation.
1797  *
1798  * \param R minimal distance of approach [m]
1799  * \param n index of refraction
1800  * \param t time at z = 0 [ns]
1801  */
1802  JRoot(const double R,
1803  const double n,
1804  const double t) :
1805  is_valid(false),
1806  first (0.0),
1807  second(0.0)
1808  {
1809  using JTOOLS::C;
1810 
1811  const double a = n*n - 1.0;
1812  const double b = 2*C*t;
1813  const double c = R*n * R*n - C*t * C*t;
1814 
1815  const double q = b*b - 4*a*c;
1816 
1817  if (q >= 0.0) {
1818 
1819  first = (-b - sqrt(q)) / (2*a);
1820  second = (-b + sqrt(q)) / (2*a);
1821 
1822  is_valid = C*t > second;
1823  }
1824  }
1825 
1826 
1827  /**
1828  * Get result by index.
1829  *
1830  * \param i index (0 or 1)
1831  * \return i == 0, first; i == 1, second; else throws exception
1832  */
1833  double operator[](const int i) const
1834  {
1835  switch (i) {
1836 
1837  case 0:
1838  return first;
1839 
1840  case 1:
1841  return second;
1842 
1843  default:
1844  throw JException("JRoot::operator[] invalid index");
1845  }
1846  }
1847 
1848  bool is_valid; //!< validity of solutions
1849  double first; //!< most upstream solution
1850  double second; //!< most downstream solution
1851  };
1852 
1853 
1854  protected:
1855  /**
1856  * Determine wavelength for a given index of refraction corresponding to the group velocity.
1857  *
1858  * \param n index of refraction
1859  * \param eps precision index of refraction
1860  * \return wavelength [nm]
1861  */
1862  virtual double getWavelength(const double n,
1863  const double eps = 1.0e-10) const
1864  {
1865  //return getWavelength(n, 0.5*(wmin + wmax), eps);
1866 
1867  double vmin = wmin;
1868  double vmax = wmax;
1869 
1870  for (int i = 0; i != 1000; ++i) {
1871 
1872  const double v = 0.5 * (vmin + vmax);
1873  const double y = getIndexOfRefractionGroup(v);
1874 
1875  if (fabs(y - n) < eps) {
1876  return v;
1877  }
1878 
1879  if (y < n)
1880  vmax = v;
1881  else
1882  vmin = v;
1883  }
1884 
1885  return 0.5 * (vmin + vmax);
1886  }
1887 
1888 
1889  /**
1890  * Determine wavelength for a given index of refraction corresponding to the group velocity.
1891  * The estimate of the wavelength is made by successive linear extrapolations.
1892  * The procedure starts from the given wavelength and terminates if the index of refraction
1893  * is equal to the target value within the given precision.
1894  *
1895  * \param n index of refraction
1896  * \param w start value wavelength [nm]
1897  * \param eps precision index of refraction
1898  * \return return value wavelength [nm]
1899  */
1900  virtual double getWavelength(const double n,
1901  const double w,
1902  const double eps) const
1903  {
1904  double v = w;
1905 
1906  // determine wavelength by linear extrapolation
1907 
1908  for ( ; ; ) {
1909 
1910  const double y = getIndexOfRefractionGroup(v);
1911 
1912  if (fabs(y - n) < eps) {
1913  break;
1914  }
1915 
1916  v += (n - y) / getDispersionGroup(v);
1917  }
1918 
1919  return v;
1920  }
1921 
1922 
1923  static double getRmin() { return 1.0e-1; } //!< minimal distance of approach of muon to PMT [m]
1924 
1925 
1926  /**
1927  * Get the inverse of the attenuation length.
1928  *
1929  * \param l_abs absorption length [m]
1930  * \param ls scattering length [m]
1931  * \param cts cosine scattering angle
1932  * \return inverse attenuation length [m^-1]
1933  */
1934  virtual double getInverseAttenuationLength(const double l_abs, const double ls, const double cts) const
1935  {
1937 
1938  if (f1.empty()) {
1939 
1940  const int nx = 100000;
1941  const double xmin = -1.0;
1942  const double xmax = +1.0;
1943 
1944  const double dx = (xmax - xmin) / (nx - 1);
1945 
1946  for (double x = xmin, W = 0.0; x < xmax; x += dx) {
1947 
1948  f1[x] = W;
1949 
1950  W += 2*PI * dx * getScatteringProbability(x + 0.5*dx);
1951  }
1952 
1953  f1[xmin] = 0.0;
1954  f1[xmax] = 1.0;
1955 
1956  f1.compile();
1957  }
1958 
1959  return 1.0/l_abs + f1(cts)/ls;
1960  }
1961 
1962 
1963  protected:
1964  /**
1965  * Integration limits
1966  */
1967  const double wmin; //!< minimal wavelength for integration [nm]
1968  const double wmax; //!< maximal wavelength for integration [nm]
1969 
1970  std::vector<element_type> phd; //!< fast evaluation of phi integral
1971  };
1972 
1973 
1974  /**
1975  * Probability Density Functions of the time response of a PMT
1976  * with an implementation for the JDispersionInterface interface.
1977  */
1978  class JAbstractPDF :
1979  public JPDF,
1980  public JDispersion
1981  {
1982  public:
1983  /**
1984  * Constructor.
1985  *
1986  * \param P_atm ambient pressure [atm]
1987  * \param Wmin minimal wavelength for integration [nm]
1988  * \param Wmax maximal wavelength for integration [nm]
1989  * \param numberOfPoints number of points for integration
1990  * \param epsilon precision of points for integration
1991  */
1992  JAbstractPDF(const double P_atm,
1993  const double Wmin,
1994  const double Wmax,
1995  const int numberOfPoints = 20,
1996  const double epsilon = 1e-12) :
1997  JPDF(Wmin, Wmax, numberOfPoints, epsilon),
1998  JDispersion(P_atm)
1999  {}
2000  };
2001 
2002 
2003  /**
2004  * Probability Density Functions of the time response of a PMT
2005  * with an implementation of the JAbstractPMT and JAbstractMedium interfaces via C-like methods.
2006  */
2007  class JPDF_C :
2008  public JAbstractPDF
2009  {
2010  public:
2011  /**
2012  * Constructor.
2013  *
2014  * \param Apmt photo-cathode area [m^2]
2015  * \param pF_qe pointer to function for quantum efficiency of PMT
2016  * \param pF_pmt pointer to function for angular acceptence of PMT
2017  * \param pF_l_abs pointer to function for absorption length [m]
2018  * \param pF_ls pointer to function for scattering length [m]
2019  * \param pF_ps pointer to model specific function to describe light scattering in water
2020  * \param P_atm ambient pressure [atm]
2021  * \param Wmin minimal wavelength for integration [nm]
2022  * \param Wmax maximal wavelength for integration [nm]
2023  * \param numberOfPoints number of points for integration
2024  * \param epsilon precision of points for integration
2025  */
2026  JPDF_C(const double Apmt,
2027  //
2028  // pointers to static functions
2029  //
2030  double (*pF_qe) (const double),
2031  double (*pF_pmt) (const double),
2032  double (*pF_l_abs)(const double),
2033  double (*pF_ls) (const double),
2034  double (*pF_ps) (const double),
2035  //
2036  // parameters for base class
2037  //
2038  const double P_atm,
2039  const double Wmin,
2040  const double Wmax,
2041  const int numberOfPoints = 20,
2042  const double epsilon = 1e-12) :
2043  JAbstractPDF(P_atm, Wmin, Wmax, numberOfPoints, epsilon),
2044  A (Apmt),
2045  qe (pF_qe),
2046  l_abs(pF_l_abs),
2047  ls (pF_ls),
2048  pmt (pF_pmt),
2049  ps (pF_ps)
2050  {}
2051 
2052 
2053  /**
2054  * Photo-cathode area of PMT.
2055  *
2056  * \return photo-cathode area [m^2]
2057  */
2058  virtual double getPhotocathodeArea() const
2059  {
2060  return A;
2061  }
2062 
2063 
2064  /**
2065  * Quantum efficiency of PMT (incl. absorption in glass, gel, etc.).
2066  *
2067  * \param lambda wavelenth [nm]
2068  * \return QE
2069  */
2070  virtual double getQE(const double lambda) const
2071  {
2072  return qe(lambda);
2073  }
2074 
2075 
2076  /**
2077  * Angular acceptence of PMT (normalised to one at cos() = -1).
2078  *
2079  * \param ct cosine angle of incidence
2080  * \return relative efficiency
2081  */
2082  virtual double getAngularAcceptance(const double ct) const
2083  {
2084  return pmt(ct);
2085  }
2086 
2087 
2088  /**
2089  * Absorption length.
2090  *
2091  * \param lambda wavelenth [nm]
2092  * \return absorption length [m]
2093  */
2094  virtual double getAbsorptionLength(const double lambda) const
2095  {
2096  return l_abs(lambda);
2097  }
2098 
2099 
2100  /**
2101  * Scattering length.
2102  *
2103  * \param lambda wavelenth [nm]
2104  * \return scattering length [m]
2105  */
2106  virtual double getScatteringLength(const double lambda) const
2107  {
2108  return ls(lambda);
2109  }
2110 
2111 
2112  /**
2113  * Model specific function to describe light scattering in water
2114  * (integral over full solid angle normalised to one).
2115  *
2116  * \param ct cosine scattering angle
2117  * \return probability
2118  */
2119  virtual double getScatteringProbability(const double ct) const
2120  {
2121  return ps(ct);
2122  }
2123 
2124  protected:
2125  /**
2126  * photo-cathode area [m2]
2127  */
2128  const double A;
2129 
2130  /**
2131  * Quantum efficiency of PMT (incl. absorption in glass, gel, etc.)
2132  *
2133  * \param lambda wavelenth [nm]
2134  * \return QE
2135  */
2136  double (*qe)(const double lambda);
2137 
2138  /**
2139  * Absorption length
2140  *
2141  * \param lambda wavelenth [nm]
2142  * \return absorption length [m]
2143  */
2144  double (*l_abs)(const double lambda);
2145 
2146  /**
2147  * Scattering length
2148  *
2149  * \param lambda wavelenth [nm]
2150  * \return scattering length [m]
2151  */
2152  double (*ls)(const double lambda);
2153 
2154  /**
2155  * Angular acceptence of PMT (normalised to one at cos() = -1)
2156  *
2157  * \param ct cosine angle of incidence
2158  * \return relative efficiency
2159  */
2160  double (*pmt)(const double ct);
2161 
2162  /**
2163  * Model specific function to describe light scattering in water
2164  *
2165  * \param ct cosine scattering angle
2166  * \return probability
2167  */
2168  double (*ps)(const double ct);
2169  };
2170 }
2171 
2172 
2173 #endif
General exception.
Definition: JException.hh:40
double getLightFromMuon(const double E_GeV, const double R_m, const double theta, const double phi, const double t_ns) const
Probability density function for light from muon.
Definition: JPDF.hh:1661
Exceptions.
static const JGeane gWater(2.67e-1 *JTOOLS::DENSITY_SEA_WATER, 3.4e-4 *JTOOLS::DENSITY_SEA_WATER)
Function object for Energy loss of muon in sea water.
2D Element.
Definition: JElement.hh:44
double getDirectLightFromEMshower(const double D_m, const double cd, const double theta, const double phi, const double t_ns) const
Probability density function for direct light from EM-shower.
Definition: JPDF.hh:1011
double getScatteredLightFromEMshower(const double E, const double D_m, const double cd, const double theta, const double phi, const double t_ns) const
Probability density function for scattered light from EM-shower.
Definition: JPDF.hh:1311
Numerical integrator for W(x) = 1.
Definition: JQuadrature.hh:113
double getScatteredLightFromEMshower(const double D_m, const double cd, const double theta, const double phi, const double t_ns) const
Probability density function for scattered light from EM-shower.
Definition: JPDF.hh:1069
JTOOLS::JElement2D< double, double > element_type
Definition: JPDF.hh:283
Auxiliary methods for PDF calculations.
double second
most downstream solution
Definition: JPDF.hh:1850
double getNumberOfPhotons() const
Number of Cherenkov photons per unit track length.
Definition: JPDF.hh:324
double getIndexOfRefraction()
Get average index of refraction of water.
Definition: JConstants.hh:111
double geanc()
Equivalent muon track length per unit shower energy.
Definition: JGeane.hh:23
Probability Density Functions of the time response of a PMT with an implementation for the JDispersio...
Definition: JPDF.hh:1978
scattered light from EM shower
Definition: JPDFTypes.hh:41
Implementation of dispersion for water in deep sea.
Definition: JDispersion.hh:26
double getDirectLightFromMuon(const double R_m, const double theta, const double phi) const
Number of photo-electrons from direct Cherenkov light from muon.
Definition: JPDF.hh:356
virtual double getPhotocathodeArea() const
Photo-cathode area of PMT.
Definition: JPDF.hh:2058
double getLightFromMuon(const int type, const double E_GeV, const double R_m, const double theta, const double phi, const double t_ns) const
Probability density function for light from muon.
Definition: JPDF.hh:1618
virtual double getScatteringProbability(const double ct) const
Model specific function to describe light scattering in water (integral over full solid angle normali...
Definition: JPDF.hh:2119
static const double PI
Constants.
Definition: JConstants.hh:20
JRoot(const double R, const double n, const double t)
Determine solution(s) of quadratic equation.
Definition: JPDF.hh:1802
direct light from EM showers
Definition: JPDFTypes.hh:32
double getLightFromEMshower(const int type, const double E_GeV, const double D_m, const double cd, const double theta, const double phi, const double t_ns) const
Probability density function for light from EM-shower.
Definition: JPDF.hh:1741
double getScatteredLightFromEMshowers(const double R_m, const double theta, const double phi, const double t_ns) const
Probability density function for scattered light from EM-showers.
Definition: JPDF.hh:733
virtual double getDispersionGroup(const double lambda) const =0
Dispersion of light for group velocity.
JPDF_C(const double Apmt, double(*pF_qe)(const double), double(*pF_pmt)(const double), double(*pF_l_abs)(const double), double(*pF_ls)(const double), double(*pF_ps)(const double), const double P_atm, const double Wmin, const double Wmax, const int numberOfPoints=20, const double epsilon=1e-12)
Constructor.
Definition: JPDF.hh:2026
virtual ~JPDF()
Virtual destructor.
Definition: JPDF.hh:315
static const JGeant geant(geanx, 0.0001)
Function object for the number of photons from EM-shower as a function of emission angle...
direct light from muon
Definition: JPDFTypes.hh:29
double getScatteredLightFromMuon(const double R_m, const double theta, const double phi, const double t_ns) const
Probability density function for scattered light from muon.
Definition: JPDF.hh:499
JAbstractPDF(const double P_atm, const double Wmin, const double Wmax, const int numberOfPoints=20, const double epsilon=1e-12)
Constructor.
Definition: JPDF.hh:1992
PMT interface.
Definition: JAbstractPMT.hh:17
Numbering scheme for PDF types.
double operator[](const int i) const
Get result by index.
Definition: JPDF.hh:1833
Auxiliary class to find solution(s) to of the square root expression: where is the index of refrac...
Definition: JPDF.hh:1793
Type definition of a 1st degree polynomial interpolation based on a JGridCollection with result type ...
double getLightFromEMshower(const double E_GeV, const double D_m, const double cd, const double theta, const double phi, const double t_ns) const
Probability density function for light from EM-shower.
Definition: JPDF.hh:1774
std::vector< element_type > phd
fast evaluation of phi integral
Definition: JPDF.hh:1970
scattered light from muon
Definition: JPDFTypes.hh:30
static double MODULE_RADIUS_M
Radius of optical module [m].
Definition: JPDF.hh:39
Compiler version dependent expressions, macros, etc.
Constants.
virtual double getQE(const double lambda) const
Quantum efficiency of PMT (incl.
Definition: JPDF.hh:2070
virtual double getAngularAcceptance(const double ct) const
Angular acceptence of PMT (normalised to one at cos() = -1).
Definition: JPDF.hh:2082
double getDirectLightFromEMshower(const double E, const double D_m, const double cd, const double theta, const double phi, const double t_ns) const
Probability density function for direct light from EM-shower.
Definition: JPDF.hh:1207
virtual double getScatteringLength(const double lambda) const =0
Scattering length.
static const JGeanz geanz(1.85, 0.62, 0.54)
Function object for longitudinal EM-shower profile.
Probability Density Functions of the time response of a PMT with an implementation of the JAbstractPM...
Definition: JPDF.hh:2007
scattered light from delta-rays
Definition: JPDFTypes.hh:36
virtual double getScatteringLength(const double lambda) const
Scattering length.
Definition: JPDF.hh:2106
virtual double getAbsorptionLength(const double lambda) const =0
Absorption length.
direct light from EM shower
Definition: JPDFTypes.hh:40
virtual double getWavelength(const double n, const double eps=1.0e-10) const
Determine wavelength for a given index of refraction corresponding to the group velocity.
Definition: JPDF.hh:1862
scattered light from EM showers
Definition: JPDFTypes.hh:33
virtual double getIndexOfRefractionPhase(const double lambda) const =0
Index of refraction for phase velocity.
double getDirectLightFromDeltaRays(const double R_m, const double theta, const double phi, const double t_ns) const
Probability density function for direct light from delta-rays.
Definition: JPDF.hh:1388
virtual double getPhotocathodeArea() const =0
Photo-cathode area of PMT.
bool is_valid
validity of solutions
Definition: JPDF.hh:1848
direct light from delta-rays
Definition: JPDFTypes.hh:35
static double getRmin()
minimal distance of approach of muon to PMT [m]
Definition: JPDF.hh:1923
const double wmax
maximal wavelength for integration [nm]
Definition: JPDF.hh:1968
double cherenkov(const double lambda, const double n)
Number of Cherenkov photons per unit track length and per unit wavelength.
Definition: JPDFToolkit.hh:62
Auxiliary classes for numerical integration.
virtual double getIndexOfRefractionGroup(const double lambda) const
Index of refraction for group velocity.
double getIntegral(const double E, const double z) const
Integral of PDF (starting from 0).
Definition: JGeanz.hh:95
virtual double getWavelength(const double n, const double w, const double eps) const
Determine wavelength for a given index of refraction corresponding to the group velocity.
Definition: JPDF.hh:1900
virtual double getInverseAttenuationLength(const double l_abs, const double ls, const double cts) const
Get the inverse of the attenuation length.
Definition: JPDF.hh:1934
int numberOfPoints
Definition: JResultPDF.cc:22
const double wmin
Integration limits.
Definition: JPDF.hh:1967
double getDeltaRaysFromMuon(const double E)
Equivalent EM-shower energy due to delta-rays per unit muon track length.
Definition: JPDFToolkit.hh:81
virtual double getAngularAcceptance(const double ct) const =0
Angular acceptence of PMT.
virtual double getAbsorptionLength(const double lambda) const
Absorption length.
Definition: JPDF.hh:2094
double getScatteredLightFromDeltaRays(const double R_m, const double theta, const double phi, const double t_ns) const
Probability density function for direct light from delta-rays.
Definition: JPDF.hh:1474
double getScatteredLightFromMuon(const double D_m, const double cd, const double theta, const double phi, const double t_ns) const
Probability density function for scattered light from muon.
Definition: JPDF.hh:881
container_type::const_iterator const_iterator
Definition: JCollection.hh:89
double getLightFromEMshower(const int type, const double D_m, const double cd, const double theta, const double phi, const double t_ns) const
Probability density function for light from EM-shower.
Definition: JPDF.hh:1687
double getLightFromEMshower(const double D_m, const double cd, const double theta, const double phi, const double t_ns) const
Probability density function for light from EM-shower.
Definition: JPDF.hh:1718
double getLength(const double E, const double P, const double eps=1.0e-3) const
Get shower length for a given integrated probability.
Definition: JGeanz.hh:122
virtual double getQE(const double lambda) const =0
Quantum efficiency of PMT (incl.
double getDirectLightFromEMshowers(const double R_m, const double theta, const double phi, const double t_ns) const
Probability density function for direct light from EM-showers.
Definition: JPDF.hh:645
static const double C
Speed of light in vacuum [m/ns].
Definition: JConstants.hh:22
double getTanThetaC()
Get average tangent of Cherenkov angle of water.
Definition: JConstants.hh:122
Light dispersion inteface.
double getDirectLightFromMuon(const double R_m, const double theta, const double phi, const double t_ns) const
Probability density function for direct light from muon.
Definition: JPDF.hh:408
virtual double getDispersionPhase(const double lambda) const =0
Dispersion of light for phase velocity.
virtual double getScatteringProbability(const double ct) const =0
Model specific function to describe light scattering in water (integral over full solid angle normali...
double first
most upstream solution
Definition: JPDF.hh:1849
JPDF(const double Wmin, const double Wmax, const int numberOfPoints=20, const double epsilon=1e-12)
Constructor.
Definition: JPDF.hh:294
const double A
photo-cathode area [m2]
Definition: JPDF.hh:2128
Low level interface for the calculation of the Probability Density Functions (PDFs) of the arrival ti...
Definition: JPDF.hh:276