CherenkovFluorescenceMatrix.cc
Go to the documentation of this file.
3 #include "diagonalMatrix.h"
4 
5 #include <iomanip>
6 #include <limits>
7 
8 #include <boost/io/ios_state.hpp>
9 
10 #include <utl/Vector.h>
11 #include <utl/UTMPoint.h>
12 #include <utl/AugerUnits.h>
13 #include <utl/AugerException.h>
14 #include <utl/MathConstants.h>
15 #include <utl/PhysicalConstants.h>
16 #include <utl/PhysicalFunctions.h>
17 #include <utl/TabulatedFunctionErrors.h>
18 
19 #include <det/Detector.h>
20 
21 #include <atm/ProfileResult.h>
22 #include <atm/Atmosphere.h>
23 #include <atm/ScatteringResult.h>
24 #include <atm/AttenuationResult.h>
25 
26 #include <det/Detector.h>
27 #include <fdet/FDetector.h>
28 #include <fdet/Eye.h>
29 #include <fwk/CentralConfig.h>
30 #include <fwk/CoordinateSystemRegistry.h>
31 #include <fwk/RandomEngineRegistry.h>
32 #include <utl/UTMPoint.h>
33 #include <utl/ReferenceEllipsoid.h>
34 #include <CLHEP/Random/RandFlat.h>
35 #include <utl/RandomEngine.h>
36 
37 using CLHEP::RandFlat;
38 
39 using namespace fwk;
40 using namespace det;
41 
42 using std::cerr;
43 using std::cout;
44 using std::endl;
45 
46 using namespace oBLAS;
47 using namespace atm;
48 using namespace det;
49 using namespace FdProfileReconstructorKG;
50 
51 
52 #undef _CFM_DEBUG
53 
54 
55 // constructor with geometry, relative detector efficiency and shower maximum as input
56 
57 CherenkovFluorescenceMatrix::CherenkovFluorescenceMatrix(
58  const double xMax, const utl::Point& eyePosition,
59  const std::deque<std::vector<utl::Point>>& showerGeometry,
60  const utl::TabulatedFunction& relEff,
61  const std::deque<double>& depth,
62  const double eCut, const double zeta, const double cFac, const double fFac,
63  const eFluorescenceLDF fLDF,
64  const eDirectCherenkovLDF dcLDF,
65  const eScatteredCherenkovLDF scLDF,
66  const eMultipleScatteringLDF msLDF,
67  const bool cherenkovCone,
68  const OpticalHalo::EHaloType spotHalo
69 ) :
70  fXmax(xMax),
71  fEcut(eCut),
72  fEyePosition(eyePosition),
73  fShowerGeometry(showerGeometry),
74  fRelEff(relEff),
75  fDepth(depth),
76  fZeta(zeta),
77  fCfac(cFac),
78  fFfac(fFac),
79  fFluoLDF(fLDF),
80  fDirCherLDF(dcLDF),
81  fScatCherLDF(scLDF),
82  fMultScatLDF(msLDF),
83  fCherenkovCone(cherenkovCone),
84  fOpticalHalo(spotHalo)
85 {
86 #ifdef _CFM_DEBUG
87  cout << " -->CherenkovFluorescenceMatrix()" << endl;
88 #endif
89 
90  // set number of depth points
91  const unsigned int nDepth = fShowerGeometry.size();
92  for (unsigned int i = 0; i < nDepth; ++i)
93  fShowerPoints.push_back(fShowerGeometry[i][0] -
94  0.5*(fShowerGeometry[i][0] - fShowerGeometry[i][1]));
95 
96  // create matrices
100  fFluorescenceMatrix = new diagonalMatrix(nDepth);
102 
103  fTanZeta = tan(fZeta);
104 
105  // calculate necessary ingredients ...
106 
107  // a) get wavelengths to be used for Cherenkov and Fluorescence
109 
110  // b) geometry dependend stuff
115 
116  // c) age dependend stuff
119 
120  // ... and finally the matrices
124 }
125 
126 
127 // destructor deletes allocated space
128 
130 {
131 #ifdef _CFM_DEBUG
132  cout << " -->~CherenkovFluorescenceMatrix()" << endl;
133 #endif
136  delete fDirectCherenkovMatrix;
137  delete fFluorescenceMatrix;
139 }
140 
141 
142 void
144 {
145 #ifdef _CFM_DEBUG
146  cout << " -->CalculateFluorescenceMatrix()" << endl;
147 #endif
148 
150 
151  // current atmosphere
152  const auto& atmo = det::Detector::GetInstance().GetAtmosphere();
153 
154  const double dEdX0 = atmo.GetdEdX0();
155 
156  // vector of wave lengths
157  const auto& lambdaVec = fFWaveLength;
158 
160 
161  for (unsigned int i = 0, n = fShowerPoints.size(); i < n; ++i) {
162  const utl::Point& meanPos = fShowerPoints[i];
163 
164  // get vector from point to eye
165  const double showerAge = utl::ShowerAge(fDepth[i], fXmax);
166  const double disteye = (meanPos - fEyePosition).GetMag();
167  const double spotFraction = fOpticalHalo.GetHaloFraction(fZeta, showerAge, disteye);
168 
169  double height = 0;
170 
171  try {
173  height = UTMp.GetHeight();
174  } catch (utl::UTMPoint::UTMZoneException& d) {
175  cout << d.GetExceptionName() << endl;
176  const ProfileResult& densityProfile = atmo.EvaluateDensityVsHeight();
177  height = densityProfile.MaxX();
178  }
179 
180  const auto& fluoyield_tab = atmo.EvaluateFluorescenceYield(height);
181 
182  double epsYTsum = 0;
183  for (unsigned int j = 0, n = lambdaVec.size(); j < n; ++j) {
184  const double y_j = fluoyield_tab.Y(lambdaVec[j]) * fFfac;
185  epsYTsum += y_j * fRelEff.Y(lambdaVec[j]) * fFT2eye[i][j];
186  }
187 
188  const double msFactor = 1 / (1 - MultipleScatteringFraction(i, lambdaVec, fluoyield_tab));
189  fFluorescenceMultipleScattering.push_back(msFactor);
190 
191  const double deltaL = (fShowerGeometry[i][0] - fShowerGeometry[i][1]).GetMag();
192  const double zetaFraction = FluorescenceLDFFraction(i);
193  flMat(i, i) = msFactor * spotFraction * zetaFraction * epsYTsum * fGfac[i] / dEdX0 * deltaL;
194  }
195 }
196 
197 
198 // gets wavelengths to be used for Cherenkov and Fluorescence
199 
200 void
202 {
203 #ifdef _CFM_DEBUG
204  cout << " -->GetWaveLengths()" << endl;
205 #endif
206 
207  // current atmosphere
208  const auto& atmo = det::Detector::GetInstance().GetAtmosphere();
209 
210  fCWaveLength = atmo.GetWavelengths(Atmosphere::eCerenkov);
211  fFWaveLength = atmo.GetWavelengths(Atmosphere::eFluorescence);
212 
213  // remove wave lengths with no or zero efficiency
214  const double effMinLam = fRelEff[0].X();
215  const double effMaxLam = fRelEff[fRelEff.GetNPoints()-1].X();
216 
217  for (auto it = fFWaveLength.begin(); it != fFWaveLength.end(); ) {
218  const auto& lam = *it;
219  if (effMinLam <= lam && lam <= effMaxLam && fRelEff.Y(lam) > 0)
220  ++it;
221  else
222  fFWaveLength.erase(it);
223  }
224 
225  for (auto it = fCWaveLength.begin(); it != fCWaveLength.end(); ) {
226  const auto& lam = *it;
227  if (effMinLam <= lam && lam <= effMaxLam)
228  //&& fRelEff.Y(*it) > 0) // !!!C-bins are integration bounds!!!
229  ++it;
230  else
231  fCWaveLength.erase(it);
232  }
233 }
234 
235 
236 void
238 {
239 #ifdef _CFM_DEBUG
240  cout << " -->CalculateDirectCherenkovMatrix()" << endl;
241 #endif
242 
244 
245  // current atmosphere
246  const Atmosphere& atmo = det::Detector::GetInstance().GetAtmosphere();
247 
248  // vector of wave lengths
249  const std::vector<double>& lambdaVec = fCWaveLength;
250 
252 
253  for (unsigned int i = 0; i < fShowerPoints.size(); ++i) {
254  const double showerAge = utl::ShowerAge(fDepth[i], fXmax);
255 
256  // get vector from point to eye
257  const utl::Point& meanPos = fShowerPoints[i];
258  const double disteye = (meanPos - fEyePosition).GetMag();
259  const double spotFraction =
260  fOpticalHalo.GetHaloFraction(fZeta, showerAge, disteye);
261 
262  const utl::TabulatedFunction& directCherenkov =
264  fShowerGeometry[i][1],
265  fEyePosition,showerAge);
266  double epsYTsum = 0;
267  for (unsigned int j = 0; j < lambdaVec.size(); ++j) {
268  const double y_j = directCherenkov.GetY(j) * fCfac;
269  epsYTsum += y_j * fRelEff.Y(lambdaVec[j]) * fCT2eye[i][j];
270  }
271 
272  const double msFactor =
273  1 / (1 - MultipleScatteringFraction(i, lambdaVec, directCherenkov));
274  fCherenkovMultipleScattering.push_back(msFactor);
275  const double zetaFraction = DirectCherenkovLDFFraction(i);
276  cDirMat(i, i) = msFactor * spotFraction * zetaFraction * epsYTsum / fMeandEdX[i];
277  }
278 }
279 
280 
281 void
283 {
284 #ifdef _CFM_DEBUG
285  cout << " -->CalculateMieAndRayScattCherenkovMatrix()" << endl;
286 #endif
287 
288  // make sure CalculateDirectCherenkovMatrix() was
289  // called before ....
290  if (fCherenkovMultipleScattering.size() != fShowerPoints.size()) {
291  cerr << " CalculateMieAndRayScattCherenkovMatrix() "
292  << " Error - no multiple scattering factors " << endl;
293  throw utl::OutOfBoundException();
294  }
295 
296  // vector of wave lengths
297  const std::vector<double>& lambdaVec = fCWaveLength;
298  const unsigned int nLambda = lambdaVec.size();
299  double t[nLambda];
300 
303 
304  for (unsigned int i = 0; i < fShowerPoints.size(); ++i) {
305 
306  const double showerAge = utl::ShowerAge(fDepth[i],fXmax);
307 
308  // get vector from point to eye
309  const utl::Point& meanPos = fShowerPoints[i];
310  const double disteye = (meanPos - fEyePosition).GetMag();
311  const double spotFraction =
312  fOpticalHalo.GetHaloFraction(fZeta, showerAge, disteye);
313 
314  const double msFactor = fCherenkovMultipleScattering[i];
315 
316  for (unsigned int k = 0; k < nLambda; ++k)
317  t[k] = 1;
318 
319  for (int j = i; j >= 0; --j) {
320  double epsYTsumMie = 0;
321  double epsYTsumRay = 0;
322  for (unsigned int k = 0; k < nLambda; ++k) {
323  if (j != int(i))
324  t[k] *= fTShower[j][k];
325 
326  const double detEff = fRelEff.Y(lambdaVec[k]);
327  const double factor = t[k] * detEff * fCherAtTrack[j][k] * fCT2eye[i][k];
328  epsYTsumMie += factor * fMieScat2eye[i][k];
329  epsYTsumRay += factor * fRayScat2eye[i][k];
330  }
331  const double zetaFraction = ScatteredCherenkovLDFFraction(i, j);
332  const double zetaPerAlpha = zetaFraction / fMeandEdX[j];
333  cMieMat(i, j) = msFactor * spotFraction * zetaPerAlpha * epsYTsumMie;
334  cRayMat(i, j) = msFactor * spotFraction * zetaPerAlpha * epsYTsumRay;
335  }
336 
337  }
338 }
339 
340 
341 // Mie- and Rayleigh-attenuation from shower to eye
342 void
344 {
345 #ifdef _CFM_DEBUG
346  cout << " -->CalculateAttenuationToEye()" << endl;
347 #endif
348 
349  fCT2eye.clear();
350  fFT2eye.clear();
351 
352  // current atmosphere
353  const Atmosphere& atmo = det::Detector::GetInstance().GetAtmosphere();
354 
355  // vector of C/F wave lengths
356  const std::vector<double>& lambdaCVec = fCWaveLength;
357  const unsigned int nCLambda = lambdaCVec.size();
358  std::vector<double> tC(nCLambda);
359  const std::vector<double>& lambdaFVec = fFWaveLength;
360  const unsigned int nFLambda = lambdaFVec.size();
361  std::vector<double> tF(nFLambda);
362 
363  for (unsigned int i = 0; i < fShowerPoints.size(); ++i) {
364 
365  const utl::Point& meanPos = fShowerPoints[i];
366 
367  // ---- for Ch. wave langth
368 
369  // Mie attenuation
370  const AttenuationResult mCAtt =
371  atmo.EvaluateMieAttenuation(fEyePosition, meanPos, lambdaCVec);
372  const utl::TabulatedFunctionErrors& mieCAtt = mCAtt.GetTransmissionFactor();
373  // Rayleigh attenuation
374  const AttenuationResult rCAtt =
375  atmo.EvaluateRayleighAttenuation(fEyePosition, meanPos, lambdaCVec);
376  const utl::TabulatedFunctionErrors& rayCAtt = rCAtt.GetTransmissionFactor();
377 
378  for (unsigned int j = 0; j < nCLambda; ++j) {
379  tC[j] = mieCAtt.GetY(j) * rayCAtt.GetY(j);
380  }
381  fCT2eye.push_back(tC);
382 
383  // ---- for Fl. wave langth
384 
385  // Mie attenuation
386  const AttenuationResult mFAtt =
387  atmo.EvaluateMieAttenuation(fEyePosition, meanPos, lambdaFVec);
388  const utl::TabulatedFunctionErrors& mieFAtt = mFAtt.GetTransmissionFactor();
389  // Rayleigh attenuation
390  const AttenuationResult rFAtt =
391  atmo.EvaluateRayleighAttenuation(fEyePosition, meanPos, lambdaFVec);
392  const utl::TabulatedFunctionErrors& rayFAtt = rFAtt.GetTransmissionFactor();
393 
394  for (unsigned int j = 0; j < nFLambda; ++j) {
395  tF[j] = mieFAtt.GetY(j) * rayFAtt.GetY(j);
396  }
397  fFT2eye.push_back(tF);
398 
399  }
400 }
401 
402 
403 // Mie- and Rayleigh-attenuation along the track
404 
405 void
407 {
408 #ifdef _CFM_DEBUG
409  cout << " -->CalculateAttenuationAlongTrack()" << endl;
410 #endif
411 
412  fTShower.clear();
413 
414  // current atmosphere
415  const Atmosphere& atmo = det::Detector::GetInstance().GetAtmosphere();
416 
417  // vector of wave lengths
418  const std::vector<double>& lambdaVec = fCWaveLength;
419  const unsigned int nLambda = lambdaVec.size();
420  std::vector<double> transmission(nLambda);
421 
422  for (unsigned int i = 0; i < fShowerPoints.size()-1; ++i) {
423 
424  const utl::Point& meanPos_i = fShowerPoints[i];
425  const int j = i + 1;
426  const utl::Point& meanPos_j = fShowerPoints[j];
427 
428  // Mie attenuation
429  const AttenuationResult mAtt =
430  atmo.EvaluateMieAttenuation(meanPos_i, meanPos_j, lambdaVec);
432 
433  // Rayleigh attenuation
434  const AttenuationResult rAtt =
435  atmo.EvaluateRayleighAttenuation(meanPos_i, meanPos_j, lambdaVec);
437 
438  for (unsigned int k = 0; k < nLambda; ++k) {
439  transmission[k] = mieAtt.GetY(k) * rayAtt.GetY(k);
440  }
441  fTShower.push_back(transmission);
442 
443  }
444 }
445 
446 
447 // Mie- and Rayleigh scattering from shower to eye
448 
449 void
451 {
452 #ifdef _CFM_DEBUG
453  cout << " -->CalculateScatteringToEye()" << endl;
454 #endif
455 
456  fMieScat2eye.clear();
457  fRayScat2eye.clear();
458 
459  // current atmosphere
460  const Atmosphere& atmo = det::Detector::GetInstance().GetAtmosphere();
461 
462  // vector of wave lengths
463  const std::vector<double>& lambdaVec = fCWaveLength;
464  const unsigned int nLambda = lambdaVec.size();
465  std::vector<double> tR(nLambda);
466  std::vector<double> tM(nLambda);
467 
468  // unit vector along shower
469  const utl::Vector shwDir = fShowerGeometry[0][1] - fShowerGeometry[0][0];
470 
471  for (unsigned int i = 0; i < fShowerPoints.size(); ++i) {
472  const utl::Point& meanPos = fShowerPoints[i];
473 
474  // average vector from shower to eye
475  utl::Vector meanVec = meanPos - fEyePosition;
476  const double disteye = meanVec.GetMag();
477 
478  // emission angle.
479  const double angle = Angle(-shwDir,meanVec);
480 
481  const ScatteringResult& rScattering =
482  atmo.EvaluateRayleighScattering(fShowerGeometry[i][0],
483  fShowerGeometry[i][1],
484  angle, disteye, lambdaVec);
485  const ScatteringResult& mScattering =
486  atmo.EvaluateMieScattering(fShowerGeometry[i][0],
487  fShowerGeometry[i][1],
488  angle, disteye, lambdaVec);
489  const utl::TabulatedFunctionErrors& rayleighScattTrackEye =
490  rScattering.GetScatteringFactor();
491  const utl::TabulatedFunctionErrors& mieScattTrackEye =
492  mScattering.GetScatteringFactor();
493  for (unsigned int j = 0; j < nLambda; ++j) {
494  tR[j] = rayleighScattTrackEye.GetY(j);
495  tM[j] = mieScattTrackEye.GetY(j);
496  }
497  fRayScat2eye.push_back(tR);
498  fMieScat2eye.push_back(tM);
499 
500  }
501 }
502 
503 
504 // Cherenkov light per electron produced at track
505 
506 void
508 {
509 #ifdef _CFM_DEBUG
510  cout << " -->CalculateCherenkovAtTrack()" << endl;
511 #endif
512 
513  // current atmosphere
514  const Atmosphere& atmo = det::Detector::GetInstance().GetAtmosphere();
515 
516  fCherAtTrack.clear();
517 
518  // vector of wave lengths
519  const std::vector<double>& lambdaVec = fCWaveLength;
520  const unsigned int nLambda = lambdaVec.size();
521  std::vector<double> t(nLambda);
522 
523  for (unsigned int i = 0; i < fShowerPoints.size(); ++i) {
524  const double showerAge = utl::ShowerAge(fDepth[i], fXmax);
525  const utl::TabulatedFunction& CherenkovProd =
526  atmo.EvaluateCherenkovPhotons(fShowerGeometry[i][0], fShowerGeometry[i][1], showerAge);
527  for (unsigned int j = 0; j < nLambda; ++j) {
528  t[j] = CherenkovProd.GetY(j) * fCfac;
529  }
530  fCherAtTrack.push_back(t);
531  }
532 }
533 
534 
535 // Calculates fraction of light 1/(4*pi*r^2) received by telescope
536 
537 void
539 {
540 #ifdef _CFM_DEBUG
541  cout << " -->CalculateGeometricalFactor()" << endl;
542 #endif
543 
544  fGfac.clear();
545  const double fourPi = 4*utl::kPi;
546  for (unsigned int i = 0; i < fShowerPoints.size(); ++i) {
547  const utl::Vector r = fShowerPoints[i] - fEyePosition;
548  const double rSquared = r.GetMag2();
549  fGfac.push_back(1/(fourPi*rSquared));
550  }
551 }
552 
553 
554 // Calculates the mean energy deposit per electron
555 
556 void
558 {
559  fMeandEdX.clear();
560  for (unsigned int i = 0; i < fShowerPoints.size(); ++i) {
561  const double dEdXperElectron = utl::EnergyDeposit(fDepth[i], fXmax, fEcut);
562  fMeandEdX.push_back(dEdXperElectron);
563  }
564 }
565 
566 
567 // Calculates sum of Cherenkov and fluorescence matrixes and returns pointer to total CherenkovFluorescenceMatrix
568 
571  const
572 {
573 #ifdef _CFM_DEBUG
574  cout << " -->GetCherenkovFluorescenceMatrix()" << endl;
575 #endif
576  if (!fDirectCherenkovMatrix ||
581  return nullptr;
582 
583  if (!fUpToDate) {
584  const diagonalMatrix& fl = *fFluorescenceMatrix;
589 
590  for (unsigned int i = 0, n = fShowerPoints.size(); i < n; ++i) {
591  tot(i, i) = fl(i, i) + dc(i, i) + rc(i, i) + mc(i, i);
592  for (unsigned int j = 0; j < i; ++j)
593  tot(i, j) = rc(i, j) + mc(i, j);
594  }
595  fUpToDate = true;
596  }
598 }
599 
600 
601 // recalculate matrices depending on shower age
602 
603 void
605 {
606 #ifdef _CFM_DEBUG
607  cout << " -->updateXmax()" << endl;
608 #endif
609  fXmax = xMax;
610 
616 
617  // flag GetCherenkovFluorescenceMatrix()
618  // that it needs to recalculate
619  fUpToDate = false;
620 }
621 
622 
623 // fraction of direct Cherenkov light shower image
624 
625 double
627  const
628 {
629  switch (fDirCherLDF) {
630  case eNoDirCherLDF:
631  return 1;
632  case eGoraDirCherLDF:
633  return GoraFraction(iPosition);
634  }
635  return 1;
636 }
637 
638 
639 // fraction of scattered Cherenkov light shower image
640 
641 double
643  const int jOrigin)
644  const
645 {
646  switch (fScatCherLDF) {
647  case eNoScatCherLDF:
648  return 1;
649  case eGoraScatCherLDF:
650  return GoraFraction(iObserved);
651  case eExpoScatCherLDF:
652  return ExponentialFraction(iObserved);
653  case eGillerScatCherLDF:
654  return GillerFraction(iObserved,jOrigin);
655  }
656  return 1;
657 }
658 
659 
660 // fraction of lateral fluorescence light shower image
661 
662 double
664  const
665 {
666  switch (fFluoLDF) {
667  case eNoFluoLDF:
668  return 1;
669  case eGoraFluoLDF:
670  return GoraFraction(iPosition);
671  }
672  return 1;
673 }
674 
675 
676 /* fraction of scattered Cherenkov light
677  B. Dawson, M. Giller, G. Wieczorek, ICRC07 Merida, #0651 */
678 
679 double
681  const int jOrigin)
682  const
683 {
684  const double pathLength = (fShowerGeometry[iObserved][0] -
685  fShowerGeometry[jOrigin][0]).GetMag();
686  const double zetaDistance = GetZetaDistance(iObserved);
687 
688  const double maxEmissionAngle = atan2(zetaDistance, pathLength);
689 
690  const Atmosphere& atmo = det::Detector::GetInstance().GetAtmosphere();
691  const ProfileResult& depthProfile = atmo.EvaluateDepthVsHeight();
692 
693  double height = 0;
694  try {
695  const utl::UTMPoint UTMp(fShowerPoints[jOrigin],
697  height = UTMp.GetHeight();
698  } catch (utl::UTMPoint::UTMZoneException& d) {
699  cout << d.GetExceptionName() << endl;
700  height = depthProfile.MaxX();
701  }
702 
703  const double xVert = depthProfile.Y(height);
704  const double xSlant = fDepth[jOrigin];
705  const double showerAge = utl::ShowerAge(xSlant, fXmax);
706 
707  const double minValidCherenkovAngle = 5*utl::degree;
708 
709  const double fraction =
710  (!fCherenkovCone || maxEmissionAngle>minValidCherenkovAngle) ?
711  atmo.AngularCherenkovCDF(maxEmissionAngle,xVert,showerAge) :
712  AngularCherenkovCDFWithCone(maxEmissionAngle, xVert, showerAge);
713 
714  return fraction;
715 }
716 
717 
718 // modified angular Cherenkov CDF taking into account the Cherenkov cone
719 
720 double
722  const double xVert, const double showerAge)
723  const
724 {
725  // number of MC evaluations
726  const int nMC = 1000;
727 
728  const Atmosphere& atmo = det::Detector::GetInstance().GetAtmosphere();
729 
730  // Cherenkov angle for beta=1
731  const double nRefrac = utl::RefractionIndex::LorentzLorentz(xVert);
732  const double cosThetaCher = 1/nRefrac;
733  const double sinThetaCher = sqrt(1 - cosThetaCher*cosThetaCher);
734 
735  // array of angular CDF for random number generation
736  // (yes, Hillas&Nerling are exponentials, but are we supposed to know
737  // this outside of utl::Atmosphere??)
738 
739  const double angularBinning = 0.25*utl::degree;
740  std::vector<double> cdf;
741 
742  const double maxIntegrationAngle = 90*utl::degree;
743  double thisAngle = 0;
744 
745  while (thisAngle <= maxIntegrationAngle) {
746  const double cumulative = atmo.AngularCherenkovCDF(thisAngle, xVert, showerAge);
747  cdf.push_back(cumulative);
748  thisAngle += angularBinning;
749  }
750 
751  utl::RandomEngine& theRandom =
752  RandomEngineRegistry::GetInstance().Get(RandomEngineRegistry::ePhysics);
753 
754  std::vector<double> randomNumbers1(nMC);
755  std::vector<double> randomNumbers2(nMC);
756 
757  RandFlat::shootArray(&theRandom.GetEngine(), nMC, &randomNumbers1.front());
758  RandFlat::shootArray(&theRandom.GetEngine(), nMC, &randomNumbers2.front());
759 
760  // calculate fraction of photons within [maxEmissionAngle]
761 
762  const double cosThetaEmission = cos(maxEmissionAngle);
763 
764  int nInsideZeta = 0;
765 
766  for (int i = 0; i < nMC; ++i) {
767  const double x = randomNumbers1[i];
768  double alpha = maxIntegrationAngle;
769  for (unsigned int k = 0, n = cdf.size()-1; k < n; ++k) {
770  if (x > cdf[k] && x < cdf[k+1]) {
771  alpha = k*angularBinning + angularBinning/(cdf[k] - cdf[k+1]) * (cdf[k] - x);
772  break;
773  }
774  }
775 
776  const double phi = randomNumbers2[i]*utl::kTwoPi;
777  const double cosTheta = sinThetaCher*cos(phi)*sin(alpha) + cos(alpha)*cosThetaCher;
778 
779  if (cosTheta > cosThetaEmission)
780  ++nInsideZeta;
781  }
782 
783  const double fractionWithinEmissionAngle = double(nInsideZeta) / nMC;
784 
785  // cout << fractionWithinEmissionAngle
786  // << " " << atmo.AngularCherenkovCDF(maxEmissionAngle,xVert,showerAge)
787  // << " " << maxEmissionAngle/utl::degree
788  // << " " << acos(cosThetaCher)/utl::degree << endl;
789 
790  return fractionWithinEmissionAngle;
791 }
792 
793 
794 /* fraction of multiple scattered light wrt. total signal from
795  M. Roberts, J. Phys. G 31 (2005) 1291 */
796 
797 double
799  const std::vector<double>& waveLengths,
800  const utl::TabulatedFunction& yield)
801  const
802 {
803  const Atmosphere& atmo = det::Detector::GetInstance().GetAtmosphere();
804 
805  // optical depth and scattering coefficient
806 
807  // attenuation shower-->eye
808  const utl::Point& meanPos = fShowerPoints[iPosition];
809  const AttenuationResult mieResultAttShowerToEye =
810  atmo.EvaluateMieAttenuation(fEyePosition, meanPos, waveLengths);
811  const utl::TabulatedFunctionErrors& mieAttShowerToEye =
812  mieResultAttShowerToEye.GetTransmissionFactor();
813 
814  const AttenuationResult rayAttResultShowerToEye =
815  atmo.EvaluateRayleighAttenuation(fEyePosition, meanPos, waveLengths);
816  const utl::TabulatedFunctionErrors& rayAttShowerToEye =
817  rayAttResultShowerToEye.GetTransmissionFactor();
818 
819  // attenuation within bin
820  const AttenuationResult mieAttResultInBin =
821  atmo.EvaluateMieAttenuation(fShowerGeometry[iPosition][0],
822  fShowerGeometry[iPosition][1],
823  waveLengths);
824  const utl::TabulatedFunctionErrors& mieAttInBin =
825  mieAttResultInBin.GetTransmissionFactor();
826 
827  const AttenuationResult rayAttResultInBin =
828  atmo.EvaluateRayleighAttenuation(fShowerGeometry[iPosition][0],
829  fShowerGeometry[iPosition][1],
830  waveLengths);
831  const utl::TabulatedFunctionErrors& rayAttInBin =
832  rayAttResultInBin.GetTransmissionFactor();
833 
834  double yieldEffSum = 0;
835  double yieldEffAttEyeSum = 0;
836  double yieldEffAttBinSum = 0;
837 
838  for (unsigned int j = 0, n = waveLengths.size(); j < n; ++j) {
839  const double y_j = yield.Y(waveLengths[j]);
840  const double eff = fRelEff.Y(waveLengths[j]);
841  const double attEye = rayAttShowerToEye.GetY(j) * mieAttShowerToEye.GetY(j);
842  const double attBin = rayAttInBin.GetY(j) * mieAttInBin.GetY(j);
843 
844  const double yEff = y_j * eff;
845  yieldEffSum += yEff;
846  yieldEffAttEyeSum += yEff * attEye;
847  yieldEffAttBinSum += yEff * attBin;
848  }
849 
850  const double distanceToEye = (fShowerPoints[iPosition] - fEyePosition).GetMag();
851  const double binLength = (fShowerGeometry[iPosition][0] -
852  fShowerGeometry[iPosition][1]).GetMag();
853 
854  const double attenuationToEye = yieldEffAttEyeSum / yieldEffSum;
855  const double attenuationInBin = yieldEffAttBinSum / yieldEffSum;
856 
857  const double opticalDepth = attenuationToEye > 0 ?
858  -log(attenuationToEye) :
860  const double alphaTot = attenuationInBin > 0 ?
861  -log(attenuationInBin)/binLength :
863 
864  // see Eq. (3) in Mike's paper
865  const double argument = opticalDepth * alphaTot/utl::m *
866  sqrt(distanceToEye/utl::m) *
867  pow(fZeta/utl::degree, 1.1);
868  const double fraction = 0.774 * pow(argument, 0.68);
869 
870  return fraction;
871 }
872 
873 
874 /* fraction of multiple scattered light wrt. total signal from
875  Jan Pekala et al., GAP-2008-087 */
876 
877 double
879  const std::vector<double>& waveLengths,
880  const utl::TabulatedFunction& yield)
881  const
882 {
883  const Atmosphere& atmo = det::Detector::GetInstance().GetAtmosphere();
884 
885  // optical depth
886 
887  // attenuation shower-->eye
888  const utl::Point& meanPos = fShowerPoints[iPosition];
889 
890  const AttenuationResult mieResultAttShowerToEye =
891  atmo.EvaluateMieAttenuation(fEyePosition, meanPos, waveLengths);
892  const utl::TabulatedFunctionErrors& mieAttShowerToEye =
893  mieResultAttShowerToEye.GetTransmissionFactor();
894 
895  const AttenuationResult rayAttResultShowerToEye =
896  atmo.EvaluateRayleighAttenuation(fEyePosition, meanPos, waveLengths);
897  const utl::TabulatedFunctionErrors& rayAttShowerToEye =
898  rayAttResultShowerToEye.GetTransmissionFactor();
899 
900  double yieldEffSum = 0;
901  double yieldEffAttEyeSum = 0;
902 
903  for (unsigned int j = 0, n = waveLengths.size(); j < n; ++j) {
904  const double y_j = yield.Y(waveLengths[j]);
905  const double eff = fRelEff.Y(waveLengths[j]);
906  const double attEye = rayAttShowerToEye.GetY(j) * mieAttShowerToEye.GetY(j);
907 
908  const double yEff = y_j * eff;
909  yieldEffSum += yEff;
910  yieldEffAttEyeSum += yEff * attEye;
911  }
912 
913  const double attenuationToEye = yieldEffAttEyeSum / yieldEffSum;
914 
915  const double opticalDepth = attenuationToEye > 0 ?
916  -log(attenuationToEye) :
918 
919  double height;
920  try {
922  height = UTMp.GetHeight();
923  } catch (utl::UTMPoint::UTMZoneException& d) {
924  cout << d.GetExceptionName() << endl;
925  height = atmo.EvaluateDensityVsHeight().MaxX();
926  }
927 
928  const double g = 5.426*utl::km;
929  // const double f = 3.318e-2;
930  // height above array --> height a.s.l. exp(1.4/G) = 1.2943
931  const double f = 4.2947e-2;
932 
933  // fraction wrt. direct light
934  const double fraction1 = f * opticalDepth * (fZeta/utl::degree) * exp(-height/g);
935 
936  // fraction wrt. total light
937  const double fraction2 = fraction1 / (fraction1 + 1);
938 
939  return fraction2;
940 }
941 
942 
943 /* fraction of lateral shower image according to phenomenological
944  LDF proposed by Spot group
945  (see talk by M. Tueros, Malargue meeting Nov 2007) */
946 
947 double
949  const
950 {
951  const double r = GetZetaDistance(iPosition);
952  const double alpha = 1.65;
953  const double beta = 325.*utl::m;
954  const double fraction = 1 - exp(-pow(r/beta, alpha));
955 
956  return fraction;
957 }
958 
959 
960 /* fraction of lateral shower image according to
961  Gora et. al Astropart. Phys. 24(2006) 484. */
962 
963 double
965  const
966 {
967  const Atmosphere& atmo = det::Detector::GetInstance().GetAtmosphere();
968 
969  const ProfileResult& tempProfile = atmo.EvaluateTemperatureVsHeight();
970  const ProfileResult& depthProfile = atmo.EvaluateDepthVsHeight();
971  const ProfileResult& pressureProfile = atmo.EvaluatePressureVsHeight();
972 
973  // cos(zenith) for moliere radius
974  const utl::CoordinateSystemPtr cs = det::Detector::GetInstance().GetSiteCoordinateSystem();
975  const utl::Vector shwDir = fShowerGeometry[0][0] - fShowerGeometry[0][1];
976  const double cosTheta = shwDir.GetCosTheta(cs);
977 
978  const utl::Point& meanPos = fShowerPoints[iPosition];
979 
980  double height;
981  try {
983  height = UTMp.GetHeight();
984  } catch (utl::UTMPoint::UTMZoneException& d) {
985  cout << d.GetExceptionName() << endl;
986  height = depthProfile.MaxX();
987  }
988 
989  const double xSlant = fDepth[iPosition];
990  const double pressure = pressureProfile.Y(height);
991  const double temperature = tempProfile.Y(height);
992  const double age = utl::ShowerAge(xSlant, fXmax);
993 
994  const double rm = utl::MoliereRadius(temperature, pressure, cosTheta);
995 
996  const double rStar = GetZetaDistance(iPosition) / rm;
997 
998  return utl::GoraCDF(rStar, age);
999 }
1000 
1001 
1002 // distance to shower axis corresponding to zeta
1003 
1004 double
1006  const
1007 {
1008  const utl::Point& meanPos = fShowerPoints[iPosition];
1009  const double r = (meanPos - fEyePosition).GetMag() * fTanZeta;
1010  return r;
1011 }
1012 
1013 
1014 double
1016  const std::vector<double>& waveLengths,
1017  const utl::TabulatedFunction& yield)
1018  const
1019 {
1020  switch (fMultScatLDF) {
1021  case eNoMultScatLDF:
1022  return 0;
1023  case eRobertsLDF:
1024  return RobertsFraction(iPosition, waveLengths, yield);
1025  case ePekalaLDF:
1026  return PekalaFraction(iPosition, waveLengths, yield);
1027  }
1028  return 0;
1029 }
1030 
1031 
1032 // set a new zeta value and recalculate width dependend stuff
1033 
1034 void
1036 {
1037  fUpToDate = false;
1038  fTanZeta = tan(zeta);
1039  fZeta = zeta;
1040 
1044 }
1045 
1046 
1047 // rescale matrix elements for new yield factors
1048 
1049 void
1051  const double chkovFac)
1052 {
1058 
1059  const double fluoRescale = fluoFac / fFfac;
1060  const double chkovRescale = chkovFac / fCfac;
1061 
1062  for (unsigned int i = 0, n = fShowerPoints.size(); i < n; ++i) {
1063  fl(i, i) *= fluoRescale;
1064  dc(i, i) *= chkovRescale;
1065  rc(i, i) *= chkovRescale;
1066  mc(i, i) *= chkovRescale;
1067  tot(i, i) = fl(i, i) + dc(i, i) + rc(i, i) + mc(i, i);
1068  for (unsigned int j = 0; j < i; ++j) {
1069  rc(i, j) *= chkovRescale;
1070  mc(i, j) *= chkovRescale;
1071  tot(i, j) = rc(i, j) + mc(i, j);
1072  }
1073  }
1074 
1075  fCfac = chkovFac;
1076  fFfac = fluoFac;
1077 }
1078 
1079 
1080 /* print extensive informations about current data members (for debugging)
1081  iwhat=0 -> print transmission to eye
1082  =1 -> print transmission along track */
1083 
1084 void
1086  const
1087 {
1088  boost::io::ios_all_saver save(cout);
1089  cout.flags(std::ios::scientific);
1090  cout.precision(2);
1091 
1092  // print transmission to eye
1093  const std::vector<double>& lambdaVec = fCWaveLength;
1094  const unsigned int nLambda = lambdaVec.size();
1095 
1096  if (!iwhat) {
1097  cout << "\n wave lengths:\n";
1098  for (unsigned int j = 0; j < nLambda; ++j)
1099  cout << std::setw(9) << lambdaVec[j];
1100  cout << endl;
1101 
1102  cout << "\n transmission to eye:\n";
1103  for (unsigned int i = 0; i < fShowerPoints.size(); ++i) {
1104  for (unsigned int j = 0; j < nLambda; ++j)
1105  cout << std::setw(9) << fCT2eye[i][j];
1106  cout << endl;
1107  }
1108  } else if (iwhat == 1) {
1109  const int kLam = 9;
1110  for (unsigned int i = 0; i < fShowerPoints.size(); ++i) {
1111  cout << std::setw(9) << i
1112  << std::setw(9) << lambdaVec[kLam]
1113  << std::setw(9) << fCherAtTrack[i][kLam]
1114  << std::setw(9) << fCT2eye[i][kLam]
1115  << std::setw(9) << fMieScat2eye[i][kLam]
1116  << endl;
1117  }
1118  }
1119 }
double AngularCherenkovCDFWithCone(const double maxEmissionAngle, const double xVert, const double showerAge) const
unsigned int GetNPoints() const
Top of the interface to Atmosphere information.
Point object.
Definition: Point.h:32
double GoraCDF(const double rStar, const double age)
double Angle(const double theta1, const double phi1, const double theta2, const double phi2)
atm::AttenuationResult EvaluateMieAttenuation(const utl::Point &xInit, const utl::Point &xFinal, const std::vector< double > &wLength) const
constexpr double km
Definition: AugerUnits.h:125
const utl::TabulatedFunctionErrors & GetTransmissionFactor() const
Transmission factor.
RandomEngineType & GetEngine()
Definition: RandomEngine.h:32
Class to hold and convert a point in geodetic coordinates.
Definition: UTMPoint.h:40
Class to hold collection (x,y) points and provide interpolation between them.
const atm::ProfileResult & EvaluatePressureVsHeight() const
Tabulated function giving Y=air pressure as a function of X=height.
double RobertsFraction(const int, const std::vector< double > &, const utl::TabulatedFunction &) const
double GetCosTheta(const CoordinateSystemPtr &coordinateSystem) const
cos of zenith (theta) angle
Definition: BasicVector.h:251
const atm::ProfileResult & EvaluateDensityVsHeight() const
Tabulated function giving Y=density as a function of X=height.
double pow(const double x, const unsigned int i)
double GetMag() const
Definition: Vector.h:58
Report attempts to use invalid UTM zone.
Definition: UTMPoint.h:300
double Y(const double x) const
Get the Y value (coordinate) for given X (ordinate)
Exception for reporting variable out of valid range.
Class holding the output of the ScatteringResult function.
boost::shared_ptr< const CoordinateTransformer > CoordinateSystemPtr
Shared pointer for coordinate systems.
double AngularCherenkovCDF(const double theta, const double verticalDepth, const double showerAge) const
cumulative of angular Cherenkov distribution from 0 to theta
#define max(a, b)
double GetHeight() const
Get the height.
Definition: UTMPoint.h:212
double GetHaloFraction(const double zeta, const double age, const double dist) const
Definition: OpticalHalo.cc:19
double MoliereRadius(double temperature, double pressure, const double cosTheta)
The Moliere Radius (2 radiation length above obs-level, GAP-1998-002)
Wraps the random number engine used to generate distributions.
Definition: RandomEngine.h:27
Class describing the Atmospheric profile.
Definition: ProfileResult.h:25
const utl::TabulatedFunction & EvaluateCherenkovDirect(const utl::Point &xA, const utl::Point &xB, const utl::Point &xEye, const double showerAge) const
constexpr double kPi
Definition: MathConstants.h:24
void UpdateXmax(const double)
update matrices for new xmax value
const std::deque< std::vector< utl::Point > > & fShowerGeometry
constexpr double fraction
Definition: AugerUnits.h:281
atm::AttenuationResult EvaluateRayleighAttenuation(const utl::Point &xInit, const utl::Point &xFinal, const std::vector< double > &wLength) const
Compute Rayleigh attenuation between points.
double GetZetaDistance(const int) const
get distance to shower axis corresponding to zeta
constexpr double kTwoPi
Definition: MathConstants.h:27
const atm::ProfileResult & EvaluateDepthVsHeight() const
Tabulated function giving Y=depth as a function of X=height.
static const ReferenceEllipsoid & GetWGS84()
Get the auger standard ellipsoid: wgs84.
constexpr double degree
atm::ScatteringResult EvaluateRayleighScattering(const utl::Point &xA, const utl::Point &xB, const double angle, const double distance, const std::vector< double > &xLength) const
constexpr double g
Definition: AugerUnits.h:200
fZeta(t.GetZeta())
const oBLAS::lowerTriangularMatrix * GetCherenkovFluorescenceMatrix() const
returns total light matrix (not const as we eventually want to invert it ...)
const double & GetY(const unsigned int idx) const
double LorentzLorentz(const double verticalDepth)
Calculate the refraction index for a given depth.
void SetYieldFactors(const double fluoFac, const double chkovFac)
set yield factors
const utl::TabulatedFunctionErrors & GetScatteringFactor() const
Scattering factor.
double ShowerAge(const double slantDepth, const double showerMax)
General definition of shower age.
const utl::TabulatedFunction & EvaluateCherenkovPhotons(const utl::Point &xA, const utl::Point &xB, const double showerAge) const
double EnergyDeposit(const double age, const double enCut)
Parametrization for the average energy deposit per particle.
double MultipleScatteringFraction(const int, const std::vector< double > &, const utl::TabulatedFunction &) const
Vector object.
Definition: Vector.h:30
double Y(const double x) const
Get or interpolate the Y value that corresponds to parameter x.
constexpr double m
Definition: AugerUnits.h:121
double PekalaFraction(const int, const std::vector< double > &, const utl::TabulatedFunction &) const
const atm::ProfileResult & EvaluateTemperatureVsHeight() const
Tabulated function giving Y=temperature as a function of X=height.
Class describing the Atmospheric attenuation.
double MaxX() const
Return the maximum value for X (ordinate) stored in the profile.
double GetMag2() const
Definition: Vector.h:61
atm::ScatteringResult EvaluateMieScattering(const utl::Point &xA, const utl::Point &xB, const double angle, const double distance, const std::vector< double > &xLength) const

, generated on Tue Sep 26 2023.