SdHorizontalReconstruction.cc
Go to the documentation of this file.
2 #include "FitInterface.h"
3 #include "ShowerFrontFunction.h"
4 #include "ShowerSizeFunction.h"
5 #include "Utilities.h"
6 
7 #include <fwk/LocalCoordinateSystem.h>
8 #include <fwk/CentralConfig.h>
9 
10 #include <utl/ErrorLogger.h>
11 #include <utl/MathConstants.h>
12 #include <utl/PhysicalConstants.h>
13 #include <utl/AugerUnits.h>
14 #include <utl/String.h>
15 #include <utl/NumericalErrorPropagator.h>
16 #include <utl/Transformation.h>
17 #include <utl/EquationSolver.h>
18 
19 #include <tls/MuonProfile.h>
20 #include <tls/VTankResponse.h>
21 #include <tls/TankResponseFactory.h>
22 #include <tls/EMComponent.h>
23 
24 #include <det/Detector.h>
25 
26 #include <sdet/SDetector.h>
27 #include <sdet/STimeVariance.h>
28 
29 #include <fdet/FDetector.h>
30 #include <fdet/Eye.h>
31 
32 #include <evt/Event.h>
33 #include <evt/ShowerRecData.h>
34 #include <evt/ShowerSRecData.h>
35 #include <evt/ShowerFRecData.h>
36 #include <evt/ShowerSimData.h>
37 
38 #include <fevt/FEvent.h>
39 #include <fevt/Eye.h>
40 #include <fevt/EyeRecData.h>
41 #include <fevt/FdComponentSelector.h>
42 
43 #include <sevt/SEvent.h>
44 #include <sevt/EventTrigger.h>
45 #include <sevt/Station.h>
46 #include <sevt/StationRecData.h>
47 #include <sevt/SortCriteria.h>
48 #include <sevt/Header.h>
49 
50 #include <Minuit2/MnMinimize.h>
51 #include <Minuit2/MnHesse.h>
52 #include <Minuit2/MnMinos.h>
53 #include <Minuit2/MnMigrad.h>
54 #include <Minuit2/FCNBase.h>
55 #include <Minuit2/FunctionMinimum.h>
56 #include <Minuit2/MnUserParameters.h>
57 #include <Minuit2/MnUserCovariance.h>
58 #include <Minuit2/MnPrint.h>
59 
60 #include <iomanip>
61 
62 using namespace std;
63 using namespace SdHorizontalReconstructionNS;
64 using namespace fwk;
65 using namespace utl;
66 using namespace evt;
67 using namespace sevt;
68 using namespace fevt;
69 using namespace tls;
70 
72 public:
74  const CoordinateSystemPtr& eyeCS)
75  : fParent(parent), fEyeCS(eyeCS)
76  {}
77 
78  void
79  Transform(vector<double>& output, const vector<double>& input)
80  const
81  {
82  const double sDPtheta = input[0];
83  const double sDPphi = input[1];
84  const double rp = input[2];
85  const double chi0 = input[3];
86 
87  const Point eyePos(0, 0, 0, fEyeCS);
88 
89  // sdp vector: vertical on SDP plane
90  const Vector sdp(1.0, sDPtheta, sDPphi, fEyeCS, Vector::kSpherical);
91 
92  const Vector vertical(0, 0, 1, fEyeCS);
93  Vector horizontalInSDP = cross(sdp, vertical); // horizontal in eyeCS
94  horizontalInSDP.Normalize();
95 
96  const Vector core_eye_vec = rp / sin(kPi - chi0) * horizontalInSDP;
97  Point core = eyePos + core_eye_vec; // preliminary core
98 
99  Transformation rot(Transformation::Rotation(-chi0, sdp, fEyeCS));
100 
101  const Vector axis(rot * horizontalInSDP); // is normalized
102 
103  // shift core along axis to barycenter altitude
104  core -= axis * core.GetZ(fParent.fBaryCS)/axis.GetZ(fParent.fBaryCS);
105 
106  output[eCoreXExt] = core.GetX(fParent.fBaryCS);
107  output[eCoreYExt] = core.GetY(fParent.fBaryCS);
108  output[eThetaExt] = axis.GetTheta(fParent.fBaryCS);
109  output[ePhiExt] = axis.GetPhi(fParent.fBaryCS);
110  }
111 
112 private:
115 };
116 
117 
119 public:
121  const vector<Point>& posList)
122  : fParent(parent), fPosList(posList)
123  {}
124 
125  void
126  Transform(vector<double>& output, const vector<double>& input)
127  const
128  {
129  const double coreX = input[0];
130  const double coreY = input[1];
131  const double theta = input[2];
132  const double phi = input[3];
133  const double distance = input[4];
134  const double ctime = input[5];
135 
136  Point core, origin;
137  fParent.GetShowerAxis(core, origin, coreX, coreY, theta, phi, distance);
138  const Vector showerAxis = origin - core;
139 
140  const CoordinateSystemPtr coreCS = LocalCoordinateSystem::Create(core);
141 
142  output[0] = showerAxis.GetTheta(coreCS);
143  output[1] = showerAxis.GetPhi(coreCS);
144  output[2] = showerAxis.GetMag();
145  output[3] = ctime + showerAxis.GetMag();
146 
147  const size_t n = fPosList.size();
148  for (size_t i = 0; i < n; ++i)
149  output[4 + i] = GetRho(fPosList[i], core, origin);
150  }
151 
152 protected:
154  const vector<Point>& fPosList;
155 };
156 
159 {
160  CentralConfig* cc = CentralConfig::GetInstance();
161 
162  Branch topB = cc->GetTopBranch("SdHorizontalReconstruction");
163 
164  topB.GetChild("MaxRadiusNonTriggeringStations").GetData(fMaxSilentRadius);
165 
166  topB.GetChild("MaxRelativeDistanceNonTriggeringStations").GetData(fMaxSilentRelDistance);
167 
168  topB.GetChild("SilentSignalThreshold").GetData(fSilentSignalThreshold);
169 
170  topB.GetChild("DropStationsBelowThreshold").GetData(fDropStationsBelowThreshold);
171 
172  topB.GetChild("MinTheta").GetData(fMinTheta);
173  topB.GetChild("MaxTheta").GetData(fMaxTheta);
174 
175  string showerFrontModel;
176  topB.GetChild("ShowerFrontModel").GetData(showerFrontModel);
177  if (showerFrontModel == "MuonArrival")
178  fShowerFrontModel = eMuonArrival;
179  else
180  fShowerFrontModel = eSphere;
181 
182  topB.GetChild("MaxDistanceCoreToBarycenter").GetData(fMaxDistanceCoreToBarycenter);
183 
184  topB.GetChild("MaxThetaDifference").GetData(fMaxThetaDifference);
185 
186  topB.GetChild("MaxTimeSigma").GetData(fMaxTimeSigma);
187 
188  topB.GetChild("MaxDistanceStationToExternalCore").GetData(fMaxDistanceStationToExternalCore);
189 
190  topB.GetChild("MinStationsForEnergyFit").GetData(fMinStationsForEnergyFit);
191 
192  topB.GetChild("MinStationsForProductionDistanceFit").GetData(fMinStationsForProductionDistanceFit);
193 
194  string muonProfile;
195  topB.GetChild("MuonProfile").GetData(muonProfile);
196  const Branch muonProfileBranch = cc->GetTopBranch("MuonProfile").GetChild(muonProfile.c_str());
197  fMuonProfile = boost::shared_ptr<MuonProfile>(new MuonProfile(muonProfileBranch));
198 
199  string tankResponse;
200  topB.GetChild("TankResponse").GetData(tankResponse);
201  const Branch tankResponseBranch = cc->GetTopBranch("TankResponse").GetChild(tankResponse.c_str());
202  fTankResponse = &TankResponseFactory::GetInstance().
203  GetTankResponse(tankResponseBranch);
204 
205  string emComponent;
206  topB.GetChild("EMComponent").GetData(emComponent);
207  const Branch EMComponentBranch = cc->GetTopBranch("EMComponent").GetChild(emComponent.c_str());
208  fEMComponent = boost::shared_ptr<EMComponent>(new EMComponent(EMComponentBranch));
209 
210  topB.GetChild("N19Correction").GetData(fN19Correction);
211 
212  topB.GetChild("EnergyConstant").GetData(fEnergyConstant);
213  topB.GetChild("Gamma") .GetData(fGamma);
214 
215  fExternalGeometry = eNone;
216  string externalGeometry;
217  topB.GetChild("ExternalGeometry").GetData(externalGeometry);
218  if (externalGeometry == "MC") fExternalGeometry = eMC;
219  if (externalGeometry == "FixHybrid") fExternalGeometry = eFixHybrid;
220  if (externalGeometry == "SoftHybrid") fExternalGeometry = eSoftHybrid;
221 
222  topB.GetChild("PropagateAxisUncertainty").GetData(fPropagateAxisUncertainty);
223 
224  topB.GetChild("CurvatureModelParameters").GetData(fCurvModelPars);
225 
226  ostringstream msg;
227  msg << "\nParameters:\n"
228  << " Accepted theta angle range : [" << fMinTheta/degree << " , " << fMaxTheta/degree << " ] deg" << '\n'
229  << " Max. radius of non-triggering stations : " << fMaxSilentRadius/km << " km\n"
230  << " Max. rel. distance of non-trig. stations : " << fMaxSilentRelDistance/km << " km\n"
231  << " Silent signal threshold : " << fSilentSignalThreshold << " VEM\n"
232  << " Drop stations below threshold : " << (fDropStationsBelowThreshold ? "yes" : "no") << "\n"
233  << " Allowed distance core,barycenter : " << fMaxDistanceCoreToBarycenter/km << " km"
234  << (fMaxDistanceCoreToBarycenter == 0 ? " (check disabled)\n" : "\n")
235  << " Allowed theta change : " << fMaxThetaDifference/degree << " deg"
236  << (fMaxThetaDifference == 0 ? " (check disabled)\n" : "\n")
237  << " Required stations for energy fit : " << fMinStationsForEnergyFit << '\n'
238  << " Required stations for prod. distance fit : " << fMinStationsForProductionDistanceFit << '\n'
239  << " ShowerFrontModel : " << showerFrontModel << '\n'
240  << " MuonProfile : " << muonProfileBranch.GetName()
241  << " Theta limits [" << fMuonProfile->GetThetaMin()/degree << " , "
242  << fMuonProfile->GetThetaMax()/degree << " ] deg" << "\n"
243  << " TankResponse : " << tankResponseBranch.GetName()
244  << " Theta limits [" << fTankResponse->GetThetaMin()/degree << " , "
245  << fTankResponse->GetThetaMax()/degree << " ] deg" << "\n"
246  << " EMComponent : " << EMComponentBranch.GetName()
247  << " Theta limits [" << fEMComponent->GetThetaMin()/degree << " , "
248  << fEMComponent->GetThetaMax()/degree << " ] deg" << "\n"
249  << " Applying empirical correction N19-unbiased = (1 + A + B*lg(N19))*N19\n"
250  << " A : " << fN19Correction[0] << "\n"
251  << " B : " << fN19Correction[1] << "\n"
252  << " Energy calibration\n"
253  << " EnergyConstant: " << fEnergyConstant/EeV << " EeV\n"
254  << " Gamma : " << fGamma << "\n"
255  << " External geometry : " << externalGeometry << "\n"
256  << " Max. time offset [ext.geom.] : " << fMaxTimeSigma << " sigma\n"
257  << " Allowed station distance [ext.geom.] : " << fMaxDistanceStationToExternalCore/km << " km"
258  << (fMaxDistanceStationToExternalCore == 0 ? " (check disabled)" : "");
259  INFO(msg);
260 
261  return eSuccess;
262 }
263 
265 SdHorizontalReconstruction::Run(evt::Event & event)
266 {
267  {
268  ostringstream msg;
269  msg << "Event " << event.GetHeader().GetId();
270  INFO(msg);
271  }
272 
273  // nothing to do if there is no SEvent with trigger
274  if (!event.HasSEvent())
275  return eContinueLoop;
276  if (!event.GetSEvent().HasTrigger())
277  return eContinueLoop;
278 
279  SEvent& sEvent = event.GetSEvent();
280 
282 
283  SizeData sizeData;
284  AxisData axisData;
285  StationList list;
286  SilentStationList slist;
287  ExternalGeometryData extGeomData;
288 
289  size_t nCandidates = 0;
290 
291  if (!UpdateBarycenter(nCandidates, sEvent))
292  {
293  ERROR("Could not find barycenter!");
294  return eContinueLoop;
295  }
296 
297  if (nCandidates < fMinStationsForEnergyFit) {
298  ostringstream msg;
299  msg << "Event has less than " << fMinStationsForEnergyFit
300  << " stations. Dropping it...";
301  INFO(msg);
302  return eContinueLoop;
303  }
304 
305  if (fExternalGeometry == eNone) {
306  // angular reco is required prior to this module
307  if (!event.HasRecShower() && !event.GetRecShower().HasSRecShower())
308  return eContinueLoop;
309  const ShowerSRecData& sRecSh = event.GetRecShower().GetSRecShower();
310 
311  // initialize core to surface-shifted barycenter
312  // initialize axis to whatever the previous module set
313  sizeData.fPar[eCoreX] = 0;
314  sizeData.fPar[eCoreY] = 0;
315  const Vector& axis = sRecSh.GetAxis();
316  axisData.fPar[eTheta] = axis.GetTheta(fBaryCS);
317  axisData.fPar[ePhi] = axis.GetPhi(fBaryCS);
318  axisData.fPar[eDistance] = ExpectedCurvatureRadius(axisData.fPar[eTheta]);
319  axisData.fPar[eCTime] = -axisData.fPar[eDistance];
320  axisData.fCov[eTheta] = Sqr(sRecSh.GetThetaError());
321  axisData.fCov[ePhi] = Sqr(sRecSh.GetPhiError());
322  axisData.fCov(eTheta,ePhi) = sRecSh.GetCorrelationThetaPhi()*sRecSh.GetThetaError()*sRecSh.GetPhiError();
323  axisData.fChi2 = event.GetRecShower().GetSRecShower().GetAngleChi2();
324  }
325  else
326  {
327  if (!GetExternalGeometry(extGeomData, event))
328  return eContinueLoop;
329 
330  if (!event.HasRecShower())
331  event.MakeRecShower();
332 
333  if (!event.GetRecShower().HasSRecShower())
334  event.GetRecShower().MakeSRecShower();
335 
336  // initialize core to external core
337  // initialize axis to external axis
338  sizeData.fPar[eCoreX] = extGeomData.fPar[eCoreXExt];
339  sizeData.fPar[eCoreY] = extGeomData.fPar[eCoreYExt];
340  axisData.fPar[eTheta] = extGeomData.fPar[eThetaExt];
341  axisData.fPar[ePhi] = extGeomData.fPar[ePhiExt];
342  axisData.fPar[eDistance] = ExpectedCurvatureRadius(axisData.fPar[eTheta]);
343  axisData.fPar[eCTime] = -axisData.fPar[eDistance];
344 
345  if (!CleanEvent(nCandidates, sEvent, axisData, sizeData))
346  return eContinueLoop;
347  }
348 
349  // check whether event is outside of valid theta range
350  if (axisData.fPar[eTheta] < fMinTheta || fMaxTheta < axisData.fPar[eTheta]) {
351  ostringstream msg;
352  msg << " theta = " << axisData.fPar[eTheta]/degree << " deg outside range ["
353  << fMinTheta/degree << ", " << fMaxTheta/degree << "] deg, skipping...";
354  WARNING(msg);
355  return eContinueLoop;
356  }
357 
358  Point core, origin;
359  GetShowerAxis(core, origin, sizeData, axisData);
360  PrepareStationData(list, slist, core, origin, sEvent);
361 
362  ostringstream msg;
363  msg << "\n SD event " << sEvent.GetHeader().GetId() << "\n"
364  << " Theta " << axisData.fPar[eTheta]/deg << " deg (bary)" << '\n'
365  << " # candidate stations = " << nCandidates << '\n'
366  << " # included non-triggering stations = " << slist.size();
367  INFO(msg);
368 
369  {
370  const bool fixAxis = (fExternalGeometry == eMC || fExternalGeometry == eFixHybrid);
371 
372  AxisData update = axisData;
373  INFO("Fit shower front with fixed production distance");
374  if (FitShowerFront(core, update, extGeomData, list, eFixCurvature | (fixAxis ? eFixAxis : 0)))
375  axisData = update;
376 
377  if (nCandidates >= fMinStationsForProductionDistanceFit)
378  {
379  AxisData update = axisData;
380  INFO("Fit shower front with free production distance");
381  if (FitShowerFront(core, update, extGeomData, list, fixAxis ? eFixAxis : 0))
382  axisData = update;
383  }
384  }
385 
386  const bool haveCurv = axisData.fCov[eDistance] > 0;
387 
388  INFO("Fit N19 with core fixed to barycenter, fixed axis, approximate chi2 method");
389  sizeData.fPar[eN19] = 1.0;
390  if (!FitShowerSize(sizeData, axisData, extGeomData, list, slist, eFixCore | eFixAxis | eApproximate))
391  {
392  ERROR("N19 estimate failed, this should never happen! Skipping event...");
393  return eContinueLoop;
394  }
395 
396  if (fExternalGeometry == eMC || fExternalGeometry == eFixHybrid)
397  {
398  INFO("Fit N19 with fixed external geometry (core, axis)");
399  SizeData update = sizeData;
400  if (FitShowerSize(update, axisData, extGeomData, list, slist, eFixCore | eFixAxis))
401  {
402  update.fRecStage = haveCurv ?
403  ShowerSRecData::kLDFSilentsAndCurvature : ShowerSRecData::kLDFSilents;
404  sizeData = update;
405  }
406  }
407  else
408  {
409  INFO("Fit N19 with free core, fixed axis, approximate chi2 method");
410  if (!FitShowerSize(sizeData, axisData, extGeomData, list, slist, eFixAxis | eApproximate))
411  {
412  ERROR("N19 estimate failed, this should never happen! Skipping event...");
413  return eContinueLoop;
414  }
415 
416  SizeData update = sizeData;
417  INFO("Fit N19 with free core, fixed axis");
418  if (FitShowerSize(update, axisData, extGeomData, list, slist, eFixAxis))
419  {
420  update.fRecStage = haveCurv ?
421  ShowerSRecData::kLDFSilentsAndCurvature : ShowerSRecData::kLDFSilents;
422  sizeData = update;
423 
424  if (fPropagateAxisUncertainty)
425  {
426  INFO("Fit N19 with free core, free axis");
427  if (FitShowerSize(update, axisData, extGeomData, list, slist))
428  {
429  update.fRecStage = ShowerSRecData::kLDFGlobalFit;
430  sizeData = update;
431  }
432  }
433  }
434  }
435 
436  // apply empirical N19 correction
437  const double correctionFactor =
438  1.0 + fN19Correction[0] + fN19Correction[1]*log10(sizeData.fPar[eN19]);
439  sizeData.fPar[eN19] *= correctionFactor;
440  for (size_t i = 0; i < SizeData::size; ++i)
441  sizeData.fCov(eN19,i) *= correctionFactor;
442  sizeData.fCov(eN19,eN19) *= correctionFactor;
443 
444  SetReconstructedValues(event, sizeData, axisData, list, slist, extGeomData);
445 
446  return eSuccess;
447 }
448 
449 
450 VModule::ResultFlag SdHorizontalReconstruction::Finish()
451 {
452  return eSuccess;
453 }
454 
455 
456 bool
457 SdHorizontalReconstruction::UpdateBarycenter(size_t& nCandidates,
458  const SEvent& sEvent)
459 {
460  const sdet::SDetector& sDetector = det::Detector::GetInstance().GetSDetector();
461  const CoordinateSystemPtr siteCS =
462  det::Detector::GetInstance().GetSiteCoordinateSystem();
463  const Point siteOrigin(0,0,0, siteCS);
464  const TimeStamp eventTime(sEvent.GetTrigger().GetTime());
465  Vector barySum(0,0,0, siteCS);
466  double timeSum = 0;
467  double weightSum = 0;
468  nCandidates = 0;
470  sIt = sEvent.CandidateStationsBegin(),
471  sEnd = sEvent.CandidateStationsEnd();
472  sIt != sEnd; ++sIt)
473  {
474  const StationRecData& sRec = sIt->GetRecData();
475  const double weight = sqrt(sRec.GetTotalSignal());
476  weightSum += weight;
477  barySum += weight * (sDetector.GetStation(*sIt).GetPosition() - siteOrigin);
478  timeSum += weight * (sRec.GetSignalStartTime() - eventTime).GetInterval();
479  if (!(fDropStationsBelowThreshold && (sRec.GetTotalSignal() < fSilentSignalThreshold)))
480  ++nCandidates;
481  }
482 
483  if (!weightSum) {
484  FATAL("sum of weights = 0!");
485  return false;
486  }
487 
488  fBary = siteOrigin + barySum/weightSum;
489  fBaryTime = eventTime + timeSum/weightSum;
490 
491  // barycenter usually is under Earth's surface
492  // shift barycenter vertically to altitude of closest station
493  double bestR2 = numeric_limits<double>::max();
494  Point bestPos;
496  sIt = sDetector.AllStationsBegin(),
497  sEnd = sDetector.AllStationsEnd();
498  sIt != sEnd; ++sIt)
499  {
500  const double r2 = (sIt->GetPosition() - fBary).GetMag2();
501  if (r2 < bestR2)
502  {
503  bestR2 = r2;
504  bestPos = sIt->GetPosition();
505  }
506  }
507 
508  const CoordinateSystemPtr prelimCS = LocalCoordinateSystem::Create(fBary);
509  fBary += Vector(0, 0, bestPos.GetZ(prelimCS), prelimCS);
510 
511  fBaryCS = LocalCoordinateSystem::Create(fBary);
512  // approximately...
513  fEarthCenter = Point(0, 0, -(kEarthRadius + 1.4*km), fBaryCS);
514 
515  ostringstream msg;
516  msg << "\n # candidate stations = " << nCandidates << "\n"
517  << " barycenter = ( " << fBary.GetX(siteCS)/km
518  << ", " << fBary.GetY(siteCS)/km << ", " << fBary.GetZ(siteCS)/km
519  << ") km (site)\n"
520  << " bary time = " << (timeSum/weightSum)/nanosecond
521  << " [ns] (to event time)";
522  INFO(msg);
523 
524  return true;
525 }
526 
527 
528 bool
529 SdHorizontalReconstruction::GetExternalGeometry(ExternalGeometryData& extGeomData,
530  const Event& event)
531 {
532  // need to reset baryCS: event may still contain accidental stations
533  const sdet::SDetector& sDetector = det::Detector::GetInstance().GetSDetector();
534 
535  switch (fExternalGeometry)
536  {
537  case eMC:
538  {
539  if (!event.HasSimShower()) {
540  ERROR("Event contains no simulation data.");
541  return false;
542  }
543 
544  const ShowerSimData& simShower = event.GetSimShower();
545 
546  const Vector axis = -simShower.GetDirection();
547  Point core = simShower.GetPosition();
548 
549  const CoordinateSystemPtr prelimCS = LocalCoordinateSystem::Create(core);
550 
551  // core may be floating, shift to altitude of closest station
552  double bestR2 = numeric_limits<double>::max();
553  double bestZ = 0.0;
555  sIt = sDetector.AllStationsBegin(),
556  sEnd = sDetector.AllStationsEnd();
557  sIt != sEnd; ++sIt)
558  {
559  const double r2 = (sIt->GetPosition() - core).GetMag2();
560  if (r2 < bestR2)
561  {
562  bestR2 = r2;
563  bestZ = sIt->GetPosition().GetZ(prelimCS);
564  }
565  }
566 
567  core += axis * bestZ/axis.GetZ(prelimCS);
568  fBary = core;
569  fBaryCS = LocalCoordinateSystem::Create(fBary);
570 
571  extGeomData.fPar[eCoreXExt] = 0;
572  extGeomData.fPar[eCoreYExt] = 0;
573  extGeomData.fPar[eThetaExt] = axis.GetTheta(fBaryCS);
574  extGeomData.fPar[ePhiExt] = axis.GetPhi(fBaryCS);
575  }
576  break;
577 
578  case eFixHybrid:
579  case eSoftHybrid:
580  {
581  if (!event.HasFEvent()) {
582  ERROR("Event contains no data from a hybrid reconstruction.");
583  return false;
584  }
585 
586  // compute average over available Fd geometries
587 
588  Point core(0, 0, 0, fBaryCS);
589  Vector axis(0, 0, 0, fBaryCS);
590 
591  int nEyes = 0;
593  eIt = event.GetFEvent().EyesBegin(ComponentSelector::eHasData),
594  eEnd = event.GetFEvent().EyesEnd(ComponentSelector::eHasData);
595  eIt != eEnd; ++eIt)
596  {
597  const EyeRecData& r = eIt->GetRecData();
598  if (r.GetTimeFitChiSquare() >= 10*sqrt(2*r.GetTimeFitNDof())) continue;
599  ++nEyes;
600  const fdet::Eye& detEye = det::Detector::GetInstance().GetFDetector().GetEye(*eIt);
601  const CoordinateSystemPtr eyeCS = detEye.GetEyeCoordinateSystem();
602  const Point eyePos(0, 0, 0, eyeCS);
603 
604  // sdp vector: vertical on SDP plane
605  const Vector sdp(1.0,
606  r.GetSDP().GetTheta(eyeCS),
607  r.GetSDP().GetPhi(eyeCS),
608  eyeCS, Vector::kSpherical);
609 
610  const Vector vertical(0, 0, 1, eyeCS);
611  Vector horizontalInSDP = cross(sdp, vertical); // horizontal in eyeCS
612  horizontalInSDP.Normalize();
613 
614  const Vector core_eye_vec = r.GetRp() / sin(kPi - r.GetChiZero()) * horizontalInSDP;
615  core += (eyePos-fBary) + core_eye_vec;
616 
617  Transformation rot(Transformation::Rotation(-r.GetChiZero(), sdp, eyeCS));
618 
619  axis += rot * horizontalInSDP; // is normalized
620  }
621 
622  if (!nEyes)
623  {
624  ERROR("Event contains no data from a hybrid reconstruction.");
625  return false;
626  }
627 
628  core /= nEyes;
629  axis /= nEyes;
630 
631  const CoordinateSystemPtr prelimCS = LocalCoordinateSystem::Create(core);
632 
633  // core may be floating, shift to altitude of closest station
634  const SEvent& sEvent = event.GetSEvent();
635  const sdet::SDetector& sDetector = det::Detector::GetInstance().GetSDetector();
636  Point bestPos = fEarthCenter;
638  sIt = sEvent.CandidateStationsBegin(),
639  sEnd = sEvent.CandidateStationsEnd();
640  sIt != sEnd; ++sIt)
641  {
642  const Point& pos = sDetector.GetStation(sIt->GetId()).GetPosition();
643  if ((pos - core).GetMag2() < (bestPos - core).GetMag2())
644  bestPos = pos;
645  }
646 
647  core += axis * bestPos.GetZ(prelimCS)/axis.GetZ(prelimCS);
648  if (fMaxDistanceStationToExternalCore > 0 &&
649  (bestPos - core).GetMag() > fMaxDistanceStationToExternalCore)
650  {
651  ostringstream msg;
652  msg << "Event rejected: station with signal " << (bestPos-core).GetMag()/km
653  << " km away from hybrid core [limit: " << fMaxDistanceStationToExternalCore/km << " km]";
654  ERROR(msg);
655  return false;
656  }
657 
658  fBary = core;
659  fBaryCS = LocalCoordinateSystem::Create(fBary);
660 
662  eIt = event.GetFEvent().EyesBegin(ComponentSelector::eHasData),
663  eEnd = event.GetFEvent().EyesEnd(ComponentSelector::eHasData);
664  eIt != eEnd; ++eIt)
665  {
666  const EyeRecData& r = eIt->GetRecData();
667  if (r.GetTimeFitChiSquare() >= 10*sqrt(2*r.GetTimeFitNDof())) continue;
668  const fdet::Eye& detEye = det::Detector::GetInstance().GetFDetector().GetEye(*eIt);
669  const CoordinateSystemPtr eyeCS = detEye.GetEyeCoordinateSystem();
670  FdGeometryPropagator propagate(*this, eyeCS);
671 
672  vector<double> iPar(4), oPar(4);
673  CovarianceMatrix iCov(4), oCov(4);
674 
675  enum Parameters { eTheta = 0, ePhi = 1, eRp = 2, eChi0 = 3 };
676  iPar[eTheta] = r.GetSDP().GetTheta(eyeCS);
677  iPar[ePhi] = r.GetSDP().GetPhi(eyeCS);
678  iPar[eRp] = r.GetRp();
679  iPar[eChi0] = r.GetChiZero();
680  iCov[eTheta] = Sqr(r.GetSDPThetaError());
681  iCov[ePhi] = Sqr(r.GetSDPPhiError());
682  iCov[eRp] = Sqr(r.GetRpError());
683  iCov[eChi0] = Sqr(r.GetChiZeroError());
684  iCov(eTheta, ePhi) = r.GetSDPCorrThetaPhi()*sqrt(iCov[eTheta]*iCov[ePhi]);
685  iCov(eRp, eChi0) = r.GetRpChi0Correlation()*sqrt(iCov[eRp]*iCov[eChi0]);
686 
687  propagate(oPar, oCov, iPar, iCov);
688 
689  for (size_t i = 0; i < 4; ++i)
690  {
691  extGeomData.fPar[i] += oPar[i];
692  for (size_t j = 0; j < 4; ++j)
693  extGeomData.fInvCov[i][j] += oCov(i,j);
694  }
695  }
696 
697  for (size_t i = 0; i < 4; ++i)
698  {
699  extGeomData.fPar[i] /= nEyes;
700  for (size_t j = 0; j < 4; ++j)
701  extGeomData.fInvCov[i][j] /= nEyes;
702  }
703 
704  try {
705  InvertMatrix(4, extGeomData.fInvCov);
706  }
707  catch (const DoesNotComputeException& e)
708  {
709  return false;
710  }
711  }
712  break;
713  default:
714  return false;
715  }
716 
717  return true;
718 }
719 
720 
721 bool
722 SdHorizontalReconstruction::CleanEvent(std::size_t& nCandidates,
723  sevt::SEvent& sEvent,
724  const AxisData& axisData,
725  const SizeData& sizeData)
726  const
727 { // reject stations that are grossly inconsistent with external geometry
728  Point core, origin;
729  GetShowerAxis(core, origin, sizeData, axisData);
730  ShowerFrontFunction frontFcn(*this, core, StationList(), ExternalGeometryData());
731 
732  const sdet::SDetector& sDetector =
733  det::Detector::GetInstance().GetSDetector();
734 
735  // pick most probable station as reference
736  double bestWeight = 0;
737  int bestId = 0;
738  double bestSigmaCT = 0;
740  sIt = sEvent.CandidateStationsBegin(),
741  sEnd = sEvent.CandidateStationsEnd();
742  sIt != sEnd; ++sIt)
743  {
744  const int sId = sIt->GetId();
745  const double s = sIt->GetRecData().GetTotalSignal();
746  const double rho = GetRho(sDetector.GetStation(*sIt).GetPosition(), core, origin);
747  const double weight = s/rho;
748  if (bestWeight < weight)
749  {
750  bestWeight = weight;
751  bestId = sId;
752  }
753  }
754 
755  // use it to set originCT
756  double originCT = 0;
757  if (bestId > 0)
758  {
759  ostringstream msg;
760  msg << "Station " << bestId << " serves as time reference to clean event";
761  INFO(msg);
762  const StationRecData& sRec = sEvent.GetStation(bestId).GetRecData();
763  StationData sd;
764  sd.fPos = sDetector.GetStation(bestId).GetPosition();
765  sd.fSignal = sRec.GetTotalSignal();
766  sd.fCTime = kSpeedOfLight *
767  (sRec.GetSignalStartTime() - fBaryTime).GetInterval();
768  sd.fT50 = sRec.GetT50();
769  double meanCT;
770  frontFcn.Predict(meanCT, bestSigmaCT, sd, origin, 0);
771  originCT = sd.fCTime-meanCT;
772  }
773  else
774  {
775  ERROR("No reference station found");
776  return false;
777  }
778 
779  // reject stations based on shower front model
781  sIt = sEvent.CandidateStationsBegin(),
782  sEnd = sEvent.CandidateStationsEnd();
783  sIt != sEnd; ++sIt)
784  {
785  const StationRecData& sRec = sIt->GetRecData();
786 
787  StationData sd;
788  sd.fPos = sDetector.GetStation(*sIt).GetPosition();
789  sd.fSignal = sRec.GetTotalSignal();
790  sd.fCTime = kSpeedOfLight *
791  (sRec.GetSignalStartTime() - fBaryTime).GetInterval();
792  sd.fT50 = sRec.GetT50();
793 
794  double meanCT, sigmaCT;
795  frontFcn.Predict(meanCT, sigmaCT, sd, origin, originCT);
796  sigmaCT = sqrt(Sqr(sigmaCT) + Sqr(bestSigmaCT));
797 
798  if (abs(sd.fCTime - meanCT) > fMaxTimeSigma*sigmaCT)
799  {
800  ostringstream msg;
801  msg << "Station " << sIt->GetId() << " rejected:"
802  " time residual to external geometry = "
803  << fixed << setprecision(2)
804  << (sd.fCTime - meanCT)/sigmaCT << " sigma [limit: " << fMaxTimeSigma << "]";
805  INFO(msg);
806  sIt->SetRejected(sevt::StationConstants::eOutOfTime);
807  if (!(fDropStationsBelowThreshold && (sd.fSignal < fSilentSignalThreshold)))
808  --nCandidates;
809  }
810  }
811 
812  return nCandidates > 0;
813 }
814 
815 
816 bool
817 SdHorizontalReconstruction::FitShowerFront(const Point& core,
818  AxisData& ad,
819  const ExternalGeometryData& gd,
820  const StationList& list,
821  const int option)
822  const
823 {
824  using namespace ROOT::Minuit2;
825 
826  MnUserParameters pars;
827 
828  if (ad.fPar[eTheta] >= 89*degree) ad.fPar[eTheta] = 88*degree;
829 
830  pars.Add("theta", ad.fPar[eTheta], 0.01); // 0
831  pars.Add("phi", ad.fPar[ePhi], 0.01); // 1
832  pars.Add("distance", ad.fPar[eDistance]/km, 0.1); // 2
833  pars.Add("ctime", ad.fPar[eCTime]/km, 0.1); // 3
834 
835  pars.SetLimits("theta", 0, 89*degree);
836  pars.SetLowerLimit("distance", 0);
837 
838  ad.fNFree = 4;
839  if (option & eFixDirection)
840  {
841  pars.Fix("theta");
842  pars.Fix("phi");
843  ad.fNFree -= 2;
844  }
845 
846  if (option & eFixCurvature)
847  {
848  pars.Fix("distance");
849  ad.fNFree -= 1;
850  }
851 
852  ShowerFrontFunction fcn(*this, core, list, gd);
853 
854  MnMinimize m(fcn, pars, 1);
855 
856  FunctionMinimum fmin = m(10000);
857 
858  if (fmin.IsAboveMaxEdm() || fmin.HasReachedCallLimit() || !fmin.IsValid())
859  {
860  ERROR("Fit failed: no convergence");
861  return false;
862  }
863 
864  MnHesse hesse(2);
865  hesse(fcn, fmin, 10000);
866 
867  if (!fmin.IsValid())
868  {
869  ERROR("Fit failed: error in computation of covariance matrix");
870  return false;
871  }
872 
873  const double oldTheta = ad.fPar[eTheta];
874 
875  // get best parameters
876  ad.fPar[eTheta] = fmin.UserParameters().Value(0);
877  ad.fPar[ePhi] = fmin.UserParameters().Value(1);
878  ad.fPar[eDistance] = fmin.UserParameters().Value(2)*km;
879  ad.fPar[eCTime] = fmin.UserParameters().Value(3)*km;
880 
881  const size_t nVar = pars.VariableParameters();
882 
883  // get covariance
884  ad.fCov = 0;
885  for (size_t i = 0; i < nVar; ++i)
886  for (size_t j = 0; j < nVar; ++j)
887  {
888  if (std::isnan(fmin.UserCovariance()(i, j)))
889  return false;
890 
891  const size_t k = m.ExtOfInt(i);
892  const size_t l = m.ExtOfInt(j);
893  ad.fCov(k, l) = fmin.UserCovariance()(i, j);
894  if (k == eDistance || k == eCTime)
895  ad.fCov(k, l) *= km;
896  if (l == eDistance || l == eCTime)
897  ad.fCov(k, l) *= km;
898  }
899 
900  {
901  ostringstream msg;
902  msg << fixed << setprecision(2)
903  << "Found minimum after " << fmin.NFcn() << " evaluations\n"
904  << " theta = " << ad.fPar[eTheta]/degree
905  << " +/- " << ad.fCov.Std(eTheta)/degree << " deg (bary)\n"
906  << " phi = " << ad.fPar[ePhi]/degree
907  << " +/- " << ad.fCov.Std(ePhi)/degree << " deg (bary)\n"
908  << " distance = " << ad.fPar[eDistance]/km
909  << " +/- " << ad.fCov.Std(eDistance)/km << " km (bary)\n"
910  << " ctime = " << ad.fPar[eCTime]/km
911  << " +/- " << ad.fCov.Std(eCTime)/km << " km (bary)";
912  INFO(msg);
913  }
914 
915  if (fMaxThetaDifference > 0 && (abs(oldTheta - ad.fPar[eTheta]) > fMaxThetaDifference))
916  {
917  ostringstream msg;
918  msg << fixed << setprecision(2)
919  << "Fit rejected: theta changed by " << abs(oldTheta - ad.fPar[eTheta])/degree << " deg, [limit: "
920  << fMaxThetaDifference/degree << " deg]";
921  ERROR(msg);
922  return false;
923  }
924 
925  const double newChi2 = fmin.Fval();
926 
927  // do not allow new chi2 to be larger than old chi2 + 1 sigma + 1
928  if (ad.fChi2 > 1e-3 && (newChi2 > (ad.fChi2 + sqrt(2*max(ad.fChi2,newChi2)) + 1)))
929  {
930  ostringstream msg;
931  msg << fixed << setprecision(2)
932  << "Fit rejected: new chi^2 = " << newChi2 << ", old chi^2 = " << ad.fChi2;
933  ERROR(msg);
934  return false;
935  }
936 
937  ad.fChi2 = newChi2;
938 
939  return true;
940 }
941 
942 
943 bool
944 SdHorizontalReconstruction::FitShowerSize(SizeData& sd,
945  const AxisData& ad,
946  const ExternalGeometryData& gd,
947  const StationList& list,
948  const SilentStationList& slist,
949  const int option)
950  const
951 {
952  using namespace ROOT::Minuit2;
953 
954  MnUserParameters pars;
955 
956  pars.Add("n19", sd.fPar[eN19], 1.0); // 0
957  pars.Add("coreX", sd.fPar[eCoreX]/km, 0.1); // 1
958  pars.Add("coreY", sd.fPar[eCoreY]/km, 0.1); // 2
959  pars.Add("theta", ad.fPar[eTheta], 0.01); // 3
960  pars.Add("phi", ad.fPar[ePhi], 0.01); // 4
961  pars.Add("distance", ad.fPar[eDistance]/km, 0.1); // 5
962 
963  pars.SetLowerLimit("n19", 0);
964  pars.SetLimits("theta", 0, 89*degree);
965  pars.SetLowerLimit("distance", 0);
966 
967  sd.fNFree = 3;
968  if (option & eFixCore)
969  {
970  pars.Fix("coreX");
971  pars.Fix("coreY");
972  sd.fNFree -= 2;
973  }
974 
975  if (option & eFixAxis || ad.fCov[eTheta] < 1e-8 || ad.fCov[ePhi] < 1e-8)
976  {
977  pars.Fix("theta");
978  pars.Fix("phi");
979  }
980 
981  if (option & eFixAxis || ad.fCov[eDistance] < 1e-8)
982  pars.Fix("distance");
983 
984  ShowerSizeFunction fcn(*this, list, slist, ad, gd);
985  if (option & eApproximate)
986  fcn.SetType(ShowerSizeFunction::eApprox);
987 
988  MnMinimize m(fcn, pars, 1);
989 
990  FunctionMinimum fmin = m(10000);
991 
992  if (fmin.IsAboveMaxEdm() || fmin.HasReachedCallLimit() || !fmin.IsValid())
993  {
994  ERROR("Fit failed: no convergence");
995  return false;
996  }
997 
998  MnHesse hesse(2);
999  hesse(fcn, fmin, 10000);
1000 
1001  if (!fmin.IsValid())
1002  {
1003  ERROR("Fit failed: error in computation of covariance matrix");
1004  return false;
1005  }
1006 
1007  sd.fNLogLike = fmin.Fval();
1008 
1009  // get best parameters
1010  sd.fPar[eN19] = fmin.UserParameters().Value(0);
1011  sd.fPar[eCoreX] = fmin.UserParameters().Value(1)*km;
1012  sd.fPar[eCoreY] = fmin.UserParameters().Value(2)*km;
1013 
1014  const size_t nVar = pars.VariableParameters();
1015 
1016  // get covariance
1017  sd.fCov = 0;
1018  for (size_t i=0;i<nVar;++i)
1019  for (size_t j=0;j<nVar;++j)
1020  {
1021  if (std::isnan(fmin.UserCovariance()(i, j)))
1022  return false;
1023 
1024  const size_t k = m.ExtOfInt(i);
1025  const size_t l = m.ExtOfInt(j);
1026  if (k < 3 && l < 3)
1027  {
1028  sd.fCov(k, l) = fmin.UserCovariance()(i, j);
1029  if (k == eCoreX || k == eCoreY)
1030  sd.fCov(k, l) *= km;
1031  if (l == eCoreX || l == eCoreY)
1032  sd.fCov(k, l) *= km;
1033  }
1034  }
1035 
1036  {
1037  ostringstream msg;
1038  msg << fixed << setprecision(2)
1039  << "Found minimum after " << fmin.NFcn() << " evaluations\n"
1040  << " N19 = " << sd.fPar[eN19] <<
1041  " +/- " << sd.fCov.Std(eN19) << "\n"
1042  << " coreX = " << sd.fPar[eCoreX]/km <<
1043  " +/- " << sd.fCov.Std(eCoreX)/km << " km (bary)\n"
1044  << " coreY = " << sd.fPar[eCoreY]/km <<
1045  " +/- " << sd.fCov.Std(eCoreY)/km << " km (bary)";
1046  INFO(msg);
1047  }
1048 
1049  if (fMaxDistanceCoreToBarycenter > 0)
1050  {
1051  Point core, origin;
1052  GetShowerAxis(core, origin, sd, ad);
1053  Point bary(0, 0, 0, fBaryCS);
1054 
1055  // check for unreasonable core
1056  const double d = (core - bary).GetMag();
1057  if (d > fMaxDistanceCoreToBarycenter) {
1058  ostringstream err;
1059  err << "Fit rejected: Distance between core and barycenter " << d/kilometer
1060  << " km too large [limit: " << fMaxDistanceCoreToBarycenter/km << " km]";
1061  ERROR(err);
1062  return false;
1063  }
1064  }
1065 
1066  return true;
1067 }
1068 
1069 
1070 void
1071 SdHorizontalReconstruction::PrepareStationData(StationList& list,
1072  SilentStationList& slist,
1073  const Point& core,
1074  const Point& origin,
1075  const SEvent& sEvent)
1076  const
1077 {
1078  const sdet::SDetector& sDetector =
1079  det::Detector::GetInstance().GetSDetector();
1080 
1082  sIt = sEvent.CandidateStationsBegin(),
1083  sEnd = sEvent.CandidateStationsEnd();
1084  sIt != sEnd; ++sIt)
1085  {
1086  list.push_back(StationData());
1087  StationData& sd = list.back();
1088  const StationRecData& sRec = sIt->GetRecData();
1089 
1090  sd.fId = sIt->GetId();
1091  sd.fPos = sDetector.GetStation(*sIt).GetPosition();
1092  sd.fSignal = sRec.GetTotalSignal();
1093  sd.fCTime = kSpeedOfLight *
1094  (sRec.GetSignalStartTime() - fBaryTime).GetInterval();
1095  sd.fT50 = sRec.GetT50();
1096  sd.fSaturated = sIt->IsLowGainSaturation();
1098  if (sd.fSaturated && sd.fRecoveryErr > 0)
1099  sd.fSignal = sRec.GetRecoveredSignal();
1100  sd.fRejected = !sIt->IsCandidate();
1101  }
1102 
1104  sIt = sEvent.SilentStationsBegin(),
1105  sEnd = sEvent.SilentStationsEnd();
1106  sIt != sEnd; ++sIt)
1107  {
1108  const Point& pos = sDetector.GetStation(*sIt).GetPosition();
1109 
1110  if (GetRho(pos, core, origin) > fMaxSilentRadius)
1111  continue;
1112 
1113  for (StationList::const_iterator it = list.begin();
1114  it != list.end(); ++it)
1115  {
1116  if ((pos - it->fPos).GetMag() < fMaxSilentRelDistance)
1117  {
1118  slist.push_back(SilentStationData());
1119  SilentStationData& sd = slist.back();
1120  sd.fId = sIt->GetId();
1121  sd.fPos = pos;
1122  // finding one candidate station nearby is enough
1123  break;
1124  }
1125  }
1126  }
1127 }
1128 
1129 
1130 void
1131 SdHorizontalReconstruction::SetReconstructedValues(Event& event,
1132  const SizeData& sizeData,
1133  const AxisData& axisData,
1134  const StationList& list,
1135  const SilentStationList& slist,
1136  const ExternalGeometryData& extGeomData)
1137  const
1138 {
1139  // Convert N19 to energy
1140  const double energy =
1141  fEnergyConstant * pow(sizeData.fPar[eN19],fGamma);
1142  const double energyErr =
1143  fGamma * sizeData.fCov.Std(eN19) / sizeData.fPar[eN19] * energy;
1144 
1145  {
1146  ostringstream msg;
1147 
1148  msg << "Result:\n"
1149  << fixed << setprecision(2)
1150  << " N19 (corrected) : "
1151  << sizeData.fPar[eN19] << " +/- " << sizeData.fCov.Std(eN19) << "\n"
1152  << " Energy / EeV : "
1153  << energy/EeV << " +/- " << energyErr/EeV;
1154 
1155  if (event.HasSimShower()) {
1156  const double energyMC = event.GetSimShower().GetEnergy();
1157  const double diffToMC = energy/energyMC-1.;
1158  const double diffToMCSigma =
1159  (energy-energyMC)/energyErr;
1160  msg << "\n Energy (MC-input) / EeV : "
1161  << energyMC/EeV
1162  << " ( " << diffToMC*100.
1163  << " % | " << diffToMCSigma << " std.dev. )";
1164  }
1165 
1166  INFO(msg);
1167  }
1168 
1169  const bool haveCurvature = axisData.fCov[eDistance] > 0;
1170 
1171  Point core, origin;
1172  GetShowerAxis(core, origin, sizeData, axisData);
1173  Vector axis = origin - core;
1174  axis.Normalize();
1175 
1176  vector<double> oPar;
1177  CovarianceMatrix oCov;
1178  const size_t nAxis = 4;
1179  { // propagate core uncertainty into shower axis parameters and station radii and
1180  // propagate axis parameters from bary CS to core CS
1181  // Beware: eCTime is time *at core* (not at origin) after propagation
1182  vector<double> iPar(6);
1183  iPar[0] = sizeData.fPar[eCoreX];
1184  iPar[1] = sizeData.fPar[eCoreY];
1185  iPar[2] = axisData.fPar[eTheta];
1186  iPar[3] = axisData.fPar[ePhi];
1187  iPar[4] = axisData.fPar[eDistance];
1188  iPar[5] = axisData.fPar[eCTime];
1189  CovarianceMatrix iCov(6);
1190  iCov[0] = sizeData.fCov[eCoreX];
1191  iCov[1] = sizeData.fCov[eCoreY];
1192  iCov(0,1) = sizeData.fCov(eCoreX, eCoreY);
1193  for (size_t i = 0; i < AxisData::size; ++i)
1194  for (size_t j = i; j < AxisData::size; ++j)
1195  iCov(2+i, 2+j) = axisData.fCov(i, j);
1196 
1197  vector<Point> posList;
1198  for (StationList::const_iterator
1199  sIt = list.begin(),
1200  sEnd = list.end();
1201  sIt != sEnd; ++sIt)
1202  posList.push_back(sIt->fPos);
1203 
1204  oPar.resize(nAxis + posList.size());
1205  oCov.SetExtent(nAxis + posList.size());
1206 
1207  FinalPropagator prop(*this, posList);
1208  prop(oPar, oCov, iPar, iCov);
1209 
1210  // if parameter was fixed to begin with
1211  // the error propagation may not assign a non-zero uncertainty
1212  for (size_t i = 0; i < 4; ++i)
1213  for (size_t j = i; j < 4; ++j)
1214  if (iCov(2+i,2+j) == 0) oCov(i,j) = 0;
1215  }
1216 
1217  const double n19 = sizeData.fPar[eN19];
1218 
1219  const CoordinateSystemPtr coreCS =
1220  LocalCoordinateSystem::Create(core);
1221 
1222  const double theta = axis.GetTheta(coreCS);
1223  const double phi = axis.GetPhi(coreCS);
1224 
1225  const CoordinateSystemPtr showerPlaneCS =
1226  GetShowerCoordinateSystem(theta, phi, coreCS);
1227 
1228  double timeSum = 0;
1229  double energyChi2 = 0;
1230  double axisChi2 = 0;
1231  int nUsed = 0;
1232  // calculate signal and time residuals and corresponding chi2s
1233  ShowerFrontFunction frontFcn(*this, core, list, extGeomData);
1234  ShowerSizeFunction sizeFcn(*this, list, slist, axisData, extGeomData);
1235  for (size_t i = 0; i < list.size(); ++i)
1236  {
1237  const StationData& sd = list[i];
1238  StationRecData& sRec = event.GetSEvent().GetStation(sd.fId).GetRecData();
1239 
1240  sRec.SetAzimuthShowerPlane(sd.fPos.GetPhi(showerPlaneCS));
1241  sRec.SetSPDistance(oPar[nAxis + i], oCov.Std(nAxis + i));
1242 
1243  double signalPred = 0, signalSigma = 0;
1244  sizeFcn.Predict(signalPred, signalSigma, sd.fPos, origin, n19, core, sd.fRecoveryErr);
1245 
1246  if (signalSigma == 0)
1247  {
1248  ostringstream msg;
1249  msg << fixed << setprecision(2)
1250  << "Station " << sd.fId << ":"
1251  << "signal = " << sd.fSignal << " "
1252  << "pred = " << signalPred << " "
1253  << "sigma = " << signalSigma;
1254  WARNING(msg);
1255  }
1256  else
1257  {
1258  const double residual = (sd.fSignal - signalPred)/signalSigma;
1259  // sd.fSignal may be recovered, set original signal here (like in LDFFinder)
1260  sRec.SetTotalSignal(sRec.GetTotalSignal(), signalSigma);
1261  sRec.SetLDFResidual(residual);
1262  if (!sd.fRejected)
1263  energyChi2 += Sqr(residual);
1264  }
1265 
1266  if (axisData.fNFree > 0) {
1267  double meanCT, sigmaCT;
1268  frontFcn.Predict(meanCT, sigmaCT, sd, origin, axisData.fPar[eCTime]);
1269  const double timeResidual = (sd.fCTime - meanCT)/sigmaCT;
1270  sRec.SetResidual(timeResidual);
1271  if (!sd.fRejected)
1272  {
1273  axisChi2 += Sqr(timeResidual);
1274  timeSum += timeResidual;
1275  }
1276  }
1277 
1278  if (!sd.fRejected)
1279  ++nUsed;
1280  }
1281 
1282  ShowerSRecData& recShower = event.GetRecShower().GetSRecShower();
1283 
1284  // make average 1D LDF for the lack of something better
1285  if (!recShower.HasLDF())
1286  recShower.MakeLDF();
1287 
1288  {
1289  TabulatedFunctionErrors& tabulatedLDF = recShower.GetLDF();
1290  tabulatedLDF.Clear();
1291 
1292  const double x0 = log(1);
1293  const double x1 = log(10000);
1294 
1295  const size_t nLDFPoints = 20;
1296  for (size_t i = 0; i < nLDFPoints; ++i)
1297  {
1298  const double z = float(i)/(nLDFPoints-1);
1299  double mean = 0, smin = 0, smax = 0;
1300  const size_t nPsi = 4;
1301  const double rho0 = exp((1.0-z)*x0 + z*x1);
1302  for (size_t j = 0; j < nPsi; ++j) {
1303  const double psi = 2*kPi*double(j)/(nPsi-1);
1304  Point pos(rho0, psi, 0, showerPlaneCS, Point::kCylindrical);
1305  pos -= pos.GetZ(coreCS)/axis.GetZ(coreCS)*axis;
1306 
1307  double signalPred = 0, signalSigma = 0;
1308  sizeFcn.Predict(signalPred, signalSigma, pos, origin, n19, core);
1309 
1310  mean += signalPred/nPsi;
1311  if (signalPred < smin || smin == 0) smin = signalPred;
1312  if (signalPred > smax || smax == 0) smax = signalPred;
1313  }
1314  tabulatedLDF.PushBack(rho0, 0, mean, 0.5*(smax-smin));
1315  }
1316  }
1317 
1318  if (axisData.fNFree > 0)
1319  {
1320  // oPar[eCTime] is time at core, not origin time!
1321  const TimeStamp finalCoreTime = fBaryTime + oPar[eCTime]/kSpeedOfLight;
1322  const double finalCoreTimeErr = oCov.Std(eCTime)/kSpeedOfLight;
1323  recShower.SetAxis(axis);
1324  recShower.SetCoreTime(finalCoreTime, finalCoreTimeErr);
1325  recShower.SetAngleChi2(axisChi2, max(nUsed - axisData.fNFree, 0));
1326  const double timeMean = timeSum / nUsed;
1327  const double timeSpread = sqrt(axisChi2/(nUsed - 1));
1328  recShower.SetTimeResidualMean(timeMean);
1329  recShower.SetTimeResidualSpread(timeSpread);
1330 
1331  recShower.SetThetaError(oCov.Std(eTheta));
1332  recShower.SetPhiError(oCov.Std(ePhi));
1333  recShower.SetCorrelationThetaPhi( oCov(eTheta,ePhi)/sqrt(oCov[eTheta]*oCov[ePhi]) );
1334 
1335  const double rc = oPar[eDistance];
1336  if (haveCurvature)
1337  {
1338  const double rcErr = oCov.Std(eDistance);
1339  recShower.SetCurvature(1.0/rc, rcErr/Sqr(rc));
1340  }
1341  else
1342  recShower.SetCurvature(1.0/rc, 0);
1343  }
1344  else
1345  {
1346  // core moved but have axis from plane fit: shift core time
1347  const TimeInterval cdiff =
1348  recShower.GetAxis() * (recShower.GetCorePosition() - core);
1349  const TimeStamp newCoreTime =
1350  recShower.GetCoreTime() + cdiff/kSpeedOfLight;
1351  recShower.SetCurvature(0.0, 0.0);
1352  recShower.SetCoreTime(newCoreTime, recShower.GetCoreTimeError());
1353  }
1354 
1355  const Vector coreErr(sizeData.fCov.Std(eCoreX),
1356  sizeData.fCov.Std(eCoreY),
1357  0, coreCS);
1358 
1359  recShower.SetCorePosition (core);
1360  recShower.SetCoreError (coreErr);
1361  recShower.SetCorrelationXY(sizeData.fCov(eCoreX, eCoreY)/
1362  sqrt(sizeData.fCov[eCoreX]*sizeData.fCov[eCoreY]));
1363  recShower.SetEnergy (energy, energyErr);
1365  recShower.SetShowerSize (sizeData.fPar[eN19], sizeData.fCov.Std(eN19));
1366  recShower.SetLDFChi2 (energyChi2, max(nUsed - sizeData.fNFree, 0));
1367  recShower.SetLDFLikelihood(sizeData.fNLogLike);
1368 
1369  recShower.SetLDFRecStage (sizeData.fRecStage);
1370 }
1371 
1372 
1373 void
1374 SdHorizontalReconstruction::GetShowerAxis(Point& core,
1375  Point& origin,
1376  const double coreX,
1377  const double coreY,
1378  const double theta,
1379  const double phi,
1380  const double distance)
1381  const
1382 {
1383  core = Point(coreX, coreY, 0, fBaryCS);
1384  origin = Point(distance, theta, phi, fBaryCS, Point::kSpherical);
1385 }
1386 
1387 
1388 void
1389 SdHorizontalReconstruction::GetShowerAxis(Point& core,
1390  Point& origin,
1391  const SizeData& sd,
1392  const AxisData& ad)
1393  const
1394 {
1395  GetShowerAxis(core, origin, sd.fPar[eCoreX], sd.fPar[eCoreY],
1396  ad.fPar[eTheta], ad.fPar[ePhi], ad.fPar[eDistance]);
1397 }
1398 
1399 
1400 void
1401 SdHorizontalReconstruction::LocalCoordinates(double& xProjected,
1402  double& yProjected,
1403  double& rho, double& theta,
1404  const utl::Point& pos,
1405  const utl::Point& origin,
1406  const utl::Point& core)
1407  const
1408 {
1409  using namespace utl;
1410 
1411  const Vector posToOrigin = origin - pos;
1412  const double d = pos.GetZ(fBaryCS)/posToOrigin.GetZ(fBaryCS);
1413  const Vector corePlanePos = pos - core - d*posToOrigin;
1414  // good approximation: pretend that baryCS has same orientation as coreCS
1415  xProjected = corePlanePos.GetX(fBaryCS);
1416  yProjected = corePlanePos.GetY(fBaryCS);
1417  rho = GetRho(pos, core, origin);
1418  theta = Angle(posToOrigin, (pos - fEarthCenter));
1419 }
1420 
1421 
1422 double
1423 SdHorizontalReconstruction::ExpectedCurvatureRadius(const double theta)
1424  const
1425 {
1426  /* Empirical parameterization obtained by fitting real events,
1427  valid from 50 deg to 90 deg */
1428  return exp(fCurvModelPars[0] + fCurvModelPars[1] * pow(theta, fCurvModelPars[2]))*utl::km;
1429 }
AxialVector cross(const Vector &l, const Vector &r)
vector cross product
Definition: OperationsAV.h:32
const SdHorizontalReconstruction & fParent
Class to access station level reconstructed data.
Facade for any instance of EMComponent.
Definition: EMComponent.h:43
void SetCurvature(const double curvature, const double error)
gaussian curvature = 1 / Rc
void SetTotalSignal(const double signal, const double sErr=0)
Total integrated signal in VEM unit, averaged over pmts.
void SetShowerSize(const double value, const double error)
void Normalize()
Definition: Vector.h:64
const double degree
constexpr T Sqr(const T &x)
Point object.
Definition: Point.h:32
double Angle(const double theta1, const double phi1, const double theta2, const double phi2)
SilentStationIterator SilentStationsEnd()
Definition: SEvent.h:90
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 SetPhiError(const double err)
constexpr double km
Definition: AugerUnits.h:125
Interface class to access to the SD Reconstruction of a Shower.
StationIterator AllStationsEnd() const
End of the collection of pointers to all stations in the history of the array.
Definition: SDetector.h:126
boost::filter_iterator< ComponentSelector, ConstAllEyeIterator > ConstEyeIterator
Definition: FEvent.h:56
Class to handle average muon profiles.
Definition: MuonProfile.h:38
bool HasRecShower() const
const utl::TabulatedFunctionErrors & GetLDF() const
bool HasFEvent() const
Interface class to access to the SD part of an event.
Definition: SEvent.h:39
void SetAzimuthShowerPlane(const double azimuth)
Azimuth in shower plane coordinates.
double GetTheta(const CoordinateSystemPtr &coordinateSystem) const
zenith (theta) angle in spherical coordinates
Definition: BasicVector.h:248
double GetChiZero() const
Definition: EyeRecData.h:85
ShowerRecData & GetRecShower()
bool HasSimShower() const
const SdHorizontalReconstruction & fParent
EventTrigger & GetTrigger()
Get the object with central trigger data, throw if n.a.
Definition: SEvent.h:148
unsigned int GetTimeFitNDof() const
Definition: EyeRecData.h:93
sevt::StationRecData & GetRecData()
Get station level reconstructed data.
#define INFO(message)
Macro for logging informational messages.
Definition: ErrorLogger.h:161
double GetRho(const utl::Point &pos, const utl::Point &core, const utl::Point &origin)
void SetAngleChi2(const double chi2, const double ndof)
int GetId() const
Definition: SEvent/Header.h:20
void Predict(double &meanCT, double &sigmaCT, const StationData &sd, const utl::Point &originPos, const double originCT) const
#define FATAL(message)
Macro for logging fatal messages.
Definition: ErrorLogger.h:167
boost::filter_iterator< CandidateStationFilter, StationIterator > CandidateStationIterator
Iterator over candidate stations.
Definition: SEvent.h:68
void Init()
Initialise the registry.
Detector description interface for Eye-related data.
Definition: FDetector/Eye.h:45
Branch GetChild(const std::string &childName) const
Get child of this Branch by child name.
Definition: Branch.cc:211
CoordinateSystemPtr GetShowerCoordinateSystem(const double theta, const double phi, const Point &core)
boost::filter_iterator< SilentStationFilter, ConstStationIterator > ConstSilentStationIterator
Definition: SEvent.h:86
double pow(const double x, const unsigned int i)
const double EeV
Definition: GalacticUnits.h:34
double GetMag() const
Definition: Vector.h:58
double GetSDPPhiError() const
Definition: EyeRecData.h:78
void SortStations(const OrderingCriterion ord) const
Sort the list of stations by the criterion specified in an OrderingCriterion object.
Definition: SEvent.h:172
void SetLDFChi2(const double chi2, const double ndof)
void SetExtent(const unsigned int n)
double GetChiZeroError() const
Definition: EyeRecData.h:86
void Predict(double &meanSignal, double &sigmaSignal, const utl::Point &station, const utl::Point &origin, const double n19, const utl::Point &core, const double recoveryErr=0) const
A TimeStamp holds GPS second and nanosecond for some event.
Definition: TimeStamp.h:110
utl::Point GetPosition() const
Tank position.
StationIterator AllStationsBegin() const
Beginning of the collection of pointers to all stations in the history of the array.
Definition: SDetector.h:121
constexpr double deg
Definition: AugerUnits.h:140
void SetCorrelationThetaPhi(const double corr)
void SetTimeResidualMean(const double mean)
Interface class to access Shower Simulated parameters.
Definition: ShowerSimData.h:49
CandidateStationIterator CandidateStationsBegin()
Definition: SEvent.h:72
Criterion to sort stations by decreasing signal.
Definition: SortCriteria.h:41
void SetCoreError(const utl::Vector &coreerr)
boost::shared_ptr< const CoordinateTransformer > CoordinateSystemPtr
Shared pointer for coordinate systems.
#define max(a, b)
Class representing a document branch.
Definition: Branch.h:107
double GetRecoveredSignalError() const
double GetRecoveredSignal() const
Total recovered signal in VEM unit, averaged over pmts.
void SetResidual(const double residual)
Residual of geometry fit.
constexpr double s
Definition: AugerUnits.h:163
void SetLDFResidual(const double LDFresidual)
Residual of lateral fit.
const utl::Vector & GetDirection() const
Get the direction of the shower axis. This is the true direction of shower movement.
utl::TimeStamp GetSignalStartTime() const
Start time of the signal.
void InvertMatrix(const size_t n, AMatrix &a)
Invert A in place with Gauss-Jordan elimination and full pivoting.
SilentStationIterator SilentStationsBegin()
Definition: SEvent.h:88
double GetX(const CoordinateSystemPtr &coordinateSystem) const
Definition: BasicVector.h:206
utl::CoordinateSystemPtr GetEyeCoordinateSystem() const
Returns the Eye Coordinate system.
constexpr double kPi
Definition: MathConstants.h:24
constexpr double nanosecond
Definition: AugerUnits.h:143
const utl::TimeStamp & GetCoreTime() const
time when shower front passes through the core point
double abs(const SVector< n, T > &v)
void SetAxis(const utl::Vector &axis)
double GetTotalSignal() const
Total integrated signal in VEM unit, averaged over pmts.
Active transformations of geometrical objects.
const utl::Point & GetPosition() const
Get the position of the shower core.
bool HasTrigger() const
check whether the central trigger object exists
Definition: SEvent.h:153
EyeIterator EyesBegin(const ComponentSelector::Status status)
Definition: FEvent.h:58
void SetThetaError(const double err)
double GetSDPCorrThetaPhi() const
Definition: EyeRecData.h:79
const double km
double GetThetaError() const
const utl::Vector & GetAxis() const
double GetPhiError() const
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
void GetData(bool &b) const
Overloads of the GetData member template function.
Definition: Branch.cc:644
std::string GetName() const
function to get the Branch name
Definition: Branch.cc:374
std::vector< StationData > StationList
Definition: FitInterface.h:80
const CoordinateSystemPtr & fEyeCS
Eye-specific shower reconstruction data.
Definition: EyeRecData.h:65
Base class for inconsistency/illogicality exceptions.
void SetCoreTime(const utl::TimeStamp &coreTime, const utl::TimeInterval &coreTimeErr)
Station & GetStation(const int stationId)
retrieve station by id throw utl::NonExistentComponentException if n.a.
Definition: SEvent.h:116
FinalPropagator(const SdHorizontalReconstruction &parent, const vector< Point > &posList)
const utl::AxialVector & GetSDP() const
Definition: EyeRecData.h:75
double GetTimeFitChiSquare() const
Definition: EyeRecData.h:92
fevt::FEvent & GetFEvent()
double GetRpChi0Correlation() const
Definition: EyeRecData.h:89
double GetY(const CoordinateSystemPtr &coordinateSystem) const
Definition: BasicVector.h:209
const utl::TimeInterval & GetCoreTimeError() const
constexpr double kSpeedOfLight
A TimeInterval is used to represent time elapsed between two events.
Definition: TimeInterval.h:43
utl::TimeStamp GetTime() const
Get time of the trigger.
ResultFlag
Flag returned by module methods to the RunController.
Definition: VModule.h:60
void SetTimeResidualSpread(const double spread)
double GetCorrelationThetaPhi() const
double GetRp() const
Definition: EyeRecData.h:87
FdGeometryPropagator(const SdHorizontalReconstruction &parent, const CoordinateSystemPtr &eyeCS)
constexpr double kilometer
Definition: AugerUnits.h:93
std::vector< SilentStationData > SilentStationList
Definition: FitInterface.h:79
Vector object.
Definition: Vector.h:30
Detector description interface for SDetector-related data.
Definition: SDetector.h:42
const utl::Point & GetCorePosition() const
void SetCorePosition(const utl::Point &core)
sevt::Header & GetHeader()
Definition: SEvent.h:155
Main configuration utility.
Definition: CentralConfig.h:51
void SetLDFLikelihood(const double likelihood)
CandidateStationIterator CandidateStationsEnd()
Definition: SEvent.h:74
void SetShowerSizeType(const ShowerSizeType type)
bool HasLDF() const
void SetEnergy(const double energy, const double error)
void SetLDFRecStage(const double stage)
double GetZ(const CoordinateSystemPtr &coordinateSystem) const
Definition: BasicVector.h:212
void SetCorrelationXY(const double corr)
const Station & GetStation(const int stationId) const
Get station by Station Id.
Definition: SDetector.cc:192
void SetSPDistance(const double distance, const double error)
Distance from core in shower plane coordinates.
#define ERROR(message)
Macro for logging error messages.
Definition: ErrorLogger.h:165
constexpr double m
Definition: AugerUnits.h:121
bool HasSRecShower() const
sevt::SEvent & GetSEvent()
bool HasSEvent() const
const vector< Point > & fPosList
const double kEarthRadius
utl::Branch GetTopBranch(const std::string &id)
Get top branch for moduleConfigLink with given id (XML files)
boost::filter_iterator< CandidateStationFilter, ConstStationIterator > ConstCandidateStationIterator
Definition: SEvent.h:70
double GetSDPThetaError() const
Definition: EyeRecData.h:77

, generated on Tue Sep 26 2023.