ScintillatorLDFFinder.cc
Go to the documentation of this file.
1 #include <evt/Event.h>
2 
3 #include <evt/ShowerRecData.h>
4 #include <evt/ShowerSRecData.h>
5 #include <evt/ShowerScintillatorRecData.h>
6 
7 #include <evt/ShowerFRecData.h>
8 #include <evt/ShowerSimData.h>
9 
10 #include <sevt/SEvent.h>
11 #include <sevt/StationRecData.h>
12 #include <sevt/EventTrigger.h>
13 #include <sevt/Station.h>
14 #include <sevt/StationConstants.h>
15 #include <sevt/Scintillator.h>
16 #include <sevt/ScintillatorRecData.h>
17 
18 #include <fevt/FEvent.h>
19 #include <fevt/Header.h>
20 #include <fevt/Eye.h>
21 #include <fevt/Telescope.h>
22 #include <fevt/EyeHeader.h>
23 #include <fevt/EyeRecData.h>
24 
25 #include <det/Detector.h>
26 
27 #include <sdet/SDetector.h>
28 #include <sdet/SDetectorConstants.h>
29 #include <sdet/Station.h>
30 #include <sdet/STimeVariance.h>
31 
32 #include <fdet/FDetector.h>
33 #include <fdet/Eye.h>
34 #include <fdet/Telescope.h>
35 
36 #include <fwk/LocalCoordinateSystem.h>
37 #include <fwk/CentralConfig.h>
38 #include <fwk/RunController.h>
39 
40 #include <utl/CoordinateSystem.h>
41 #include <utl/PhysicalConstants.h>
42 #include <utl/ErrorLogger.h>
43 #include <utl/TabulatedFunctionErrors.h>
44 #include <utl/TimeStamp.h>
45 #include <utl/AxialVector.h>
46 #include <utl/Math.h>
47 #include <utl/Reader.h>
48 #include <utl/Accumulator.h>
49 #include <utl/NumericalErrorPropagator.h>
50 
51 #include <Minuit2/MnMinimize.h>
52 #include <Minuit2/MnHesse.h>
53 #include <Minuit2/FCNBase.h>
54 #include <Minuit2/FunctionMinimum.h>
55 #include <Minuit2/MnUserParameters.h>
56 #include <Minuit2/MnUserCovariance.h>
57 #include <Minuit2/MnPrint.h>
58 
59 #include "ScintillatorLDFFinder.h"
60 
61 #include <boost/range/iterator_range.hpp>
62 #include <cmath>
63 
64 using namespace ScintillatorLDFFinderKG;
65 using namespace sevt;
66 using namespace fevt;
67 using namespace evt;
68 using namespace fwk;
69 using namespace std;
70 using namespace utl;
71 
72 using CLHEP::HepRotation;
73 
74 #define OUT(x) if ((x) <= fInfoLevel) cerr
75 
76 
77 namespace ScintillatorLDFFinderKG {
78 
79  // local helpers
80 
81  template<typename T>
82  inline
83  bool
84  HasNaN(const T& result)
85  {
86  const size_t npar = result.fPar.size();
87  for (size_t i = 0; i < npar; ++i) {
88  if (std::isnan(result.fPar[i]))
89  return true;
90  for (size_t j = i; j < npar; ++j)
91  if (std::isnan(result.fCov(i, j)))
92  return true;
93  }
94  return false;
95  }
96 
97 
98  template<typename G>
99  inline
100  string
101  ToString(const G& g, const CoordinateSystemPtr cs, bool units = true)
102  {
103  ostringstream os;
104  if (units)
105  os << '('
106  << g.GetX(cs)/meter << ", "
107  << g.GetY(cs)/meter << ", "
108  << g.GetZ(cs)/meter << ") [m]";
109  else
110  os << '('
111  << g.GetX(cs) << ", "
112  << g.GetY(cs) << ", "
113  << g.GetZ(cs) << ')';
114  return os.str();
115  }
116 
117 
118  inline
119  string
121  {
122  ostringstream label;
123  const int refdist = static_cast<int>(config.fLDF.GetReferenceDistance());
124  label << "S" << refdist/meter;
125  if (refdist < 1000*meter)
126  label << ' ';
127  return label.str();
128  }
129 
130 
131  inline
132  const char*
133  GetShapeLabel(const int iShape)
134  {
135  static const char* const labels[] = { "beta ", "gamma", "mu ", "tau " };
136  return labels[iShape];
137  }
138 
139 
140  /*
141  This is the calculation of the core uncertainties from WCD measurement,
142  parametrized by Quentin L.
143  It probably shouldn't stay here, but moved to
144  a more appropriate place.
145  */
146  inline
147  double
148  DeltaR(const double wcdShowerSize, const double cosTheta)
149  {
150  const double f0 = 112.71;
151  const double f1 = 30.85;
152  const double f2 = -58.08;
153  const double f3 = -12.43;
154  const double f4 = 10.28;
155  const double f5 = 11.96;
156 
157  const double sinTheta2 = 1 - cosTheta * cosTheta;
158 
159  const double a = f0 + f1 * sinTheta2;
160  const double b = f2 + f3 * sinTheta2;
161  const double c = f4 + f5 * sinTheta2;
162 
163  const double deltaR = a + b * std::log10(wcdShowerSize)
164  + c * std::log10(wcdShowerSize)* std::log10(wcdShowerSize);
165 
166  return deltaR;
167  }
168 
169 }
170 
171 
172 
173 
174 void
176  const
177 {
178  const ShowerSRecData& recShower = event.GetRecShower().GetSRecShower();
179  const ShowerScintillatorRecData& scinRecShower = recShower.GetScintillatorRecShower();
180  OUT(eFinal)
181  << "***** Final reconstructed shower data *****\n"
182  " LDF stage = " << " --- " << "\n"
183  " " << GetShowerSizeLabel(fLDFFitConfig) << " = "
184  << scinRecShower.GetShowerSize()
185  << " +/- " << scinRecShower.GetShowerSizeError() << "\n"
186  " beta = " << scinRecShower.GetBeta() << " +/- " << scinRecShower.GetBetaError() << "\n"
187  " gamma = " << scinRecShower.GetGamma() << " +/- " << scinRecShower.GetGammaError() << "\n"
188  " LDF chi2 / ndof = " << scinRecShower.GetLDFChi2() << " / " << scinRecShower.GetLDFNdof() << "\n"
189  << endl;
190 }
191 
192 
195 {
196  CentralConfig* const cc = CentralConfig::GetInstance();
197 
198  const Branch topB = cc->GetTopBranch("ScintillatorLDFFinder");
199 
200  topB.GetChild("infoLevel").GetData(fInfoLevel); // for verbosity
201 
202  {
203  const string sigVariance = topB.GetChild("signalVariance").Get<string>();
204  if (sigVariance == "eGAP2018_025")
205  fLDFFitConfig.fSignalVarianceModel = ssd::eGAP2018_025;
206  else if (sigVariance == "eGAP2019_000")
207  fLDFFitConfig.fSignalVarianceModel = ssd::eGAP2019_000;
208  else {
209  ERROR("Unknown signal variance");
210  return eFailure;
211  }
212 
213  // setup LDF
214  string ldfType;
215  topB.GetChild("ldfType").GetData(ldfType);
216 
217  double ldfReferenceDistance;
218  topB.GetChild("ldfReferenceDistance").GetData(ldfReferenceDistance);
219 
220  vector<double> ldfParameters;
221  topB.GetChild("ldfParameters").GetData(ldfParameters);
222 
223  vector<double> ldfUncertaintyParameters;
224  topB.GetChild("ldfUncertaintyParameters").GetData(ldfUncertaintyParameters);
225 
226  fLDFFitConfig.fLDF = LDF(ldfType, ldfReferenceDistance,
227  ldfParameters, ldfUncertaintyParameters);
228  fLDFFitConfig.fLDFShapeTreatment.resize(fLDFFitConfig.fLDF.GetNShapeParameters(), eFitted);
229  }
230 
231  topB.GetChild("useReconstructedCore").GetData(fFixedCore);
232  fLDFFitConfig.fFixCore = fFixedCore;
233 
234  topB.GetChild("propagateCoreUncertainty").GetData(fCorePropagation);
235  fLDFFitConfig.fCorePropagationEnabled = fCorePropagation;
236 
237  string minimizationMethod;
238  topB.GetChild("minimizationMethod").GetData(minimizationMethod);
239  fUseMaxLikelihood = (minimizationMethod == "MaxLike");
240 
241  topB.GetChild("maxChi2").GetData(fMaxChi2);
242 
243  topB.GetChild("maxBaryToCoreDistance").GetData(fMaxBaryToCoreDistance);
244  if (fMaxBaryToCoreDistance <= 0) {
245  ERROR("<maxBaryToCoreDistance> must be > 0");
246  return eFailure;
247  }
248 
249  const Branch stage0B = topB.GetChild("stage0");
250  stage0B.GetChild("minNumberOfStations").GetData(fStage0.fMinNumberOfStations);
251 
252  const Branch stage1B = topB.GetChild("stage1");
253  stage1B.GetChild("minNumberOfStations").GetData(fStage1.fMinNumberOfStations);
254 
255  // Keep in mind to implement stage where beta and gamma are relaxed
256  const Branch stage2B = topB.GetChild("stage2");
257  stage2B.GetChild("minNumberRelaxBeta").GetData(fStage2.fMinNumberRelaxBeta);
258  stage2B.GetChild("minNumberRelaxGamma").GetData(fStage2.fMinNumberRelaxGamma);
259 
260  {
261  ostringstream info;
262  info << "\n"
263  << " LDF type: " << fLDFFitConfig.fLDF.GetType() << "\n"
264  << " Core type: " << (fFixedCore ? "Reconstructed" : "Fitted") << "\n"
265  << " Core uncertainties: " << (fCorePropagation ? "Propagated" : "Not included") << "\n"
266  << "Shower size estimator: " << GetShowerSizeLabel(fLDFFitConfig) << "\n"
267  << " Minimization method: " << (fUseMaxLikelihood ? "Maximum-Likelihood" : "Chi2") << "\n";
268  INFO(info);
269  }
270 
271  return eSuccess;
272 }
273 
274 
277 {
278  // nothing to do if there is no SEvent
279  if (!(event.HasSEvent() && event.HasRecShower() &&
280  event.GetRecShower().HasSRecShower()))
281  return eContinueLoop;
282 
283  const SEvent& sEvent = event.GetSEvent();
284 
285  const ShowerSRecData& showerRec = event.GetRecShower().GetSRecShower();
286 
287  if (!showerRec.HasLDF()) {
288  OUT(eFinal)
289  << "No LDF found from SD reconstruction!\n";
290  return eContinueLoop;
291  }
292 
293  // barycenter is done by the SdPlaneFitOG module
294  fBarycenter = showerRec.GetBarycenter();
295  fBaryTime = showerRec.GetBarytime();
297 
298  // load variables from SD reconstruction
299  Point core = showerRec.GetCorePosition();
300  Vector showerAxis = showerRec.GetAxis();
301  const double cosTheta = showerAxis.GetCosTheta(gBaryCS);
302  const double wcdShowerSize = showerRec.GetShowerSize();
303 
304  if (!fBaryTime)
305  throw utl::NonExistentComponentException("needs barycenter!");
306 
307  OUT(eIntermediate)
308  << "Distance cut for SSDs = " << DistanceCut(wcdShowerSize, cosTheta) << " m\n";
309 
310  int nStations = 0;
311  {
312  int nSaturated = 0;
313  int nSilent = 0;
314  int nDistant = 0;
315  for (const auto& station : boost::make_iterator_range(sEvent.StationsBegin(), sEvent.StationsEnd()))
316  if (station.IsCandidate() && station.HasScintillator() && station.GetScintillator().HasRecData()) {
317  ++nStations;
318 
319  const sdet::SDetector& sDetector = det::Detector::GetInstance().GetSDetector();
320  const utl::Point pos = sDetector.GetStation(station).GetPosition();
321  const double rho = RPerp(showerAxis, pos - core);
322  if (rho > DistanceCut(wcdShowerSize, cosTheta))
323  ++nDistant;
324 
325  if (station.GetScintillator().IsLowGainSaturation())
326  ++nSaturated;
327 
328  } else if (station.IsSilent())
329  ++nSilent;
330 
331  // right now saturated SSDs are not handled in the likelihood
332  nStations -= (nDistant + nSaturated);
333 
334  OUT(eIntermediate)
335  << "# candidate stations = " << nStations
336  << " (" << nSaturated << " saturated, " << nDistant << " distant), " << nSilent << " silent\n";
337  }
338 
339  // not worth it
340  if (nStations < fStage0.fMinNumberOfStations) {
341  OUT(eFinal)
342  << "Not enough stations.\n";
343  return eContinueLoop;
344  }
345 
346  fLDFFitConfig.deltaR = DeltaR(wcdShowerSize,cosTheta); // Calculate DeltaR, should be moved
347  LDFFitConfig config = fLDFFitConfig; // from XML
348  LDFFitResult best(config);
349 
350  best.fPar[eCoreX] = core.GetX(gBaryCS);
351  best.fPar[eCoreY] = core.GetY(gBaryCS);
352 
353  /*
354  showersize, shower axis and core position
355  from SD reconstruction are needed to apply distance cut
356  on SSD signals.
357 
358  */
359  vector<StationFitData> stationFitData = MakeStationFitData(sEvent, core, wcdShowerSize, showerAxis);
360 
361  // --- Stage: fit shower size, LDF shape & core fixed --------------------
362 
363  best.fRecStage = ShowerSRecData::kLDFEstimate;
364  OUT(eIntermediate)
365  << "Stage " << best.fRecStage << ": fit " << GetShowerSizeLabel(config)
366  << " - LDF shape fixed\n";
367 
368  FitLDFSimplified(best, config, showerAxis, stationFitData);
369 
370  if (nStations < fStage1.fMinNumberOfStations) {
371  SetRecData(event, best);
372  OutputResults(event);
373  return eSuccess;
374  }
375 
376  // --- Stage: fit shower size, shape fixed --------------
377  {
378  LDFFitResult result = best;
379 
380  config.fLDFShapeTreatment[0] = eModeled;
381  config.fLDFShapeTreatment[1] = eModeled;
382 
383  OUT(eIntermediate)
384  << "Stage " << result.fRecStage << ": fit "
385  << GetShowerSizeLabel(config)
386  << " - core and shape fixed \n";
387 
388  if (!FitLDF(result, config, showerAxis, stationFitData)){
389  OUT(eFinal)
390  << "Fit of the LDF FAILED! \n";
391  return eContinueLoop; // check this
392  }
393 
394  result.fRecStage = ShowerSRecData::kLDF;
395  best = result;
396 
397  } // stage
398 
399  // --- Stage: fit shower size, shape fitting (optional) --------------
400  {
401  LDFFitResult result = best;
402 
403  config.fLDFShapeTreatment[0] =
404  (nStations < fStage2.fMinNumberRelaxBeta ||
405  FixBeta(result, showerAxis, stationFitData)) ? eModeled : eFitted;
406  config.fLDFShapeTreatment[1] =
407  (nStations < fStage2.fMinNumberRelaxGamma ||
408  FixGamma(result, showerAxis, stationFitData)) ? eModeled : eFitted;
409 
410  if (config.fLDFShapeTreatment[0] == eFitted ||
411  config.fLDFShapeTreatment[1] == eFitted) {
412  OUT(eIntermediate)
413  << "Stage " << result.fRecStage << ": fit "
414  << GetShowerSizeLabel(config)
415  << " - core fixed"
416  << (config.fLDFShapeTreatment[0] == eFitted ? ", beta" : "")
417  << (config.fLDFShapeTreatment[1] == eFitted ? ", gamma\n" : "\n");
418 
419  if (FitLDF(result, config, showerAxis, stationFitData)) {
420  const bool fixBeta = FixBeta(result, showerAxis, stationFitData);
421  const bool fixGamma = FixGamma(result, showerAxis, stationFitData);
422  if ((config.fLDFShapeTreatment[0] == eModeled) == fixBeta &&
423  (config.fLDFShapeTreatment[1] == eModeled) == fixGamma) {
424  result.fRecStage = ShowerSRecData::kLDF +
425  (config.fLDFShapeTreatment[0] == eFitted) * ShowerSRecData::kLDFBeta +
426  (config.fLDFShapeTreatment[0] == eFitted) * ShowerSRecData::kLDFGamma;
427  best = result;
428  } else {
429  if (fixBeta)
430  config.fLDFShapeTreatment[0] = eModeled;
431  if (fixGamma)
432  config.fLDFShapeTreatment[1] = eModeled;
433 
434  if (FitLDF(result, config, showerAxis, stationFitData)) {
435  result.fRecStage = ShowerSRecData::kLDF +
436  (config.fLDFShapeTreatment[0] == eFitted) * ShowerSRecData::kLDFBeta +
437  (config.fLDFShapeTreatment[1] == eFitted) * ShowerSRecData::kLDFGamma;
438  best = result;
439  }
440  }
441  }
442  }
443  } // stage
444 
445  SetRecData(event, best);
446  OutputResults(event);
447 
448  return eSuccess;
449 }
450 
451 // From Pierre Billoir Thoughts....
452 // - if there are enough stations (especially at distances around 1000 m), a fit
453 // with a variable LDF slope is attempted (B is set as adjustable in (3)); the
454 // conditions are:
455 // * at least 5 stations, with one of the following requirements:
456 // * at least 2 within (500, 1500), with a difference at least 500 in between
457 // * at least 3 within (500, 1500), with a maximal difference at least 400
458 // * at least 4 within (500, 1500), with a maximal difference at least 300
459 //
460 // - Adjustments for 750 m infill:
461 // - Interval: (250, 750); distances: 250, 200, 150
462 //
463 // New version much stricter
464 bool
466  const Vector& showerAxis,
467  const vector<StationFitData>& data)
468  const
469 {
470  size_t nStations = 0;
471  for (const auto& station : data) {
472  if (!station.fSignal)
473  continue;
474  ++nStations;
475  }
476 
477  if (nStations < 5) {
478  OUT(eIntermediate)
479  << "FixBeta = " << true
480  << ": nStations = " << nStations << '\n';
481  return true;
482  }
483 
484  int nStationsInRange = 0;
485  double maxDistance = 0;
486 
487  double rRange[2];
488  double leverArms[3];
489  double refDist(fLDFFitConfig.fLDF.GetReferenceDistance());
490 
491  if (refDist == 1000*meter) {
492  rRange[0] = 400*meter;
493  rRange[1] = 1600*meter;
494  leverArms[0] = 900*meter;
495  leverArms[1] = 800*meter;
496  leverArms[2] = 700*meter;
497  } else if (refDist == 450*meter) {
498  rRange[0] = 180*meter;
499  rRange[1] = 720*meter;
500  leverArms[0] = 405*meter;
501  leverArms[1] = 360*meter;
502  leverArms[2] = 315*meter;
503  } else if (refDist == 250*meter) {
504  rRange[0] = 100*meter;
505  rRange[1] = 400*meter;
506  leverArms[0] = 225*meter;
507  leverArms[1] = 200*meter;
508  leverArms[2] = 175*meter;
509  } else // unknown case
510  return false;
511 
512  const Point core = result.GetCore();
513 
514  for (const auto& station : data) {
515 
516  if (!station.fSignal)
517  continue;
518 
519  const double r = RPerp(showerAxis, station.fPos - core);
520 
521  if (rRange[0] < r && r < rRange[1]) {
522  ++nStationsInRange;
523 
524  for (const auto& s : data) {
525  const double rr = RPerp(showerAxis, s.fPos - core);
526 
527  if (rRange[0] < rr && rr < rRange[1]) {
528  const double distance = fabs(r - rr);
529  if (distance > maxDistance)
530  maxDistance = distance;
531  }
532  }
533  }
534  }
535 
536  const bool fixBeta = !((nStationsInRange > 1 && maxDistance > leverArms[0]) ||
537  (nStationsInRange > 2 && maxDistance > leverArms[1]) ||
538  (nStationsInRange > 3 && maxDistance > leverArms[2]));
539  OUT(eIntermediate)
540  << "FixBeta = " << fixBeta << ": "
541  "nStations (InRange) = " << nStations << " (" << nStationsInRange << "), "
542  "maxDistance = " << maxDistance/meter << " [m]\n";
543 
544  return fixBeta;
545 }
546 
547 
549 bool
551  const Vector& showerAxis,
552  const vector<StationFitData>& data)
553  const
554 {
555  size_t nStations = 0;
556  for (const auto& station : data) {
557  if (!station.fSignal)
558  continue;
559  ++nStations;
560  }
561 
562  if (nStations < 5) {
563  OUT(eIntermediate)
564  << "FixGamma = " << true << ": nStations = " << nStations << '\n';
565  return true;
566  }
567 
568  int nStationsInRange = 0;
569  double maxDistance = 0;
570 
571  double rRange[2];
572  double leverArms[3];
573  double refDist(fLDFFitConfig.fLDF.GetReferenceDistance());
574 
575  if (refDist == 1000*meter) {
576  rRange[0] = 1000*meter;
577  rRange[1] = 2000*meter;
578  leverArms[0] = 500*meter;
579  leverArms[1] = 400*meter;
580  leverArms[2] = 300*meter;
581  } else if (refDist == 450*meter) {
582  rRange[0] = 450*meter;
583  rRange[1] = 1500*meter;
584  leverArms[0] = 250*meter;
585  leverArms[1] = 200*meter;
586  leverArms[2] = 150*meter;
587  } else { // unknown case
588  return false;
589  }
590 
591  const Point core = result.GetCore();
592 
593  for (const auto& station : data) {
594  if (!station.fSignal)
595  continue;
596 
597  const double r = RPerp(showerAxis, station.fPos - core);
598 
599  if (rRange[0] < r && r < rRange[1]) {
600 
601  ++nStationsInRange;
602 
603  for (const auto& s : data) {
604 
605  const double rr = RPerp(showerAxis, s.fPos - core);
606 
607  if (rRange[0] < rr && rr < rRange[1]) {
608  const double distance = fabs(r - rr);
609  if (distance > maxDistance)
610  maxDistance = distance;
611  }
612  }
613  }
614  }
615 
616  const bool fixGamma = !((nStationsInRange > 1 && maxDistance > leverArms[0]) ||
617  (nStationsInRange > 2 && maxDistance > leverArms[1]) ||
618  (nStationsInRange > 3 && maxDistance > leverArms[2]));
619  OUT(eIntermediate)
620  << "FixGamma = " << fixGamma << ": "
621  "nStations (InRange) = " << nStations << " (" << nStationsInRange << "), "
622  "maxDistance = " << maxDistance/meter << " [m]\n";
623 
624  return fixGamma;
625 }
626 
629 {
630  return eSuccess;
631 }
632 
633 
634 void
636  const
637 {
638  ShowerSRecData& recShower = event.GetRecShower().GetSRecShower();
639 
640  if (!recShower.HasScintillatorRecShower())
641  recShower.MakeScintillatorRecShower();
642 
643  ShowerScintillatorRecData& scinRecShower = recShower.GetScintillatorRecShower();
644 
645  const sdet::SDetector& sDetector = det::Detector::GetInstance().GetSDetector();
646 
647  const LDF& ldf = fLDFFitConfig.fLDF;
648  const double showerSize = lres.fPar[eShowerSize];
649  const vector<double>& ldfShapePars = lres.GetLDFShapeParameters();
650  const Point& core = lres.GetCore();
651  const CoordinateSystemPtr coreCS = LocalCoordinateSystem::Create(core);
652  const Vector& axis = recShower.GetAxis();
653  const double cosTheta = axis.GetCosTheta(coreCS);
654 
655  SEvent& sEvent = event.GetSEvent();
656 
657  const double theta = axis.GetTheta(coreCS);
658  const double phi = axis.GetPhi(coreCS);
659  const CoordinateSystemPtr showerPlaneCS(
660  CoordinateSystem::RotationY(
661  theta,
662  CoordinateSystem::RotationZ(
663  phi,
664  coreCS
665  )
666  )
667  );
668 
669  Accumulator::MinMax<double> minMaxRho(1000*kilometer, 0);
670  //Accumulator::SampleStandardDeviation timeStat;// unused. LN.
671 
672  for (auto& station : boost::make_iterator_range(sEvent.StationsBegin(), sEvent.StationsEnd())) {
673  if (!station.HasRecData())
674  continue;
675 
676  if (!station.HasScintillator())
677  continue;
678 
679  Scintillator& scintillator = station.GetScintillator();
680 
681  if (!scintillator.HasRecData())
682  continue;
683 
684  const Point& sPos = sDetector.GetStation(station).GetPosition();
685  const double x = sPos.GetX(showerPlaneCS);
686  const double y = sPos.GetY(showerPlaneCS);
687  const double rho = sqrt(x*x + y*y);
688 
689  if (station.IsCandidate())
690  minMaxRho(rho);
691 
692  ScintillatorRecData& scinRecData = scintillator.GetRecData();
693  const double signal = scinRecData.GetTotalSignal();
694  const double funcval = showerSize * ldf(rho, ldfShapePars);
695  double sigma = utl::ssd::SignalUncertainty(fLDFFitConfig.fSignalVarianceModel, cosTheta, funcval);
696  scinRecData.SetTotalSignal(signal, sigma);
697  scinRecData.SetLDFResidual((signal - funcval)/sigma);
698 
699  } // loop over stations with RecData and ScintillatorRecData
700 
701  if (!scinRecShower.HasLDF())
702  scinRecShower.MakeLDF();
703  TabulatedFunctionErrors& tabulatedLDF = scinRecShower.GetLDF();
704  tabulatedLDF.Clear();
705 
706  {
707  const double x0 = log(1);
708  const double x1 = log(10000);
709  const int nLDFPoints = 20;
710 
711  for (int i = 0; i < nLDFPoints; ++i) {
712  const double z = double(i) / (nLDFPoints-1);
713  const double rho = exp((1-z)*x0 + z*x1);
714  const double funcval = showerSize * ldf(rho, ldfShapePars);
715  const double sigma = utl::ssd::SignalUncertainty(fLDFFitConfig.fSignalVarianceModel, cosTheta, funcval);
716  tabulatedLDF.PushBack(rho, 0, funcval, sigma);
717  }
718  }
719 
720  {
721  const double showerSizeErr = lres.fCov.Std(eShowerSize);
722  vector<double> ldfShapeParsErr;
723  for (size_t i = 0, n = fLDFFitConfig.fLDF.GetNShapeParameters(); i < n; ++i)
724  ldfShapeParsErr.push_back(lres.fCov.Std(eShapeParameters + i));
725 
726  switch (size_t(round(ldf.GetReferenceDistance()/meter))) {
727  case 1000:
728  scinRecShower.SetShowerSizeType(ShowerScintillatorRecData::eS1000);
729  break;
730  default:
732  break;
733  }
734 
735  scinRecShower.SetShowerSize(showerSize, showerSizeErr);
736  scinRecShower.SetBeta(ldfShapePars[0], ldfShapeParsErr[0]);
737 
738  if (ldfShapePars.size() > 1)
739  scinRecShower.SetGamma(ldfShapePars[1], ldfShapeParsErr[1]);
740  else
741  scinRecShower.SetGamma(0, 0);
742 
743  scinRecShower.SetLDFChi2(lres.fChi2, lres.fNdof);
744  scinRecShower.SetLDFLikelihood(lres.fLogLikelihood);
745  scinRecShower.SetLDFRecStage(lres.fRecStage);
746  }
747 }
748 
749 
751 vector<StationFitData>
752 ScintillatorLDFFinder::MakeStationFitData(const SEvent& sEvent, const Point core, const double wcdShowerSize, const Vector& showerAxis)
753  const
754 {
755  vector<StationFitData> sFitData;
756 
757  const sdet::SDetector& sDetector = det::Detector::GetInstance().GetSDetector();
758 
759  for (const auto& station : boost::make_iterator_range(sEvent.StationsBegin(), sEvent.StationsEnd())) {
760  /*
761  * For now, only consider scintillators which were WCD
762  * candidates. Silent WCD stations do not guarantee that
763  * you would have had a zero signal in the scintillator
764  * as well. We need to deal with this properly in the likelihood,
765  * but here we do not store information from the scintillators for
766  * now.
767  */
768 
769  if (!station.IsCandidate())
770  continue;
771 
772  if (!station.HasScintillator())
773  continue;
774 
775  if (!station.GetScintillator().HasRecData())
776  continue;
777 
778  const double cosTheta = showerAxis.GetCosTheta(gBaryCS);
779  const utl::Point pos = sDetector.GetStation(station).GetPosition();
780  const double rho = RPerp(showerAxis, pos - core);
781  /*
782  Apply distance cut to remove scintillator with low signals:
783  For a given shower size and zenith angle, the cut is determined
784  in such a way that >95% of the SSDs below that distance
785  have at least 1 MIP of signal.
786  */
787 
788  if (rho > DistanceCut(wcdShowerSize, cosTheta))
789  continue;
790 
791  StationFitData current;
792 
793  const ScintillatorRecData& scinRec = station.GetScintillator().GetRecData();
794 
795  current.fId = station.GetId();
796  current.fIsSaturated = station.GetScintillator().IsLowGainSaturation();
797  current.fPos = pos;
798  current.fSignal = scinRec.GetTotalSignal();
799  sFitData.push_back(current);
800 
801  } // loop over stations
802 
803  return sFitData;
804 }
805 
806 
808 void
810  LDFFitConfig& config,
811  const Vector& showerAxis,
812  const vector<StationFitData>& data)
813  const
814 {
815  result.fCov = 0;
816 
817  const utl::Point core = result.GetCore();
818 
819  const double cosTheta = showerAxis.GetCosTheta(gBaryCS);
820 
821  const vector<double> shape = config.fLDF.ShapeModel(cosTheta, 10);
822 
823  LDFLikelihoodFunctionTN likeFcn(config, showerAxis, data);
824 
825  LDFFitResult resultA = result;
826  LDFFitResult resultB = result;
827 
828  {
829  // estimate shower size from station closest to reference distance
830 
831  const double kRefDist = config.fLDF.GetReferenceDistance();
832  double minDistance = numeric_limits<double>::max();
833  double rhoClosest = kRefDist;
834  double signalClosest = 1;
835 
836  // loop over normal stations, ignore silent/saturated stations
837  for (const auto& station : data) {
838 
839  if (!station.fSignal)
840  continue;
841 
842  const double rho = RPerp(showerAxis, station.fPos - core);
843  const double distance = fabs(rho - kRefDist);
844 
845  if (distance < minDistance) {
846  minDistance = distance;
847  rhoClosest = rho;
848  signalClosest = station.fSignal;
849  }
850  }
851 
852  resultA.fPar[eShowerSize] = signalClosest / config.fLDF(rhoClosest, shape);
853  resultA.fLogLikelihood = likeFcn(resultA.fPar);
854 
855  OUT(eIntermediate)
856  << " " << GetShowerSizeLabel(config) << " [estimate A] = "
857  << resultA.fPar[eShowerSize] << " ( logLike = " << resultA.fLogLikelihood << " )" << endl;
858  }
859 
860  {
861  /*
862  If core and shape of the LDF are fixed, the least-squares
863  estimate of shower size S0 can be calculated analytically.
864 
865  S_i ... data
866  S(r_i) = S0 f(r_i) ... model
867  sigma^2(S) = S ... simplest signal uncertainty model
868 
869  chi^2 = sum_i (S_i - S(r_i))^2/S(r_i)
870 
871  With maximum condition d chi^2/d S0 = 0 one obtains
872  S0^2 = sum_i S_i^2 f^(-1)(r_i) / sum_i f(r_i)
873  */
874 
875  double sumA = 0;
876  double sumB = 0;
877  for (const auto& station : data) {
878  const double s = station.fSignal;
879 
880  if (!s)
881  continue;
882 
883  const double rho = RPerp(showerAxis, station.fPos - core);
884  const double f = config.fLDF(rho, shape);
885 
886  sumA += s*s / f;
887  sumB += f;
888  }
889 
890  resultB.fPar[eShowerSize] = sqrt(sumA / sumB);
891  resultB.fLogLikelihood = likeFcn(resultB.fPar);
892 
893  OUT(eIntermediate)
894  << " " << GetShowerSizeLabel(config) << " [estimate B] = "
895  << resultB.fPar[eShowerSize] << " ( logLike = " << resultB.fLogLikelihood << " )" << endl;
896  }
897 
898  // use better estimate of the two
899  result = resultA.fLogLikelihood < resultB.fLogLikelihood ? resultA : resultB;
900 
901  // Finally, perform full-featured fit with fixed core
902  // gamma set to WCD parameterisation
903  // fit beta
904  LDFFitConfig thisConfig = config;
905  thisConfig.fFixCore = true;
906  thisConfig.fLDFShapeTreatment[0] = eModeled;
907  thisConfig.fLDFShapeTreatment[1] = eModeled;
908  FitLDF(result, thisConfig, showerAxis, data);
909 }
910 
911 
912 bool
914  LDFFitConfig& config /* needs to be mutable */,
915  const Vector& showerAxis,
916  const vector<StationFitData>& data)
917  const
918 {
919  using namespace ROOT::Minuit2;
920 
921  MnUserParameters pars;
922 
923  pars.Add("showerSize", result.fPar[0], 1.0);
924  pars.SetLowerLimit("showerSize", 0);
925  pars.Add("coreX", result.fPar[1], 200*meter);
926  pars.Add("coreY", result.fPar[2], 200*meter);
927 
928  for (size_t i = 0, n = config.fLDF.GetNShapeParameters(); i < n; ++i) {
929  pars.Add(GetShapeLabel(i), result.fPar[3+i], 0.1);
930  if (config.fLDFShapeTreatment[i] != eFitted)
931  pars.Fix(GetShapeLabel(i));
932  }
933 
934  if (config.fFixCore) {
935  pars.Fix("coreX");
936  pars.Fix("coreY");
937  }
938 
939  LDFChi2Function chi2Fcn(config, showerAxis, data);
940  LDFLikelihoodFunctionTN likeFcn(config, showerAxis, data);
941 
942  MnMinimize m(fUseMaxLikelihood ?
943  static_cast<const FCNBase&>(likeFcn) :
944  static_cast<const FCNBase&>(chi2Fcn), pars, 1);
945 
946  FunctionMinimum fmin = m(10000);
947 
948  if (fmin.IsAboveMaxEdm() || fmin.HasReachedCallLimit() || !fmin.IsValid()) {
949  OUT(eIntermediate)
950  << "\n**************** Minimize FAILED ****************\n"
951  << fmin
952  << "**************** Minimize FAILED ****************\n\n";
953  return false;
954  }
955 
956  {
957  ostringstream msg;
958  msg << "Found minimum after " << fmin.NFcn() << " evaluations";
959  INFO(msg);
960  }
961 
962  MnHesse hesse(1);
963  hesse(m.Fcnbase(), fmin, 10000);
964 
965  if (!fmin.IsValid() || fmin.HesseFailed()) {
966  OUT(eIntermediate)
967  << "\n**************** Hesse FAILED ****************\n"
968  << fmin
969  << "**************** Hesse FAILED ****************\n\n";
970  return false;
971  }
972 
973  if (fInfoLevel >= eMinuit)
974  OUT(eIntermediate)
975  << "\n**************** Minuit Output ****************\n"
976  << fmin
977  << "**************** Minuit Output ****************\n\n";
978 
979  // get fit results
980  result.fPar = fmin.UserParameters().Params();
981 
982  const vector<double> modeledShape =
983  config.fLDF.ShapeModel(showerAxis.GetCosTheta(gBaryCS), result.fPar[0]);
984  for (size_t i = 0, n = config.fLDF.GetNShapeParameters(); i < n; ++i)
985  if (config.fLDFShapeTreatment[i] == eModeled)
986  result.fPar[3+i] = modeledShape[i];
987 
988  const size_t nVar = pars.VariableParameters();
989 
990  // get covariance
991  result.fCov = 0;
992 
993  for (size_t i = 0; i < nVar; ++i)
994  for (size_t j = 0; j < nVar; ++j)
995  result.fCov(m.ExtOfInt(i), m.ExtOfInt(j)) = fmin.UserCovariance()(i,j);
996 
997  const double minValue = fmin.Fval();
998  if (fUseMaxLikelihood) {
999  result.fLogLikelihood = minValue;
1000  result.fChi2 = chi2Fcn(result.fPar);
1001  } else {
1002  result.fLogLikelihood = likeFcn(result.fPar);
1003  result.fChi2 = minValue;
1004  }
1005 
1006  result.fNdof = 0;
1007  for (const auto& station : data)
1008  if (station.fSignal > 0)
1009  ++result.fNdof;
1010  result.fNdof -= nVar;
1011 
1012  const double reducedChi2 = (result.fNdof > 0) ? result.fChi2/result.fNdof : 0;
1013 
1014  const utl::Point core = result.GetCore();
1015 
1016  const utl::Point coreErr(result.fCov.Std(eCoreX), result.fCov.Std(eCoreY), 0, gBaryCS);
1017  OUT(eIntermediate)
1018  << " chi2 = " << result.fChi2 << " / " << result.fNdof << "\n"
1019  " " << GetShowerSizeLabel(config) << " = "
1020  << result.fPar[eShowerSize] << " +/- " << result.fCov.Std(eShowerSize) << "\n"
1021  " core = " << ToString(core, gBaryCS) << " +/-\n"
1022  " " << ToString(coreErr, gBaryCS) << " (bary)";
1023  for (size_t i = 0, n = config.fLDF.GetNShapeParameters(); i < n; ++i)
1024  OUT(eIntermediate) << "\n " << GetShapeLabel(i)
1025  << " = " << result.fPar[eShapeParameters + i] << " +/- " << result.fCov.Std(eShapeParameters + i);
1026  OUT(eIntermediate) << endl;
1027 
1028  if (reducedChi2 > fMaxChi2) {
1029  OUT(eIntermediate)
1030  << " Chi2/Ndof = " << reducedChi2 << " exceeds limit "
1031  << fMaxChi2 << '\n';
1032  return false;
1033  }
1034 
1035  const double d = (core - fBarycenter).GetMag();
1036  if (d > fMaxBaryToCoreDistance) {
1037  OUT(eIntermediate)
1038  << " Distance to core " << d/km << " [km] exceeds limit.\n";
1039  return false;
1040  }
1041 
1042  return !HasNaN(result);
1043 }
string ToString(const G &g, const CoordinateSystemPtr cs, bool units=true)
StationIterator StationsEnd()
End of all stations.
Definition: SEvent.h:59
Point object.
Definition: Point.h:32
double GetPhi(const CoordinateSystemPtr &coordinateSystem) const
azimuth (phi) angle in spherical and cylindrical coordinates
Definition: BasicVector.h:254
void SetRecData(evt::Event &event, const LDFFitResult &lresult) const
void SetTotalSignal(const double s, const double sErr)
Interface class to access to the SD Reconstruction of a Shower.
Interface class to access to the SD part of an event.
Definition: SEvent.h:39
const utl::TimeStamp & GetBarytime() const
std::vector< double > ShapeModel(const double cosTheta, const double showerSize) const
double GetTheta(const CoordinateSystemPtr &coordinateSystem) const
zenith (theta) angle in spherical coordinates
Definition: BasicVector.h:248
double GetCosTheta(const CoordinateSystemPtr &coordinateSystem) const
cos of zenith (theta) angle
Definition: BasicVector.h:251
bool HasScintillatorRecShower() const
const utl::CoordinateSystemPtr & GetBarycenterCoordinateSystem() const
origin = GetBarycenter(), z-axis = local vertical, x-axis = east
const double meter
Definition: GalacticUnits.h:29
ScintillatorRecData & GetRecData()
Get object containing scintillator reconstructed data.
void SetShowerSize(const double value, const double error)
#define INFO(message)
Macro for logging informational messages.
Definition: ErrorLogger.h:161
void SetBeta(const double beta, const double error)
const unsigned int npar
Definition: UnivRec.h:75
double GetShowerSize() const
Base class for exceptions trying to access non-existing components.
bool FitLDF(LDFFitResult &result, LDFFitConfig &config, const utl::Vector &showerAxis, const std::vector< StationFitData > &data) const
Branch GetChild(const std::string &childName) const
Get child of this Branch by child name.
Definition: Branch.cc:211
fwk::VModule::ResultFlag Init()
Initialize: invoked at beginning of run (NOT beginning of event)
double RPerp(const utl::Vector &axis, const utl::Vector &station)
double DeltaR(const double wcdShowerSize, const double cosTheta)
utl::Point GetPosition() const
Tank position.
void SetGamma(const double gamma, const double error)
T Get() const
Definition: Branch.h:271
#define OUT(x)
boost::shared_ptr< const CoordinateTransformer > CoordinateSystemPtr
Shared pointer for coordinate systems.
void SetLDFChi2(const double chi2, const double ndof)
#define max(a, b)
Class representing a document branch.
Definition: Branch.h:107
bool HasRecData() const
Check for existence of scintillator reconstructed data object.
constexpr double s
Definition: AugerUnits.h:163
double GetX(const CoordinateSystemPtr &coordinateSystem) const
Definition: BasicVector.h:206
void SetLDFLikelihood(const double likelihood)
const Data result[]
void OutputResults(const evt::Event &event) const
const utl::Point & GetBarycenter() const
bool HasNaN(const T &result)
const char * GetShapeLabel(const int iShape)
string GetShowerSizeLabel(const LDFFitConfig &config)
const utl::TabulatedFunctionErrors & GetLDF() const
ShowerScintillatorRecData & GetScintillatorRecShower()
const double km
constexpr double g
Definition: AugerUnits.h:200
const utl::Vector & GetAxis() const
void SetLDFRecStage(const double stage)
void PushBack(const double x, const double xErr, const double y, const double yErr)
void GetData(bool &b) const
Overloads of the GetData member template function.
Definition: Branch.cc:644
void FitLDFSimplified(LDFFitResult &result, LDFFitConfig &config, const utl::Vector &showerAxis, const std::vector< StationFitData > &data) const
Early estimate of shower size.
double GetY(const CoordinateSystemPtr &coordinateSystem) const
Definition: BasicVector.h:209
class to hold data for station Scintillator
ResultFlag
Flag returned by module methods to the RunController.
Definition: VModule.h:60
utl::CoordinateSystemPtr gBaryCS
void SetLDFResidual(const double res)
double DistanceCut(const double showerSize, const double cosTheta)
StationIterator StationsBegin()
Beginning of all stations.
Definition: SEvent.h:57
uint16_t * data
Definition: dump1090.h:228
Class to access station scintillator reconstructed data.
constexpr double kilometer
Definition: AugerUnits.h:93
Vector object.
Definition: Vector.h:30
void SetShowerSizeType(const ShowerSizeType type)
Detector description interface for SDetector-related data.
Definition: SDetector.h:42
const utl::Point & GetCorePosition() const
Main configuration utility.
Definition: CentralConfig.h:51
fwk::VModule::ResultFlag Finish()
Finish: invoked at end of the run (NOT end of the event)
Class to access shower scintillator reconstructed data.
bool FixBeta(const LDFFitResult &result, const utl::Vector &showerAxis, const std::vector< StationFitData > &data) const
double SignalUncertainty(const ESignalVarianceModel model, const double cosTheta, const double signal)
bool HasLDF() const
void MakeScintillatorRecShower()
fwk::VModule::ResultFlag Run(evt::Event &event)
Run: invoked once per event.
const Station & GetStation(const int stationId) const
Get station by Station Id.
Definition: SDetector.cc:192
#define ERROR(message)
Macro for logging error messages.
Definition: ErrorLogger.h:165
constexpr double m
Definition: AugerUnits.h:121
bool FixGamma(const LDFFitResult &result, const utl::Vector &showerAxis, const std::vector< StationFitData > &data) const
Criterion if gamma can be fitted analogue to beta must be checked/updated.
std::vector< StationFitData > MakeStationFitData(const sevt::SEvent &sEvent, const utl::Point core, const double showerSize, const utl::Vector &showerAxis) const
Init station data used by LDF fit.
bool HasSEvent() const
utl::Branch GetTopBranch(const std::string &id)
Get top branch for moduleConfigLink with given id (XML files)

, generated on Tue Sep 26 2023.