ZombieGraveyard/LDFFinderOG/LDFFinder.cc
Go to the documentation of this file.
1 
11 #include <cmath>
12 
13 #include <evt/Event.h>
14 #include <evt/ShowerRecData.h>
15 #include <evt/ShowerSRecData.h>
16 #include <evt/ShowerFRecData.h>
17 #include <evt/ShowerSimData.h>
18 
19 #include <sevt/SEvent.h>
20 #include <sevt/StationRecData.h>
21 #include <sevt/EventTrigger.h>
22 #include <sevt/Station.h>
23 
24 #include <fevt/FEvent.h>
25 #include <fevt/Header.h>
26 #include <fevt/Eye.h>
27 #include <fevt/Telescope.h>
28 #include <fevt/EyeHeader.h>
29 #include <fevt/EyeRecData.h>
30 
31 #include <det/Detector.h>
32 
33 #include <sdet/SDetector.h>
34 #include <sdet/Station.h>
35 #include <sdet/STimeVariance.h>
36 
37 #include <fdet/FDetector.h>
38 #include <fdet/Eye.h>
39 #include <fdet/Telescope.h>
40 
41 #include <fwk/LocalCoordinateSystem.h>
42 #include <fwk/CentralConfig.h>
43 
44 #include <utl/CoordinateSystem.h>
45 #include <utl/PhysicalConstants.h>
46 #include <utl/PhysicalFunctions.h>
47 #include <utl/ErrorLogger.h>
48 #include <utl/TabulatedFunctionErrors.h>
49 #include <utl/TimeStamp.h>
50 #include <utl/AxialVector.h>
51 #include <utl/Math.h>
52 #include <utl/Reader.h>
53 #include <utl/Accumulator.h>
54 
55 #include <TMinuit.h>
56 
57 #include <CLHEP/Matrix/Matrix.h>
58 #include <CLHEP/Matrix/Vector.h>
59 
60 #include "RoptFit.h"
61 #include "LDFFinder.h"
62 
63 using namespace LDFFinderOG;
64 using namespace sevt;
65 using namespace fevt;
66 using namespace evt;
67 using namespace fwk;
68 using namespace std;
69 using namespace utl;
70 
71 using CLHEP::HepMatrix;
72 using CLHEP::HepVector;
73 using CLHEP::HepRotation;
74 
75 
76 #define OUT(x) if ((x) <= fInfoLevel) cerr << " "
77 
78 
94 
95 namespace LDFFinderOG {
96 
97  // square of the perpendicular distance from the axis
98  inline
99  double
100  RPerp2(const Vector& axis, const Vector& station)
101  {
102  const double scal = axis*station;
103  return station*station - scal*scal;
104  }
105 
106 
107  // perpendicular distance from the axis
108  inline
109  double
110  RPerp(const Vector& axis, const Vector& station)
111  {
112  return sqrt(RPerp2(axis, station));
113  }
114 
115 
116  template<typename G>
117  inline
118  string
119  ToString(const G& g, const CoordinateSystemPtr cs, bool units = true)
120  {
121  ostringstream os;
122  if (units)
123  os << '('
124  << g.GetX(cs)/meter << ", "
125  << g.GetY(cs)/meter << ", "
126  << g.GetZ(cs)/meter << ") [m]";
127  else
128  os << '('
129  << g.GetX(cs) << ", "
130  << g.GetY(cs) << ", "
131  << g.GetZ(cs) << ')';
132  return os.str();
133  }
134 
135 }
136 
137 
139  fS1000(0), fS1000Err(0),
140  // fCore & fCoreErr ctor() ok
141  fFixedBeta(false), fBeta(0), fBetaErr(0),
142  fFixedGamma(false), fGamma(0), fGammaErr(0),
143  fEnergy(0), fEnergyErr(0),
144  fChi2(0), fNdof(0), fRecStage(0)
145 { }
146 
147 
149  // fCore
150  fFixedAxis(false),
151  // fAxis, fAxisErr
152  // fSigmaU2, fSigmaV2, fSigmaUV
153  fFixedRc(false),
154  fRc(0), fRcErr(0),
155  fct0(0), fct0Err(0)
156 { }
157 
158 
159 void
161  const
162 {
163  const sdet::SDetector& sDetector = det::Detector::GetInstance().GetSDetector();
164 
165  // loop on stations
167  sIt != fgCurrentSEvent->StationsEnd(); ++sIt)
168  if (sIt->IsCandidate()) {
169 
170  const double r =
171  RPerp(fgShowerAxis, sDetector.GetStation(*sIt).GetPosition() - fgBarycenter);
172 
173  cout << " candidate " << sIt->GetId() << ": " << r << ' '
174  << sIt->GetRecData().GetTotalSignal() << ' '
175  << fi.fS1000 * LDFFunction(fgLDFType, r, fi.fBeta, fi.fGamma, fgNKGFermiMu, fgNKGFermiTau) << '\n';
176 
177  } else if (sIt->IsSilent()) {
178 
179  const double r =
180  RPerp(fgShowerAxis, sDetector.GetStation(*sIt).GetPosition() - fgBarycenter);
181 
182  cout << " silent " << sIt->GetId() << ": " << r << ' '
183  << fi.fS1000 * LDFFunction(fgLDFType, r, fi.fBeta, fi.fGamma, fgNKGFermiMu, fgNKGFermiTau) << '\n';
184  }
185 }
186 
187 
188 void
190  const
191 {
192  const ShowerSRecData& recShower = event.GetRecShower().GetSRecShower();
193 
194  OUT(eFinal)
195  << "***** Final reconstructed shower data *****\n"
196  " LDF stage = " << recShower.GetLDFRecStage() << "\n"
197  " S1000 = " << recShower.GetShowerSize() << " +/- " << recShower.GetShowerSizeError() << "\n"
198  " core = " << ToString(recShower.GetCorePosition(),
199  det::Detector::GetInstance().GetSiteCoordinateSystem()) << " (site)\n"
200  " = " << ToString(recShower.GetCorePosition(), fgLocalCS) << " (bary) +/-\n"
201  " " << ToString(recShower.GetCoreError(), fgLocalCS) << "\n"
202  " x-y correlation = " << recShower.GetCorrelationXY() << "\n"
203  " beta = " << recShower.GetBeta() << " +/- " << recShower.GetBetaError() << "\n"
204  " gamma = " << recShower.GetGamma() << " +/- " << recShower.GetGammaError() << "\n"
205  " energy = " << recShower.GetEnergy()/EeV << " +/- " << recShower.GetEnergyError()/EeV
206  << " [EeV]\n";
207  const double curv = recShower.GetCurvature();
208  if (curv) {
209  const Vector& axis = recShower.GetAxis();
210  const double rc = 1/curv;
211  const Vector::Triple uvw(axis.GetCoordinates(fgLocalCS));
212  OUT(eFinal)
213  << "axis = (" << uvw.get<0>() << ", " << uvw.get<1>() << ", " << uvw.get<2>()
214  << ") (bary)" << "\n"
215  " theta = " << axis.GetTheta(fgLocalCS)/degree << " +/- "
216  << recShower.GetThetaError()/degree << " [deg] (bary)\n"
217  " phi = " << axis.GetPhi(fgLocalCS)/degree << " +/- "
218  << recShower.GetPhiError()/degree << " [deg]\n"
219  " theta-phi correlation = " << recShower.GetCorrelationThetaPhi() << "\n"
220  " Rc = " << rc/km << " +- " << recShower.GetCurvatureError()*rc*rc/km << " [km]\n"
221  " time chi2 = " << recShower.GetAngleChi2() << " / "
222  << recShower.GetAngleNdof() << "\n"
223  " time residual = " << recShower.GetTimeResidualMean()/nanosecond << " +/- "
224  << recShower.GetTimeResidualSpread()/nanosecond << " [ns]\n";
225  }
226  const double rOpt = recShower.GetLDFOptimumDistance();
227  if (rOpt)
228  OUT(eFinal)
229  << "Ropt = " << rOpt/meter << " [m]\n";
230  cerr << flush;
231 }
232 
233 
236 {
237  CentralConfig* const cc = CentralConfig::GetInstance();
238 
239  const Branch topB = cc->GetTopBranch("LDFFinder");
240 
241  topB.GetChild("infoLevel").GetData(fInfoLevel);
242  if (fInfoLevel < eNone || fInfoLevel > eMinuit) {
243  ERROR("<infoLevel> out of bounds");
244  return eFailure;
245  }
247 
248  string tmp;
249  topB.GetChild("coreType").GetData(tmp);
250  fCoreType = (tmp == "MC" ? eMC : (tmp == "Hybrid" ? eHybrid : eFit));
251 
252  topB.GetChild("maxTheta").GetData(fMaxTheta);
253  if (fMaxTheta <= 0 || fMaxTheta > 90*degree) {
254  ERROR("<maxTheta> does not make sense");
255  return eFailure;
256  }
257 
258  // string tmp;
259  topB.GetChild("ldfType").GetData(tmp);
260  fgLDFType = (tmp == "PL" ? ePL : (tmp == "NKG") ? eNKG : eNKGFermi);
261 
262  topB.GetChild("NKGFermiMu").GetData(fgNKGFermiMu);
263  if (fgNKGFermiMu <= 0) {
264  ERROR("<NKGFermiMu> must be > 0");
265  return eFailure;
266  }
267 
268  topB.GetChild("NKGFermiTau").GetData(fgNKGFermiTau);
269  if (fgNKGFermiTau <= 0) {
270  ERROR("<NKGFermiTau> must be > 0");
271  return eFailure;
272  }
273 
274  topB.GetChild("minimizationMethod").GetData(tmp);
275  fUseMaxLike = (tmp == "MaxLike");
276 
277  topB.GetChild("maxChi2").GetData(fMaxChi2);
278 
279  topB.GetChild("useSilentStations").GetData(fUseSilentStations);
280 
281  topB.GetChild("silentMaxRadius").GetData(fgSilentMaxRadius);
282  if (fgSilentMaxRadius <= 0) {
283  ERROR("<silentMaxRadius> must be > 0");
284  return eFailure;
285  }
286 
287  topB.GetChild("silentRadiusTransition").GetData(fgSilentRadiusTransition);
288  if (fgSilentRadiusTransition <= 0) {
289  ERROR("<silentRadiusTransition> must be > 0");
290  return eFailure;
291  }
292 
293  topB.GetChild("silentSignalThreshold").GetData(fgSilentSignalThreshold);
294 
295  topB.GetChild("maxBaryToCoreDistance").GetData(fMaxBaryToCoreDistance);
296  if (fMaxBaryToCoreDistance <= 0) {
297  ERROR("<maxBaryToCoreDistance> must be > 0");
298  return eFailure;
299  }
300 
301  topB.GetChild("RoptN").GetData(fRoptN);
302 
303  const Branch stage0B = topB.GetChild("stage0");
304  stage0B.GetChild("minNumberOfStations").GetData(fStage0.fMinNumberOfStations);
305  stage0B.GetChild("useCorePosition").GetData(fStage0.fUseCorePosition);
306 
307  const Branch stage1B = topB.GetChild("stage1");
308  stage1B.GetChild("minNumberOfStations").GetData(fStage1.fMinNumberOfStations);
309  stage1B.GetChild("maxChi2").GetData(fStage1.fMaxChi2);
310 
311  const Branch stage2B = topB.GetChild("stage2");
312  stage2B.GetChild("minNumberRelaxBeta").GetData(fStage2.fMinNumberRelaxBeta);
313  stage2B.GetChild("minNumberRelaxGamma").GetData(fStage2.fMinNumberRelaxGamma);
314 
315  const Branch stage3B = topB.GetChild("stage3");
316  stage3B.GetChild("minNumberOfStations").GetData(fStage3.fMinNumberOfStations);
317  stage3B.GetChild("minNumberForFullCurvatureFit").GetData(fStage3.fMinNumberForFullCurvatureFit);
318  stage3B.GetChild("maxAxisAngleDifference").GetData(fStage3.fMaxAxisAngleDifference);
319 
320  if (fInfoLevel != eNone) {
321  ostringstream info;
322  info << "LDF type: " << (fgLDFType == ePL ? "PL" : (fgLDFType == eNKG ? "NKG" : "NKGFermi"))
323  << ", minimization: " << (fUseMaxLike ? "Maximum-Likelihood" : "Chi2");
324  INFO(info);
325  }
326 
327  const Branch energyBranch = topB.GetChild("energyCalibration");
328  energyBranch.GetChild("attenuationPar1").GetData(fEnergyConversion.fAttenuationPar1);
329  energyBranch.GetChild("attenuationPar2").GetData(fEnergyConversion.fAttenuationPar2);
330  energyBranch.GetChild("attenuationPar3").GetData(fEnergyConversion.fAttenuationPar3);
331  energyBranch.GetChild("energyS38Const").GetData(fEnergyConversion.fEnergyS38Const);
332  energyBranch.GetChild("energyS38Slope").GetData(fEnergyConversion.fEnergyS38Slope);
333 
334  if (fInfoLevel != eNone) {
335  ostringstream info;
336  info << "S38 conversion: " << "1+(" << fEnergyConversion.fAttenuationPar1 << ")*x+("
337  << fEnergyConversion.fAttenuationPar2 << ")*x^2+("
338  << fEnergyConversion.fAttenuationPar3 << ")*x^3 ;"
339  " energy [eV] = " << fEnergyConversion.fEnergyS38Const << "*"
340  " pow(S38," << fEnergyConversion.fEnergyS38Slope << ')';
341  INFO(info);
342  }
343 
344  //the limit for the second derivative of the ldf
345  fgNoRecovery = 1;
346  return eSuccess;
347 }
348 
349 
350 inline
351 void
353  const
354 {
356  EstimateS1000(fi);
358  << " S1000 = " << fi.fS1000 << ", "
359  "beta = " << fi.fBeta << ", "
360  "gamma = " << fi.fGamma << '\n';
362  // project core to the local tangent plane
363  Vector localNormal(0,0,1, fgLocalCS);
364  fi.fCore = core -
365  (localNormal*(core-fgBarycenter))/(localNormal*fgShowerAxis)*fgShowerAxis;
367  << " core = " << ToString(fi.fCore, fgLocalCS) << " (bary)\n";
368  } else {
369  fi.fCore = fgBarycenter;
371  << " using barycenter as core\n";
372  }
373  EstimateEnergy(fi);
375  << " energy = " << fi.fEnergy/EeV << " [EeV]\n";
376 }
377 
378 
379 inline
380 bool
381 LDFFinder::FitLDF(LDFFitInterface& fi, const int nStations)
382  const
383 {
385  fi.fLikelihood = FitLDFDriver(fi);
386 
387  if (fUseMaxLike && fi.fLikelihood)
388  fi.fChi2 = EstimateChi2(fi);
389 
390  if (fi.fLikelihood < 0) {
392  << " Fit failed.\n";
393  return false;
394  } else {
395 
396  fi.fNdof = nStations - 1 - (fCoreType == eFit ? 2 : 0) - !fi.fFixedBeta - !fi.fFixedGamma;
397 
398  const double nchi2 = fi.fNdof > 0 ? fi.fChi2/fi.fNdof : 0;
399 
400  if (nchi2 > fi.fMaxChi2) {
402  << " Chi2/NDOF = " << nchi2 << " exceeds the limit "
403  << fi.fMaxChi2 << '\n';
404  return false;
405  } else {
406 
407  const double d = (fi.fCore - fgBarycenter).GetMag();
408  if (d > fMaxBaryToCoreDistance) {
410  << " Distance to core " << d/km << " [km] is above the limit.\n";
411  return false;
412  } else {
413 
414  EstimateEnergy(fi);
415 
417  << " chi2 = " << fi.fChi2 << " / " << fi.fNdof << "\n "
418  " S1000 = " << fi.fS1000 << " +/- " << fi.fS1000Err << "\n "
419  " core = " << ToString(fi.fCore, fgLocalCS) << " +/-\n "
420  " " << ToString(fi.fCoreErr, fgLocalCS) << " (bary)\n";
421  if (!fi.fFixedBeta)
423  << " beta = " << fi.fBeta << " +/- " << fi.fBetaErr << '\n';
424  if (!fi.fFixedGamma)
426  << " gamma = " << fi.fGamma << " +/- " << fi.fGammaErr << '\n';
428  << " energy = "
429  << fi.fEnergy/EeV << " +/- "
430  << fi.fEnergyErr/EeV << " [EeV]\n";
431  }
432  }
433  }
434 
435  return true;
436 }
437 
438 
441 {
442  INFO("");
443 
444  // nothing to do if there is no SEvent
445  if (!(event.HasSEvent() && event.HasRecShower() &&
446  event.GetRecShower().HasSRecShower()))
447  return eContinueLoop;
448 
449  const SEvent& sEvent = event.GetSEvent();
450  fgCurrentSEvent = &sEvent;
451 
452  const ShowerSRecData& showerRec = event.GetRecShower().GetSRecShower();
453 
454  int nStations = 0;
455  fgLowerLimit = false;
456  {
457  int nSaturated = 0;
458  int nSilent = 0;
459  for (SEvent::ConstStationIterator sIt = sEvent.StationsBegin();
460  sIt != sEvent.StationsEnd(); ++sIt)
461  if (sIt->IsCandidate()) {
462  ++nStations;
463  if (sIt->IsLowGainSaturation())
464  ++nSaturated;
465  } else if (sIt->IsSilent())
466  ++nSilent;
467 
469  << "# candidate stations = " << nStations
470  << " (" << nSaturated << " saturated), " << nSilent << " silent\n";
471  }
472 
473  // not worth it
474  if (nStations < fStage0.fMinNumberOfStations) {
475  OUT(eFinal)
476  << "Not enough stations.\n";
477  return eContinueLoop;
478  }
479 
480  fgBarycenter = showerRec.GetBarycenter();
481  fgBaryTime = showerRec.GetBarytime();
483 
484  if (!fgBaryTime)
485  throw utl::NonExistentComponentException("needs barycenter!");
486 
487  if (fCoreType != eFit) {
488 
489  Point core;
490  TimeStamp coreTime;
491 
492  if (!FixCore(event, core, coreTime, fgShowerAxis))
493  return eContinueLoop;
494 
495  ShowerSRecData& showerRec = event.GetRecShower().GetSRecShower();
496  showerRec.SetAxis(fgShowerAxis);
497  showerRec.SetCorePosition(core);
498  showerRec.SetCoreTime(coreTime, TimeInterval(0));
499  showerRec.SetAngleErrors(fgShowerAxis.GetCoordinates(fgLocalCS), Vector::Triple(0,0,0));
500  showerRec.SetCurvature(0, 0);
501 
502  }
503 
504  // assume SdPlaneFit module has been run already
505  fgShowerAxis = showerRec.GetAxis();
506  const double theta = fgShowerAxis.GetTheta(fgLocalCS);
507 
508  if (theta > fMaxTheta) {
509  OUT(eFinal)
510  << " theta = " << theta/degree << " is > than limit "
511  << fMaxTheta/degree << " [deg], skipping...\n";
512  return eContinueLoop;
513  }
514 
515  const Point& core = showerRec.GetCorePosition();
516 
517  const CoordinateSystemPtr siteCS = det::Detector::GetInstance().GetSiteCoordinateSystem();
518  const TimeStamp eventTime(sEvent.GetTrigger().GetTime());
519 
521  << "barycenter = " << ToString(fgBarycenter, siteCS) << " (site)\n "
522  "bary time = " << (fgBaryTime - eventTime).GetInterval()/nanosecond
523  << " [ns] (to event time)\n "
524  "axis = " << ToString(fgShowerAxis, siteCS, false) << " (site)\n "
525  " = " << ToString(fgShowerAxis, fgLocalCS, false) << " (bary)\n "
526  "theta = " << theta/degree << " [deg] (bary)\n "
527  "phi = " << fgShowerAxis.GetPhi(fgLocalCS)/degree << " [deg] (bary)\n";
528 
529  OUT(eObscure)
530  << "local/site zenith angle diff. = "
531  << acos(Vector(0,0,1, fgLocalCS)*Vector(0,0,1, siteCS))/degree
532  << " [deg]\n";
533 
534  LDFFitInterface best;
535  CurvatureFitInterface cbest;
536  cbest.fAxis = fgShowerAxis;
537 
538  // --- Stage: LDF estimation ------------------------------------------------
539 
540  best.fRecStage = ShowerSRecData::kLDFEstimate;
542  << "Stage " << best.fRecStage << ": estimate beta, gamma, S1000\n";
543  EstimateLDF(best, core);
544 
545  if (nStations < fStage1.fMinNumberOfStations) {
546  SetRecData(event, best, cbest);
547  OutputResults(event);
548  return eSuccess;
549  }
550 
551  bool useSilentStations = (nStations > 4);
552  // loop: without/with silents
553  do {
554  useSilentStations = !useSilentStations;
555  const bool failOnError = !fUseSilentStations || useSilentStations;
556  const string stationType = useSilentStations ? "candidate+silents" : "candidates";
557 
558  // --- Stage: S1000 & core fitting ----------------------------------------
559  {
560  LDFFitInterface fi = best;
561  fi.fRecStage = (useSilentStations ? ShowerSRecData::kLDFSilents : ShowerSRecData::kLDF);
562 
563  fi.fFixedBeta = true;
564  fi.fFixedGamma = true;
565  fi.fUseSilents = useSilentStations;
567  fgFixLDF = (fi.fFixedBeta && fi.fFixedGamma);
568 
570  << "Stage " << fi.fRecStage << ": fit " << stationType << " for S1000, core\n";
571  fgLowerLimit = false;
572  if (FitLDF(fi, nStations))
573  best = fi;
574  else if (failOnError)
575  break;
576 
577  } // stage
578 
579  // --- Stage: S1000, core, beta (gamma) fitting ---------------------------
580  {
581  LDFFitInterface fi = best;
582 
583  fi.fFixedBeta = (nStations < fStage2.fMinNumberRelaxBeta || FixBeta(fi)) ? true : false;
584  fi.fFixedGamma = (nStations < fStage2.fMinNumberRelaxGamma || FixGamma(fi)) ? true : false;
585  fgFixLDF = (fi.fFixedBeta && fi.fFixedGamma);
586  if (!fi.fFixedBeta || !fi.fFixedGamma) {
587 
588  fi.fRecStage = (fgUseSilentStations ? ShowerSRecData::kLDFSilents : ShowerSRecData::kLDF) +
589  (!fi.fFixedBeta) * ShowerSRecData::kLDFBeta +
590  (!fi.fFixedGamma) * ShowerSRecData::kLDFGamma;
591  fi.fUseSilents = useSilentStations;
592  fi.fMaxChi2 = fMaxChi2;
593 
595  << "Stage " << fi.fRecStage << ": fit " << stationType << " for S1000, core"
596  << (!fi.fFixedBeta ? ", beta" : "")
597  << (!fi.fFixedGamma ? ", gamma\n" : "\n");
598  fgLowerLimit = false;
599  if (FitLDF(fi, nStations)) {
600  const bool fixBeta = FixBeta(fi);
601  const bool fixGamma = FixGamma(fi);
602  if (fi.fFixedBeta == fixBeta && fi.fFixedGamma == fixGamma)
603  best = fi;
604  else {
605  fi.fFixedBeta = fi.fFixedBeta ? fi.fFixedBeta : fixBeta;
606  fi.fFixedGamma = fi.fFixedGamma ? fi.fFixedGamma : fixGamma;
607  fgFixLDF = (fi.fFixedBeta && fi.fFixedGamma);
608  fi.fRecStage = (fgUseSilentStations ? ShowerSRecData::kLDFSilents : ShowerSRecData::kLDF) +
609  (!fi.fFixedBeta) * ShowerSRecData::kLDFBeta +
610  (!fi.fFixedGamma) * ShowerSRecData::kLDFGamma;
611  fgLowerLimit = false;
612  if (FitLDF(fi, nStations))
613  best = fi;
614  else if (failOnError)
615  break;
616 
617  }
618  } else if (failOnError)
619  break;
620 
621  }
622 
623  } // stage
624 
625  } while (fUseSilentStations && !useSilentStations);
626 
627  if (nStations < fStage3.fMinNumberOfStations) {
628  SetRecData(event, best, cbest);
629  OutputResults(event);
630  return eSuccess;
631  }
632 
633  {
635  cfi.fCore = best.fCore;
636  cfi.fAxis = cbest.fAxis;
637  const double parameterizedRc = ParameterizedRc(best);
638  cfi.fRc = parameterizedRc;
639  cfi.fct0 = -cfi.fRc;
640  double chi2 = 0;
641 
642  if (nStations < fStage3.fMinNumberForFullCurvatureFit) {
643  cfi.fFixedRc = true;
645  << "Fit for axis with fixed Rc = " << cfi.fRc/kilometer << " [km]\n";
646  chi2 = FitCurvatureDriver(cfi);
647  } else {
648  cfi.fFixedRc = false;
650  << "Fit for shower-front curvature and axis.\n";
651  chi2 = FitCurvatureDriver(cfi);
652  if (chi2 <= 0) {
654  << " Fit failed, retrying with fixed Rc = " << parameterizedRc << " [km]\n";
655  cfi.fFixedRc = true;
656  cfi.fRc = parameterizedRc;
657  cfi.fRcErr = 0;
658  cfi.fct0 = -cfi.fRc;
659  chi2 = FitCurvatureDriver(cfi);
660  }
661  }
662 
663  if (chi2 <= 0) {
665  << " Last fit failed.\n";
666  cbest.fRc = 0;
667  } else {
668  const double diff = acos(cfi.fAxis * fgShowerAxis);
670  << " axis = " << ToString(cfi.fAxis, fgLocalCS) << " (bary)\n "
671  " axis diff = " << diff/degree << " [deg] (to plain-front fit)\n "
672  " Rc = " << cfi.fRc/meter << " +/- " << cfi.fRcErr/meter << " [m]\n "
673  " ct0 = " << cfi.fct0/meter << " +/- " << cfi.fct0Err/meter << " [m]\n";
674  if (diff > fStage3.fMaxAxisAngleDifference) {
676  << " Opening-angle axis difference is above the limit.\n";
677  cbest.fRc = 0;
678  } else
679  cbest = cfi;
680  }
681  }
682 
683  const double newTheta = cbest.fAxis.GetTheta(fgLocalCS);
684  if (newTheta > fMaxTheta) {
685  OUT(eFinal)
686  << " theta = " << newTheta/degree << " is > than limit "
687  << fMaxTheta/degree << " [deg], skipping...\n";
688  return eContinueLoop;
689  }
690 
691  // redo LDF fit after the axis change
692  if (cbest.fRc) {
693  LDFFitInterface fi = best;
694  const Vector oldAxis = fgShowerAxis;
695  fgShowerAxis = cbest.fAxis;
696 
697  if (best.fRecStage == ShowerSRecData::kLDFEstimate) {
699  << "Redo Stage " << best.fRecStage << ": estimate beta, gamma, S1000\n";
700  EstimateLDF(best, core);
701  best.fRecStage = ShowerSRecData::kLDFEstimateAndCurvature;
702  } else {
703  const string stationType = fi.fUseSilents ? "candidate+silents" : "candidates";
705  << "Redo Stage " << fi.fRecStage << ": fit " << stationType << " for S1000, core"
706  << (!fi.fFixedBeta ? ", beta" : "")
707  << (!fi.fFixedGamma ? ", gamma\n" : "\n");
708 
711  fgLowerLimit = false;
712  if (FitLDF(fi, nStations)) {
713  // showerCenter = oldCore + oldAxis * oldRc
714  const Point showerCenter = best.fCore + cbest.fAxis * cbest.fRc;
715  // newAxis = normalized(showerCenter - newCore)
716  const Vector coreCenter = showerCenter - fi.fCore;
717  // newRc = |showerCenter - newCore|
718  const double newRc = coreCenter.GetMag();
719  cbest.fRc = newRc;
720  cbest.fAxis = coreCenter / newRc;
721  best = fi;
722  best.fRecStage += 0.5;
723  } else {
724  // return to the last successful results if the LDF fit fails
725  fgShowerAxis = oldAxis;
726  cbest.fRc = 0;
727  }
728  }
729  }
730 
731  SetRecData(event, best, cbest);
732 
733  // calculation of Ropt, see GAP-2006-045
734  const double finalBeta = best.fBeta;
735  const double betaFixSigma = SigmaForFixedBeta(best.fS1000);
736  // const int fRoptN = 2;
737  double vS1000[fRoptN];
738  double vBeta[fRoptN];
739  const double startp = NormalCDF(-1);
740  const double stopp = NormalCDF(1);
741  const double deltap = (stopp - startp) / (fRoptN - 1);
743  << "Ropt determination: \n";
744  for (int i = 0; i < fRoptN; ++i) {
745  LDFFitInterface fi = best;
746  const double p = startp + i*deltap;
747  fi.fBeta = vBeta[i] = finalBeta + InverseNormalCDF(p, betaFixSigma);
748  fi.fFixedBeta = true;
749  fgFixLDF = false;
750  fi.fGamma = best.fGamma;
751  fi.fFixedGamma = true;
752  FitLDF(fi, nStations);
753  vS1000[i] = fi.fS1000;
754  }
755 
756  RoptFit roptFit;
757  pair<double, double> ropt = roptFit.Fit(fgLDFType, fRoptN, vS1000, vBeta, fMinuitOutput);
758  ShowerSRecData& shRec = event.GetRecShower().GetSRecShower();
759  shRec.SetLDFOptimumDistance(ropt.first);
760  // "derivative" (finite difference)
761  const double dS1000_dBeta = (vS1000[0] - vS1000[fRoptN-1]) / (vBeta[0] - vBeta[fRoptN-1]);
762  // beta spread parameterization from Talianna
763  shRec.SetBetaSystematics(betaFixSigma);
764  shRec.SetShowerSizeSystematics(fabs(betaFixSigma * dS1000_dBeta));
765 
766  OutputResults(event);
767 
768  return eSuccess;
769 }
770 
771 
772 bool
773 LDFFinder::FixCore(const evt::Event& event, Point& core,
774  TimeStamp& refTime, Vector& axis)
775  const
776 {
777  const Vector localNormal(0,0,1, fgLocalCS);
778  Point coreReference;
779 
780 
781  switch (fCoreType) {
782  case eMC: {
783  if (!event.HasSimShower()) {
784  ERROR("The event is not a simulated shower.");
785  return false;
786  }
787  const ShowerSimData& simShower = event.GetSimShower();
788  axis = -simShower.GetDirection();
789  coreReference = simShower.GetPosition();
790  refTime = simShower.GetTimeStamp();
791  break;
792  }
793  case eHybrid:
794  if (!event.HasFEvent()) {
795  ERROR("The event has no FD shower.");
796  return false;
797  }
798 
799  const fevt::FEvent& fEvent = event.GetFEvent();
800  const bool stereoRec =
801  event.HasRecShower() && event.GetRecShower().HasFRecShower();
802  // remember area of FD core error ellipse to choose best FD eye
803  double bestErrorEllipse = 0;
804 
805  const evt::ShowerFRecData* showerFRec = 0;
806  if (stereoRec)
807  showerFRec = &event.GetRecShower().GetFRecShower();
808 
809  for (FEvent::ConstEyeIterator eyeIt = fEvent.EyesBegin(ComponentSelector::eHasData);
810  eyeIt != fEvent.EyesEnd(ComponentSelector::eHasData); ++eyeIt) {
811 
812  // skip eyes without reconstruction
813  if (!eyeIt->HasRecData())
814  continue;
815 
816  const fevt::EyeRecData& eyeRec = eyeIt->GetRecData();
817  if (eyeRec.GetSDPFitNDof() <= 0 || eyeRec.GetTimeFitNDof() <= 0)
818  continue;
819 
820  if (!eyeRec.HasFRecShower())
821  continue;
822 
823  if (!stereoRec)
824  showerFRec = &eyeRec.GetFRecShower();
825 
826  const fdet::Eye& dEye = det::Detector::GetInstance().GetFDetector().GetEye(*eyeIt);
827  const CoordinateSystemPtr eyeCS = dEye.GetEyeCoordinateSystem();
828  const Point eyePos = dEye.GetPosition();
829  const Vector vecEyeCore = eyePos - showerFRec->GetCorePosition();
830 
831  const double rp = eyeRec.GetRp();
832  const double rpErr = eyeRec.GetRpError();
833  const double t0 = eyeRec.GetTZero();
834  const double chi0 = eyeRec.GetChiZero();
835  const double chi0Err = eyeRec.GetChiZeroError();
836  const double sdpPhiErr = eyeRec.GetSDPPhiError();
837  const double rhoChi0Rp = eyeRec.GetRpChi0Correlation();
838  const double distEyeCore = vecEyeCore.GetMag();
839 
840  // calculation of core error in SDP
841  // rp error projected on ground+
842  // chi0 error+ correlation of errors in rp and chi0
843  const double sinChi0 = sin(chi0);
844  const double errorInSDP = sqrt(Sqr(rpErr/sinChi0) +
845  Sqr((chi0Err*distEyeCore)/(cos(chi0)*sinChi0)) +
846  rhoChi0Rp * rpErr * chi0Err);
847 
848  // error due to SDP azimuth uncertainty
849  const double errorPerpSDP = distEyeCore * sin(sdpPhiErr);
850 
851  // area of core error ellipse of this FD event
852  const double coreErrorEllipse = errorInSDP * errorPerpSDP * kPi;
853 
854  // if error ellipse set AND error ellipse larger than previous eye(s)
855  // don't update core with actual eye
856  if (bestErrorEllipse && bestErrorEllipse < coreErrorEllipse)
857  continue;
858 
859  bestErrorEllipse = coreErrorEllipse;
860  axis = showerFRec->GetAxis();
861  coreReference = showerFRec->GetCorePosition();
862 
863  const Vector vertical(0,0,1, eyeCS);
864  const double alpha = 0.5*kPi - Angle(vertical, vecEyeCore);
865  const double cosBeta = CosAngle(axis, vecEyeCore);
866  // 1e5ns have to be subtracted to jump from the end to the
867  // start of the pixel trace (don't even think of removing the
868  // comment here)
869  refTime = eyeIt->GetHeader().GetTimeStamp() +
870  TimeInterval(-1e5*ns + t0 + (rp*tan(alpha) + distEyeCore*cosBeta)/kSpeedOfLight);
871  break;
872  }
873 
874  if (!showerFRec)
875  return false;
876  break;
877  }
878 
879  core = coreReference -
880  (localNormal * (coreReference - fgBarycenter)) / (localNormal*axis) * axis;
881 
882  const double d = (core - fgBarycenter).GetMag();
883  if (d > fMaxBaryToCoreDistance) {
884  ostringstream err;
885  err << "Bary-centric distance to core " << d/kilometer
886  << " [km] is above the limit.";
887  ERROR(err);
888  return false;
889  }
890 
891  return true;
892 }
893 
894 
895 // From Pierre Billoir Thoughts....
896 // - if there are enough stations (especially at distances around 1000 m), a fit
897 // with a variable LDF slope is attempted (B is set as adjustable in (3)); the
898 // conditions are:
899 // * at least 5 stations, with one of the following requirements:
900 // * at least 2 within (500, 1500), with a difference at least 500 in between
901 // * at least 3 within (500, 1500), with a maximal difference at least 400
902 // * at least 4 within (500, 1500), with a maximal difference at least 300
903 bool
905  const
906 {
907  vector<int> candidates;
910  sIt != sEnd; ++sIt)
911  if (!sIt->IsLowGainSaturation() || sIt->GetRecData().GetRecoveredSignal())
912  candidates.push_back(sIt->GetId());
913 
914  const int nStations = candidates.size();
915  if (nStations < 5) {
917  << "FixBeta = " << true
918  << ": nStations = " << nStations << '\n';
919  return true;
920  }
921 
922  const sdet::SDetector& sDetector = det::Detector::GetInstance().GetSDetector();
923  int nStationsInRange = 0;
924  double maxDistance = 0;
925 
926  for (vector<int>::const_iterator sIt = candidates.begin();
927  sIt != candidates.end(); ++sIt) {
928 
929  const double r =
930  RPerp(fgShowerAxis, sDetector.GetStation(*sIt).GetPosition() - fi.fCore);
931 
932  if (500*meter < r && r < 1500*meter) {
933 
934  ++nStationsInRange;
935 
936  for (vector<int>::const_iterator sJt = sIt + 1;
937  sJt != candidates.end(); ++sJt) {
938 
939  const double rr =
940  RPerp(fgShowerAxis, sDetector.GetStation(*sJt).GetPosition() - fi.fCore);
941 
942  if (500*meter < rr && rr < 1500*meter) {
943  const double distance = fabs(r - rr);
944  if (distance > maxDistance)
945  maxDistance = distance;
946  }
947  }
948  }
949  }
950 
951  const bool fixBeta = !((nStationsInRange > 1 && maxDistance > 500*meter) ||
952  (nStationsInRange > 2 && maxDistance > 400*meter) ||
953  (nStationsInRange > 3 && maxDistance > 300*meter));
955  << "FixBeta = " << fixBeta
956  << ": nStations (InRange) = " << nStations << " (" << nStationsInRange
957  << "), maxDistance = " << maxDistance/meter << " [m]\n";
958 
959  return fixBeta;
960 }
961 
962 
963 // Criterion if gamma can be fitted analogue to FixBeta.
964 bool
966  const
967 {
968  vector<int> candidates;
971  sIt != sEnd; ++sIt)
972  if (!sIt->IsLowGainSaturation() || sIt->GetRecData().GetRecoveredSignal())
973  candidates.push_back(sIt->GetId());
974 
975  const int nStations = candidates.size();
976  if (nStations < 5) {
978  << "FixGamma = " << true
979  << ": nStations = " << nStations << '\n';
980  return true;
981  }
982 
983  const sdet::SDetector& sDetector = det::Detector::GetInstance().GetSDetector();
984  int nStationsInRange = 0;
985  double maxDistance = 0;
986 
987  for (vector<int>::const_iterator sIt = candidates.begin();
988  sIt != candidates.end(); ++sIt) {
989 
990  const double r =
991  RPerp(fgShowerAxis, sDetector.GetStation(*sIt).GetPosition() - fi.fCore);
992 
993  if (1000*meter < r && r < 2000*meter) {
994 
995  ++nStationsInRange;
996 
997  for (vector<int>::const_iterator sJt = sIt + 1;
998  sJt != candidates.end(); ++sJt) {
999 
1000  const double rr =
1001  RPerp(fgShowerAxis, sDetector.GetStation(*sJt).GetPosition() - fi.fCore);
1002 
1003  if (1000*meter < rr && rr < 2000*meter) {
1004  const double distance = fabs(r - rr);
1005  if (distance > maxDistance)
1006  maxDistance = distance;
1007  }
1008  }
1009  }
1010  }
1011 
1012  const bool fixGamma = !((nStationsInRange > 1 && maxDistance > 500*meter) ||
1013  (nStationsInRange > 2 && maxDistance > 400*meter) ||
1014  (nStationsInRange > 3 && maxDistance > 300*meter));
1016  << "FixGamma = " << fixGamma
1017  << ": nStations (InRange) = " << nStations << " (" << nStationsInRange
1018  << "), maxDistance = " << maxDistance/meter << " [m]\n";
1019 
1020  return fixGamma;
1021 }
1022 
1023 
1025 void
1027  const
1028 {
1029  const double k1000m = 1000*meter;
1030  double rMin = 1e20;
1031  double rClosest = k1000m;
1032  double signal = 1;
1033 
1034  const sdet::SDetector& sDetector = det::Detector::GetInstance().GetSDetector();
1035 
1036  // loop on stations
1038  sIt != fgCurrentSEvent->CandidateStationsEnd(); ++sIt) {
1039 
1040  const double r =
1041  RPerp(fgShowerAxis, sDetector.GetStation(*sIt).GetPosition() - fgBarycenter);
1042 
1043  if (abs(r - k1000m) < rMin) {
1044  rMin = fabs(r - k1000m);
1045  signal = sIt->GetRecData().GetTotalSignal();
1046  rClosest = r;
1047  }
1048 
1049  }
1050 
1051  fi.fS1000 = signal / LDFFunction(fgLDFType, rClosest, fi.fBeta, fi.fGamma, fgNKGFermiMu, fgNKGFermiTau);
1052 }
1053 
1054 
1055 double
1057  const
1058 {
1059  const sdet::SDetector& sDetector = det::Detector::GetInstance().GetSDetector();
1060 
1061  double nStations = 0;
1062  // loop on stations
1064  sIt != fgCurrentSEvent->StationsEnd(); ++sIt) {
1065 
1066  if (sIt->IsCandidate())
1067  ++nStations;
1068  else if (fgUseSilentStations && sIt->IsSilent()) {
1069  const double r =
1070  RPerp(fgShowerAxis, sDetector.GetStation(*sIt).GetPosition() - fi.fCore);
1071  nStations +=
1073  }
1074 
1075  }
1076 
1077  return nStations;
1078 }
1079 
1080 
1081 void
1083  const
1084 {
1086  fi.fEnergy, fi.fEnergyErr);
1087 }
1088 
1089 
1090 double
1092  const
1093 {
1094  const double s = log10(fi.fS1000);
1095  const double s2 = Sqr(s);
1096  /* markus' fit
1097  const double offset = 9.03 - 3.08*s + 1.08*s2;
1098  const double slope = 7.28 + 4.03*s - 1.01*s2;
1099  */
1100  const double offset = 7.418 - 3.0613*s + 2.5262*s2;
1101  const double slope = 3.9779 + 3.2245*s + 4.5705*s2;
1102  const double sec1 = 1/fgShowerAxis.GetCosTheta(fgLocalCS) - 1;
1103  return (offset + slope*sec1) * kilometer;
1104 }
1105 
1106 
1107 void
1109  const CurvatureFitInterface& cfi)
1110  const
1111 {
1112  ShowerSRecData& recShower =
1113  event.GetRecShower().GetSRecShower();
1114 
1115  const sdet::SDetector& sDetector =
1116  det::Detector::GetInstance().GetSDetector();
1117 
1118  const double s1000 = lfi.fS1000;
1119  const double beta = lfi.fBeta;
1120  const double gamma = lfi.fGamma;
1121  const double cosTheta = fgShowerAxis.GetCosTheta(fgLocalCS);
1122  const double sigmaFactor = wcd::SignalUncertaintyFactor(wcd::eGAP2012_012, cosTheta);
1123 
1124  SEvent& sEvent = event.GetSEvent();
1125 
1126  const bool haveCurvature = (cfi.fRc != 0);
1127  const Point showerOrigin(lfi.fCore + cfi.fRc * cfi.fAxis);
1128  const double ct0 = cfi.fct0;
1129 
1130  const double theta = fgShowerAxis.GetTheta(fgLocalCS);
1131  const double phi = fgShowerAxis.GetPhi(fgLocalCS);
1132  const CoordinateSystemPtr showerPlaneCS(
1134  theta,
1136  phi,
1137  LocalCoordinateSystem::Create(lfi.fCore)
1138  )
1139  )
1140  );
1141 
1142  HepMatrix hepErrMatrix(3,3,0);
1143  if (fCoreType == eFit) {
1144  hepErrMatrix[0][0] = lfi.fErrMatrix[1][1];
1145  hepErrMatrix[0][1] = lfi.fErrMatrix[1][2];
1146  hepErrMatrix[1][0] = lfi.fErrMatrix[2][1];
1147  hepErrMatrix[1][1] = lfi.fErrMatrix[2][2];
1148  } else
1149  for (int i = 0; i < 2; ++i)
1150  for (int j = 0; j < 2; ++j)
1151  hepErrMatrix[i][j] = (i == j);
1152 
1153  HepRotation r;
1154  r.rotateZ(-phi);
1155  r.rotateY(-theta);
1156 
1157  HepMatrix hepRotationMatrix(3,3);
1158  for (int i = 0; i < 3; ++i)
1159  for (int j = 0; j < 3; ++j)
1160  hepRotationMatrix[i][j] = r[i][j];
1161 
1162  HepMatrix hepRotatedErrMatrix(3,3);
1163  hepRotatedErrMatrix = hepRotationMatrix * hepErrMatrix * hepRotationMatrix.T();
1164 
1165  const sdet::STimeVariance& timeVariance = sdet::STimeVariance::GetInstance();
1166  Accumulator::MinMax<double> minMaxRho(1000*kilometer, 0);
1168 
1169  for (SEvent::StationIterator sIt = sEvent.StationsBegin();
1170  sIt != sEvent.StationsEnd(); ++sIt)
1171 
1172  if (sIt->HasRecData()) {
1173 
1174  const Point& sPos = sDetector.GetStation(*sIt).GetPosition();
1175  const double rho2 = RPerp2(cfi.fAxis, sPos - lfi.fCore);
1176  const double rho = sqrt(rho2);
1177  minMaxRho(rho);
1178 
1179  StationRecData& sRec = sIt->GetRecData();
1180  const double signal = sRec.GetTotalSignal();
1181  const double funcval = s1000 * LDFFunction(fgLDFType, rho, beta, gamma, fgNKGFermiMu, fgNKGFermiTau);
1182  const double sigma = sigmaFactor * sqrt(funcval);
1183 
1184  const double drho2 =
1185  (Sqr(sPos.GetX(showerPlaneCS)) * hepRotatedErrMatrix[0][0] +
1186  Sqr(sPos.GetY(showerPlaneCS)) * hepRotatedErrMatrix[1][1] +
1187  2 * sPos.GetX(showerPlaneCS) * sPos.GetY(showerPlaneCS) * hepRotatedErrMatrix[0][1]) / rho2;
1188 
1189  const double drho = sqrt(drho2);
1190 
1191  sRec.SetAzimuthShowerPlane(sPos.GetPhi(showerPlaneCS));
1192  sRec.SetTotalSignal(signal,sigma);
1193  sRec.SetLDFResidual((signal - funcval)/sigma);
1194  sRec.SetSPDistance(rho, drho);
1195 
1196  if (haveCurvature) {
1197  const double measuredTime = (sRec.GetSignalStartTime() - fgBaryTime).GetInterval();
1198  const Vector stationOrigin = showerOrigin - sPos;
1199  const double distOrigin = stationOrigin.GetMag();
1200  const double predictedTime = (distOrigin + ct0) / kSpeedOfLight;
1201  const double stationCosTheta = stationOrigin.GetZ(fgLocalCS) / distOrigin;
1202  const double sigma =
1203  sqrt(timeVariance.GetTimeSigma2(signal, sRec.GetT50(), stationCosTheta, rho));
1204  const double residual = (measuredTime - predictedTime)/sigma;
1205  sRec.SetResidual(residual);
1206  if (sIt->IsCandidate())
1207  timeStat(residual);
1208  }
1209 
1210  }
1211 
1212  double minRho = 0.5 * minMaxRho.GetMin();
1213  double maxRho = 1.2 * minMaxRho.GetMax();
1214  if (maxRho < 1200*meter)
1215  maxRho = 1200*meter;
1216 
1217  if (!recShower.HasLDF())
1218  recShower.MakeLDF();
1219  TabulatedFunctionErrors& ldf = recShower.GetLDF();
1220  ldf.Clear();
1221 
1222  const int nLDFPoints = 200;
1223  const double dRho = (maxRho - minRho)/(nLDFPoints - 1);
1224  for (int i = 0; i < nLDFPoints; ++i) {
1225  const double rho = minRho + i*dRho;
1226  const double funcval = s1000 * LDFFunction(fgLDFType, rho, beta, gamma, fgNKGFermiMu, fgNKGFermiTau);
1227  const double sigma = sigmaFactor * sqrt(funcval);
1228  ldf.PushBack(rho, 0, funcval, sigma);
1229  }
1230 
1231  // set the reconstruction data
1232  if (haveCurvature) {
1233  recShower.SetAxis(cfi.fAxis);
1234  const double rc = cfi.fRc;
1235  recShower.SetCurvature(1/rc, cfi.fRcErr/Sqr(rc));
1236  recShower.SetCoreTime(fgBaryTime + TimeInterval((cfi.fct0 + rc)/kSpeedOfLight),
1238  const double timeMean = timeStat.GetAverage();
1239  const double timeSpread = timeStat.GetStandardDeviation();
1240  recShower.SetTimeResidualMean(timeMean);
1241  recShower.SetTimeResidualSpread(timeSpread);
1242  const int ndof = timeStat.GetN() // number of candidate stations
1243  - (cfi.fFixedAxis ? 0 : 2) // for u and v
1244  - (cfi.fFixedRc ? 0 : 1) // for Rc
1245  - 1; // for t0
1246  recShower.SetAngleChi2(timeStat.GetSumOfSquares(), ndof);
1247  recShower.SetAngleErrors(cfi.fAxis.GetCoordinates(fgLocalCS),
1248  Vector::Triple(cfi.fSigmaU2, cfi.fSigmaUV, cfi.fSigmaV2));
1249  } else {
1250  // we have moved the core but have axis from plane fit, recalc t0
1251  const TimeInterval cdiff =
1252  recShower.GetAxis() * (recShower.GetCorePosition() - lfi.fCore);
1253  const TimeStamp newCoreTime =
1254  recShower.GetCoreTime() + cdiff/kSpeedOfLight;
1255  recShower.SetCoreTime(newCoreTime, recShower.GetCoreTimeError());
1256  /*OUT(eIntermediate)
1257  << "Core moved, core time change: " << cdiff/meter << " [m].\n";*/
1258  }
1259  recShower.SetNumberOfActiveStations(timeStat.GetN());
1260  recShower.SetShowerSizeType(ShowerSRecData::eS1000);
1261  recShower.SetShowerSize(lfi.fS1000, lfi.fS1000Err);
1262  recShower.SetCorePosition(lfi.fCore);
1263  recShower.SetCoreError(lfi.fCoreErr);
1264  recShower.SetCorrelationXY(hepErrMatrix[0][1]/sqrt(hepErrMatrix[0][0]*hepErrMatrix[1][1]));
1265  recShower.SetBeta(lfi.fBeta, lfi.fBetaErr);
1266  recShower.SetGamma(lfi.fGamma, lfi.fGammaErr);
1268  recShower.SetLDFChi2(lfi.fChi2, lfi.fNdof);
1269  recShower.SetLDFLikelihood(lfi.fLikelihood);
1270  double energy = 0;
1271  double energyErr = 0;
1272 
1274  energy, energyErr);
1275 
1276  recShower.SetEnergy(energy, energyErr);
1277  recShower.SetLDFRecStage(lfi.fRecStage + fgLowerLimit*ShowerSRecData::kLDFLowerLimit);
1278 }
1279 
1280 
1283 {
1284  return eSuccess;
1285 }
1286 
1287 
1289 double
1291  const
1292 {
1293  TMinuit minuit(5);
1294  int errFlag = 0;
1295  double argList[10];
1296  argList[0] = -1;
1297  if (!fMinuitOutput) {
1298  minuit.mnexcm("SET PRINTOUT", argList, 1, errFlag);
1299  minuit.mnexcm("SET NOWARNINGS", argList, 0, errFlag);
1300  minuit.SetPrintLevel(-1);
1301  }
1302 
1303  if (fUseMaxLike) {
1304  minuit.SetFCN(LDFFinder::LDFFitMaxLikeFnc);
1305  argList[0] = 0.5;
1306  } else {
1307  minuit.SetFCN(LDFFinder::LDFFitChi2Fnc);
1308  argList[0] = 1;
1309  }
1310  minuit.mnexcm("SET ERRORDEF", argList, 1, errFlag);
1311 
1312  minuit.mnparm(0, "s1000", fi.fS1000, 1., 0, 0, errFlag);
1313  minuit.mnparm(1, "x", fi.fCore.GetX(fgLocalCS), 200*meter, 0, 0, errFlag);
1314  minuit.mnparm(2, "y", fi.fCore.GetY(fgLocalCS), 200*meter, 0, 0, errFlag);
1315  minuit.mnparm(3, "beta", fi.fBeta, 0.1, 0, 0, errFlag);
1316  minuit.mnparm(4, "gamma", fi.fGamma, 0.02, 0, 0, errFlag);
1317 
1318  if (fCoreType != eFit) {
1319  minuit.FixParameter(1);
1320  minuit.FixParameter(2);
1321  }
1322 
1323  if (fi.fFixedBeta)
1324  minuit.FixParameter(3);
1325  if (fi.fFixedGamma)
1326  minuit.FixParameter(4);
1327 
1328  // init fnc
1329  argList[0] = 1;
1330  minuit.mnexcm("CALI", argList, 1, errFlag);
1331 
1332  argList[0] = 500;
1333  minuit.mnexcm("MINIMIZE", argList, 1, errFlag);
1334  if (errFlag) {
1335  OUT(eObscure)
1336  << " minuit minimize error: " << errFlag << '\n';
1337  minuit.mnexcm("MINOS", argList, 0, errFlag);
1338  if (errFlag) {
1339  OUT(eObscure)
1340  << " minuit minos error: " << errFlag << '\n';
1341  return -1;
1342  }
1343  }
1344 
1345  // Get results
1346  minuit.GetParameter(0, fi.fS1000, fi.fS1000Err);
1347  double x;
1348  double y;
1349  double xErr;
1350  double yErr;
1351  if (fCoreType == eFit) {
1352  minuit.GetParameter(1, x, xErr);
1353  minuit.GetParameter(2, y, yErr);
1354  fi.fCore = Point(x, y, 0, fgLocalCS);
1355  fi.fCoreErr = Vector(xErr, yErr, 0, fgLocalCS);
1356  }
1357  if (!fi.fFixedBeta)
1358  minuit.GetParameter(3, fi.fBeta, fi.fBetaErr);
1359  else {
1360  fi.fBetaErr = 0;
1363  }
1364  if (!fi.fFixedGamma)
1365  minuit.GetParameter(4, fi.fGamma, fi.fGammaErr);
1366  else
1367  fi.fGammaErr = 0;
1368 
1369  // error matrix
1370  if (minuit.fNpar > 5) {
1371  ostringstream err;
1372  err << "Number of parameters used in Minuit covarince matrix larger "
1373  "than size of matrix fErrMatrix";
1374  ERROR(err);
1375 
1376  throw utl::OutOfBoundException(err.str());
1377  }
1378 
1379  minuit.mnemat(&fi.fErrMatrix[0][0], 5);
1380 
1381  return minuit.fAmin;
1382 }
1383 
1384 
1386 double
1388  const
1389 {
1390  TMinuit minuit(5);
1391  int errFlag = 0;
1392  double argList[10];
1393  argList[0] = -1;
1394  if (!fMinuitOutput) {
1395  minuit.mnexcm("SET PRINTOUT", argList, 1, errFlag);
1396  minuit.mnexcm("SET NOWARNINGS", argList, 0, errFlag);
1397  minuit.SetPrintLevel(-1);
1398  }
1399 
1400  // disable silent stations for chi2 calculation
1401  const bool saveSilent = LDFFinder::fgUseSilentStations;
1403 
1404  minuit.SetFCN(LDFFinder::LDFFitChi2Fnc);
1405  argList[0] = 1;
1406  minuit.mnexcm("SET ERRORDEF", argList, 1, errFlag);
1407 
1408  minuit.mnparm(0, "s1000", fi.fS1000, 0, 0, 0, errFlag);
1409  minuit.mnparm(1, "x", fi.fCore.GetX(fgLocalCS), 0, 0, 0, errFlag);
1410  minuit.mnparm(2, "y", fi.fCore.GetY(fgLocalCS), 0, 0, 0, errFlag);
1411  minuit.mnparm(3, "beta", fi.fBeta, 0, 0, 0, errFlag);
1412  minuit.mnparm(4, "gamma", fi.fGamma, 0, 0, 0, errFlag);
1413 
1414  argList[0] = 1;
1415  minuit.mnexcm("CALI", argList, 1, errFlag);
1416 
1417  // restore
1418  LDFFinder::fgUseSilentStations = saveSilent;
1419 
1420  if (errFlag) {
1421  OUT(eObscure)
1422  << " minuit get chi2 error: " << errFlag << '\n';
1423  return 0;
1424  }
1425 
1426  return minuit.fAmin;
1427 }
1428 
1429 
1431 void
1432 LDFFinder::LDFFitMaxLikeFnc(int& /*nPar*/, double* const /*grad*/, double& value,
1433  double* const par, const int iFlag)
1434 {
1435  // One comment on the following conversion factor called PoissonFactor:
1436  // The factor reflects the electron-gamma to muon ratio and gives rise to
1437  // criticism of the algorithm. But as long as we would like to include
1438  // "active" Zero stations, we have to assume a conversion factor. Otherwise we
1439  // cannot employ a maximum likelihood method! By definion a \chi^2 method gives
1440  // biased results (more strongly stated: in a mathematical sense they are
1441  // wrong) !
1442  // This factor has to be studied in detail by means of simulated AND real
1443  // data. See Haverah Park analysis for more details (Lapikens? or England?)
1444 
1445  const double& x = par[1];
1446  const double& y = par[2];
1447  const double s1000 = par[0];
1448  double beta = 0;
1449  double gamma = 0;
1450 
1451  if (s1000 <= 0) {
1452  value = numeric_limits<double>::max();
1453  return;
1454  }
1455 
1456  if (LDFFinder::fgFixLDF)
1458  else {
1459  beta = par[3];
1460  gamma = par[4];
1461  }
1462 
1463  static vector<bool> sIsCandidate;
1464  static vector<Point> sPosition;
1465  static vector<double> sSignal;
1466  static vector<double> sSignalError;
1467  static vector<bool> sIsSaturation;
1468 
1469  if (iFlag == 1) { // fnc init
1470 
1471  sIsCandidate.clear();
1472  sPosition.clear();
1473  sSignal.clear();
1474  sSignalError.clear();
1475  sIsSaturation.clear();
1476 
1477  const sdet::SDetector& sDetector = det::Detector::GetInstance().GetSDetector();
1478 
1480  sIt != fgCurrentSEvent->StationsEnd(); ++sIt)
1481 
1482  if (sIt->IsCandidate()) {
1483 
1484  sIsCandidate.push_back(true);
1485  sPosition.push_back(sDetector.GetStation(*sIt).GetPosition());
1486  const bool saturated = sIt->IsLowGainSaturation();
1487  if (saturated && sIt->GetRecData().GetRecoveredSignal()) {
1488  sSignal.push_back(sIt->GetRecData().GetRecoveredSignal());
1489  sSignalError.push_back(sIt->GetRecData().GetRecoveredSignalError());
1490  } else {
1491  sSignal.push_back(sIt->GetRecData().GetTotalSignal());
1492  sSignalError.push_back(0);
1493  }
1494  sIsSaturation.push_back(saturated);
1495 
1496  } else if (LDFFinder::fgUseSilentStations && sIt->IsSilent()) {
1497 
1498  sIsCandidate.push_back(false);
1499  sPosition.push_back(sDetector.GetStation(*sIt).GetPosition());
1500  sSignal.push_back(0);
1501  sSignalError.push_back(0);
1502  sIsSaturation.push_back(false);
1503 
1504  }
1505 
1506  } // fnc init
1507 
1508  const int nStations = sIsCandidate.size();
1509 
1510  const double cosTheta = fgShowerAxis.GetCosTheta(fgLocalCS);
1511  const double sigmaFactor = wcd::SignalUncertaintyFactor(wcd::eGAP2012_012, cosTheta);
1512  const double poissonFactor = max(1., 1/Sqr(sigmaFactor));
1513 
1514  const Point core(x, y, 0, fgLocalCS);
1515 
1516  double logLikelihood = 0;
1517 
1518  for (int i = 0; i < nStations; ++i) {
1519 
1520  if (sIsCandidate[i]) {
1521 
1522  const double r = RPerp(fgShowerAxis, sPosition[i] - core);
1523 
1524  const double secDerivative = LDFFunctionSecondDerivative(fgLDFType, r, beta, gamma, fgNKGFermiMu, fgNKGFermiTau);
1525  if (!fgLowerLimit && secDerivative > fgNoRecovery)
1526  fgLowerLimit = true;
1527  const bool hasRecovery = (!fgLowerLimit && sSignalError[i]);
1528 
1529  const double particlesInStation = (sIsSaturation[i] && !hasRecovery) ?
1530  poissonFactor * (sSignal[i] - sSignalError[i]) :
1531  poissonFactor * sSignal[i];
1532 
1533  const double signalPrediction = s1000 * LDFFunction(fgLDFType, r, beta, gamma, fgNKGFermiMu, fgNKGFermiTau);
1534  const double particlePrediction = poissonFactor * signalPrediction;
1535 
1536  // if recovery used
1537  const double sigma = (sIsSaturation[i] && hasRecovery) ?
1538  poissonFactor * sqrt(Sqr(sSignalError[i]) + Sqr(sigmaFactor) * signalPrediction) :
1539  poissonFactor * sigmaFactor * sqrt(signalPrediction);
1540 
1541  // if saturation and no recovery use as lower limit
1542  if (sIsSaturation[i] && !hasRecovery && nStations > 3)
1543 
1544  logLikelihood += LogarithmOfNormalComplementCDF(particlesInStation, particlePrediction, sigma);
1545 
1546  else if (particlesInStation > 30)
1547 
1548  // Stations with large signals: approximately gaussian probability
1549  logLikelihood += LogarithmOfNormalPDF(particlesInStation, particlePrediction, sigma);
1550 
1551  else {
1552 
1553  // Stations with low signal: Poisson probability
1554  logLikelihood += particlesInStation * log(particlePrediction) - particlePrediction;
1555 
1556  double logarithmicFactor = 0;
1557  const int stop = int(particlesInStation + 0.5);
1558  for (int j = 1; j <= stop; ++j)
1559  logarithmicFactor += log(double(j));
1560 
1561  logLikelihood -= logarithmicFactor;
1562 
1563  }
1564 
1565  } else if (s1000 > 0) {
1566 
1567  const double r = RPerp(fgShowerAxis, sPosition[i] - core);
1568  const double signalPrediction = s1000 * LDFFunction(fgLDFType, r, beta, gamma, fgNKGFermiMu, fgNKGFermiTau);
1569  const double particlePrediction = poissonFactor * signalPrediction;
1570 
1571  logLikelihood += particlePrediction > 0.03 ?
1572  -particlePrediction +
1573  log(1 + // 0
1574  particlePrediction * (1 + // 1
1575  0.5*particlePrediction * (1 + // 2
1576  (1./3)*particlePrediction // 3
1577  )))
1578  :
1579  -(1./24)*Sqr(Sqr(particlePrediction));
1580 
1581  }
1582 
1583  }
1584 
1585  // maximize log-likelihood = minimize -(log-likelihood)
1586  value = -logLikelihood;
1587 }
1588 
1589 
1590 void
1591 LDFFinder::LDFFitChi2Fnc(int& /*nPar*/, double* const /*grad*/, double& value,
1592  double* const par, const int iFlag)
1593 {
1594  const double& x = par[1];
1595  const double& y = par[2];
1596  const double s1000 = par[0];
1597  double beta = 0;
1598  double gamma = 0;
1599  static int nStations = 0;
1600  static vector<bool> sIsCandidate;
1601  static vector<Point> sPosition;
1602  static vector<double> sSignal;
1603  static vector<double> sSignalError;
1604  static vector<double> sIsSaturation;
1605 
1606  const double cosTheta = fgShowerAxis.GetCosTheta(fgLocalCS);
1607  const double sigmaFactor = wcd::SignalUncertaintyFactor(wcd::eGAP2012_012, cosTheta);
1608 
1609  if (iFlag == 1) { // fnc init
1610 
1611  sIsCandidate.clear();
1612  sPosition.clear();
1613  sSignal.clear();
1614  sSignalError.clear();
1615  sIsSaturation.clear();
1616 
1617  const sdet::SDetector& sDetector = det::Detector::GetInstance().GetSDetector();
1618 
1620  sIt != fgCurrentSEvent->StationsEnd(); ++sIt)
1621 
1622  if (sIt->IsCandidate()) {
1623 
1624  sIsCandidate.push_back(true);
1625  sPosition.push_back(sDetector.GetStation(*sIt).GetPosition());
1626  const bool saturation = sIt->IsLowGainSaturation();
1627  if (saturation && sIt->GetRecData().GetRecoveredSignal()) {
1628  sSignal.push_back(sIt->GetRecData().GetRecoveredSignal());
1629  sSignalError.push_back(sIt->GetRecData().GetRecoveredSignalError());
1630  } else {
1631  sSignal.push_back(sIt->GetRecData().GetTotalSignal());
1632  sSignalError.push_back(0.);
1633  }
1634  sIsSaturation.push_back(saturation);
1635 
1636  } else if (LDFFinder::fgUseSilentStations && sIt->IsSilent()) {
1637 
1638  sIsCandidate.push_back(false);
1639  sPosition.push_back(sDetector.GetStation(*sIt).GetPosition());
1640  sSignal.push_back(0.);
1641 
1642  }
1643 
1644  nStations = sIsCandidate.size();
1645 
1646  } // fnc init
1647 
1648  const Point core(x, y, 0, fgLocalCS);
1649 
1650  double chi2 = 0;
1651 
1652  if (LDFFinder::fgFixLDF)
1654  else {
1655  beta = par[3];
1656  gamma = par[4];
1657  }
1658 
1659  for (int i = 0; i < nStations; ++i)
1660 
1661  if (sIsCandidate[i]) {
1662 
1663  const double rho = RPerp(fgShowerAxis, sPosition[i] - core);
1664  const double predictedSignal = s1000 * LDFFunction(fgLDFType, rho, beta, gamma, fgNKGFermiMu, fgNKGFermiTau);
1665  const double secDerivative =
1667  const double sigma =
1668  (sIsSaturation[i] && sSignalError[i] && secDerivative < fgNoRecovery) ?
1669  sqrt(Sqr(sSignalError[i]) + Sqr(sigmaFactor) * predictedSignal) :
1670  sigmaFactor * sqrt(predictedSignal);
1671 
1672  // we do NOT add any contribution to the chi2, as it it would be a bias.
1673  if (!sIsSaturation[i] || (sSignalError[i] && secDerivative < 1)) {
1674  const double dev =
1675  (predictedSignal > numeric_limits<double>::min() ?
1676  (sSignal[i] - predictedSignal) / sigma :
1677  pow(numeric_limits<double>::max(), 0.25));
1678  const double dev2 = Sqr(dev);
1679  chi2 += dev2;
1680  }
1681 
1682  } else {
1683 
1684  const double rho = RPerp(fgShowerAxis, sPosition[i] - core);
1685 
1686  chi2 +=
1689 
1690  }
1691 
1692  value = chi2;
1693 }
1694 
1695 
1696 bool
1698  const
1699 {
1700  const sdet::SDetector& sDetector = det::Detector::GetInstance().GetSDetector();
1701  const Point& core = cfi.fCore;
1702 
1703  double sx = 0;
1704  double sy = 0;
1705  double st = 0;
1706  double sm2 = 0;
1707  double dxx = 0;
1708  double dxy = 0;
1709  double dxt = 0;
1710  double dxm = 0;
1711  double dyy = 0;
1712  double dyt = 0;
1713  double dym = 0;
1714  double dtt = 0;
1715  double dtm = 0;
1716  int nStations = 0;
1717 
1719  sIt != fgCurrentSEvent->CandidateStationsEnd(); ++sIt) {
1720 
1721  const Vector& xi = sDetector.GetStation(*sIt).GetPosition() - core;
1722 
1723  sx += xi.GetX(fgLocalCS);
1724  sy += xi.GetY(fgLocalCS);
1725 
1726  const double cti =
1727  kSpeedOfLight*(sIt->GetRecData().GetSignalStartTime() - fgBaryTime).GetInterval();
1728 
1729  st += cti;
1730 
1731  const double mi2 = 0.5*(xi.GetMag2() - Sqr(cti));
1732 
1733  sm2 += mi2;
1734 
1735  ++nStations;
1736 
1738  sJt != fgCurrentSEvent->CandidateStationsEnd(); ++sJt)
1739 
1740  if (sIt->GetId() < sJt->GetId()) {
1741 
1742  const Vector& xj = sDetector.GetStation(*sJt).GetPosition() - core;
1743 
1744  const Vector xij(xi - xj);
1745 
1746  const double dxij = xij.GetX(fgLocalCS);
1747  const double dyij = xij.GetY(fgLocalCS);
1748 
1749  const double ctj =
1750  kSpeedOfLight*(sJt->GetRecData().GetSignalStartTime() - fgBaryTime).GetInterval();
1751 
1752  const double cdtij = cti - ctj;
1753 
1754  const double mj2 = 0.5*(xj.GetMag2() - Sqr(ctj));
1755 
1756  const double dmij2 = mi2 - mj2;
1757 
1758  dxx += Sqr(dxij);
1759  dxy += dxij*dyij;
1760  dxt += dxij*cdtij;
1761  dxm += dxij*dmij2;
1762  dyy += Sqr(dyij);
1763  dyt += dyij*cdtij;
1764  dym += dyij*dmij2;
1765  dtt += Sqr(cdtij);
1766  dtm += cdtij*dmij2;
1767 
1768  }
1769 
1770  }
1771 
1772  sx /= nStations;
1773  sy /= nStations;
1774  st /= nStations;
1775  sm2 /= nStations;
1776 
1777  HepMatrix delta(3,3);
1778  delta[0][0] = dxx; delta[0][1] = dxy; delta[0][2] = -dxt;
1779  delta[1][0] = dxy; delta[1][1] = dyy; delta[1][2] = -dyt;
1780  delta[2][0] = -dxt; delta[2][1] = -dyt; delta[2][2] = dtt;
1781 
1782  int ierr;
1783  delta.invert(ierr);
1784 
1785  HepVector k(3);
1786  k[0] = dxm;
1787  k[1] = dym;
1788  k[2] = -dtm;
1789 
1790  HepVector p(delta*k);
1791 
1792  const double& rcu = p[0];
1793  const double& rcv = p[1];
1794  const double& ct0 = p[2];
1795 
1796  const double rc2 = 2*(rcu*sx + rcv*sy - ct0*st - sm2) + Sqr(ct0);
1797 
1798  if (rc2 < 0) {
1799  cfi.fRc = 0;
1800  return false;
1801  } else {
1802  const double rc = sqrt(rc2);
1803  const double rcw2 = rc2 - Sqr(rcu) - Sqr(rcv);
1804  if (rcw2 < 0) {
1805  cfi.fRc = 0;
1806  return false;
1807  } else {
1808  const double rcw = sqrt(rcw2);
1809  Vector curvAxis(rcu,rcv,rcw, fgLocalCS);
1810  curvAxis.Normalize();
1811  cfi.fAxis = curvAxis;
1812  cfi.fRc = rc;
1813  cfi.fRcErr = 0;
1814  cfi.fct0 = ct0;
1815  cfi.fct0Err = 0;
1816  cfi.fSigmaU2 = 0;
1817  cfi.fSigmaUV = 0;
1818  cfi.fSigmaV2 = 0;
1819  }
1820  }
1821 
1822  return true;
1823 }
1824 
1825 
1826 namespace LDFFinderOG {
1827 
1829 
1831  const char* complexWMessage = "complex w";
1832 
1833 }
1834 
1835 
1836 double
1838  const
1839 {
1840  gCore = cfi.fCore;
1841 
1842  TMinuit minuit(4);
1843  int errFlag = 0;
1844  double argList[10];
1845  argList[0] = -1;
1846  if (!fMinuitOutput) {
1847  minuit.mnexcm("SET PRINTOUT", argList, 1, errFlag);
1848  minuit.mnexcm("SET NOWARNINGS", argList, 0, errFlag);
1849  minuit.SetPrintLevel(-1);
1850  }
1851 
1852  complexWCounter = 0;
1853  minuit.SetFCN(LDFFinder::CurvatureFitFnc);
1854  argList[0] = 1;
1855  minuit.mnexcm("SET ERRORDEF", argList, 1, errFlag);
1856 
1857  minuit.mnparm(0, "u", cfi.fAxis.GetX(fgLocalCS), 0.01, 0, 0, errFlag);
1858  minuit.mnparm(1, "v", cfi.fAxis.GetY(fgLocalCS), 0.01, 0, 0, errFlag);
1859  minuit.mnparm(2, "Rc", cfi.fRc, 10*meter, 0, 0, errFlag);
1860  minuit.mnparm(3, "ct0", cfi.fct0+ cfi.fRc, 10*meter, 0, 0, errFlag);
1861 
1862  if (cfi.fFixedAxis) {
1863  minuit.FixParameter(0);
1864  minuit.FixParameter(1);
1865  }
1866 
1867  if (cfi.fFixedRc)
1868  minuit.FixParameter(2);
1869 
1870  // init fnc
1871  argList[0] = 1;
1872  minuit.mnexcm("CALI", argList, 1, errFlag);
1873 
1874  bool fatalError = false;
1875 
1876  argList[0] = 500;
1877  minuit.mnexcm("MINIMIZE", argList, 1, errFlag);
1878  if (errFlag) {
1879  OUT(eObscure)
1880  << " minuit minimize error: " << errFlag << '\n';
1881  minuit.mnexcm("MINOS", argList, 0, errFlag);
1882  if (errFlag) {
1883  OUT(eObscure)
1884  << " minuit minos error: " << errFlag << '\n';
1885  fatalError = true;
1886  }
1887  }
1888 
1889  if (complexWCounter > 1) {
1890  ostringstream warn;
1891  warn << "Message \'" << complexWMessage << "\' repeated "
1892  << complexWCounter << " times.";
1893  WARNING(warn);
1894  }
1895 
1896  if (fatalError)
1897  return 0;
1898 
1899  // Get results
1900  double u;
1901  double uErr;
1902  minuit.GetParameter(0, u, uErr);
1903  double v;
1904  double vErr;
1905  minuit.GetParameter(1, v, vErr);
1906  const double w2 = 1 - Sqr(u) - Sqr(v);
1907  if (w2 < 0) {
1909  << " Fit failed due to unphysical angle cosines.\n";
1910  return 0;
1911  }
1912  cfi.fAxis = Vector(u,v,sqrt(w2), fgLocalCS);
1913  cfi.fAxisErr = Vector(uErr,vErr,0, fgLocalCS);
1914 
1915  minuit.GetParameter(2, cfi.fRc, cfi.fRcErr);
1916  if (cfi.fRc <= 0) {
1918  << " Fit failed due to Rc <= 0.\n";
1919  return 0;
1920  }
1921  if (!cfi.fFixedRc && cfi.fRc > 100*kilometer) {
1923  << " Rc too large, reverting to plane fit.\n";
1924  return 0;
1925  }
1926 
1927  double ct0;
1928  double ct0Err;
1929  minuit.GetParameter(3, ct0, ct0Err);
1930  cfi.fct0 = ct0 - cfi.fRc;
1931  cfi.fct0Err = sqrt(Sqr(ct0Err) + Sqr(cfi.fRcErr));
1932 
1933  // error matrix
1934  double emat[4][4];
1935  minuit.mnemat(&emat[0][0], 4);
1936  cfi.fSigmaU2 = emat[0][0];
1937  cfi.fSigmaV2 = emat[1][1];
1938  cfi.fSigmaUV = emat[0][1];
1939 
1940  return minuit.fAmin / Sqr(kSpeedOfLight);
1941 }
1942 
1943 
1944 namespace LDFFinderOG {
1945 
1947  double fCTiming;
1948  double fT50;
1949  double fSignal;
1951  };
1952 
1953 }
1954 
1955 
1956 void
1957 LDFFinder::CurvatureFitFnc(int& /*nPar*/, double* const /*grad*/, double& value,
1958  double* const par, const int flag)
1959 {
1960  const double& u = par[0];
1961  const double& v = par[1];
1962  const double& rc = par[2];
1963  const double& ct0 = par[3];
1964 
1965  static vector<CurvatureFitStationInfo> sStationInfo;
1966  static const sdet::STimeVariance* timeVariance = 0;
1967 
1968  if (flag == 1) { // fnc init
1969 
1970  sStationInfo.clear();
1971  const sdet::SDetector& sDetector = det::Detector::GetInstance().GetSDetector();
1972 
1974  sIt != fgCurrentSEvent->CandidateStationsEnd(); ++sIt) {
1975 
1976  const StationRecData& sRec = sIt->GetRecData();
1977  const CurvatureFitStationInfo si = {
1978  kSpeedOfLight * ((sRec.GetSignalStartTime() - fgBaryTime).GetInterval()),
1979  sRec.GetT50(),
1980  sRec.GetTotalSignal(),
1981  sDetector.GetStation(*sIt).GetPosition() - gCore
1982  };
1983  sStationInfo.push_back(si);
1984 
1985  }
1986 
1987  timeVariance = &sdet::STimeVariance::GetInstance();
1988 
1989  } // fnc init
1990 
1991  const double w2 = 1 - Sqr(u) - Sqr(v);
1992 
1993  if (w2 < 0) {
1994  if (!complexWCounter)
1996  ++complexWCounter;
1997  value = 1e30;
1998  return;
1999  }
2000 
2001  const double w = sqrt(w2);
2002 
2003  const Vector axis = Vector(u,v,w, fgLocalCS);
2004  const Vector rcAxis = rc * axis;
2005 
2006  double chi2 = 0;
2007 
2008  for (vector<CurvatureFitStationInfo>::const_iterator siIt = sStationInfo.begin();
2009  siIt != sStationInfo.end(); ++siIt) {
2010 
2011  const Vector stationCenter = rcAxis - siIt->fPosition;
2012  const double drc = stationCenter.GetMag();
2013 
2014  const double stationCosTheta = stationCenter.GetZ(fgLocalCS) / drc;
2015 
2016  const double sigma2 =
2017  timeVariance->GetTimeSigma2(siIt->fSignal, siIt->fT50, stationCosTheta, sqrt(RPerp2(axis, siIt->fPosition)));
2018 
2019  const double cdt = siIt->fCTiming - ct0 - drc + rc;
2020 
2021  chi2 += Sqr(cdt) / sigma2;
2022 
2023  }
2024 
2025  value = chi2 / Sqr(kSpeedOfLight);
2026 }
2027 
2028 
2029 // Configure (x)emacs for this file ...
2030 // Local Variables:
2031 // mode: c++
2032 // End:
double LogarithmOfNormalComplementCDF(const double x)
Class to access station level reconstructed data.
double GetCorrelationXY() const
void SetCurvature(const double curvature, const double error)
gaussian curvature = 1 / Rc
double GetCurvatureError() const
StationIterator StationsEnd()
End of all stations.
Definition: SEvent.h:59
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)
const utl::TimeStamp & GetTimeStamp() const
Get the TimeStamp of the absolute shower core-time.
double GetRpError() const
Definition: EyeRecData.h:91
double GetAngleNdof() const
double LDFFunction(const LDFFunctionType type, const double r, const double beta, const double gamma=0, const double mu=2660.*meter, const double tau=242.*meter)
Definition: LDFFunctions.h:66
double GetPhi(const CoordinateSystemPtr &coordinateSystem) const
azimuth (phi) angle in spherical and cylindrical coordinates
Definition: BasicVector.h:254
double GetCurvature() const
gaussian curvature = 1 / Rc
void SetBeta(const double beta, const double error)
double RPerp(const Vector &axis, const Vector &station)
Report success to RunController.
Definition: VModule.h:62
void EstimateBetaGamma(double &beta, double &gamma, const LDFFunctionType type, const double cosTheta, const double s1000=0)
Definition: LDFFunctions.h:253
double SigmaForFixedBeta(const double s1000)
Definition: LDFFunctions.h:153
Interface class to access to the SD Reconstruction of a Shower.
bool FixGamma(const LDFFitInterface &fi) const
void SetLDFOptimumDistance(const double rOpt)
boost::filter_iterator< ComponentSelector, ConstAllEyeIterator > ConstEyeIterator
Definition: FEvent.h:56
const utl::TabulatedFunctionErrors & GetLDF() const
bool HasFEvent() const
boost::tuple< double, double, double > Triple
Coordinate triple for easy getting or setting of coordinates.
Definition: BasicVector.h:147
Interface class to access to the SD part of an event.
Definition: SEvent.h:39
double GetBetaError() const
const utl::TimeStamp & GetBarytime() const
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
double ParameterizedRc(const LDFFitInterface &fi) const
double FitCurvatureDriver(CurvatureFitInterface &fi) const
Skip remaining modules in the current loop and continue with next iteration of the loop...
Definition: VModule.h:68
double GetAngleChi2() const
double GetCosTheta(const CoordinateSystemPtr &coordinateSystem) const
cos of zenith (theta) angle
Definition: BasicVector.h:251
unsigned int GetSDPFitNDof() const
Definition: EyeRecData.h:81
bool HasSimShower() const
EventTrigger & GetTrigger()
Get the object with central trigger data, throw if n.a.
Definition: SEvent.h:148
EyeIterator EyesEnd(const ComponentSelector::Status status)
Definition: FEvent.h:66
const utl::CoordinateSystemPtr & GetBarycenterCoordinateSystem() const
origin = GetBarycenter(), z-axis = local vertical, x-axis = east
unsigned int GetTimeFitNDof() const
Definition: EyeRecData.h:93
bool EstimateCurvature(CurvatureFitInterface &fi) const
const double meter
Definition: GalacticUnits.h:29
const utl::Vector & GetCoreError() const
#define INFO(message)
Macro for logging informational messages.
Definition: ErrorLogger.h:161
struct LDFFinderOG::LDFFinder::Stage3 fStage3
void SetAngleChi2(const double chi2, const double ndof)
static const sevt::SEvent * fgCurrentSEvent
double GetShowerSize() const
bool FixBeta(const LDFFitInterface &fi) const
Base class for exceptions trying to access non-existing components.
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
double pow(const double x, const unsigned int i)
double InverseNormalCDF(const double p)
Inverse of the comulative normal distribution. Taken from http://home.online.no/~pjacklam/notes/invno...
const double EeV
Definition: GalacticUnits.h:34
double GetMag() const
Definition: Vector.h:58
void SetBetaSystematics(const double betasys)
double NormalCDF(const double x)
double GetSDPPhiError() const
Definition: EyeRecData.h:78
void SetLDFChi2(const double chi2, const double ndof)
double GetEnergyError() const
fwk::VModule::ResultFlag Init()
Initialize: invoked at beginning of run (NOT beginning of event)
double GetChiZeroError() const
Definition: EyeRecData.h:86
A TimeStamp holds GPS second and nanosecond for some event.
Definition: TimeStamp.h:110
struct LDFFinderOG::LDFFinder::Stage1 fStage1
Exception for reporting variable out of valid range.
void SetAngleErrors(const utl::Vector::Triple &u_v_w, const utl::Vector::Triple &sigma_u2_uv_v2)
utl::Point GetPosition() const
Tank position.
void SetTimeResidualMean(const double mean)
Interface class to access Shower Simulated parameters.
Definition: ShowerSimData.h:49
struct LDFFinderOG::LDFFinder::Stage0 fStage0
CandidateStationIterator CandidateStationsBegin()
Definition: SEvent.h:72
double GetBeta() const
void SetCoreError(const utl::Vector &coreerr)
boost::shared_ptr< const CoordinateTransformer > CoordinateSystemPtr
Shared pointer for coordinate systems.
void EstimateEnergy(LDFFitInterface &fi) const
#define max(a, b)
Class representing a document branch.
Definition: Branch.h:107
void SetResidual(const double residual)
Residual of geometry fit.
void EstimateLDF(LDFFitInterface &fi, const utl::Point &core) const
double Fermi(const double x)
Encapsulation of the Minuit fit for Ropt.
Definition: RoptFit.h:18
constexpr double s
Definition: AugerUnits.h:163
void SetLDFResidual(const double LDFresidual)
Residual of lateral fit.
void OutputStations(const LDFFitInterface &fi) const
utl::TimeStamp GetSignalStartTime() const
Start time of the signal.
const utl::Vector & GetDirection() const
Get the direction of the shower axis. This is the true direction of shower movement.
double LDFFunctionSecondDerivative(const LDFFunctionType type, const double r, const double beta, const double gamma=0, const double mu=2660.*meter, const double tau=242.*meter)
Definition: LDFFunctions.h:136
double GetX(const CoordinateSystemPtr &coordinateSystem) const
Definition: BasicVector.h:206
fwk::VModule::ResultFlag Finish()
Finish: invoked at end of the run (NOT end of the event)
const double ns
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.
const utl::Point & GetPosition() const
Get the position of the shower core.
const utl::Point & GetBarycenter() const
bool HasFRecShower() const
Check if reconstructed shower info has been allocated.
Definition: EyeRecData.h:330
evt::ShowerFRecData & GetFRecShower()
Reconstructed shower info for this eye.
Definition: EyeRecData.h:323
EyeIterator EyesBegin(const ComponentSelector::Status status)
Definition: FEvent.h:58
void SetShowerSizeSystematics(const double sysError)
double GetTimeResidualSpread() const
static Policy::type RotationY(const double angle, const CoordinateSystemPtr &theCS)
Construct from rotation about Y axis.
double GetLDFRecStage() const
const double km
constexpr double g
Definition: AugerUnits.h:200
static Policy::type RotationZ(const double angle, const CoordinateSystemPtr &theCS)
Construct from rotation about Z axis.
double GetThetaError() const
fwk::VModule::ResultFlag Run(evt::Event &event)
Run: invoked once per event.
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
Top of Fluorescence Detector event hierarchy.
Definition: FEvent.h:33
Eye-specific shower reconstruction data.
Definition: EyeRecData.h:65
void SetCoreTime(const utl::TimeStamp &coreTime, const utl::TimeInterval &coreTimeErr)
if(dataRoot)
Definition: XXMLManager.h:1003
bool FitLDF(LDFFitInterface &fi, const int nStations) const
double GetEnergy() const
static utl::CoordinateSystemPtr fgLocalCS
static void CurvatureFitFnc(int &nPar, double *const grad, double &value, double *const par, const int iFlag)
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
double GetGammaError() const
A TimeInterval is used to represent time elapsed between two events.
Definition: TimeInterval.h:43
utl::TimeStamp GetTime() const
Get time of the trigger.
void SetRecData(evt::Event &event, const LDFFitInterface &lfi, const CurvatureFitInterface &cfi) const
ResultFlag
Flag returned by module methods to the RunController.
Definition: VModule.h:60
void SetTimeResidualSpread(const double spread)
double GetLDFOptimumDistance() const
void SetNumberOfActiveStations(const int nstations)
double GetCorrelationThetaPhi() const
string ToString(const G &g, const CoordinateSystemPtr cs, bool units=true)
rtlsdr_dev_t * dev
Definition: dump1090.h:243
double GetRp() const
Definition: EyeRecData.h:87
std::pair< double, double > Fit(const LDFFunctionType type, const int n, const double *const s1000, const double *const beta, const bool verbose=false)
Definition: RoptFit.cc:16
StationIterator StationsBegin()
Beginning of all stations.
Definition: SEvent.h:57
double RPerp2(const Vector &axis, const Vector &station)
constexpr double kilometer
Definition: AugerUnits.h:93
double EstimateChi2(const LDFFitInterface &fi) const
Estimate Chi2 using Minuit.
static void LDFFitMaxLikeFnc(int &nPar, double *const grad, double &value, double *const par, const int iFlag)
Likelihood function to minimize.
Vector object.
Definition: Vector.h:30
Interface class to access to Fluorescence reconstruction of a Shower.
Detector description interface for SDetector-related data.
Definition: SDetector.h:42
double GetShowerSizeError() const
double SignalUncertaintyFactor(const ESignalVarianceModel model, const double cosTheta)
double CosAngle(const Vector &l, const Vector &r)
Definition: OperationsVV.h:71
Report failure to RunController, causing RunController to terminate execution.
Definition: VModule.h:64
const utl::Point & GetCorePosition() const
void SetCorePosition(const utl::Point &core)
Main configuration utility.
Definition: CentralConfig.h:51
boost::indirect_iterator< InternalStationIterator, Station & > StationIterator
Iterator over all stations.
Definition: SEvent.h:52
void SetNKGFermiParameters(const double mu, const double tau)
void SetLDFLikelihood(const double likelihood)
Accumulates and calculates standard deviation.
CandidateStationIterator CandidateStationsEnd()
Definition: SEvent.h:74
void SetShowerSizeType(const ShowerSizeType type)
void SetGamma(const double gamma, const double error)
bool HasLDF() const
double GetTZero() const
Definition: EyeRecData.h:83
void SetEnergy(const double energy, const double error)
void GetEnergy(const double cosTheta, const double s1000, const double s1000Err, double &energy, double &energyErr) const
bool FixCore(const evt::Event &event, Point &core, TimeStamp &coreTime, Vector &axis) const
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
boost::indirect_iterator< InternalConstStationIterator, const Station & > ConstStationIterator
Definition: SEvent.h:54
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
double GetTimeResidualMean() const
void EstimateS1000(LDFFitInterface &fi) const
First guess of S1000 to give a starting point.
const utl::Point & GetCorePosition() const
Shower core as reconstructed by the FD or FD eye.
double LogarithmOfNormalPDF(const double x)
bool HasSEvent() const
double GetGamma() const
utl::Point GetPosition() const
Eye position.
utl::Branch GetTopBranch(const std::string &id)
Get top branch for moduleConfigLink with given id (XML files)
struct LDFFinderOG::LDFFinder::Stage2 fStage2
static void LDFFitChi2Fnc(int &nPar, double *const grad, double &value, double *const par, const int iFlag)
boost::filter_iterator< CandidateStationFilter, ConstStationIterator > ConstCandidateStationIterator
Definition: SEvent.h:70
double FitLDFDriver(LDFFitInterface &fi) const
Fit using Minuit.
double GetMag2() const
Definition: Vector.h:61
void OutputResults(const evt::Event &event) const
double EstimateNStationsInFit(const LDFFitInterface &fi) const
const utl::Vector & GetAxis() const
Shower Axis as reconstructed by the FD or FD eye.
double GetTimeSigma2(const double signal, const double t50, const double cosTheta, const double distance=0) const

, generated on Tue Sep 26 2023.