FdProfileReconstructor.cc
Go to the documentation of this file.
1 
10 #include "EnergyFitter.h"
12 #include "RootCFMatrixOutput.h"
13 #include "OpticalHalo.h"
15 #include "diagonalMatrix.h"
16 #include "lowerTriangularMatrix.h"
17 #include "upperTriangularMatrix.h"
18 
20 
21 #include <utl/ErrorLogger.h>
22 #include <utl/Reader.h>
23 
24 #include <evt/Event.h>
25 #include <evt/ShowerRecData.h>
26 #include <evt/ShowerFRecData.h>
27 #include <evt/GaisserHillas4Parameter.h>
28 
29 #include <fevt/FEvent.h>
30 #include <fevt/Eye.h>
31 #include <fevt/Telescope.h>
32 #include <fevt/EyeRecData.h>
33 
34 #include <det/Detector.h>
35 #include <fdet/FDetector.h>
36 #include <fdet/Telescope.h>
37 #include <fdet/Eye.h>
38 #include <fdet/Pixel.h>
39 #include <fdet/Channel.h>
40 
41 #include <utl/PhysicalConstants.h>
42 #include <utl/PhysicalFunctions.h>
43 #include <utl/UTMPoint.h>
44 #include <utl/Transformation.h>
45 
46 #include <fwk/LocalCoordinateSystem.h>
47 #include <fwk/CoordinateSystemRegistry.h>
48 #include <fwk/CentralConfig.h>
49 
50 #include <atm/Atmosphere.h>
51 #include <atm/ProfileResult.h>
52 #include <atm/AttenuationResult.h>
53 #include <atm/InclinedAtmosphericProfile.h>
54 
55 #include <boost/io/ios_state.hpp>
56 
57 #include <iostream>
58 #include <string>
59 #include <sstream>
60 #include <sstream>
61 #include <vector>
62 
63 using namespace FdProfileReconstructorKG;
64 using namespace fwk;
65 using namespace utl;
66 using namespace fevt;
67 using namespace fdet;
68 using namespace evt;
69 using namespace atm;
70 using namespace oBLAS;
71 using namespace std;
72 
73 
74 
75 
76 /******************************************************************\
77  *
78  * constructor
79  *
80 \******************************************************************/
82  fInclinedModelDepthBinning(10*g/cm2),
83  fYieldRefit(false),
84  fAlwaysGuessXMaxFromAperture(false),
85  fIsMultiEyeEvent(false),
86  fXmax(0.),
87  fEnergyFitter(NULL),
88  fRootCFMOutput(NULL)
89 {
90 }
91 
92 
93 /******************************************************************\
94  *
95  * destructor
96  *
97 \******************************************************************/
99 {
100 }
101 
102 
103 /******************************************************************\
104  *
105  * initialize and read XML cards
106  *
107 \******************************************************************/
109 {
110 
111  CentralConfig* cc = CentralConfig::GetInstance();
112 
113  Branch topB =
114  cc->GetTopBranch("FdProfileReconstructor");
115 
116  Branch profCalcB = topB.GetChild("profileCalculation");
117 
118  // verbosity flag controls general output (-1: no output)
119  profCalcB.GetChild("verbosity").GetData(fVerbosity);
120 
121  // energy cut off for number of electrons
122  profCalcB.GetChild("energyCutoff").GetData(fEcut);
123 
124  // scaling factors for fluorescence and Cherenkov yields
125  profCalcB.GetChild("fluoScaleFac").GetData(fFfac);
126  profCalcB.GetChild("cherScaleFac").GetData(fCfac);
127 
128  // angle above which inclined atmosphere should be used
129  double inclinedModelMinZenith;
130  profCalcB.GetChild("inclinedModelMinZenith").GetData(inclinedModelMinZenith);
131  fInclinedModelMaxCosZenith=cos(inclinedModelMinZenith);
132 
133  profCalcB.GetChild("inclinedModelDepthBinning").GetData(fInclinedModelDepthBinning);
134 
135 
136  // correction of shower image width
137  std::string fluoLDF, dirCherLDF, scatCherLDF, multscatLDF, haloType;
138 
139  profCalcB.GetChild("fluorescenceLDF").GetData(fluoLDF);
140  profCalcB.GetChild("directCherenkovLDF").GetData(dirCherLDF);
141  profCalcB.GetChild("scatteredCherenkovLDF").GetData(scatCherLDF);
142  profCalcB.GetChild("multipleScatteringLDF").GetData(multscatLDF);
143  profCalcB.GetChild("cherenkovCone").GetData(fCherenkovCone);
144  profCalcB.GetChild("opticalHalo").GetData(haloType);
145 
146  if ( fluoLDF == "eNone")
148  else if ( fluoLDF == "eGora")
150  else {
151  ERROR("unknown fluorescence LDF");
153  }
154 
155  if ( dirCherLDF == "eNone")
157  else if ( dirCherLDF == "eGora")
159  else {
160  ERROR("unknown direct Cherenkov LDF");
162  }
163 
164  if ( scatCherLDF == "eNone")
166  else if ( scatCherLDF == "eGora")
168  else if ( scatCherLDF == "eExponential")
170  else if ( scatCherLDF == "eGiller")
172  else {
173  ERROR("unknown scattered Cherenkov LDF");
175  }
176 
177  if ( multscatLDF == "eNone")
179  else if ( multscatLDF == "eRoberts")
181  else if ( multscatLDF == "ePekala")
183  else {
184  ERROR("unknown multiple scattering model");
186  }
187 
188  if ( haloType == "eNone")
190  else if ( haloType == "eFlasher2005" )
192  else if ( haloType == "eFlasher2008" )
194  else if ( haloType == "eSpotGroup" )
196  else if ( haloType == "eSpotGroup2" )
198  else {
199  ERROR("unknown optical halo type");
201  }
202 
203  Branch errPropB = topB.GetChild("errorPropagation");
204  // controls print level for EnergyFitter
205  errPropB.GetChild("verbosity").GetData(fErrPropVerb);
206  // option to propagate geometry errors
207  errPropB.GetChild("propagateGeometryErrors").GetData(fPropagateGeometryErrors);
208  // option to propagate atmospheric errors
209  errPropB.GetChild("propagateAtmUncertainties").GetData(fPropagateAtmUncertainties);
210  // option to rescale errors for propagation
211  errPropB.GetChild("rescaleErrors").GetData(fRescaleErrors);
212  // option to combine data points for faster error propagation
213  errPropB.GetChild("maxErrPropPoints").GetData(fmaxErrPropPoints);
214 
215  Branch rootB = topB.GetChild("rootOutput");
216  rootB.GetChild("saveToRoot").GetData(fSaveToRoot);
217 
218  // invisible energy options
219  Branch eCalcB = topB.GetChild("invisibleEnergy");
220  string compositionOption;
221  eCalcB.GetChild("composition").GetData(compositionOption);
222 
223  fComposition =
224  (compositionOption == "data") ?
226  (compositionOption == "mixed") ?
228  (compositionOption == "proton") ?
230 
231  string interactionOption;
232  eCalcB.GetChild("interactionModel").GetData(interactionOption);
233  if (interactionOption == "SIBYLL21") {
235  } else if (interactionOption == "QGSJET01") {
237  } else if (interactionOption == "DATA") {
239  } else {
240  ostringstream err;
241  err << "Unknown hadronic interaction model used: " << interactionOption;
242  ERROR(err);
243  return eFailure;
244  }
245 
247  ERROR("inconsistent invisible energy options (data options cannot "
248  "be mixed with other options)");
249  return eFailure;
250  }
251 
252  if (fVerbosity > -1) {
253  // ----- info output
254  std::string idstr("$Id$");
255 
256  std::istringstream is(idstr);
257  std::string version;
258  is >> version >> version >> version;
259 
260  std::ostringstream info;
261  info << " Version: " << version
262  << "\n Parameters:\n"
263  << "\t energy cutoff: "
264  << fEcut/MeV << " MeV \n"
265  << "\t yield scale factors: F="
266  << fFfac << " C=" << fCfac << "\n"
267  << "\t using inclined profile model above "
268  << inclinedModelMinZenith/degree << " deg. (dX="
269  << fInclinedModelDepthBinning/g*cm2 << "g/cm^2)\n"
270  << "\t geometric error propagation is "
271  << (fPropagateGeometryErrors?"on":"off") << "\n"
272  << "\t atmospheric error propagation is "
273  << (fPropagateAtmUncertainties?"on":"off") << "\n"
274  << "\t lateral fluorescence light model: " << fluoLDF << "\n"
275  << "\t lateral direct Cherenkov light model: " << dirCherLDF << "\n"
276  << "\t lateral scattered Cherenkov light model: " << scatCherLDF
278  (fCherenkovCone?" (with Cherenkov cone)":" (without Cherenkov cone)"):
279  "") << "\n"
280  << "\t optical halo: " << haloType << "\n"
281  << "\t multiple scattering model: " << multscatLDF << "\n"
282  << "\t invisible energy model: "
283  << interactionOption << "/"
284  << compositionOption << "\n";
285 
286  INFO(info);
287  }
288 
289 
290  if (fSaveToRoot)
292 
293  // create an EnergyFitter and initialize it
294 
296  if(fEnergyFitter->Init()) {
297  return eSuccess;
298  }
299  else
300  return eFailure;
301 
302 }
303 
304 /******************************************************************\
305  *
306  * things to do at end of run
307  *
308 \******************************************************************/
310 {
311 
312  DeleteCFMatrix();
313 
314  delete fEnergyFitter; fEnergyFitter=NULL;
315  delete fRootCFMOutput;fRootCFMOutput=NULL;
316 
317  if(fEnergyFitter->Finish())
318  return eSuccess;
319  else
320  return eFailure;
321 }
322 
323 
324 /******************************************************************\
325  *
326  * steering routine for profile calculation for each eye
327  *
328 \******************************************************************/
331 {
332  if (event.HasSimShower() &&
334  WARNING("############################################################################\n"
335  "############################################################################\n"
336  "# really reconstruct simulated shower with\n"
337  "# multiple scattering and/or spot halo ???\n"
338  "# note: none of these effects is currently simulated,\n"
339  "# i.e. unless you know what you are doing, the profile reconstruction\n"
340  "# will be probably wrong...)\n"
341  "############################################################################\n"
342  "############################################################################");
343  }
344 
345  // clean up
346  if (!fYieldRefit)
347  DeleteCFMatrix();
348 
349  if (!event.HasFEvent())
350  return eSuccess;
351 
352  // set cout format (but remember old one)
353  boost::io::ios_all_saver save(cout);
354  cout.flags(std::ios::scientific);
355  cout.precision(3);
356 
357  // count eyes with profile reconstruction
358  int nEyes = 0;
359 
360  if (fVerbosity > -1)
361  cout << "\n --[FdProfileReconstructor]--> " << endl;
362 
363  // loop on eyes for profile reconstruction
364  fevt::FEvent& fdEvent = event.GetFEvent();
365  fIsMultiEyeEvent = (fdEvent.GetNEyes() > 1);
366  for (fevt::FEvent::EyeIterator eyeIter = fdEvent.EyesBegin(ComponentSelector::eHasData);
367  eyeIter != fdEvent.EyesEnd(ComponentSelector::eHasData);
368  ++eyeIter) {
369 
370  fevt::Eye& eye = *eyeIter;
371  fErrorCalcMode = false;
372 
373  // check for geometry and light at aperture
374  if (!eye.HasRecData() ||
376  continue;
377 
378  if (fVerbosity > -1)
379  cout << "\n calculating profile for eye " << eye.GetId() << endl;
380 
381  // set default geometry
382  SetGeometry(eye, 0,0,0,0,0);
383  fGeomVariance.clear();
384  fAtmVariance.clear();
385 
386  // retrieve the reconstructed data
387  if (GetShowerFRecData(event, eye)) {
388 
389  CalculateDetEff(eye);
390 
391  // calculate the shower geometry, depth and efficiencies
392  if (!CalculateGeometryAndDepth(eye))
393  continue;
394 
395  // calculate the profiles at track
396  fXmax = GuessShowerMaximum(event, eye);
397  if (!CalculateProfiles(eye))
398  continue;
399 
400  // fit Gaisser-Hillas and calculate energy
401  if (fEnergyFitter->Run(eye, fChFlPtr)) {
402  ++nEyes;
403 
404  if (fSaveToRoot)
405  fRootCFMOutput->Write(event, eye, *fChFlPtr);
406 
407  // calculate total errors and save them
409 
410  }
411 
412  }
413 
414  }
415 
416  fRelEff.Clear();
417  fTrackPositions.clear();
418  fDepth.clear();
419 
420  // check if at least one eye was sucessful
421  return (nEyes > 0) ? eSuccess : eContinueLoop;
422 }
423 
424 
425 /******************************************************************\
426  *
427  * get ShowerFRecData from data structure
428  * either from global data from event (if calculated stereo or hybrid)
429  * or from the current eye
430  *
431 \******************************************************************/
432 bool
434 {
435  // stuff below eventually for global showers (i.e. stereo
436  // currently not supported)
437 
438  /*
439  fShowerFRecData=NULL;
440  if (event.HasRecShower()) {
441  if(event.GetRecShower().HasFRecShower()) {
442  fShowerFRecData=&event.GetRecShower().GetFRecShower();
443  // set the cut off value in data structure
444  fShowerFRecData->SetEnergyCutoff(fEcut);
445  }
446  }
447  */
448 
449  if (fShowerFRecData == NULL &&
450  eye.GetRecData().HasFRecShower()) {
453  }
454 
455  return fShowerFRecData != NULL;
456 }
457 
458 
459 /******************************************************************\
460  *
461  * calculation of
462  *
463  * - dEdX at track
464  * - N_e at track
465  * - fluorescence photons at aperture
466  * - scattered Cherenkov photons at aperture
467  * - direct Cherenkov photons at aperture
468  *
469 \******************************************************************/
470 bool
472 {
473  namespace ublas = boost::numeric::ublas;
474 
475  if (fVerbosity > -1)
476  cout << " current shower maximum is " << fXmax/(g/cm2) << endl;
477 
478  // eye position
479  const Point& eyepos =
480  det::Detector::GetInstance().GetFDetector().GetEye(eye).GetPosition();
481 
482  // light flux at diaphragm
483  const TabulatedFunctionErrors& lightflux =
485 
486  const unsigned int nF = fDepth.size();
487 
488  const unsigned int kMinPoints = 5;
489  if (fDepth.size() - fOutSideFOV<kMinPoints) {
490  if (fVerbosity > -1)
491  cout << " too few points for fit: nF="
492  << fDepth.size()-fOutSideFOV << endl;
493  return false;
494  }
495 
496  // vector of light flux and its covariance
497  ublas::vector<double> n(nF);
498  diagonalMatrix Vn(nF);
499  for (unsigned int i = 0; i < nF ; ++i) {
500  if (i < fOutSideFOV) {
501  n(i) = 0;
502  Vn(i, i) = 0;
503  } else {
504  const int j = i - fOutSideFOV;
505  n(i) = lightflux.GetY(j);
506  const double en = lightflux.GetYErr(j);
507  Vn(i, i) = en*en;
508  }
509  }
510 
511  const double zeta = eye.GetRecData().GetZeta();
512  if (zeta <= 1.e-12) {
513  ostringstream msg;
514  msg << "############################################################################\n"
515  "# Eye " << eye.GetId() << "'s Zeta angle is " << zeta << ". There was likely a problem\n"
516  "# in the aperture-light finding. Check your configuration! Skipping Eye...\n"
517  "############################################################################";
518  WARNING(msg);
519  return false;
520  }
521 
522  double fluoScaleFac = fFfac;
523  double cherScaleFac = fCfac;
524  if (fluoScaleFac < 0) {
525  fluoScaleFac *= -1;
526  cherScaleFac *= -1;
527  }
528 
529  // solve n=CF*dEdX
530  if (!fYieldRefit) {
531  fChFlPtr =
533  fRelEff, fDepth, fEcut, zeta,
534  cherScaleFac, fluoScaleFac,
538  fChFlPtrMap[eye.GetId()] = fChFlPtr;
539  } else {
540  std::map<int, CherenkovFluorescenceMatrix*>::iterator currentCFMatrix =
541  fChFlPtrMap.find(eye.GetId());
542  if (currentCFMatrix != fChFlPtrMap.end()) {
543  fChFlPtr = currentCFMatrix->second;
544  fChFlPtr->SetYieldFactors(fluoScaleFac, cherScaleFac);
545  } else {
546  cout << " could not find CFM for eye " << eye.GetId()
547  << "\n map contains " << fChFlPtrMap.size()
548  << " entries :";
549  for (std::map<int, CherenkovFluorescenceMatrix*>::iterator iter = fChFlPtrMap.begin();
550  iter != fChFlPtrMap.end(); ++iter)
551  cout<< iter->first << " ";
552  cout << endl;
553  return false;
554  }
555  }
556 
558 
559  if (fVerbosity > -1)
560  cout << " inverting (" << fDepth.size() << "x" <<fDepth.size()
561  << ") CherenkovFluorescenceMatrix ... " << endl;
562 
564  const lowerTriangularMatrix* CFinvPtr = nullptr;
565  try {
566  CFinvPtr = CF.GetInverse();
567  } catch (SingularMatrixException& s) {
568  cerr << " FdProfileReconstructor::CalculateProfiles - Error:"
569  << " SingularMatrixException for CF" << endl;
570  return false;
571  }
572  const lowerTriangularMatrix& CFinv = *CFinvPtr;
573 
574  // calculate covariance matrix
575 
576  if (fVerbosity > -1)
577  cout << " covariance matrix ... " << endl;
578 
579  // calculate diagonal elements of CF*V*(CF^T)^(-1)
580 
581  std::vector<double> covdEdX(nF);
582  for (unsigned int i = 0; i < nF; ++i) {
583  double sum = 0;
584  for (unsigned int k = i; k < nF; ++k)
585  sum += CFinv(k, i) * CFinv(k, i) * Vn(i, i);
586  covdEdX[i] = sum;
587  }
588 
589  // calculate light fractions at aperture
590 
591  if (fVerbosity > -1)
592  cout << " profiles at aperture ... \n" << endl;
593 
594  // fill profiles
595 
596  if (!fErrorCalcMode) {
597 
598  InitProfiles(eye);
599 
600  fevt::EyeRecData& eyeRecData = eye.GetRecData();
605  TabulatedFunctionErrors& dedxProf = eyeRecData.GetFRecShower().GetEnergyDeposit();
606  ublas::vector<double> dEdX = ublas::prod(CFinv, n);
607  ublas::vector<double> vChDir = ublas::prod(*(ChFl.GetDirectCherenkovMatrix()), dEdX);
608  ublas::vector<double> vChMScat = ublas::prod(*(ChFl.GetMieScatteredCherenkovMatrix()), dEdX);
609  ublas::vector<double> vChRScat = ublas::prod(*(ChFl.GetRayleighScatteredCherenkovMatrix()), dEdX);
610  for (unsigned int i = 0; i < nF-fOutSideFOV; ++i) {
611  const int j = i + fOutSideFOV;
612  const double eDep = dEdX(j);
613  const double eDepErr = sqrt(covdEdX[j]); // sqrt(covdEdX(j,j));
614  const double dEdXperElectron = utl::EnergyDeposit(fDepth[j], fXmax, fEcut);
615  const double Ne = eDep / dEdXperElectron;
616  const double NeErr = eDepErr / dEdXperElectron;
617  const double time = lightflux.GetX(i);
618  dedxProf.PushBack(fDepth[j], 0, eDep, eDepErr);
619  longProf.PushBack(fDepth[j], 0, Ne, NeErr);
620  dirCher.PushBack(time, 0, vChDir[j], 0);
621  scatMCher.PushBack(time, 0, vChMScat[j], 0);
622  scatRCher.PushBack(time, 0, vChRScat[j], 0);
623  }
624  } else {
625  fevt::EyeRecData& eyeRecData = eye.GetRecData();
626  TabulatedFunctionErrors& dedxProf = eyeRecData.GetFRecShower().GetEnergyDeposit();
627  ublas::vector<double> dEdX = ublas::prod(CFinv, n);
628  for (unsigned int i = 0; i < nF-fOutSideFOV; ++i) {
629  const int j = i + fOutSideFOV;
630  const double eDep = dEdX(j);
631  const double eDepErr = sqrt(covdEdX[j]); // sqrt(covdEdX(j,j));
632  dedxProf.PushBack(fDepth[j], 0, eDep, eDepErr);
633  }
634  }
635 
636  return true;
637 }
638 
639 
640 /******************************************************************\
641  *
642  * calculation of relative detector efficiency as
643  * function of wavelength
644  *
645 \******************************************************************/
647 {
648  // Relative detector efficiency of first telescope
649  fRelEff.Clear();
650 
651  // fevt::Eye::ConstTelescopeIterator itTel = eye.TelescopesBegin();
652  // const fdet::Telescope& dettel =
653  // det::Detector::GetInstance().GetFDetector().GetTelescope(*itTel);
654  //const utl::TabulatedFunction& fEfficiencyCalibration = dettel.GetModelEfficiency();
655 
656  // Note: Since the measured efficiency is really a telescope property (albeit
657  // currently the same for all telescopes), this shouldn't simply grab the
658  // efficiency of the first telescope. --Steffen 18.5.09
659  fRelEff = det::Detector::GetInstance().GetFDetector().GetEye(eye).GetTelescope(1).GetMeasuredRelativeEfficiency();
660 }
661 
662 
663 /******************************************************************\
664  *
665  * calculates vector of shower positions in local
666  * eye coordinates and fills slant depth
667  *
668 \******************************************************************/
669 bool
671 {
672  // clear vectors
673  fTrackPositions.clear();
674  fDepth.clear();
675 
676  det::Detector& theDetector = det::Detector::GetInstance();
677 
678  const Atmosphere& atmo = theDetector.GetAtmosphere();
679  const ReferenceEllipsoid& wgs84 = ReferenceEllipsoid::GetWGS84();
680 
681  // set the Cherenkov model energy threshold for this calculation
683 
684  fevt::EyeRecData& eyeRecData = eye.GetRecData();
685 
686  const Point& eyePos = theDetector.GetFDetector().GetEye(eye).GetPosition();
687  const Vector coreEyeVec = fCore - eyePos;
688  const double coreEyeDistance = coreEyeVec.GetMag();
690 
691  const double cosTheta = fAxis.GetCosTheta(coreCS);
692  const bool flatEarth = (cosTheta > fInclinedModelMaxCosZenith);
693 
694  if (flatEarth && cosTheta < 0.1) {
695  cerr << " FdProfileReconstructor::CalculateGeometryAndDepth() - "
696  " skipping upward/horizontal track\n"
697  " please use inclined model for these tracks" << endl;
698  return false;
699  }
700 
701  double minDistance;
702  double maxDistance;
703  if (!InitializeAtmosphere(flatEarth, minDistance, maxDistance))
704  return false;
705 
706  const ProfileResult& verticalDepthProfile = atmo.EvaluateDepthVsHeight();
707  const double minHeight = verticalDepthProfile.MinX();
708  const double maxHeight = verticalDepthProfile.MaxX();
709 
710  const ProfileResult& depthProfile = (flatEarth?
711  verticalDepthProfile :
713 
714  // new profiles will be filled if some points are outside atmosphere
715  unsigned int nSkip = 0;
716  TabulatedFunctionErrors newLightFlux;
717 
719  const unsigned int nAperturePoints = lightflux.GetNPoints();
720 
721  vector<Point> trackBin(2);
722 
723  // real data inside field of view
724  for (unsigned int i = 0; i < nAperturePoints; ++i) {
725 
726  // time at start and end of bin
727  double t[2] = { lightflux.GetX(i)/ns - lightflux.GetXErr(i)/ns,
728  lightflux.GetX(i)/ns + lightflux.GetXErr(i)/ns };
729  double Xdepth[2] = { 0, 0 };
730 
731  bool skipThisPoint = false;
732  for (int j = 0; j < 2; ++j) {
733 
734  const double chi_i = fChi0 - 2* atan(kSpeedOfLight / fRp *(t[j] - fT0));
735  double l = coreEyeDistance * sin(chi_i) / sin(fChi0 - chi_i);
736  double distance = -l;
737 
738  // vector and point detector-shower at t=t[j]
739  const Vector chi_i_vec = coreEyeVec + l * fAxis;
740  const Point chi_i_point = fCore + l * fAxis;
741  const double height = wgs84.PointToLatitudeLongitudeHeight(chi_i_point).get<2>();
742 
743  trackBin[j] = chi_i_point;
744 
745  if (distance<minDistance || distance>maxDistance ||
746  height < minHeight || height > maxHeight )
747  skipThisPoint = true;
748  else
749  Xdepth[j] = (flatEarth ?
750  depthProfile.Y(height)/cosTheta :
751  depthProfile.Y(distance));
752  }
753 
754  if (!skipThisPoint) {
755  fDepth.push_back(0.5*(Xdepth[0] + Xdepth[1]));
756  fTrackPositions.push_back(trackBin);
757  newLightFlux.PushBack(lightflux.GetX(i), lightflux.GetXErr(i),
758  lightflux.GetY(i), lightflux.GetYErr(i));
759  } else
760  ++nSkip;
761  }
762 
763  if (nSkip == nAperturePoints)
764  return false; // zero points left ...
765 
766  // refill light at diaphragm if there were points outside atmosphere
767  if (nSkip > 0) {
768  if (fVerbosity > -1)
769  cout << " CalculateGeometryAndDepth: " << nSkip
770  << " points outside atmosphere! -> "
771  << " refilling light at aperture" << endl;
772 
773  TabulatedFunctionErrors& flightflux =
775 
776  lightflux.Clear();
777  if (!fErrorCalcMode)
778  flightflux.Clear();
779  for (unsigned int i = 0; i < newLightFlux.GetNPoints(); ++i) {
780  const double x = newLightFlux.GetX(i);
781  const double ex = newLightFlux.GetXErr(i);
782  const double y = newLightFlux.GetY(i);
783  const double ey = newLightFlux.GetYErr(i);
784  lightflux.PushBack(x, ex, y, ey);
785  if (!fErrorCalcMode)
786  flightflux.PushBack(x, ex, y, ey);
787  }
788  }
789 
791 
792  return true;
793 }
794 
795 
796 /******************************************************************\
797  *
798  * adds points outside field of view (for Cherenkov beam)
799  *
800 \******************************************************************/
802 
803  const ReferenceEllipsoid& wgs84 = ReferenceEllipsoid::GetWGS84();
805  const double coreHeight = wgs84.PointToLatitudeLongitudeHeight(fCore).get<2>();
806  const double cosTheta = fAxis.GetCosTheta(coreCS);
807 
808  const bool flatEarth = (cosTheta>fInclinedModelMaxCosZenith);
809 
810  const Atmosphere& atmo = det::Detector::GetInstance().GetAtmosphere();
811  const ProfileResult& depthProfile = (flatEarth ?
812  atmo.EvaluateDepthVsHeight() :
814  const ProfileResult& distProfile = (flatEarth ?
815  atmo.EvaluateHeightVsDepth() :
817 
818  double minDepth = distProfile.MinX();
819  double maxDepth = distProfile.MaxX();
820 
821  const double dX = 25.*(g/cm2); // depth step size
822  const double xInit = 50.*(g/cm2); // start of shower
823 
824  double lastDepth = 0.;
825  if ( flatEarth ) {
826  const double lastHeight =
827  wgs84.PointToLatitudeLongitudeHeight(fTrackPositions[0][0]).get<2>();
828  lastDepth = depthProfile.Y(lastHeight)/cosTheta;
829  }
830  else {
831  const double lastDistance = (fTrackPositions[0][0]-fCore).GetMag()
832  * ((fCore-fTrackPositions[0][0])*fAxis>0 ? +1.0 : -1.0);
833  lastDepth = depthProfile.Y(lastDistance);
834  }
835 
836  vector<Point> trackBin(2);
837  unsigned int nAperturePoints = fTrackPositions.size();
838  fOutSideFOV=0;
839 
840  while ( fDepth[0] > xInit &&
841  fOutSideFOV < nAperturePoints ) { // do not add more points than seen
842 
843  trackBin[1]=fTrackPositions[0][0]; // end of this bin is start of previous bin
844  const double Xdepth=lastDepth-dX;
845 
846  if (!flatEarth) {
847 
848  if (Xdepth> minDepth && Xdepth<maxDepth) {
849  const double distance = distProfile.Y(Xdepth);
850  const Point pDistance(fCore - distance*fAxis); // by convention
851  trackBin[0] = pDistance;
852  fDepth.push_front(Xdepth+dX/2.);
853  fTrackPositions.push_front(trackBin);
854  lastDepth = Xdepth;
855  fOutSideFOV++;
856  }
857  else
858  break;
859 
860  }
861  else { // flat earth
862 
863  const double verticalDepth = Xdepth*cosTheta;
864  if (verticalDepth>minDepth &&
865  verticalDepth<maxDepth ) {
866  const double h = distProfile.Y(verticalDepth) - coreHeight;
867  const double l = h/cosTheta;
868  trackBin[0] = fCore + l*fAxis;
869  fDepth.push_front(Xdepth+dX/2.);
870  fTrackPositions.push_front(trackBin);
871  lastDepth = Xdepth;
872  fOutSideFOV++;
873  }
874  else
875  break;
876  }
877  }
878 
879  if(fVerbosity>-1)
880  cout << " added " << fOutSideFOV
881  << " points outside FoV" << endl;
882 
883 }
884 
885 /******************************************************************\
886  *
887  * create profile structures for current eye
888  *
889 \******************************************************************/
891 {
892  evt::ShowerFRecData& showerFRecData=eye.GetRecData().GetFRecShower();
893 
894  // set the cut off value in data structure
895  showerFRecData.SetEnergyCutoff(fEcut);
896 
897  // create longitudinal profile if necessary
898  if (!showerFRecData.HasLongitudinalProfile())
899  showerFRecData.MakeLongitudinalProfile();
900  showerFRecData.GetLongitudinalProfile().Clear();
901 
902  // create energy deposit profile if necessary
903  if (!showerFRecData.HasEnergyDeposit())
904  showerFRecData.MakeEnergyDeposit();
905  showerFRecData.GetEnergyDeposit().Clear();
906 
907  // create fluorescence photons at track if necessary
908  if (!showerFRecData.HasFluorescencePhotons())
909  showerFRecData.MakeFluorescencePhotons();
910  showerFRecData.GetFluorescencePhotons().Clear();
911 
912  // direct cherenkov light at aperture
916 
917  // Rayleigh scattered cherenkov light at aperture
921 
922  // Mie scattered cherenkov light at aperture
926 
927  // direct and multiple scattered fluorescence light at aperture
931 
935 
936  // multiple scattered cherenkov light at aperture
940 
941 }
942 
943 /******************************************************************\
944  *
945  * get current guess of shower maximum
946  *
947 \******************************************************************/
949  const fevt::Eye& eye)
950 {
951  double xMax=700.*(g/cm/cm);
952 
953  // first try Gaisser Hillas parameters of event ...
955  && event.HasRecShower()&& event.GetRecShower().HasFRecShower()
956  && event.GetRecShower().GetFRecShower().HasGHParameters()) {
957  xMax=event.GetRecShower().GetFRecShower().GetGHParameters().GetXMax();
958  }
959  // ... then Gaisser Hillas parameters of eye ...
961  && eye.GetRecData().HasFRecShower()
963  xMax=eye.GetRecData().GetFRecShower().GetGHParameters().GetXMax();
964  }
965 
966  // ... otherwise use depth where light at aperture is maximum
967  else {
968  int iMax=-1;
969  double lightMax=0.;
971  for (unsigned int i=0; i<lightflux.GetNPoints() ; i++) {
972  double flux=lightflux.GetY(i)/lightflux.GetXErr(i);
973  if(flux>lightMax) {
974  lightMax=flux;
975  iMax=i;
976  }
977  }
978  if(iMax>=0)
979  xMax=fDepth[iMax+fOutSideFOV];
980 
981  // limit this first guess to reasonable values
982  const double kxMaxMin= 400.*(g/cm/cm);
983  const double kxMaxMax= 1100.*(g/cm/cm);
984  if (xMax<kxMaxMin)
985  xMax=kxMaxMin;
986  else if (xMax>kxMaxMax)
987  xMax=kxMaxMax;
988  }
989  return xMax;
990 }
991 
992 /******************************************************************\
993  *
994  * calculation of total errors on energy, Xmax etc.
995  *
996 \******************************************************************/
998 {
999 
1000  ShowerFRecData& recShower=eye.GetRecData().GetFRecShower();
1001 
1002  // propagate atmopsheric and geometric uncertainties if required
1005 
1006  // calculate statistical invisible energy uncertainty
1007 
1008  const double calEnergy = recShower.GetEmEnergy();
1009  const double calEnergy2 = pow(calEnergy, 2);
1010 
1011  double scaleFac=1.;
1012  if(fRescaleErrors) {
1013  double chisq = recShower.GetGHParameters().GetChiSquare();
1014  double ndof = recShower.GetGHParameters().GetNdof();
1015  scaleFac = sqrt(chisq/ndof);
1016  }
1017  const double calEnergyErr =
1018  recShower.GetEmEnergyError(ShowerFRecData::eStatistical) * scaleFac;
1019  const double calEnergyStatVar = calEnergyErr * calEnergyErr;
1020 
1021  double calEnergyGeomVar=0.;
1023  if (fGeomVariance.size()==eNFitParameters)
1024  calEnergyGeomVar = fGeomVariance[eEem];
1025  else
1026  calEnergyGeomVar = calEnergy2; // refitting failed --> set error to 100%
1027  }
1028 
1029 
1030  double calEnergyAtmVar=0.;
1032  if (fAtmVariance.size()==eNFitParameters)
1033  calEnergyAtmVar = fAtmVariance[eEem];
1034  else
1035  calEnergyAtmVar = calEnergy2; // refitting failed --> set error to 100%
1036  }
1037 
1039  // ICRC 2013
1040  /*
1041  const double additionalAtmVar =
1042  calEnergy2 * (pow(gHorizontalUniformityError, 2) +
1043  pow(gAtmVariability, 2) +
1044  pow(gNightlyRelativeCalibration, 2)
1045  );
1046  */
1047  // ICRC 2019
1048  const double dEr = gHorizontalUniformityError_par[0];
1049  const double logE = log10(calEnergy);
1050  const double logEs = gHorizontalUniformityError_par[1];
1051  const double fp0 = gHorizontalUniformityError_par[2];
1052  const double fp1 = gHorizontalUniformityError_par[3];
1053  const double fp2 = gHorizontalUniformityError_par[4];
1054  const double fE = max(fp0+fp1*(logE -18.)+fp2*(logE -18.)*(logE -18.),0.);
1055  const double fEs = fp0+fp1*(logEs-18.)+fp2*(logEs-18.)*(logEs-18.);
1056  const double gHorizontalUniformityError_E = dEr*fE/fEs;
1057 
1058  const double additionalAtmVar =
1059  calEnergy2 * (pow(gHorizontalUniformityError_E, 2) +
1060  pow(gAtmVariability, 2) +
1062  pow(gEnergyTimeDrif, 2) +
1063  pow(gEnergyEyeTel, 2)
1064  );
1065 
1066  calEnergyAtmVar += additionalAtmVar;
1067 
1068  // ICRC 2019
1069  const double calorEnergyConexMissingVar =
1070  calEnergy2 * pow(gEnergyResolutionConexMissingFactor,2);
1071 
1072 
1073  // invibisible energy factors
1074 
1075 //added by Matias Tueros
1076  utl::Vector fAxis=recShower.GetAxis();
1077 
1078  utl::Point fCore = recShower.GetCorePosition();
1079 
1081 
1082  double cosZenithAngle = fAxis.GetCosTheta(coreCS);
1083 
1084 //end addition
1085 
1086  const double invEnergyFac =
1087  utl::InvisibleEnergy::Factor(calEnergy,
1089  fComposition, cosZenithAngle);
1090  const double invEnergyFacDeriv =
1093  fComposition, cosZenithAngle);
1094  // total energy
1095  double totEnergy = invEnergyFac * calEnergy;
1096 
1097  // ICRC 2013
1098  // shower to shower fluctuations of invisible energy
1099  //const double invEVar = utl::InvisibleEnergy::FactorVariance(totEnergy);
1100 
1101  // ICRC 2019
1102  const double invEVar = utl::InvisibleEnergy::FactorVariance(calEnergy,totEnergy);
1103 
1104  // geometry and statistical error of CalEnergy
1105  const double deriv = invEnergyFacDeriv * calEnergy + invEnergyFac;
1106  const double deriv2 = deriv * deriv;
1107  const double statVar = deriv2 * calEnergyStatVar;
1108  const double geomVar = deriv2 * calEnergyGeomVar;
1109  const double atmVar = deriv2 * calEnergyAtmVar;
1110  // ICRC 2013
1111  //const double totEnergyStatErr = sqrt(invEVar + geomVar + statVar);
1112  // ICRC 2019
1113  const double ResolutionConexMissingFactorVar = deriv2 * calorEnergyConexMissingVar;
1114  const double totEnergyStatErr = sqrt(invEVar + geomVar + statVar + ResolutionConexMissingFactorVar);
1115 
1116  // store total errors
1117  // ICRC 2013
1118  //recShower.SetEmEnergy(calEnergy, sqrt(calEnergyGeomVar+calEnergyStatVar),
1119  // ShowerFRecData::eStatistical);
1120  // ICRC 2019
1121  recShower.SetEmEnergy(calEnergy, sqrt(calEnergyGeomVar+calEnergyStatVar+calorEnergyConexMissingVar),
1122  ShowerFRecData::eStatistical);
1123  recShower.SetEmEnergyError(sqrt(calEnergyAtmVar), ShowerFRecData::eAtmospheric);
1124  recShower.SetTotalEnergy(totEnergy, totEnergyStatErr,ShowerFRecData::eStatistical);
1125  recShower.SetTotalEnergyError(sqrt(atmVar),ShowerFRecData::eAtmospheric);
1126 
1127  GaisserHillas4Parameter* const gh4 =
1128  dynamic_cast<GaisserHillas4Parameter*>(&recShower.GetGHParameters());
1129 
1130  // this should never, never happen ...
1131  if (!gh4) {
1132  ERROR("No 4par GH structure????");
1133  throw MissingEventDataException();
1134  }
1135 
1136  const double dEdXmax = gh4->GetNMax();
1137  const double dEdXmax_err = scaleFac * gh4->GetNMaxError();
1138  const double xmax = gh4->GetXMax();
1139  const double xmax_err = scaleFac * gh4->GetXMaxError();
1140  const double x0 = gh4->GetShapeParameter(gh::eX0);
1141  const double x0_err = scaleFac * gh4->GetShapeParameterError(gh::eX0);
1142  const double lambda = gh4->GetShapeParameter(gh::eLambda);
1143  const double lambda_err = scaleFac * gh4->GetShapeParameterError(gh::eLambda);
1144 
1145  // store total GH parameter errors
1147  double x0_tot_err, xmax_tot_err, nmax_tot_err, lambda_tot_err;
1148 
1149  if (fGeomVariance.size() == eNFitParameters) {
1150  x0_tot_err = sqrt(x0_err * x0_err + fGeomVariance[eX0]);
1151  xmax_tot_err = sqrt(xmax_err * xmax_err + fGeomVariance[eXmax]);
1152  nmax_tot_err = sqrt(dEdXmax_err * dEdXmax_err + fGeomVariance[edEdXmax]);
1153  lambda_tot_err= sqrt(lambda_err * lambda_err + fGeomVariance[eLambda]);
1154  recShower.SetXmaxError(sqrt(fAtmVariance[eXmax]), ShowerFRecData::eAtmospheric);
1155  recShower.SetXmaxError(xmax_err, ShowerFRecData::eStatistical);
1156  } else {
1157  x0_tot_err = x0;
1158  xmax_tot_err = xmax;
1159  nmax_tot_err = dEdXmax;
1160  lambda_tot_err = lambda;
1161  recShower.SetXmaxError(xmax, ShowerFRecData::eStatistical);
1162  }
1163 
1164  gh4->SetXMax(xmax, xmax_tot_err);
1165  gh4->SetNMax(dEdXmax, nmax_tot_err, true);
1166  gh4->SetShapeParameter(gh::eX0, x0, x0_tot_err);
1167  gh4->SetShapeParameter(gh::eLambda, lambda, lambda_tot_err);
1168  } else {
1169  gh4->SetXMax(xmax, xmax_err);
1170  gh4->SetNMax(dEdXmax, dEdXmax_err, true);
1171  gh4->SetShapeParameter(gh::eX0, x0, x0_err);
1172  gh4->SetShapeParameter(gh::eLambda, lambda ,lambda_err);
1173  }
1174 
1175  // do some printout ...
1176  if (fVerbosity > -1) {
1177  cout << "\n E [EeV] = " << totEnergy/EeV
1178  << " +/- " << sqrt(statVar)/EeV << " (stat.) "
1179  << " +/- " << sqrt(geomVar)/EeV << " (geom.) "
1180  << " +/- " << sqrt(invEVar)/EeV << " (inv.) "
1181  << " +/- " << sqrt(atmVar)/EeV << " (atm.) "
1182  << endl;
1183  cout << " Xmax [g/cm^2] = " << xmax/(g/cm/cm)
1184  << " +/- " << xmax_err/(g/cm/cm) << " (stat.) ";
1185  if (fGeomVariance.size() == eNFitParameters)
1186  cout << " +/- " << sqrt(fGeomVariance[eXmax])/(g/cm2) << " (geom.) "
1187  << " +/- " << sqrt(fAtmVariance[eXmax])/(g/cm2) << " (atm.) ";
1188  cout << endl;
1189  }
1190 }
1191 
1192 
1193 /******************************************************************\
1194  *
1195  * brute force propagation of axis fit, SDP and atmospheric
1196  * uncertainties
1197  *
1198  * (well, actually not so brute if fmaxErrPropPoints is
1199  * set properly ...)
1200  *
1201 \******************************************************************/
1203 {
1204 
1205  // flag that we are now in error mode
1206  fErrorCalcMode=true;
1207 
1208  fevt::EyeRecData& eyeRecData = eye.GetRecData();
1209 
1210  // use current Xmax for ChFl-Matrix
1211  fXmax = eyeRecData.GetFRecShower().GetGHParameters().GetXMax();
1212 
1213  // set verbosity for err prop.
1214  int v1Orig=fVerbosity, v2Orig=fEnergyFitter->GetVerbosity();
1217 
1218  // calculate undisturbed, but rebinned result
1219 
1220  std::vector<std::vector<double> > fitResults;
1221 
1222  const bool haveDefault = ReFitProfile(eye, 0., 0., 0., 0., 0., fitResults);
1223 
1224  if ( haveDefault && fPropagateGeometryErrors ) {
1225 
1226  const unsigned int kNGeomVars = 5;
1227 
1228  if(fErrPropVerb>-1)
1229  cout << "\n propagating geometry uncertainties ";
1230  if(fErrPropVerb>0)
1231  cout << "...\n" << endl;
1232 
1233  while ( true ) {
1234 
1235  // a) Rp
1236 
1237  if(!ReFitProfile(eye, 1., 0., 0., 0., 0., fitResults)) break;
1238  if(!ReFitProfile(eye,-1., 0., 0., 0., 0., fitResults)) break;
1239 
1240  // b) Chi0
1241 
1242  if(!ReFitProfile(eye, 0., 1., 0., 0., 0., fitResults)) break;
1243  if(!ReFitProfile(eye, 0.,-1., 0., 0., 0., fitResults)) break;
1244 
1245  // c) T0
1246 
1247  if(!ReFitProfile(eye, 0., 0., 1., 0., 0., fitResults)) break;
1248  if(!ReFitProfile(eye, 0., 0.,-1., 0., 0., fitResults)) break;
1249 
1250  // d) SDP phi
1251 
1252  if(!ReFitProfile(eye, 0., 0., 0., 1., 0., fitResults)) break;
1253  if(!ReFitProfile(eye, 0., 0., 0.,-1., 0., fitResults)) break;
1254 
1255  // e) SDP theta
1256 
1257  if(!ReFitProfile(eye, 0., 0., 0., 0., 1., fitResults)) break;
1258  if(!ReFitProfile(eye, 0., 0., 0., 0.,-1., fitResults)) break;
1259 
1260  break;
1261 
1262  }
1263 
1264 
1265  const bool geomSuccess = ( fitResults.size() == (kNGeomVars*2 +1) );
1266 
1267  if(fErrPropVerb==0) cout << endl;
1268 
1269 
1270  if ( geomSuccess ) {
1271 
1272  // rescale errors if required
1273  //
1274  // on average, the axis chi2/ndf is much larger than 1
1275  // or in other word the centroid errors are presumably
1276  // underestimated by a factor of sqrt(chi2/ndf)
1277  // (see for instance introduction in PDG long writeup)
1278  // This propagates directly to RpErr etc. and correspondingly
1279  // to energy, Xmax errors
1280  //
1281  double scaleFac=1.;
1282  if(fRescaleErrors>0) {
1283  double chi2 = eyeRecData.GetTimeFitChiSquare();
1284  double ndf = eyeRecData.GetTimeFitNDof();
1285  if(ndf>0)
1286  scaleFac=chi2/ndf;
1287  }
1288 
1289  // correlation coefficients
1290  const double rhoRT = eyeRecData.GetRpTZeroCorrelation();
1291  const double rhoRC = eyeRecData.GetRpChi0Correlation();
1292  const double rhoCT = eyeRecData.GetChi0TZeroCorrelation();
1293  const double rhoPT = eyeRecData.GetSDPCorrThetaPhi();
1294 
1295  for ( unsigned int i=0; i<eNFitParameters; i++ ) {
1296  double x0,x1,x2;
1297 
1298  x0=fitResults[0][i];
1299 
1300  double err[kNGeomVars]; // Rp,Chi0,T0,Phi and Theta errors
1301 
1302  for ( unsigned int j=0;j<kNGeomVars;j++) {
1303  x1=fitResults[2*j+1][i]; x2=fitResults[2*j+2][i];
1304 
1305  double e1=(x1-x0);
1306  double e2=(x0-x2);
1307  err[j]=0.5*(e1+e2);
1308  }
1309 
1310  // time fit variance
1311  fGeomVariance.push_back(err[0]*err[0] + err[1]*err[1] + err[2]*err[2]
1312  + 2. * err[0] * err[2] * rhoRT
1313  + 2. * err[0] * err[1] * rhoRC
1314  + 2. * err[1] * err[2] * rhoCT);
1315 
1316  fGeomVariance[i]*=scaleFac;
1317 
1318  // add SDP fit variance
1319  fGeomVariance[i]+= err[3]*err[3] + err[4]*err[4]
1320  + 2. * err[3] * err[4] * rhoPT;
1321 
1322  }
1323  }
1324  }
1325 
1326  if ( haveDefault && fPropagateAtmUncertainties ) {
1327 
1328  if(fErrPropVerb>-1) cout << " propagating atmospheric uncertainties ";
1329  if(fErrPropVerb>0) cout << "...\n" << endl;
1330 
1331  const unsigned int kNAtmVars = 1;
1332 
1333  fitResults.resize(1);
1334 
1335  const Atmosphere& atmo = det::Detector::GetInstance().GetAtmosphere();
1336 
1337  // change VAODs
1338  atmo.SetUncertaintyBound(Atmosphere::eMie,1.);
1339  if ( ReFitProfile(eye, 0., 0., 0., 0., 0., fitResults) ) {
1340  atmo.SetUncertaintyBound(Atmosphere::eMie,-1.);
1341  ReFitProfile(eye, 0., 0., 0., 0., 0., fitResults);
1342  }
1343 
1344 
1345  // reset original atmosphere
1346  atmo.SetUncertaintyBound(Atmosphere::eMie,0.);
1347 
1348  const bool atmSuccess = ( fitResults.size() == (kNAtmVars*2 +1) );
1349 
1350  if ( atmSuccess ) {
1351 
1352  for ( unsigned int i=0; i<eNFitParameters; i++ ) {
1353  double x0,x1,x2;
1354  x0=fitResults[0][i];
1355 
1356  double v=0.;
1357  for ( unsigned int j=0;j<kNAtmVars;j++) {
1358  x1=fitResults[2*j+1][i]; x2=fitResults[2*j+2][i];
1359  const double e1=(x1-x0);
1360  const double e2=(x0-x2);
1361  const double err=0.5*(e1+e2);
1362  v+=(err*err);
1363  }
1364 
1365  fAtmVariance.push_back(v);
1366 
1367  }
1368  }
1369  }
1370 
1371  if(fErrPropVerb==0) cout << endl;
1372 
1373  // restore verbosities
1374  fVerbosity=v1Orig;
1375  fEnergyFitter->SetVerbosity(v2Orig);
1376 
1377  return true;
1378 
1379 }
1380 
1381 /*********************************************************************\
1382  *
1383  * steering routine for profile refit
1384  *
1385 \*********************************************************************/
1387  double nSigRp,
1388  double nSigChi0,
1389  double nSigT0,
1390  double nSigPhi,
1391  double nSigTheta,
1392  std::vector<std::vector<double> >& fitResults)
1393 {
1394  DeleteCFMatrix();
1395 
1396  if(fErrPropVerb == 0 && !fitResults.empty())
1397  cout << "." << std::flush;
1398 
1399  // save a copy of the original lightflux and dEdX as
1400  // they might be combined or modified
1401 
1402  fevt::EyeRecData& eyeRecData = eye.GetRecData();
1403  TabulatedFunctionErrors& lightFlux =
1405  ShowerFRecData& recShower=eye.GetRecData().GetFRecShower();
1406  TabulatedFunctionErrors& dedxProf=recShower.GetEnergyDeposit();
1407 
1408  std::vector<double> x,y,ex,ey;
1409  std::vector<double> dEx,dEy,dEex,dEey;
1410  for (unsigned int i = 0; i < lightFlux.GetNPoints(); i++) {
1411  x.push_back(lightFlux.GetX(i));
1412  y.push_back(lightFlux.GetY(i));
1413  ex.push_back(lightFlux.GetXErr(i));
1414  ey.push_back(lightFlux.GetYErr(i));
1415  dEx.push_back(dedxProf.GetX(i));
1416  dEy.push_back(dedxProf.GetY(i));
1417  dEex.push_back(dedxProf.GetXErr(i));
1418  dEey.push_back(dedxProf.GetYErr(i));
1419  }
1420 
1421  // combine data points to speed up re-fits
1422  if( (int) x.size() > fmaxErrPropPoints ) {
1423 
1424  lightFlux.Clear();
1425 
1426  const double nCombi=(double) x.size()/ (double) fmaxErrPropPoints;
1427  double combined=0.;
1428  double t1=x[0]-ex[0];
1429  double sum=0.;
1430  double sum2=0.;
1431 
1432  for (unsigned int i=0;i<x.size();i++) {
1433  combined+=1.;
1434  sum += y[i];
1435  sum2+= ey[i]*ey[i];
1436 
1437  if(t1==0.) t1=x[i]-ex[i];
1438 
1439  // check for time discontinuity (mirror crossing)
1440  bool timeGap=false;
1441  if ( i<x.size()-1 && x[i]+ex[i] != x[i+1]-ex[i+1] )
1442  timeGap = true;
1443 
1444  if(combined>=nCombi||i==x.size()-1||timeGap) {
1445  double dt = x[i]-t1+ex[i];
1446  lightFlux.PushBack (t1+dt/2.,dt/2.,sum,sqrt(sum2));
1447  sum=0.; sum2=0.; t1=0.; combined=0.;
1448  }
1449  }
1450  }
1451 
1452  // start refit
1453  SetGeometry(eye,nSigRp,nSigChi0, nSigT0, nSigPhi, nSigTheta);
1454  bool success=false;
1455  dedxProf.Clear();
1456 
1457  if(CalculateGeometryAndDepth(eye)) {
1458  if(CalculateProfiles(eye)) {
1459  if(fEnergyFitter->ReFitProfile(eye, fChFlPtr)) {
1460 
1461  std::vector<double> result(eNFitParameters);
1462  result[eX0]=fEnergyFitter->GetX0();
1463  result[eXmax]=fEnergyFitter->GetXmax();
1464  result[edEdXmax]=fEnergyFitter->GetdEdXmax();
1465  result[eLambda]=fEnergyFitter->GetLambda();
1466  result[eEem]=fEnergyFitter->GetEmEnergy();
1467  fitResults.push_back(result);
1468 
1469  success=true;
1470 
1471  }
1472  }
1473  }
1474 
1475  // refill original profiles
1476  lightFlux.Clear();
1477  dedxProf.Clear();
1478  for ( unsigned int i=0;i<x.size(); i++ ) {
1479  lightFlux.PushBack(x[i],ex[i],y[i],ey[i]);
1480  dedxProf.PushBack(dEx[i],dEex[i],dEy[i],dEey[i]);
1481  }
1482  return success;
1483 
1484 }
1485 
1486 /******************************************************************\
1487  *
1488  * sets geometry data members altering Rp, Chi0 and/or T0
1489  * by nSig of their statistical errors
1490  *
1491 \******************************************************************/
1493  double nSigRp,
1494  double nSigChi0,
1495  double nSigT0,
1496  double nSigPhi,
1497  double nSigTheta)
1498  {
1499 
1500  fevt::EyeRecData& eyeRecData = eye.GetRecData();
1501  fT0 = eyeRecData.GetTZero()+nSigT0*eyeRecData.GetTZeroError();
1502  fChi0 = eyeRecData.GetChiZero()+nSigChi0*eyeRecData.GetChiZeroError();
1503  fRp = eyeRecData.GetRp()+nSigRp*eyeRecData.GetRpError();
1504 
1505  const fdet::Eye& detEye = det::Detector::GetInstance().GetFDetector().GetEye(eye);
1507  const Point& eyepos = detEye.GetPosition();
1508 
1509 
1510 
1511  const double sdpTheta = eyeRecData.GetSDP().GetTheta (eyeCS)+
1512  nSigTheta*eyeRecData.GetSDPThetaError();
1513  const double sdpPhi = eyeRecData.GetSDP().GetPhi (eyeCS)+
1514  nSigPhi*eyeRecData.GetSDPPhiError();
1515  Vector sdp = Vector(1,sdpTheta,sdpPhi,eyeCS, Vector::kSpherical);
1516 
1517  Vector vertical(0,0,1,eyeCS);
1518  Vector horizontalInSDP = cross(sdp,vertical); // horizontal
1519  horizontalInSDP.Normalize();
1520 
1521  // if ( horizontalInSDP.GetPhi(eyeCS) < 0 ||
1522  // horizontalInSDP.GetPhi(eyeCS) > kPi) {
1523  // if(fVerbosity>-1)
1524  // cout << " swapping horizontal ... " << endl;
1525  // horizontalInSDP *= -1;
1526  //}
1527 
1528  Transformation rot (Transformation::Rotation(-fChi0,sdp, eyeCS));
1529  Vector axis (rot* horizontalInSDP); // apply rotation
1530  axis.Normalize();
1531  fAxis = axis;
1532 
1533  const double core_distance = fRp / sin( kPi - fChi0);
1534  const Vector coreEyeVec = core_distance * horizontalInSDP;
1535  fCore = eyepos + coreEyeVec;
1536 
1537 }
1538 
1539 
1541 
1542  std::map<int, CherenkovFluorescenceMatrix *>::iterator iter;
1543  for (iter=fChFlPtrMap.begin(); iter!=fChFlPtrMap.end(); ++iter)
1544  delete iter->second;
1545  fChFlPtrMap.clear();
1546  fChFlPtr = NULL;
1547 
1548 }
1549 
1551 
1552  fYieldRefit=what;
1553 
1554  if ( fEnergyFitter != NULL )
1556  else
1557  std::cerr << " FdProfileReconstructor::SetYieldRefit() "
1558  << " - EnergyFitter can not be set! " << std::endl;
1559 
1560 
1561 }
1562 
1563 
1564 /******************************************************************\
1565  *
1566  * Sets the energy fitter verbosity during run-time.
1567  *
1568 \******************************************************************/
1569 
1571  if (fEnergyFitter != NULL)
1572  fEnergyFitter->SetVerbosity(verbosity);
1573 }
1574 
1575 
1576 /******************************************************************\
1577  *
1578  * Gets the energy fitter verbosity during run-time.
1579  *
1580 \******************************************************************/
1581 
1583  if (fEnergyFitter != NULL)
1584  return fEnergyFitter->GetVerbosity();
1585  else {
1586  std::cerr << " FdProfileReconstructor::GetEnergyFitterVerbosity() "
1587  << " - EnergyFitter not initialized! " << std::endl;
1588  return 0;
1589  }
1590 }
1591 
1592 /******************************************************************\
1593  *
1594  * Initializes slant atmosphere (flatEarth=false)
1595  *
1596 \******************************************************************/
1597 
1598 bool
1600  double& minDistance,
1601  double& maxDistance)
1602 {
1603  const Atmosphere& atmo = det::Detector::GetInstance().GetAtmosphere();
1604 
1605  if (flatEarth) {
1606 
1607  const atm::ProfileResult& depthProfile = atmo.EvaluateDepthVsHeight();
1608 
1610  const double cosTheta = fAxis.GetCosTheta(coreCS);
1611 
1612  const double maxHeight = depthProfile.MaxX();
1613  const double minHeight = depthProfile.MinX();
1614  const ReferenceEllipsoid& wgs84 = ReferenceEllipsoid::GetWGS84();
1615  const double coreHeight =
1616  wgs84.PointToLatitudeLongitudeHeight(fCore).get<2>();
1617  minDistance = (coreHeight-maxHeight)/cosTheta + 1*mm;
1618  maxDistance = (coreHeight-minHeight)/cosTheta - 1*mm;
1619 
1620  } else {
1621 
1622  try {
1623  if (fErrorCalcMode) {
1624  // less precision for error propagation, see GAP-2007-007, Fig. 5
1625  atmo.InitSlantProfileModel(fCore, fAxis, 100.*g/cm2);
1626  } else {
1627  if (!fYieldRefit || fIsMultiEyeEvent)
1629  }
1631  if (fVerbosity > -1) {
1632  cout << " CalculateGeometryAndDepth - "
1633  "error initializing InclinedAtmosphericProfile " << endl;
1634  }
1635  return false;
1636  }
1637 
1638  const atm::ProfileResult slantDepthProfile = atmo.EvaluateSlantDepthVsDistance();
1639  minDistance = slantDepthProfile.MinX() + 1*mm;
1640  maxDistance = slantDepthProfile.MaxX() - 1*mm;
1641 
1642  }
1643 
1644  return true;
1645 }
AxialVector cross(const Vector &l, const Vector &r)
vector cross product
Definition: OperationsAV.h:32
CherenkovFluorescenceMatrix::eDirectCherenkovLDF fDirCherLDF
double GetShapeParameter(const gh::EShapeParameter par) const
access to all variants of shape parameters (see GaisserHillasTypes.h)
unsigned int GetId() const
Definition: FEvent/Eye.h:54
double Factor(const double energyEM, const EInteractionModel intMod, const ECompositionModel compMod, const double cosTheta)
invisible energy factor, finv=Etot/Eem, given Eem. CosTheta only needed when using data driven estima...
const oBLAS::lowerTriangularMatrix * GetMieScatteredCherenkovMatrix() const
returns Mie scattered Cherenkov light matrix
void Write(const evt::Event &event, const fevt::Eye &eye, CherenkovFluorescenceMatrix chfl)
unsigned int GetNPoints() const
Top of the interface to Atmosphere information.
double GetChi0TZeroCorrelation() const
Definition: EyeRecData.h:88
bool HasLightFlux(const FdConstants::LightSource source=FdConstants::eTotal) const
Check that light profile for source /par source is present.
Definition: EyeRecData.h:297
constexpr double mm
Definition: AugerUnits.h:113
void Normalize()
Definition: Vector.h:64
const double degree
Point object.
Definition: Point.h:32
const oBLAS::diagonalMatrix * GetDirectCherenkovMatrix() const
returns direct Cherenkov light matrix
double GetRpError() const
Definition: EyeRecData.h:91
double GetPhi(const CoordinateSystemPtr &coordinateSystem) const
azimuth (phi) angle in spherical and cylindrical coordinates
Definition: BasicVector.h:254
void InitSlantProfileModel(const utl::Point &core, const utl::Vector &dir, const double deltaX) const
Report success to RunController.
Definition: VModule.h:62
bool HasRecData() const
Definition: FEvent/Eye.h:116
Fluorescence Detector Eye Event.
Definition: FEvent/Eye.h:29
bool HasFluorescencePhotons() const
void SetEmEnergyError(const double energyError, const EUncertaintyType type)
bool HasRecShower() const
bool HasFEvent() const
unsigned int GetNEyes() const
Definition: FEvent.h:74
double GetTheta(const CoordinateSystemPtr &coordinateSystem) const
zenith (theta) angle in spherical coordinates
Definition: BasicVector.h:248
double GetChiZero() const
Definition: EyeRecData.h:85
utl::InvisibleEnergy::ECompositionModel fComposition
double FactorDerivative(const double energyEM, const EInteractionModel intMod, const ECompositionModel compMod, const double cosTheta)
derivative of invisible energy factor dfinv/dEem given Eem. CosTheta only needed when using data driv...
Skip remaining modules in the current loop and continue with next iteration of the loop...
Definition: VModule.h:68
bool ReFitProfile(fevt::Eye &eye, double nSigRp, double nSigChi0, double nSigT0, double nSigPhi, double nSigTheta, std::vector< std::vector< double > > &results)
double GetCosTheta(const CoordinateSystemPtr &coordinateSystem) const
cos of zenith (theta) angle
Definition: BasicVector.h:251
const oBLAS::lowerTriangularMatrix * GetRayleighScatteredCherenkovMatrix() const
returns Rayleigh scattered Cherenkov light matrix
bool is(const double a, const double b)
Definition: testlib.cc:113
bool HasSimShower() const
static double gEnergyResolutionConexMissingFactor
EyeIterator EyesEnd(const ComponentSelector::Status status)
Definition: FEvent.h:66
unsigned int GetTimeFitNDof() const
Definition: EyeRecData.h:93
const atm::ProfileResult & EvaluateDistanceVsSlantDepth() const
Table of distance as a function of slant depth.
double GetRpTZeroCorrelation() const
Definition: EyeRecData.h:90
void SetXMax(const double xMax, const double error)
#define INFO(message)
Macro for logging informational messages.
Definition: ErrorLogger.h:161
void SetTotalEnergyError(const double energyError, const EUncertaintyType type)
bool InitializeAtmosphere(const bool flatEarth, double &minDist, double &maxDist)
void SetShapeParameter(const gh::EShapeParameter par, const double value, const double error)
Setters.
Base class for exceptions trying to access non-existing components.
const Eye & GetEye(const unsigned int eyeId) const
Find eye by numerical Id.
Definition: FDetector.cc:68
Detector description interface for Eye-related data.
Definition: FDetector/Eye.h:45
boost::filter_iterator< ComponentSelector, AllEyeIterator > EyeIterator
selective Eye iterators
Definition: FEvent.h:55
Branch GetChild(const std::string &childName) const
Get child of this Branch by child name.
Definition: Branch.cc:211
double pow(const double x, const unsigned int i)
static double gEnergyEyeTel
std::deque< std::vector< utl::Point > > fTrackPositions
const double EeV
Definition: GalacticUnits.h:34
double GetMag() const
Definition: Vector.h:58
const lowerTriangularMatrix * GetInverse() const
double GetSDPPhiError() const
Definition: EyeRecData.h:78
double GetTZeroError() const
Definition: EyeRecData.h:84
void SetGeometry(fevt::Eye &eye, double nSigRp, double nSigChi0, double nSigT0, double nSigPhi, double nSigTheta)
double GetChiZeroError() const
Definition: EyeRecData.h:86
double Y(const double x) const
Get the Y value (coordinate) for given X (ordinate)
double GetZeta() const
Definition: EyeRecData.h:76
constexpr double MeV
Definition: AugerUnits.h:184
const atm::Atmosphere & GetAtmosphere() const
Definition: Detector.h:113
fwk::VModule::ResultFlag Run(evt::Event &event)
Run: invoked once per event.
boost::shared_ptr< const CoordinateTransformer > CoordinateSystemPtr
Shared pointer for coordinate systems.
#define max(a, b)
Class representing a document branch.
Definition: Branch.h:107
const double & GetYErr(const unsigned int idx) const
constexpr double s
Definition: AugerUnits.h:163
Reference ellipsoids for UTM transformations.
bool HasLongitudinalProfile() const
const double ns
utl::CoordinateSystemPtr GetEyeCoordinateSystem() const
Returns the Eye Coordinate system.
Class describing the Atmospheric profile.
Definition: ProfileResult.h:25
constexpr double kPi
Definition: MathConstants.h:24
const Data result[]
Active transformations of geometrical objects.
Top of the hierarchy of the detector description interface.
Definition: Detector.h:81
bool HasFRecShower() const
Check if reconstructed shower info has been allocated.
Definition: EyeRecData.h:330
evt::ShowerFRecData & GetFRecShower()
Reconstructed shower info for this eye.
Definition: EyeRecData.h:323
EyeIterator EyesBegin(const ComponentSelector::Status status)
Definition: FEvent.h:58
Triple PointToLatitudeLongitudeHeight(const Point &thePoint) const
Convert Point to Lat/Long/Height.
const atm::ProfileResult & EvaluateDepthVsHeight() const
Tabulated function giving Y=depth as a function of X=height.
const fdet::FDetector & GetFDetector() const
Definition: Detector.cc:131
double GetSDPCorrThetaPhi() const
Definition: EyeRecData.h:79
constexpr double g
Definition: AugerUnits.h:200
bool GetShowerFRecData(evt::Event &event, fevt::Eye &eye)
void PushBack(const double x, const double xErr, const double y, const double yErr)
#define WARNING(message)
Macro for logging warning messages.
Definition: ErrorLogger.h:163
double GetEmEnergy() const
retrieve electromagnetic energy and its uncertainty
void GetData(bool &b) const
Overloads of the GetData member template function.
Definition: Branch.cc:644
Top of Fluorescence Detector event hierarchy.
Definition: FEvent.h:33
void SetEmEnergy(const double energy, const double energyError, const EUncertaintyType type=eTotal)
const double & GetXErr(const unsigned int idx) const
const oBLAS::lowerTriangularMatrix * GetCherenkovFluorescenceMatrix() const
returns total light matrix (not const as we eventually want to invert it ...)
Eye-specific shower reconstruction data.
Definition: EyeRecData.h:65
fwk::VModule::ResultFlag Init()
Initialize: invoked at beginning of run (NOT beginning of event)
static double gAtmVariability
double GetEmEnergyError(const EUncertaintyType type=eTotal) const
const double & GetY(const unsigned int idx) const
void SetNMax(const double nMax, const double error, const bool isEnergyDeposit=false)
fwk::VModule::ResultFlag Finish()
Finish: invoked at end of the run (NOT end of the event)
const utl::AxialVector & GetSDP() const
Definition: EyeRecData.h:75
double GetTimeFitChiSquare() const
Definition: EyeRecData.h:92
void SetYieldRefit(const bool what)
Definition: EnergyFitter.h:43
void SetYieldFactors(const double fluoFac, const double chkovFac)
set yield factors
double GetRpChi0Correlation() const
Definition: EyeRecData.h:89
bool HasGHParameters() const
Base class for exceptions arising because required info not present in the Event. ...
constexpr double kSpeedOfLight
double MinX() const
Return the minimum value for X (ordinate) stored in the profile.
ResultFlag
Flag returned by module methods to the RunController.
Definition: VModule.h:60
void SetEnergyCutoff(const double energy)
double GuessShowerMaximum(evt::Event &event, const fevt::Eye &eye)
utl::TabulatedFunctionErrors & GetLongitudinalProfile()
retrieve longitudinal profile information (size vs depth)
bool Run(fevt::Eye &eye, CherenkovFluorescenceMatrix *const chfl)
utl::TabulatedFunctionErrors & GetFluorescencePhotons()
retrieve number of fluorescence photons versus depth
double GetRp() const
Definition: EyeRecData.h:87
CherenkovFluorescenceMatrix::eMultipleScatteringLDF fMultScatLDF
void SetXmaxError(const double xmaxError, const EUncertaintyType type)
constexpr double cm
Definition: AugerUnits.h:117
Calculation of Cherenkov and Fluorescence matrix.
double EnergyDeposit(const double age, const double enCut)
Parametrization for the average energy deposit per particle.
execption handling for calculation/access for inclined atmosphere model
Vector object.
Definition: Vector.h:30
const double & GetX(const unsigned int idx) const
Interface class to access to Fluorescence reconstruction of a Shower.
Report failure to RunController, causing RunController to terminate execution.
Definition: VModule.h:64
static double gEnergyTimeDrif
void SetCherenkovEnergyCutoff(const double eCut) const
Main configuration utility.
Definition: CentralConfig.h:51
CherenkovFluorescenceMatrix::eFluorescenceLDF fFluoLDF
double GetTZero() const
Definition: EyeRecData.h:83
const atm::ProfileResult & EvaluateHeightVsDepth() const
Tabulated function giving Y=height as a function of X=depth.
static double gHorizontalUniformityError_par[5]
utl::TabulatedFunctionErrors & GetLightFlux(const FdConstants::LightSource source=fevt::FdConstants::eTotal)
Light flux at diaphragm, photons/m^2 versus time in ns.
Definition: EyeRecData.h:286
double GetShapeParameterError(const gh::EShapeParameter par) const
Gaisser Hillas with 4 parameters.
void SetTotalEnergy(const double energy, const double energyError, const EUncertaintyType type=eTotal)
static Policy::type Create(const utl::Point &theOrigin)
Create the standard local coordinate system for a Point.
const atm::ProfileResult & EvaluateSlantDepthVsDistance() const
#define ERROR(message)
Macro for logging error messages.
Definition: ErrorLogger.h:165
double FactorVariance(const double eCal, const double eTot)
CherenkovFluorescenceMatrix::eScatteredCherenkovLDF fScatCherLDF
const utl::Point & GetCorePosition() const
Shower core as reconstructed by the FD or FD eye.
void SetUncertaintyBound(const ModelWithUncertainty model, const double nSigma) const
alter Model &quot;model&quot; by &quot;nSigma&quot; standard deviations
bool HasEnergyDeposit() const
utl::Point GetPosition() const
Eye position.
void MakeLightFlux(const FdConstants::LightSource source=FdConstants::eTotal)
Definition: EyeRecData.h:293
utl::Branch GetTopBranch(const std::string &id)
Get top branch for moduleConfigLink with given id (XML files)
module to fit Gaisser-Hillas function to energy deposit profile and to derive total shower energy ...
Definition: EnergyFitter.h:28
double MaxX() const
Return the maximum value for X (ordinate) stored in the profile.
utl::TabulatedFunctionErrors & GetEnergyDeposit()
retrieve dE/dX
std::map< int, CherenkovFluorescenceMatrix * > fChFlPtrMap
utl::InvisibleEnergy::EInteractionModel fInvisibleEnergyModel
bool ReFitProfile(const fevt::Eye &eye, CherenkovFluorescenceMatrix *const chfl)
constexpr double cm2
Definition: AugerUnits.h:118
fevt::EyeRecData & GetRecData()
Reconstructed data for this eye.
Definition: FEvent/Eye.cc:130
static double gNightlyRelativeCalibration
double GetSDPThetaError() const
Definition: EyeRecData.h:77
const utl::Vector & GetAxis() const
Shower Axis as reconstructed by the FD or FD eye.

, generated on Tue Sep 26 2023.