LongitudinalXmaxScanner.cc
Go to the documentation of this file.
1 #include <utl/config.h>
3 
4 #include <adst/RecEvent.h>
5 
6 #include <utl/AugerUnits.h>
7 #include <utl/MathConstants.h>
8 #include <utl/PhysicalConstants.h>
9 #include <utl/AugerException.h>
10 #include <utl/ErrorLogger.h>
11 #include <utl/Transformation.h>
12 #include <utl/ReferenceEllipsoid.h>
13 #include <utl/PhysicalFunctions.h>
14 
15 #include <fwk/CoordinateSystemRegistry.h>
16 
17 #include <det/Detector.h>
18 #include <fdet/FDetector.h>
19 #include <fdet/Eye.h>
20 #include <fdet/Telescope.h>
21 #include <fdet/Camera.h>
22 #include <fdet/Pixel.h>
23 #include <fdet/Channel.h>
24 
25 #include <atm/ProfileResult.h>
26 #include <atm/AttenuationResult.h>
27 #include <atm/InclinedAtmosphericProfile.h>
28 
29 #include <utl/Point.h>
30 #include <utl/Vector.h>
31 #include <utl/AxialVector.h>
32 #include <utl/ReferenceEllipsoid.h>
33 
34 #include <evt/Event.h>
35 #include <evt/GaisserHillas4Parameter.h>
36 #include <evt/ShowerFRecData.h>
37 #include "evt/ShowerRecData.h"
38 
39 #include <TMatrixD.h>
40 
41 #include <iostream>
42 
43 using namespace std;
44 using namespace fwk;
45 using namespace atm;
46 using namespace det;
47 using namespace fdet;
48 using namespace utl;
49 using namespace otoa;
50 
51 
52 //--> magic constants ==> needs fix!
53 
54 const double gcm2 = utl::g/utl::cm2;
55 
56 // GH constraints
57 const double kAverageLambda = 61*gcm2;
58 const double kAverageX0 = -121*gcm2;
59 // variance of GH constraints
60 const double kLambdaVar = 13*13*gcm2*gcm2;
61 const double kX0Var = 172*172*gcm2*gcm2;
62 // value returned for singular matrices etc
63 const double kMaxVariance = 999*999*gcm2*gcm2;
64 
65 //--> end magic constants
66 
67 
68 inline
69 double
70 AverageErr(const double x0, const double x1, const double x2)
71 {
72  const double e1 = x1 - x0;
73  const double e2 = x0 - x2;
74  return 0.5*(e1 + e2);
75 }
76 
77 
78 // 68% space angle given angular track length (MC study from Jose, 09/05/28) updated (2017) taking into account the PCGf reco
79 inline
80 double
81 SpaceAngle(const double angularLength, const FDEvent& fdEvent)
82 {
83  const double refAngle = 30*degree;
84 
85  const FdRecGeometry& fdRecGeometry = fdEvent.GetFdRecGeometry();
86 
87  // hybrid
88  if (fdEvent.IsHybridEvent()) {
89  const double par = 0.213 * degree;
90  const double alpha = 2.1;
91  const double offset = 0.185 * degree;
92  return offset + par * pow(refAngle/angularLength, alpha);
93  }
94 
95  // pcgf
96  if (fdRecGeometry.HasPCGFData()) {
97  const double par = 0.266 * degree;
98  const double alpha = 0.515;
99  const double offset = 0.265 * degree;
100  return offset + par * pow(refAngle/angularLength, alpha);
101  }
102 
103  return std::numeric_limits<double>::infinity();
104 }
105 
106 
107 void
108 LongitudinalXmaxScanner::EstimateXmaxErrors(const RecEvent& theRecEvent)
109 {
110  fLongitudinalScan.clear();
111  fErrorAtXmax.clear();
112 
113  for (auto iEye = theRecEvent.EyesBegin(); iEye != theRecEvent.EyesEnd(); ++iEye) {
114 
115  fCalorimetricEnergy = iEye->GetFdRecShower().GetCalorimetricEnergy() * eV;
116  if (fCalorimetricEnergy > 0) {
117 
118  GetTelescopeProperties(iEye->GetEyeId());
119 
120  if (FillLightFactors(*iEye)) {
121  CalculateXmaxUncertainties(*iEye);
122  continue;
123  }
124  }
125 
126  // fill empty errors if reach here
127  fLongitudinalScan.push_back(LongitudinalScan());
128  fErrorAtXmax.push_back(sqrt(kMaxVariance));
129 
130  }
131 }
132 
133 
134 bool
135 LongitudinalXmaxScanner::FillLightFactors(const FDEvent& fdEvent)
136 {
137  fDepth.clear();
138  fGeomVariance.clear();
139  fTime.clear();
140  fViewingAngle.clear();
141  fDeltaAngle.clear();
142  fDeltaTime.clear();
143  fPhotoElectronFactor.clear();
144  fNoiseVariance.clear();
145  fCloseToBoundary.clear();
146  fOutsideTelescope.clear();
147 
148  det::Detector& detector = det::Detector::GetInstance();
149  CoordinateSystemPtr referenceCS = detector.GetReferenceCoordinateSystem();
150 
151  const FdRecPixel& recPixel = fdEvent.GetFdRecPixel();
152  const double maxRMS = 60; // protect against crazy values
153  const int nAverageZetaPix = 2;
154  const double averagePhotonVariance =
155  pow(fmin(maxRMS, recPixel.GetMeanPixelRMS()), 2) * nAverageZetaPix;
156  const double averagePhotoElectronVariance =
157  averagePhotonVariance * pow(fPhotonToPhotoElectron, 2);
158  fPhotoElectronBGRMS = sqrt(averagePhotoElectronVariance/nAverageZetaPix);
159 
160  const unsigned int eyeId = fdEvent.GetEyeId();
161  const FdRecShower& recShower = fdEvent.GetFdRecShower();
162  double zeta = fdEvent.GetFdRecApertureLight().GetZeta();
163  if (zeta <= 0) {
164  INFO("zeta not filled!!!");
165  zeta = 1.4*degree;
166  }
167  const TVector3& adstCore = recShower.GetCoreSiteCS();
168  const TVector3& adstAxis = recShower.GetAxisSiteCS();
169  const Vector axis(adstAxis.X(), adstAxis.Y(), adstAxis.Z(), referenceCS);
170  const Point core(adstCore.X()*m, adstCore.Y()*m, adstCore.Z()*m, referenceCS);
171  const fdet::Eye& detEye = detector.GetFDetector().GetEye(eyeId);
172  const Point& eyePos = detEye.GetPosition();
173  const Vector coreEyeVec = core - eyePos;
174 
175  const FdRecGeometry& theGeometry = fdEvent.GetFdRecGeometry();
176  const double t0 = theGeometry.GetT0();
177  const double chi0 = theGeometry.GetChi0();
178  const double rp = theGeometry.GetRp();
179 
180  const atm::Atmosphere& atmo = detector.GetAtmosphere();
181 
182  try {
183  atmo.InitSlantProfileModel(core, axis, 30.*g/cm2);
185  INFO(e.GetMessage());
186  return false;
187  }
188  const ProfileResult& distVsSlantDepth = atmo.EvaluateDistanceVsSlantDepth();
189  const double maxDepth = distVsSlantDepth.MaxX();
190  const double minDepth = distVsSlantDepth.MinX();
191 
192  const double xLow = recShower.GetXFOVMin() * g/cm2;
193  const double xUp = recShower.GetXFOVMax() * g/cm2;
194 
195  const int nBins = int((xUp - xLow) / fDepthBinWidth);
196  const double dX = (xUp - xLow) / nBins;
197 
198  double currX = xLow;
199  for (int i = 0; i < nBins+1; ++i) {
200 
201  fDepth.push_back(currX);
202 
203  const double thisX = currX - 0.5*dX;
204  const double nextX = currX + 0.5*dX;
205 
206  if (thisX >= minDepth && thisX <= maxDepth &&
207  nextX >= minDepth && nextX <= maxDepth) {
208 
209  const Point thisPoint = core - axis * distVsSlantDepth.Y(thisX);
210  const Point nextPoint = core - axis * distVsSlantDepth.Y(nextX);
211  const Point currPoint = core - axis * distVsSlantDepth.Y(currX);
212  const Vector thisVec = thisPoint - eyePos;
213  const Vector nextVec = nextPoint - eyePos;
214  const Vector currVec = currPoint - eyePos;
215  const double chi_i = Angle(currVec, coreEyeVec);
216  const double t_i = t0 + rp/kSpeedOfLight * std::tan(0.5*(chi0 - chi_i));
217  fTime.push_back(t_i);
218  fViewingAngle.push_back(chi0 - chi_i);
219  const double chi_1 = Angle(thisVec, coreEyeVec);
220  const double chi_2 = Angle(nextVec, coreEyeVec);
221  const double t_1 = t0 + rp/kSpeedOfLight * std::tan(0.5*(chi0 - chi_1));
222  const double t_2 = t0 + rp/kSpeedOfLight * std::tan(0.5*(chi0 - chi_2));
223  fDeltaAngle.push_back(fabs(chi_1 - chi_2));
224  fDeltaTime.push_back(fabs(t_1 - t_2));
225 
226  const double lightFactor =
227  CalculateLightFactor(thisPoint, nextPoint, eyeId);
228  const double timeLength =
229  CalculateTimeLength(thisPoint, nextPoint, eyeId);
230  const auto telAndPixId = GetTelescopeAndPixelId(currVec, eyeId);
231  const auto telId = telAndPixId[0];
232  if (telId) {
233  fCloseToBoundary.push_back(IsNearBorder(currVec, eyeId, telId, zeta));
234  fOutsideTelescope.push_back(false);
235  const double area = detEye.GetTelescope(telId).GetDiaphragmArea();
236  const double photoElectronFactor =
237  lightFactor * area * fPhotonToPhotoElectron;
238  fPhotoElectronFactor.push_back(photoElectronFactor);
239  if (fUseBGLoop) {
240  const fdet::Telescope& detTel = detEye.GetTelescope(telId);
241  const fdet::Channel& detChannel = detTel.GetChannel(telAndPixId[1]);
242  const double adcVar = detChannel.GetADCVariance();
243  const fdet::Pixel& detPixel = detTel.GetPixel(telAndPixId[1]);
244  const double calConst =
246  const double photonVar = adcVar * pow(calConst, 2);
247  const double var = pow(fPhotonToPhotoElectron, 2) * photonVar;
248  const double timeBin = detChannel.GetFADCBinSize();
249  const double nTimeBins = timeLength / timeBin;
250  fNoiseVariance.push_back(nTimeBins * var);
251  /*
252  cout << detEye.GetId() << " " << detTel.GetId() << " "
253  << timeBin << " " << timeLength << " "
254  << calConst << " "
255  << sqrt(var / pow(timeBin, 2))
256  << " " << averagePhotoElectronVariance/2 << endl;
257  */
258  } else {
259  // wrong for HECO and HEAT, but kept for historical reasons (ICRC17)
260  const double timeBin = 100*nanosecond;
261  fNoiseVariance.push_back(timeLength/timeBin *
262  averagePhotoElectronVariance);
263  }
264  } else {
265  fCloseToBoundary.push_back(true);
266  fOutsideTelescope.push_back(true);
267  fPhotoElectronFactor.push_back(0);
268  fNoiseVariance.push_back(0);
269  }
270  } else {
271  fPhotoElectronFactor.push_back(-1);
272  fTime.push_back(-1);
273  fViewingAngle.push_back(-1);
274  fDeltaAngle.push_back(-1);
275  fDeltaTime.push_back(-1);
276  fNoiseVariance.push_back(999);
277  fCloseToBoundary.push_back(true);
278  fOutsideTelescope.push_back(true);
279  }
280 
281  currX += dX;
282  }
283 
284  return true;
285 }
286 
287 
288 vector<double>
289 LongitudinalXmaxScanner::GetChangedDepth(const FDEvent& fdEvent,
290  const double nSigRp,
291  const double nSigChi0,
292  const double nSigT0,
293  const double nSigPhi,
294  const double nSigTheta)
295 {
296  const unsigned int eyeId = fdEvent.GetEyeId();
297  const det::Detector& detector = det::Detector::GetInstance();
298  const atm::Atmosphere& atmo = detector.GetAtmosphere();
299  const fdet::Eye& detEye = detector.GetFDetector().GetEye(eyeId);
300 
301  const FdRecGeometry& theGeometry = fdEvent.GetFdRecGeometry();
302 
303  const double t0 = theGeometry.GetT0() + nSigT0 * theGeometry.GetT0Error();
304  const double chi0 = theGeometry.GetChi0() + nSigChi0 * theGeometry.GetChi0Error();
305  const double rp = theGeometry.GetRp() + nSigRp * theGeometry.GetRpError();
306 
307  const CoordinateSystemPtr eyeCS = detEye.GetEyeCoordinateSystem();
308 
309  const double sdpTheta = theGeometry.GetSDPTheta() + nSigTheta * theGeometry.GetSDPThetaError();
310  const double sdpPhi = theGeometry.GetSDPPhi() + nSigPhi * theGeometry.GetSDPPhiError();
311  const Vector sdp = Vector(1, sdpTheta, sdpPhi, eyeCS, Vector::kSpherical);
312 
313  const Vector vertical(0,0,1, eyeCS);
314  const Vector horizontalInSDP = Normalized(Cross(sdp, vertical));
315 
316  const Transformation rot(Transformation::Rotation(-chi0, sdp, eyeCS));
317  const Vector axis(rot * horizontalInSDP);
318  const Vector coreEyeVec = rp / sin(kPi - chi0) * horizontalInSDP;
319  const Point core = detEye.GetPosition() + coreEyeVec;
320 
321  const ProfileResult* slantDepthProfile = nullptr;
322  try {
323  // less precision for error propagation, see GAP-2007-007, Fig. 5
324  atmo.InitSlantProfileModel(core, axis, 100*g/cm2);
325  slantDepthProfile = &atmo.EvaluateSlantDepthVsDistance();
327  return vector<double>();
328  }
329 
330  const double minDistance = slantDepthProfile->MinX();
331  const double maxDistance = slantDepthProfile->MaxX();
332 
333  vector<double> depthVec;
334  for (unsigned int i = 0; i < fTime.size(); ++i) {
335  const double t_i = fTime[i];
336  double depth = -1*g/cm2;
337  if (t_i > 0) {
338  const double chi_i = chi0 - 2*atan(kSpeedOfLight / rp * (t_i - t0));
339  const double distance = -coreEyeVec.GetMag() * sin(chi_i) / sin(chi0 - chi_i);
340  if (distance > minDistance && distance < maxDistance)
341  depth = slantDepthProfile->Y(distance);
342  }
343  depthVec.push_back(depth);
344  }
345 
346  return depthVec;
347 }
348 
349 
350 void
351 LongitudinalXmaxScanner::PropagateGeometryUncertainty(const FDEvent& fdEvent)
352 {
353  fXmaxGeomVar = kMaxVariance;
354 
355  vector<double> depthDefault = GetChangedDepth(fdEvent,0,0,0,0,0);
356  vector<double> depthRp1 = GetChangedDepth(fdEvent,1,0,0,0,0);
357  vector<double> depthRp2 = GetChangedDepth(fdEvent,-1,0,0,0,0);
358  vector<double> depthChi1 = GetChangedDepth(fdEvent,0,1,0,0,0);
359  vector<double> depthChi2 = GetChangedDepth(fdEvent,0,-1,0,0,0);
360  vector<double> depthT01 = GetChangedDepth(fdEvent,0,0,1,0,0);
361  vector<double> depthT02 = GetChangedDepth(fdEvent,0,0,-1,0,0);
362  vector<double> depthPhi1 = GetChangedDepth(fdEvent,0,0,0,1,0);
363  vector<double> depthPhi2 = GetChangedDepth(fdEvent,0,0,0,-1,0);
364  vector<double> depthTheta1 = GetChangedDepth(fdEvent,0,0,0,0,1);
365  vector<double> depthTheta2 = GetChangedDepth(fdEvent,0,0,0,0,-1);
366 
367  // check for InclinedModel exceptions
368  const unsigned int nDepth = fDepth.size();
369  bool allValid = (depthDefault.size() == nDepth &&
370  depthRp1.size() == nDepth &&
371  depthRp2.size() == nDepth &&
372  depthChi1.size() == nDepth &&
373  depthChi2.size() == nDepth &&
374  depthT01.size() == nDepth &&
375  depthT02.size() == nDepth &&
376  depthPhi1.size() == nDepth &&
377  depthPhi2.size() == nDepth &&
378  depthTheta1.size() == nDepth &&
379  depthTheta2.size() == nDepth);
380 
381  if (!allValid) {
382  INFO(" GetChangedDepth failed!");
383  for (unsigned int i = 0; i < nDepth; ++i)
384  fGeomVariance.push_back(kMaxVariance);
385  return;
386  }
387 
388  // correlation coefficients
389  const FdRecGeometry& theGeometry = fdEvent.GetFdRecGeometry();
390  const double rhoRT = theGeometry.GetRpT0Correlation();
391  const double rhoRC = theGeometry.GetChi0RpCorrelation();
392  const double rhoCT = theGeometry.GetChi0T0Correlation();
393  const double rhoPT = theGeometry.GetSDPThetaPhiCorrelation();
394 
395  for (unsigned int i = 0; i < nDepth; ++i) {
396  if (fDepth[i] > 0) {
397 
398  const double rpErr = AverageErr(depthDefault[i],
399  depthRp1[i],
400  depthRp2[i]);
401  const double t0Err = AverageErr(depthDefault[i],
402  depthT01[i],
403  depthT02[i]);
404 
405  const double chi0Err = AverageErr(depthDefault[i],
406  depthChi1[i],
407  depthChi2[i]);
408 
409  const double phiErr = AverageErr(depthDefault[i],
410  depthPhi1[i],
411  depthPhi2[i]);
412 
413  const double thetaErr = AverageErr(depthDefault[i],
414  depthTheta1[i],
415  depthTheta2[i]);
416 
417  const double timeFitVariance = pow(rpErr,2)
418  + pow(t0Err,2)
419  + pow(chi0Err,2)
420  + 2 * rpErr * t0Err * rhoRT
421  + 2 * rpErr * chi0Err * rhoRC
422  + 2 * t0Err * chi0Err * rhoCT;
423 
424  const double sdpFitVariance = pow(phiErr,2) + pow(thetaErr,2)
425  + 2 * phiErr * thetaErr * rhoPT;
426 
427  // chi2 scale factors as in FdProfileReconstructor
428  const double scaleFac =
429  theGeometry.GetTimeFitChi2() / theGeometry.GetTimeFitNdof();
430  fGeomVariance.push_back(scaleFac*timeFitVariance + sdpFitVariance);
431 
432  } else {
433  fGeomVariance.push_back(kMaxVariance);
434  }
435  }
436 
437  if (nDepth < 2)
438  return;
439 
440  // uncertainty at Xmax
441  const double xLow = fDepth[0];
442  const double xUp = fDepth[nDepth-1];
443  const double xMax = fXmax;
444  const double dX = (xUp - xLow) / (nDepth - 1);
445  const int index = int((xMax - xLow) / dX);
446  if (index >= 0 && index < int(nDepth) - 1) {
447  const double deltaX = xMax - xLow - index*dX;
448  const double z1 = fGeomVariance[index];
449  const double z2 = fGeomVariance[index+1];
450  fXmaxGeomVar = z1 + deltaX*(z2 - z1)/dX;
451  } else if (index == int(nDepth) - 1)
452  fXmaxGeomVar = fGeomVariance[index];
453 }
454 
455 
456 void
457 LongitudinalXmaxScanner::CalculateXmaxUncertainties(const FDEvent& fdEvent)
458 {
459  const FdRecShower& theShower = fdEvent.GetFdRecShower();
460  const FdRecApertureLight& theAp = fdEvent.GetFdRecApertureLight();
461  fXmax = theShower.GetXmax()*g/cm2;
462  fShowerAngularLength = theAp.GetMaxAngle() - theAp.GetMinAngle();
463 
464  // calculate geometry uncertainty
465  PropagateGeometryUncertainty(fdEvent);
466 
467  // uncertainty at Xmax
468  fXmaxProfVar = PropagateProfileUncertainty(fdEvent,fXmax);
469  fXmaxAngularLength = fAngularLength;
470  fXmaxTotErr = CalculateTotalError(fXmaxGeomVar,fXmaxProfVar,fdEvent);
471 
472  if (fVerbosity > 1)
473  PrintCurrentVariables(fdEvent);
474 
475  LongitudinalScan longScan;
476  for (unsigned int i = 0; i < fDepth.size(); ++i) {
477 
478  const double X = fDepth[i];
479  const double geomVar = fGeomVariance[i];
480  const double profVar = PropagateProfileUncertainty(fdEvent, X);
481  const double totErr = CalculateTotalError(geomVar, profVar, fdEvent);
482 
483  longScan.AddScanResult(X, totErr, fMinViewingAngle);
484 
485  if (fVerbosity > 0)
486  cout << " X= " << X/gcm2 << ' '
487  << sqrt(profVar)/gcm2 << ' '
488  << sqrt(fGeomVarScaleFac*geomVar)/gcm2 << ' '
489  << totErr/gcm2 << ' ' << theShower.GetXmaxError() << ' '
490  << fAngularLength/degree
491  << endl;
492  }
493 
494  fLongitudinalScan.push_back(longScan);
495  fErrorAtXmax.push_back(fXmaxTotErr);
496 }
497 
498 
499 double
500 LongitudinalXmaxScanner::PropagateProfileUncertainty(const FDEvent& fdEvent,
501  const double Xmax)
502 {
503  const FdRecShower& theShower = fdEvent.GetFdRecShower();
504 
505  // chi2 scale factor as in FdProfileReconstructor
506  const double scaleFac = theShower.GetGHChi2()/theShower.GetGHNdf();
507 
508  using namespace evt;
511  GaisserHillas4Parameter ghFunction(1, Xmax, x0, lambda);
512 
513  const double ghIntegral = ghFunction.GetIntegral();
514  const double dEdXmax = fCalorimetricEnergy/ghIntegral;
515 
516  vector<double> npeVec;
517  vector<double> ghFunc;
518  vector<double> dEdXErr;
519 
520  for (unsigned int i = 0; i < fDepth.size(); ++i) {
521 
522  const double dEdX = dEdXmax * ghFunction.Eval(fDepth[i]);
523  const double npe = dEdX * fPhotoElectronFactor[i];
524  const double variance = npe*(1 + fGainVariance) + fNoiseVariance[i];
525  const double dEdX_Err = sqrt(variance) / fPhotoElectronFactor[i];
526  dEdXErr.push_back(dEdX_Err);
527  ghFunc.push_back(dEdX);
528  npeVec.push_back(npe);
529 
530  }
531 
532  vector<unsigned short> triggerVec = CalculatePixelTrigger(npeVec);
533 
534  // "deactivate" bins without trigger by setting large uncertainty
535  // and fill some variables
536  fTrackMin = 0;
537  fTrackMax = 0;
538  fMinViewingAngle = 0;
539  fAngularLength = 0;
540  fBins = 0;
541 
542  double angSum = 0;
543  for (unsigned int i = 0; i < fDepth.size(); ++i) {
544  // MU: triggerVec can not be commented out, otherwise MVA will be wrong
545  if (!triggerVec[i] || fCloseToBoundary[i] || fOutsideTelescope[i])
546  dEdXErr[i] = ghFunc[i]*100;
547  else {
548  if (!fBins || fDepth[i] < fTrackMin)
549  fTrackMin = fDepth[i];
550  if (!fBins || fDepth[i] > fTrackMax)
551  fTrackMax = fDepth[i];
552  if (!fBins || fMinViewingAngle > fViewingAngle[i])
553  fMinViewingAngle = fViewingAngle[i];
554  angSum += fDeltaAngle[i];
555  ++fBins;
556  }
557  }
558 
559  fAngularLength = angSum;
560 
561  double profVar = kMaxVariance;
562  if (fBins > 0 && angSum > 0) {
563 
564  profVar = EstimateXmaxVariance(fDepth, ghFunc, dEdXErr,
565  dEdXmax, Xmax,
567  profVar *= scaleFac;
568  }
569 
570  if (fVerbosity > 0) {
571  if (Xmax == fXmax) {
572  for (unsigned int i = 0; i < fDepth.size(); ++i) {
573  cout << "-- X=" << fDepth[i]/g*cm2
574  << " dEdX=" << ghFunc[i]/(PeV/g*cm2)
575  << " s(dEdX)=" << dEdXErr[i]/(PeV/g*cm2)
576  << " relErr=" << dEdXErr[i]/ghFunc[i]
577  << " trig=" << triggerVec[i]
578  << " telBound=" << fCloseToBoundary[i]
579  << " isInTelescope=" << !fOutsideTelescope[i]
580  << " dAng=" << fDeltaAngle[i]/degree
581  << " dT=" << fDeltaTime[i]/(100*ns)
582  << " viewAngle= " << fViewingAngle[i]/degree
583  << '\n';
584  }
585  cout << flush;
586  }
587  }
588 
589  return profVar;
590 }
591 
592 
593 void
594 LongitudinalXmaxScanner::PrintCurrentVariables(const FDEvent& fdEvent)
595  const
596 {
597  const FdRecShower& theShower = fdEvent.GetFdRecShower();
598  const FdRecApertureLight& theAp = fdEvent.GetFdRecApertureLight();
599  cout << " check "
600  << fdEvent.GetEyeId() << ' '
601  << fdEvent.GetRunId() << ' '
602  << fdEvent.GetEventId() << ' '
603  << fBins << ' '
604  << log10(theShower.GetEnergy()) << ' '
605  << fXmax/g*cm2 << ' '
606  << theShower.GetXmaxError() << ' '
607  << sqrt(fXmaxGeomVar+fXmaxProfVar)/g*cm2 << ' '
608  << sqrt(fXmaxProfVar)/g*cm2 << ' '
609  << sqrt(fXmaxGeomVar)/g*cm2 << ' '
610  << fTrackMin/g*cm2 << ' '
611  << fTrackMax/g*cm2 << ' '
612  << theShower.GetXTrackMin() << ' '
613  << theShower.GetXTrackMax() << ' '
614  << fAngularLength/degree << ' '
615  << fMinViewingAngle/degree << ' '
616  << theAp.GetMinAngle()/degree << ' '
617  << fGeomVarScaleFac << endl;
618 }
619 
620 
621 // returns photons at aperture per dE/dX per area
622 double
623 LongitudinalXmaxScanner::CalculateLightFactor(const Point& pos1,
624  const Point& pos2,
625  const unsigned int eyeId)
626  const
627 {
628  det::Detector& detector = det::Detector::GetInstance();
629  const atm::Atmosphere& atmo = detector.GetAtmosphere();
630  const fdet::Eye& detEye = detector.GetFDetector().GetEye(eyeId);
631  const Point& eyePos = detEye.GetPosition();
632 
633  const Point meanPos = pos1 - 0.5*(pos1 - pos2);
634  const Vector Mpos = 0.5*(pos1 - pos2);
635  const double lambdaRef = detector.GetFDetector().GetReferenceLambda();
636  // FIXME tel 1
637  const utl::TabulatedFunction& eff =
639  const double lambdaEffMin = eff.GetX(0);
640  const double lambdaEffMax = eff.GetX(eff.GetNPoints()-1);
641  const double epsilonRef = eff.Y(lambdaRef);
642 
643  const vector<double>& fluoLambda =
644  atmo.GetWavelengths(Atmosphere::eFluorescence);
645 
646  // Mie attenuation
647  const AttenuationResult mAtt =
648  atmo.EvaluateMieAttenuation(eyePos,meanPos,fluoLambda);
650  // Rayleigh attenuation
651  const AttenuationResult rAtt =
652  atmo.EvaluateRayleighAttenuation(eyePos,meanPos,fluoLambda);
654 
655  ReferenceEllipsoid wgs84(ReferenceEllipsoid::Get(ReferenceEllipsoid::eWGS84));
656  const double height = wgs84.PointToLatitudeLongitudeHeight(meanPos).get<2>();
657 
658  const utl::TabulatedFunction& fluoyield_tab =
659  atmo.EvaluateFluorescenceYield(height);
660 
661  double effYTsum_F = 0;
662  for (unsigned int i = 0; i < fluoLambda.size(); ++i) {
663  if (fluoLambda[i] >= lambdaEffMin &&
664  fluoLambda[i] <= lambdaEffMax) {
665  const double lambda = fluoLambda[i];
666  const double T_i = mieAtt.GetY(i) * rayAtt.GetY(i);
667  const double Y_i = fluoyield_tab.Y(lambda);
668  effYTsum_F += eff.Y(lambda) / epsilonRef * Y_i * T_i;
669  }
670  }
671 
672  // calculate Cherenkov part
673 
674  const vector<double>& cherLambda =
675  atmo.GetWavelengths(Atmosphere::eCerenkov);
676 
677  // ---- attenuation to telescope for cherenkov
678 
679  // Mie attenuation
680  const AttenuationResult mCAtt =
681  atmo.EvaluateMieAttenuation(eyePos, meanPos, cherLambda);
683  // Rayleigh attenuation
684  const AttenuationResult rCAtt =
685  atmo.EvaluateRayleighAttenuation(eyePos, meanPos, cherLambda);
686  //const utl::TabulatedFunctionErrors& rayCAtt = rAtt.GetTransmissionFactor();// unused. LN.
687 
688  /*
689  MU: FOV calculation should *not* depend on the Xmax of the event.
690  In that sense a hardcoded value is better, but a proper fix
691  should re-calculate the Cherenkov yield for each Xmax position
692  again
693  */
694 
695  //const double Xmax = recShower.GetGHParameters().GetXMax();;
696 
697  //const double Xmax = 750*g/cm2; // used for shower age for Cherenkov // unused. LN.
698 
699  //const double slantDepth = Mpos.GetMag();// unused. LN.
700  //const double showerAge = utl::ShowerAge(slantDepth, Xmax);// unused. LN.
701  //const Point& telPos = detEye.GetTelescope(1).GetPosition();// unused. LN.
702 
703  // Cherenkov yield per electron above electronEnergyThreshold
704  const double electronEnergyThreshold = 1*MeV;
705  atmo.SetCherenkovEnergyCutoff(electronEnergyThreshold);
706  //const utl::TabulatedFunction& directCherenkov = // unused. LN.
707  // atmo.EvaluateCherenkovDirect(pos1, pos2, telPos, showerAge);
708 
709  // average energy deposit per electron above electronEnergyThreshold
710  //const double alpha = utl::EnergyDeposit(showerAge, electronEnergyThreshold);// unused. LN.
711 
713  for (unsigned int i = 0; i < cherLambda.size(); ++i) {
714  if (cherLambda[i] >= lambdaEffMin &&
715  cherLambda[i] <= lambdaEffMax) {
716  //const double lambda = cherLambda[i];// unused. LN.
717  //const double T_i = mieCAtt.GetY(i) * rayCAtt.GetY(i); // unused. LN.
718  //const double Y_i = directCherenkov.GetY(i); // unused. LN.
719  //const double epsilon_i = eff.Y(lambda) / epsilonRef; // unused. LN.
720 
721  //effYTsum_C += epsilon_i * T_i * Y_i / alpha;
722  }
723  }
724 
725  const double deltaL = (pos1 - pos2).GetMag();
726  const double fourPi = 4*kPi;
727  const utl::Vector r = meanPos - eyePos;
728  const double rSquared = r.GetMag2();
729 
730  /*
731  MU: I think this should be
732 
733  lightFac = (effYTsum_F * deltaL / (fourPi * rSquared * dEdX0)) + effYTsum_C;
734 
735  because afaik EvaluateCherenkovDirect() gives already light flux at
736  telescope
737 
738  --> please check, direct C-light contribution commented for now
739  */
740 
741  const double dEdX0 = atmo.GetdEdX0();
742  const double totalsum = effYTsum_F; // MU: FIXME + effYTsum_C;
743  const double lightFac = totalsum * deltaL / (fourPi * rSquared * dEdX0);
744 
745  return lightFac;
746 }
747 
748 
749 void
750 LongitudinalXmaxScanner::GetTelescopeProperties(unsigned int eyeId)
751 {
752  const fdet::FDetector& detFD = det::Detector::GetInstance().GetFDetector();
753  const fdet::Eye& detEye = detFD.GetEye(eyeId);
754  for (fdet::Eye::TelescopeIterator teliter = detEye.TelescopesBegin();
755  teliter != detEye.TelescopesEnd(); ++teliter) {
756  const fdet::Telescope& detTel = *teliter;
757  fGainVariance = detTel.GetCamera().GetGainVariance();
758  // FIXME hardcoded
759  fPhotonToPhotoElectron = 0.128;
760  break;
761  }
762 
763  // FIXME hardcoded
764  fPixelSize = 1.5*degree;
765 }
766 
767 
768 // returns time difference at diaphragm
769 double
770 LongitudinalXmaxScanner::CalculateTimeLength(const utl::Point& pos1,
771  const utl::Point& pos2,
772  const unsigned int eyeId)
773  const
774 {
775  det::Detector& detector = det::Detector::GetInstance();
776  const fdet::Eye& detEye = detector.GetFDetector().GetEye(eyeId);
777  const Point& eyePos = detEye.GetPosition();
778 
779  const Vector pos1Eye = pos1 - eyePos;
780  const Vector pos2Eye = pos2 - eyePos;
781  const Vector pos1pos2 = pos1 - pos2;
782 
783  const double tof1 = pos1Eye.GetMag() / kSpeedOfLight;
784  const double tof2 = (pos1pos2.GetMag() + pos2Eye.GetMag()) / kSpeedOfLight;
785 
786  return fabs(tof1 - tof2);
787 }
788 
789 
790 vector<unsigned short>
791 LongitudinalXmaxScanner::CalculatePixelTrigger(const vector<double>& npeVec)
792  const
793 {
794  vector<unsigned short> triggerVec;
795 
796  double angSum = 0;
797  double timeSum = 0;
798  double npeSum = 0;
799 
800  for (unsigned int i = 0; i < npeVec.size(); ++i) {
801 
802  if (fDeltaAngle[i] < 0) {
803  triggerVec.push_back(0);
804  continue;
805  }
806 
807  timeSum += fDeltaTime[i];
808  angSum += fDeltaAngle[i];
809  npeSum += npeVec[i];
810 
811  if (angSum > fPixelSize) {
812 
813  const bool triggered = IsTriggered(timeSum, angSum, npeSum);
814  for (unsigned int j = triggerVec.size(); j <= i; ++j)
815  triggerVec.push_back(triggered);
816 
817  angSum = 0;
818  timeSum = 0;
819  npeSum = 0;
820 
821  }
822  }
823 
824  if (timeSum != 0) {
825  const bool triggered = IsTriggered(timeSum, angSum, npeSum);
826  for (unsigned int j = triggerVec.size(); j < npeVec.size(); ++j)
827  triggerVec.push_back(triggered);
828  }
829 
830  return triggerVec;
831 }
832 
833 
834 bool
835 LongitudinalXmaxScanner::IsTriggered(const double dT, const double dAng, const double npe)
836  const
837 {
838  const double thresholdSlope = 15.;
839  const double threshold = thresholdSlope*fPhotoElectronBGRMS;
840  const int nBoxCar = 10;
841  const double timeBinLength = 100*ns;
842 
843  const double timeInPixel = fPixelSize / dAng * dT;
844  const double signalInPixel = fPixelSize / dAng * npe;
845  const double signalBoxTime = fmin(timeInPixel, nBoxCar*timeBinLength);
846 
847  return signalInPixel/timeInPixel*signalBoxTime > threshold;
848 }
849 
850 
851 double
852 LongitudinalXmaxScanner::CalculateTotalError(const double geomVar,
853  const double profVar,
854  const FDEvent& fdEvent)
855 {
856  if (geomVar == kMaxVariance ||
857  profVar == kMaxVariance ||
858  fAngularLength < 1*degree)
859  return sqrt(kMaxVariance);
860 
861  const double xmaxAngleErr = SpaceAngle(fXmaxAngularLength, fdEvent);
862  const double currAngleErr = SpaceAngle(fAngularLength, fdEvent);
863  // uncomment next two lines to re-scale to ADST track length
864  //const double adstAngleErr = SpaceAngle(fShowerAngularLength);
865  const double adstFactor = 1; //adstAngleErr/xmaxAngleErr;
866  const double currentFactor = currAngleErr / xmaxAngleErr;
867 
868  fGeomVarScaleFac = pow(adstFactor*currentFactor, 2);
869 
870  const double totErr = sqrt(fGeomVarScaleFac*geomVar + profVar);
871 
872  return totErr;
873 }
874 
875 
876 bool
877 LongitudinalXmaxScanner::IsNearBorder(const utl::Vector& direction,
878  const unsigned int eyeId,
879  const unsigned int telId,
880  const double zeta)
881  const
882 {
883  det::Detector& detector = det::Detector::GetInstance();
884  const fdet::Eye& detEye = detector.GetFDetector().GetEye(eyeId);
885  const fdet::Telescope& detTel = detEye.GetTelescope(telId);
886 
888  iter!= detTel.OutOfBorderPixelsEnd(); ++iter) {
889  const double angle = Angle(direction, *iter);
890  if (angle < zeta)
891  return true;
892  }
893 
894  return false;
895 }
896 
897 
898 std::array<unsigned int, 2>
899 LongitudinalXmaxScanner::GetTelescopeAndPixelId(const utl::Vector& direction,
900  const unsigned int eyeId)
901  const
902 {
903  det::Detector& detector = det::Detector::GetInstance();
904  const fdet::Eye& detEye = detector.GetFDetector().GetEye(eyeId);
905 
906  unsigned int iPix = 0;
907  unsigned int iTel = 0;
908  double min = std::numeric_limits<double>::infinity();
909 
910  for (fdet::Eye::TelescopeIterator tIt = detEye.TelescopesBegin();
911  tIt != detEye.TelescopesEnd(); ++tIt) {
912  for (unsigned int i = tIt->GetFirstPixelId(), n = tIt->GetLastPixelId();
913  i <= n; ++i) {
914  const double diff = Angle(direction, tIt->GetPixel(i).GetDirection());
915  if (diff < min) {
916  iTel = tIt->GetId();
917  iPix = i;
918  min = diff;
919  }
920  }
921  }
922 
923  return { iTel, iPix };
924 }
925 
926 
927 double
928 LongitudinalXmaxScanner::EstimateXmaxVariance(const vector<double>& x,
929  const vector<double>& ghFunc,
930  const vector<double>& eY,
931  const double nMax,
932  const double xMax,
933  const double x0,
934  const double lambda)
935  const
936 {
937  if (xMax < x0)
938  return xMax;
939 
940  TMatrixD a(4, 4);
941 
942  for (unsigned int i = 0; i < x.size(); ++i) {
943 
944  // skip point outside atmosphere (flagged as -1.)
945  if (eY[i] < 0)
946  continue;
947 
948  // inverse of squared relative GH errors
949  const double tmp = eY[i] / ghFunc[i];
950  const double invSqRelErr = 1 / pow(tmp, 2);
951 
952  const double logTerm = log((x0 - x[i]) / (x0 - xMax));
953  // dGH/dNmax
954  const double ghRelDeriv1 = 1 / nMax;
955  // dGH/dXmax
956  const double ghRelDeriv2 = logTerm / lambda;
957  const double nominatorX0 = (x0 - x[i]) * logTerm + (x[i] - xMax);
958  const double nominatorLambda = (x0 - xMax) * logTerm + (x[i] - xMax);
959  // dGH/dX0
960  const double ghRelDeriv3 = nominatorX0 / lambda / (x[i] - x0);
961  // dGH/dlambda
962  const double ghRelDeriv4 = nominatorLambda / (lambda * lambda);
963 
964  const double deriv[4] = { ghRelDeriv1, ghRelDeriv2, ghRelDeriv3, ghRelDeriv4 };
965 
966  for (int i = 0; i < 4; ++i)
967  for (int j = 0; j <= i; ++j)
968  a[i][j] += invSqRelErr * deriv[i] * deriv[j];
969 
970  }
971 
972  a[2][2] += 1 / kX0Var;
973  a[3][3] += 1 / kLambdaVar;
974 
975  a[0][1] = a[1][0];
976  a[0][2] = a[2][0];
977  a[0][3] = a[3][0];
978  a[1][2] = a[2][1];
979  a[1][3] = a[3][1];
980  a[2][3] = a[3][2];
981 
982  double determinant;
983  a.InvertFast(&determinant);
984 
985  if (determinant <= 0) {
986  ostringstream info;
987  info << "error matrix is singular, det="
988  << determinant
989  << ", XmaxError = " << sqrt(a[1][1])/gcm2 << endl;
990  INFO(info.str());
991  return kMaxVariance;
992  }
993 
994  return a[1][1];
995 }
AxialVector Cross(const Vector &l, const Vector &r)
Definition: OperationsAV.h:25
const double eV
Definition: GalacticUnits.h:35
unsigned int GetNPoints() const
Top of the interface to Atmosphere information.
const utl::TabulatedFunction & EvaluateFluorescenceYield(const double heightAboveSeaLevel) const
Evaluated Fluorescence Yield for a specific model.
const double degree
Point object.
Definition: Point.h:32
double Angle(const double theta1, const double phi1, const double theta2, const double phi2)
Description of the electronic channel for the 480 channels of the crate.
void InitSlantProfileModel(const utl::Point &core, const utl::Vector &dir, const double deltaX) const
const double PeV
atm::AttenuationResult EvaluateMieAttenuation(const utl::Point &xInit, const utl::Point &xFinal, const std::vector< double > &wLength) const
const std::vector< double > & GetWavelengths(const EmissionMode mode=eFluorescence) const
const utl::TabulatedFunctionErrors & GetTransmissionFactor() const
Transmission factor.
const double kAverageX0
const double kX0Var
Class to hold collection (x,y) points and provide interpolation between them.
double SpaceAngle(const double angularLength, const FDEvent &fdEvent)
std::pair< gh::EShapeParameter, double > ShapeParameter
double GetMeasuredRelativeEfficiency(const double wl) const
const atm::ProfileResult & EvaluateDistanceVsSlantDepth() const
Table of distance as a function of slant depth.
double GetGainVariance() const
const Channel & GetChannel(const unsigned int channelId) const
Get Channel by id, throw utl::NonExistentComponentException if n.a.
double GetEndToEndCalibrationAtReferenceWavelength() const
#define INFO(message)
Macro for logging informational messages.
Definition: ErrorLogger.h:161
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
double pow(const double x, const unsigned int i)
double GetMag() const
Definition: Vector.h:58
const Camera & GetCamera() const
Get the Camera object that belongs to the telescope.
Detector description interface for FDetector-related data.
Definition: FDetector.h:44
double Y(const double x) const
Get the Y value (coordinate) for given X (ordinate)
OutOfBorderPixelsIterator OutOfBorderPixelsEnd() const
End of pixels out of the border.
const Pixel & GetPixel(const unsigned int pixelId) const
Get Pixel by id, throw utl::NonExistentComponentException if n.a.
constexpr double MeV
Definition: AugerUnits.h:184
const atm::Atmosphere & GetAtmosphere() const
Definition: Detector.h:113
double AverageErr(const double x0, const double x1, const double x2)
boost::shared_ptr< const CoordinateTransformer > CoordinateSystemPtr
Shared pointer for coordinate systems.
Reference ellipsoids for UTM transformations.
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
TelescopeIterator TelescopesBegin() const
Beginning of the collection of telescopes.
Definition: FDetector/Eye.h:79
constexpr double nanosecond
Definition: AugerUnits.h:143
Active transformations of geometrical objects.
const Telescope & GetTelescope(const unsigned int telescopeId) const
Find Telescope by numerical Id.
atm::AttenuationResult EvaluateRayleighAttenuation(const utl::Point &xInit, const utl::Point &xFinal, const std::vector< double > &wLength) const
Compute Rayleigh attenuation between points.
Top of the hierarchy of the detector description interface.
Definition: Detector.h:81
Triple PointToLatitudeLongitudeHeight(const Point &thePoint) const
Convert Point to Lat/Long/Height.
const fdet::FDetector & GetFDetector() const
Definition: Detector.cc:131
constexpr double g
Definition: AugerUnits.h:200
std::vector< utl::Vector >::const_iterator OutOfBorderPixelsIterator
AxialVector Normalized(const AxialVector &v)
Definition: AxialVector.h:81
const double & GetY(const unsigned int idx) const
double Eval(const double depth) const
evaluate function a X = depth
double GetReferenceLambda() const
Definition: FDetector.cc:332
boost::filter_iterator< TelIsCommissioned, InternalConstTelescopeIterator > TelescopeIterator
An iterator over telescopes.
Definition: FDetector/Eye.h:76
constexpr double kSpeedOfLight
Detector description interface for Telescope-related data.
double MinX() const
Return the minimum value for X (ordinate) stored in the profile.
const double kAverageLambda
double GetFADCBinSize() const
utl::CoordinateSystemPtr GetReferenceCoordinateSystem() const
Get the reference coordinate system used for analysis (usually PampaAmarilla for Auger) ...
Definition: Detector.h:141
Description of a pixel.
execption handling for calculation/access for inclined atmosphere model
Vector object.
Definition: Vector.h:30
const double & GetX(const unsigned int idx) const
double GetdEdX0() const
get reference energy deposit for fluorescence yield model
OutOfBorderPixelsIterator OutOfBorderPixelsBegin() const
Begin of pixels out of the border.
void SetCherenkovEnergyCutoff(const double eCut) const
TelescopeIterator TelescopesEnd() const
End of the collection of telescopes.
Definition: FDetector/Eye.h:83
utl::CoordinateSystemPtr Get(const std::string &id)
Get a well-known Coordinate System.
const double gcm2
double GetADCVariance() const
double GetIntegral() const
calculate integral
Gaisser Hillas with 4 parameters.
double Y(const double x) const
Get or interpolate the Y value that corresponds to parameter x.
const atm::ProfileResult & EvaluateSlantDepthVsDistance() const
constexpr double m
Definition: AugerUnits.h:121
const std::string & GetMessage() const
Retrieve the message from the exception.
utl::Point GetPosition() const
Eye position.
Class describing the Atmospheric attenuation.
double MaxX() const
Return the maximum value for X (ordinate) stored in the profile.
void AddScanResult(double depth, double error, double minViewAngle)
constexpr double cm2
Definition: AugerUnits.h:118
double GetMag2() const
Definition: Vector.h:61
const double kMaxVariance
const double kLambdaVar

, generated on Tue Sep 26 2023.