UnivFitterKG.cc
Go to the documentation of this file.
1 #include "UnivFitterKG.h"
2 
3 #include <cmath>
4 #include <cstdio>
5 #include <cstdlib>
6 #include <limits>
7 #include <iostream>
8 #include <iomanip>
9 #include <string>
10 #include <sstream>
11 #include <fstream>
12 #include <vector>
13 
14 #include "Math/PdfFuncMathCore.h"
15 #include "TF1.h"
16 #include "Math/WrappedTF1.h"
17 #include "Math/RootFinder.h"
18 #include <TMath.h>
19 
20 #include <boost/format.hpp>
21 
22 #include "Minuit2/MnMigrad.h"
23 #include "Minuit2/MnHesse.h"
24 #include "Minuit2/MnPrint.h"
25 #include "Minuit2/MnStrategy.h"
26 
27 #include <tls/UnivTimeKGLogNormal.h>
28 #include <tls/UnivTimeKGGamma.h>
29 
30 #include <utl/PhysicalFunctions.h>
31 #include <utl/UTMPoint.h>
32 #include <utl/ReferenceEllipsoid.h>
33 #include <utl/TimeInterval.h>
34 #include <utl/AugerCoordinateSystem.h>
35 #include <utl/PhysicalFunctions.h>
36 #include <utl/AugerUnits.h>
37 #include <utl/CovarianceMatrix.h>
38 #include <utl/NumericalErrorPropagator.h>
39 #include <utl/GeometryUtilities.h>
40 
41 //#include <evt/Event.h>
42 //#include <sevt/SEvent.h>
43 
44 using namespace std;
45 using namespace utl;
46 using namespace ROOT::Minuit2;
47 
48 using boost::format;
49 using FitterUtil::sc_mu;
51 
52 
53 namespace UnivFitterKG {
54 
55  const double gpercm2 = utl::gram / utl::cm2;
56 
57 
58  inline
59  double
60  OldSmoothPoissonFactor(const double sigmaFactor)
61  {
62  const double z = (sigmaFactor - 1.05) / 0.05;
63  const double t = 1 / (1 + std::exp(z));
64  return t + (1 - t) / Sqr(sigmaFactor);
65  }
66 
67 
68  double
69  RelativeTrackLength(const double cosTheta)
70  {
71  const double kRadius = 1.8 * meter;
72  const double kHeight = 1.2 * meter;
73  const double sinTheta = sqrt(1 - pow(cosTheta, 2.));
74  return 1 / (cosTheta + 2 * kHeight * sinTheta / (kPi * kRadius));
75  }
76 
77 
78  double
79  PlaneFrontTime(const CoordinateSystemPtr showerCS, const Point& corePosition, const Point& position)
80  {
81  return (corePosition.GetZ(showerCS) - position.GetZ(showerCS)) / kSpeedOfLight;
82  }
83 
84 
85  // calculates energy for proton, QGSJet 2.3, this is needed to get unbiased predictions with universality
86  double
87  MCEnergyCalibration(const double showerSize, const double theta, bool isInfill)
88  {
89  if (!isInfill) {
90  const double calPars[2] = { 2.51594443, 1.03997067 }; // uncs: 0.02302776 0.00182409
91  const double cicPars[3] = { 1.07546532, 2.10875764, -0.37034705 }; // uncs: 0.01036417 0.01998492 0.10950651
92 
93  const double cossqref = pow(cos(theta / radian), 2) - pow(cos(38 * degree), 2);
94  const double s38 = showerSize / (1 + cossqref * (cicPars[0] + cossqref * (cicPars[1] + cossqref * cicPars[2])));
95  return calPars[0] * 1e17 * pow(s38, calPars[1]);
96  }
97  return 0;
98  }
99 
100 
101  double
102  ConvertToMCEnergyScale(const double sdenergy)
103  {
104  // MC calibration for p, QGSJet-II.03
105  const double calPars_p[2] = { 2.51594443, 1.03997067 };
106  // data calibration (ICRC 2013) - needs to be changed later
107  const double calPars_data[2] = { 1.89541, 1.02465 };
108 
109  const double s38 = pow(sdenergy / (calPars_data[0] * 1e17), 1 / calPars_data[1]);
110 
111  return calPars_p[0] * 1e17 * pow(s38, calPars_p[1]);
112  }
113 
114 
115  WCDFitFunction::WCDFitFunction(const Fitter& theEf) : ef(theEf) { }
116 
117 
118  double
119  WCDFitFunction::operator()(const std::vector<double>& pars)
120  const
121  {
122  // exception from Offline units:
123  // grammage and energy are rescaled such that all parameters
124  // are roughly on the same order of magnitude, see setupMinuit()
125 
126  // check sanity of parameters
127  for (unsigned int i = 0; i < pars.size(); ++i) {
128  if (std::isnan(pars[i]))
129  return -ef.fFailLikelihood;
130  }
131 
132  const Point core = Point(pars[0], pars[1], pars[2], ef.fBaryCS);
133  const CoordinateSystemPtr coreCS = AugerCoordinateSystem::Create(core, ReferenceEllipsoid::eWGS84, ef.fSiteCS);
134  const double relCoreTime = pars[3];
135  const TimeStamp coreTime = ef.initPars.coretime + relCoreTime;
136 
137  const double theta = pars[4];
138  const double phi = pars[5];
139  const Vector axis(1, theta, phi, ef.fBaryCS, Vector::kSpherical);
140  const CoordinateSystemPtr showerPlaneCS(
141  CoordinateSystem::RotationY(theta, CoordinateSystem::RotationZ(phi, coreCS))
142  );
143 
144  const double xmax = pars[6] * ef.fGrammageScale;
145  double Nmu = pars[7];
146  double totalEnergy = pars[8] * ef.fEnergyScale;
147 
148  if (ef.fUseNmuModel)
149  Nmu = FitterUtil::getMeanParametrizedNmuData(log10(totalEnergy), theta, xmax / gpercm2);
150 
151  const double mmu_offset = pars[9];
152 
153  double x0 = pars[10] * ef.fGrammageScale;
154 
155  // TODO remove this? Remove also in Offline interface?
156  if (ef.fRescaleEnergy) {
157  using namespace utl::InvisibleEnergy;
158  const double mf = ModelFactor(eQGSJET01, eProton);
159  const double* const p = FitParameters(eProton);
160 
161  TF1 func("f", "[3]*([0]-[1]*(x/1e18)**(-[2])) - x/[4]"); // formula from PhysicalFunctions.cc
162  func.SetParameter(0, p[0]);
163  func.SetParameter(1, p[1]);
164  func.SetParameter(2, p[2]);
165  func.SetParameter(3, mf);
166  func.SetParameter(4, totalEnergy);
167 
168  ROOT::Math::RootFinder rf;
169  ROOT::Math::WrappedTF1 wf1(func);
170  rf.SetFunction(wf1, 0.5 * totalEnergy, 1.5 * totalEnergy);
171  rf.Solve();
172  double calEnergy = rf.Root();
173 
174  double dummycostheta=0.7071067; //since this uses montecarlo, dummycostheta is not used,
175  totalEnergy = calEnergy * (1 + Nmu * (Factor(calEnergy, eQGSJET01, eProton,dummycostheta) - 1));
176  }
177 
178  const double logTotalEnergy = log10(totalEnergy);
179 
180  const double X0FromXmax = FitterUtil::getX0(ef.fX0XmaxModelVersion, xmax, logTotalEnergy);
181  if (ef.x0Mode == eCoupled)
182  x0 = X0FromXmax;
183  const double hfi = ef.fAtmosphere->SlantDepthToHeight(x0 / gpercm2, theta) * cm;
184 
185  if (ef.fVerbosityLevel > 1) {
186  printf("x %.4f, y %.4f, z %.4f, relct %.3f, ", pars[0], pars[1], pars[2], pars[3]);
187  printf("theta %.3f°, phi %.3f°, ", theta / degree, NormalizeAngleMinusPiPi(phi) / degree);
188  printf("xmax %.2f, x0 %.2f, ", xmax / gpercm2, x0 / gpercm2);
189  printf("Nmu %.3f, loge %.3f, ", Nmu, logTotalEnergy);
190  printf("\n");
191  }
192 
193  const double sigmaFactor = wcd::SignalUncertaintyFactor(wcd::eGAP2014_035, cos(theta));
194  const double poissonFactor = wcd::PoissonFactor(sigmaFactor);
195 
196  double TotalLikelihood = 0;
197  ef.fLDFLikelihood = 0;
198  ef.fShapeLikelihood = 0;
200 
201  for (std::vector<StationFitData>::const_iterator sIt = ef.fitData.begin(); sIt != ef.fitData.end(); ++sIt) {
202 
203  if (!(sIt->useForLDFFit || sIt->useForShapeFit || sIt->useForStartTimeFit))
204  continue;
205 
206  sIt->LDFLikelihood = 0;
207  sIt->ShapeLikelihood = 0;
208  sIt->StartTimeLikelihood = 0;
209  sIt->planeFrontTime = PlaneFrontTime(showerPlaneCS, core, sIt->position); // pf time referred to core position
210  const double stationRho = sIt->position.GetRho(showerPlaneCS);
211  const double stationPsi = sIt->position.GetPhi(showerPlaneCS);
212  sIt->height = ef.fSiteCSHeight + sIt->position.GetZ(ef.fSiteCS);
213 
214  sIt->DX_diffusive = ef.fAtmosphere->Get_DX_DL_i(stationRho / cm, stationPsi, xmax / gpercm2, theta, sIt->height / cm, false, true) * gpercm2;
215  sIt->DX_rectilinear = ef.fAtmosphere->Get_DX_DL_i(stationRho / cm, stationPsi, xmax / gpercm2, theta, sIt->height / cm, false, false) * gpercm2;
216  sIt->distToFirstInteraction = FitterUtil::getDistToFirstInteraction(hfi, sIt->height, theta, stationRho, stationPsi);
217 
218  sIt->firstParticleTimes.clear();
219  if (ef.fTimeModelVersion == 1) {
220  const double fpt_global = FitterUtil::getFirstParticleArrivalTime(stationRho, sIt->distToFirstInteraction);
221  for (int icomp = 0; icomp < ef.fNSigComps; ++icomp)
222  sIt->firstParticleTimes.push_back(fpt_global);
223  } else if (ef.fTimeModelVersion > 1) {
224  for (int icomp = 0; icomp < ef.fNSigComps; ++icomp) {
225 
226  const double D_TO = ef.fUnivParamTime->GetD_TO(xmax / gpercm2, theta, logTotalEnergy, icomp);
227  const double h1 = ef.fAtmosphere->SlantDepthToHeight(xmax / gpercm2, theta) + D_TO * 1e5 * cos(theta);
228 
229  sIt->firstParticleTimes.push_back(ef.fAtmosphere->GetTimeCF_h(stationRho / cm, stationPsi, h1, theta, sIt->height / cm));
230  }
231  }
232 
233  const Vector stationToCore = core - sIt->position;
234  const Vector stationToCenter = stationToCore + sIt->distToFirstInteraction * axis;
235  const double rStation = stationToCenter.GetMag();
236  const double cosThetaStation = stationToCenter.GetZ(ef.fBaryCS) / rStation; // should be stationCS to be really exact
237 
238  // need to add offsets for MC events (depends on primary, interaction model)
239  double mmoff = 0;
241  if (ef.isMCEvent)
242  mmoff = FitterUtil::GetMeanMuonOffsetMCCalibrated(stationRho / cm, logTotalEnergy, theta);
243  else
244  mmoff = FitterUtil::GetMeanMuonOffsetDataCalibrated(stationRho / cm, logTotalEnergy, theta);
245  else
246  mmoff = FitterUtil::GetMeanMuonOffset(stationRho / cm, mmu_offset);
247 
248  for (int icomp = 0; icomp < ef.fNSigComps; ++icomp) {
249 
250  // set mean muon offset for muonic comp. and muon decay products
251  if (ef.fUseTimeModelOffset && (icomp == 0 || icomp == 2))
252  ef.timeModels[icomp]->setParameterOffsets(mmoff, 0);
253 
254  ef.timeModels[icomp]->setShapeParameters(sIt->DX_diffusive / gpercm2, stationRho, stationPsi, theta, logTotalEnergy);
255  }
256 
257  double predTotalSignal = 0;
258  sIt->compSignals.clear();
259  for (int icomp = 0; icomp < ef.fNSigComps; ++icomp) {
260 
261  const double sig =
262  ef.fUnivParam->GetSignal(stationRho / cm, xmax / gpercm2, logTotalEnergy,
263  theta, stationPsi, ef.fDensity / (gram / cm3),
264  sIt->height / cm, Nmu, icomp, ef.atmModel);
265  sIt->compSignals.push_back(sig);
266  predTotalSignal += sig;
267  }
268  predTotalSignal *= ef.fUPFudgeFactor;
269 
270  const double totalSignalUncertainty = poissonFactor * sigmaFactor * std::sqrt(predTotalSignal);
271  sIt->signalUncertainty = totalSignalUncertainty;
272 
273  const double stationTime = (sIt->startTime - coreTime).GetInterval();
274 
275  // start time correction as it is also applied in UnivRec.cc
276  // implementation in UnivParamTime.cc, details in GAP2013_072
277  // if (stationRho < 1000 * meter)
278  // stationTime -= ef.fUnivParamTime->tStartCorrection(stationRho / cm, logTotalEnergy, theta, false) * nanosecond;
279 
280  const double stationTimePF = stationTime - sIt->planeFrontTime - ef.fStartTimeBias;
281 
282  double StationLikelihood = 0;
283  const double fem = sIt->compSignals[1] / predTotalSignal;
284 
285  if (sIt->useForShapeFit && !ef.fOnlySignalLikelihood) {
286 
287  double StationShapeLikelihood = 0;
288 
289  if (ef.fQuantileShapeFit) {
290 
291  const double qs[2] = { 0.1, 0.5 };
292  const double qts[2] = { sIt->t10, sIt->t50 };
293 
294  for (unsigned int qi = 0; qi < 2; ++qi) {
295 
296  const double pfac = ef.fUnivParamTime->GetPoissonFactor(fem, qs[qi]);
297  const double nps = predTotalSignal * pfac;
298  const double ih = nps * qs[qi];
299 
300  double pdfval = 0;
301  double cdfval = 0;
302 
303  for (int icomp = 0; icomp < ef.fNSigComps; ++icomp) {
304  pdfval += ef.timeModels[icomp]->pdf(stationTimePF + qts[qi] - sIt->firstParticleTimes[icomp]);
305  cdfval += ef.timeModels[icomp]->cdf(stationTimePF + qts[qi] - sIt->firstParticleTimes[icomp]);
306  }
307 
308  pdfval /= 4;
309  cdfval /= 4;
310 
311  const double norm = 1 / TMath::Beta(nps - ih, ih + 1);
312  const double LLq = log(norm * pow(1 - cdfval, nps - ih - 1) * pow(cdfval, ih) * pdfval);
313 
314  StationShapeLikelihood += (std::isnan(LLq) || std::isinf(LLq)) ? 200 : LLq;
315 
316  }
317 
318  } else {
319 
320  for (unsigned int curBin = 0; curBin < sIt->trace.size(); ++curBin) {
321  const double curBinContent = sIt->trace[curBin];
322 
323  if (sIt->isSaturated) {
324  if (curBinContent < ef.fMinBinContentForSatShapeFit ||
325  curBinContent > ef.fMaxBinContentForSatShapeFit ||
326  curBinContent > 0.95 * sIt->Smaxbin)
327  continue;
328  } else {
329  if (curBinContent < ef.fMinBinContentForShapeFit ||
330  curBinContent > ef.fMaxBinContentForShapeFit)
331  continue;
332  }
333 
334  if (ef.doPartialShapeFit &&
335  (int(curBin) < sIt->firstFitBin || int(curBin) > sIt->lastFitBin))
336  continue;
337 
338  const double binPFTime = stationTimePF + (curBin + 1 - sIt->startBin) * sIt->binwidth;
339 
340  if (ef.fEarlyTraceFit && (binPFTime - stationTimePF > sIt->t50 + sIt->binwidth)) {
341  if (ef.fVerbosityLevel > 3)
342  cout << "Bin " << curBin << " is skipped because it is later than t50 " << sIt->t50 << endl;
343  continue;
344  }
345 
346  double predictedBinContent = 0;
347  double predictedBinComponentContent = 0;
348  const double totalBinSigma = poissonFactor * sigmaFactor * std::sqrt(curBinContent);
349  double StationShapeBinLikelihood = 0;
350 
351  // calculation from shape model
352  for (int icomp = 0; icomp < ef.fNSigComps; ++icomp) {
353  predictedBinComponentContent =
354  (ef.timeModels[icomp]->cdf(binPFTime - sIt->firstParticleTimes[icomp] + sIt->binwidth / 2) -
355  ef.timeModels[icomp]->cdf(binPFTime - sIt->firstParticleTimes[icomp] - sIt->binwidth / 2)) *
356  sIt->compSignals[icomp];
357  predictedBinContent += predictedBinComponentContent;
358  }
359 
360  StationShapeBinLikelihood += LogarithmOfNormalPDF(curBinContent, predictedBinContent, totalBinSigma);
361  if (ef.fVerbosityLevel > 3) {
362  cout << "id=" << sIt->stationId << " bin=" << curBin
363  << " S=" << curBinContent << " pred=" << predictedBinContent
364  << " LL=" << -StationShapeBinLikelihood << endl;
365  }
366 
367  StationShapeLikelihood += StationShapeBinLikelihood;
368 
369  }
370  }
371 
372  StationLikelihood += StationShapeLikelihood;
373  ef.fShapeLikelihood += StationShapeLikelihood;
374  sIt->ShapeLikelihood = StationShapeLikelihood;
375 
376  }
377 
378  if (sIt->useForStartTimeFit && !ef.fOnlySignalLikelihood) {
379  const double muonsInStation = sIt->compSignals[sc_mu] / RelativeTrackLength(cosThetaStation);
380 
381  const double startTimeProb =
383  ef.timeModels[sc_mu]->firstParticlePdfSmeared(stationTimePF - sIt->firstParticleTimes[sc_mu], muonsInStation) :
384  ef.timeModels[sc_mu]->firstParticlePdf(stationTimePF - sIt->firstParticleTimes[sc_mu], muonsInStation);
385  const double StationStartTimeLikelihood = log(startTimeProb);
386 
387  if (ef.fVerbosityLevel > 2) {
388  cout
389  << " id " << sIt->stationId
390  << " npart " << muonsInStation
391  << " fpt " << sIt->firstParticleTimes[sc_mu] << " stpf " << stationTimePF << " stprob " << startTimeProb
392  << " pft " << format(" %.10e ") % sIt->planeFrontTime
393  << " stl " << StationStartTimeLikelihood
394  << endl;
395  }
396  StationLikelihood += StationStartTimeLikelihood;
397  ef.fStartTimeLikelihood += StationStartTimeLikelihood;
398  sIt->StartTimeLikelihood = StationStartTimeLikelihood;
399  }
400 
401  if (sIt->useForLDFFit || ((sIt->useForLDFFit || sIt->useForShapeFit) && ef.fOnlySignalLikelihood && !sIt->isSaturated)) {
402 
403  double StationLDFLikelihood = 0;
404  if (ef.fVerbosityLevel > 2) {
405  cout
406  << " id " << sIt->stationId
407  << " signal " << sIt->totalSignal
408  << " pred " << predTotalSignal
409  << " sigma " << totalSignalUncertainty
410  << endl;
411  }
412  StationLDFLikelihood +=
413  TMath::Log(TMath::Poisson(poissonFactor * sIt->totalSignal, poissonFactor * predTotalSignal));
414 
415  if (!(std::isnan(StationLDFLikelihood) || std::isinf(StationLDFLikelihood))) {
416  StationLikelihood += StationLDFLikelihood;
417  ef.fLDFLikelihood += StationLDFLikelihood;
418  sIt->LDFLikelihood = StationLDFLikelihood;
419  }
420  }
421 
422  // constraining the total predicted signal to saturation recovered measured signal
423  if (ef.addRecovSignalConstraint && ef.doLDFFit && sIt->isSaturated && sIt->recoveredSignal > 0) {
424  const double constrLL = LogarithmOfNormalPDF(sIt->recoveredSignal, predTotalSignal, sIt->recoveredSignalUncertainty);
425  StationLikelihood += constrLL;
426  }
427 
428  if (sIt->useForMuonTimeFit) {
429  double StationMuonTimeLikelihood = 0;
430 
431  for (unsigned int k = 0; k < sIt->muonTimes.size(); k++) {
432  const double muonTimePF = sIt->muonTimes[k] - sIt->planeFrontTime;
433 
434  const double MuonTimeLikelihood = log(ef.timeModels[sc_mu]->pdf(muonTimePF + 50 * nanosecond - sIt->firstParticleTimes[sc_mu]));
435  StationMuonTimeLikelihood += MuonTimeLikelihood;
436  if (ef.fVerbosityLevel > 2) {
437  cout << " id " << sIt->stationId
438  << " timepf " << muonTimePF + 50 * nanosecond
439  << " fpt " << sIt->firstParticleTimes[sc_mu]
440  << " muon LL " << MuonTimeLikelihood
441  << endl;
442  }
443  }
444  StationLikelihood += StationMuonTimeLikelihood;
445  }
446 
447  if (ef.addMuonLDFConstraint && ef.doLDFFit && (sIt->useForLDFFit || sIt->useForShapeFit)) {
448  const double predMuonSignal = sIt->compSignals[sc_mu];
449  //const double muonConstraint = LogarithmOfNormalPDF(sIt->muonSignal, predMuonSignal, sIt->muonSignalError);
450  const double muonSignal = sIt->muonTimes.size() * RelativeTrackLength(cosThetaStation);
451  const double muonConstraint = LogarithmOfNormalPDF(muonSignal, predMuonSignal, sqrt(muonSignal));
452  StationLikelihood += muonConstraint;
453  }
454 
455  TotalLikelihood += StationLikelihood;
456  }
457 
458  if (ef.x0Mode != eFixed && ef.fX0Constraint.sigma > 0)
459  TotalLikelihood += LogarithmOfNormalPDF(x0, ef.initPars.x0, ef.fX0Constraint.sigma);
460 
461  if (!ef.coreFixed) {
462  if (ef.fCoreConstraint.sigma > 0) {
463  const double distToInit = (core - ef.initPars.core).GetMag();
464  TotalLikelihood += LogarithmOfNormalPDF(distToInit, 0, ef.fCoreConstraint.sigma);
465  }
466  if (ef.fCoreTimeConstraint.sigma > 0)
467  TotalLikelihood += LogarithmOfNormalPDF(relCoreTime, 0, ef.fCoreTimeConstraint.sigma);
468  }
469 
471  TotalLikelihood += LogarithmOfNormalPDF(totalEnergy, ef.fEnergyConstraint.mean, ef.fEnergyConstraint.sigma);
472 
473  if (!ef.xmaxFixed && ef.fXmaxConstraint.sigma > 0)
475 
476  if (!ef.axisFixed) {
477  if (ef.fThetaConstraint.sigma > 0)
479 
480  if (ef.fPhiConstraint.sigma > 0)
482  }
483 
484  if (std::isnan(TotalLikelihood) || std::isinf(TotalLikelihood))
485  TotalLikelihood = ef.fFailLikelihood;
486 
487  if (ef.fVerbosityLevel > 1)
488  printf("ll %.3f\n", TotalLikelihood);
489 
490  return -TotalLikelihood;
491  }
492 
493 
494  double
495  AMIGAFitFunction::operator()(const std::vector<double>& /*pars*/)
496  const
497  {
498  // TODO implement
499  return 0;
500  }
501 
502 
503  double
504  ASCIIFitFunction::operator()(const std::vector<double>& /*pars*/)
505  const
506  {
507  // TODO implement
508  return 0;
509  }
510 
511 
512  FitFunction::FitFunction(const Fitter& theEf): ef(theEf) { }
513 
514 
515  double
517  const
518  {
519  return 0.5; // 1.0 for chi2, 0.5 for negative log likelihood
520  }
521 
522 
523  double
524  FitFunction::operator()(const std::vector<double>& pars)
525  const
526  {
527  WCDFitFunction& wcd = *(ef.fWCDFunc);
528  //AMIGAFitFunction& amiga = *(ef.fAMIGAFunc);
529  //ASCIIFitFunction& ascii = *(ef.fASCIIFunc);
530  return wcd(pars);
531  }
532 
533 
534  // Note the "Minuit units" here (for grammage and energy, see above)
535  minScan1D
536  Fitter::scanMinimum1D(const int parIndex, const double val, const double delta, const int nSteps)
537  {
538  const double minScanValue = val - delta;
539  const double maxScanValue = val + delta;
540  const double scanStep = (maxScanValue - minScanValue) / nSteps;
541 
542  vector<double> params = fFittedMinuitParams;
543 
544  minScan1D scanVals;
545 
546  // suppress output temporarily
547  const int verblevel = fVerbosityLevel;
548  if (fVerbosityLevel <= 2)
549  fVerbosityLevel = 0;
550 
551  for (double scanValue = minScanValue; scanValue < maxScanValue; scanValue += scanStep) {
552  scanVals.x.push_back(scanValue);
553  params[parIndex] = scanValue;
554  const double funcval = (*fFunc)(params);
555  scanVals.f.push_back(funcval);
556  scanVals.fLDF.push_back(-fLDFLikelihood);
557  scanVals.fShape.push_back(-fShapeLikelihood);
558  scanVals.fStartTime.push_back(-fStartTimeLikelihood);
559  }
560  if (fVerbosityLevel <= 2)
561  fVerbosityLevel = verblevel;
562  return scanVals;
563  }
564 
565 
566  // Note the "Minuit units" here (for grammage and energy, see above)
567  minScan2D
568  Fitter::scanMinimum2D(const int parIndexx, const int parIndexy, const double valx, const double valy,
569  const double deltaX, const double deltaY, const int nSteps)
570  {
571  const double minScanValuex = valx - deltaX;
572  const double maxScanValuex = valx + deltaX;
573  const double minScanValuey = valy - deltaY;
574  const double maxScanValuey = valy + deltaY;
575  const double scanStepx = (maxScanValuex - minScanValuex) / nSteps;
576  const double scanStepy = (maxScanValuey - minScanValuey) / nSteps;
577 
578  vector<double> params = fFittedMinuitParams;
579 
580  minScan2D scanVals;
581 
582  // suppress output temporarily
583  const int verblevel = fVerbosityLevel;
584  if (fVerbosityLevel < 3)
585  fVerbosityLevel = 0;
586 
587  for (int i = 0; i < nSteps; ++i) {
588  scanVals.x.push_back(minScanValuex + i * scanStepx);
589  scanVals.y.push_back(minScanValuey + i * scanStepy);
590  }
591 
592  for (int iy = 0; iy < nSteps; ++iy) {
593  for (int ix = 0; ix < nSteps; ++ix) {
594  params[parIndexx] = scanVals.x[ix];
595  params[parIndexy] = scanVals.y[iy];
596  scanVals.f.push_back(-(*fFunc)(params));
597  }
598  }
599  if (fVerbosityLevel < 3)
600  fVerbosityLevel = verblevel;
601  return scanVals;
602  }
603 
604 
605  void
607  {
608  const int nSteps = 1000;
609 
610  //minScan1D scan = scanMinimum1D(0, fittedPars.core.GetX(fBaryCS), 50, nSteps);
611  //minScan1D scan = scanMinimum1D(1, fittedPars.core.GetY(fBaryCS), 50, nSteps);
612  //minScan1D scan = scanMinimum1D(4, fittedPars.axis.GetTheta(fBaryCS), .2*degree, nSteps);
613  //minScan1D scan = scanMinimum1D(5, fittedPars.axis.GetPhi(fBaryCS), .05*degree, nSteps);
614  minScan1D scan = scanMinimum1D(6, fittedPars.xmax / gpercm2, 300, nSteps);
615 
616  std::ofstream out("scan_out.txt");
617  for (unsigned int i = 0; i < scan.x.size(); ++i) {
618  out << format("%.15e ") % scan.x[i]
619  << format("%.15e ") % scan.f[i]
620  << format("%.15e ") % scan.fLDF[i]
621  << format("%.15e ") % scan.fShape[i]
622  << format("%.15e ") % scan.fStartTime[i]
623  << endl;
624  }
625  }
626 
627 
629  {
630  fUnivParam.reset(new UnivParamNS::UnivParam(0)); // 0 for WCD
631  fUnivParamTime.reset(new UnivParamTimeNS::UnivParamTime(0)); // 0 for WCD
632 
633  fFunc.reset(new FitFunction(*this));
634  fWCDFunc.reset(new WCDFitFunction(*this));
635  //fAMIGAFunc.reset(new AMIGAFitFunction(*this));
636  //fASCIIFunc.reset(new ASCIIFitFunction(*this));
637 
638  fSiteCSHeight = 1400 * m;
639 
640  CoordinateSystemPtr ecef = CoordinateSystem::GetRootCoordinateSystem();
641  ReferenceEllipsoid wgs84 = ReferenceEllipsoid::Get(ReferenceEllipsoid::eWGS84);
642 
643  UTMPoint malargueOrigin(6060000 * m, 440000 * m, 0, 19, 'H', wgs84);
644  CoordinateSystemPtr malargueCS = AugerBaseCoordinateSystem::Create(malargueOrigin, ecef);
645 
646  UTMPoint pampaAmarillaOrigin(-35.25 * deg, -69.25 * deg, fSiteCSHeight, wgs84);
647  CoordinateSystemPtr pampaAmarillaCS = AugerCoordinateSystem::Create(pampaAmarillaOrigin, malargueCS);
648 
649  fSiteCS = pampaAmarillaCS;
650 
651  fNSigComps = 4;
652  fUPFudgeFactor = 1.0; // new plots confirm correct prediction of signals when using local muon number
653  fStartTimeBias = 14.5 * nanosecond; // bias in start time that needs to be corrected in order to unbias MC
654 
660 
661  fLowerRadiusCutLDF = 100 * meter;
662  fUpperRadiusCutLDF = 2500 * meter;
663  fLowerRadiusCutShape = 100 * meter;
664  fUpperRadiusCutShape = 2200 * meter;
665  fLowerRadiusCutTime = 100 * meter;
666  fUpperRadiusCutTime = 2200 * meter;
667 
668  fXmaxLowerLimit = 200 * gpercm2;
669  fXmaxUpperLimit = 2000 * gpercm2;
670  fAxisFitLimit = 10 * degree;
671  fCoreFitLimit = 0 * meter;
672 
673  fMigradTol = 0.1;
674  // the likelihood function returns -1*total likelihood
675  // so this value becomes a huge positive value for minuit
676  fFailLikelihood = -1e8;
677  fMigradStrategy = 1;
678  fEnergyScale = 1e18 * eV;
679  fGrammageScale = gram / cm2;
680  fVerbosityLevel = 0;
681 
682  fPrintResults = true;
683 
684  // apply missing energy correction (off for MC showers)
685  // Not necessary since Observer v9r3 due to new missing energy correction (GAP 2013-026)
686  fRescaleEnergy = false;
687 
688  // for old time model (part of the bias stems from problems with start time fit)
689  fApplyXmaxBiasCorrection = false;
690  fUseMCEnergyScale = false;
691  fEarlyTraceFit = false;
692  fQuantileShapeFit = false;
693  fIterativeFit = false;
694  fCalibMode = false;
695  fOnlySignalLikelihood = false;
696  fUseTimeModelOffset = true;
697  fUseNmuModel = false;
698 
699  isMCEvent = false;
700 
701  fX0XmaxModelVersion = 2; // see FitterUtil.cc
702 
703  doLDFFit = true; // fit to the total signal
704  doShapeFit = true; // bin-by-bin fit to VEM trace
705  doPartialShapeFit = false; // fit to VEM trace between predefined quantiles (e.g. to avoid long tails)
706  doStartTimeFit = false; // fit start time to pdf of first particle, leads to an additional bias with the current impl.
707  doSaturatedStartTimeFit = false;
708  addMuonLDFConstraint = false;
709  doMuonTimeFit = false;
710  smearFirstParticlePdf = true;
711  addRecovSignalConstraint = false;
712 
713  coreFixed = false;
714  axisFixed = false;
715  xmaxFixed = false;
716  NmuFixed = false;
717  energyFixed = true;
718  TimeModelOffsetFixed = true;
719 
720  x0Mode = eCoupled;
721 
722  reset();
723  }
724 
725 
727  {
728  clearTimeModel();
729  }
730 
731 
732  void
734  {
735  fitData.clear();
736 
737  mcPars.valid = false;
738  sdPars.valid = false;
739  fdPars.valid = false;
740 
741  eventHasSaturation = false;
742  atmModel = 0;
743  atmType = "monthly";
744  atmUseGDAS = false;
745 
746  fNStationsLDF = 0;
747  fNStationsShape = 0;
749  }
750 
751 
752  void
753  Fitter::initTimeModel(unsigned int version)
754  {
755  fTimeModelVersion = version;
756  if (version == 1) {
757  for (int icomp = 0; icomp < fNSigComps; ++icomp)
758  timeModels.push_back(new UnivTimeKG::LogNormalTimeModel(icomp));
759  } else if (version == 2) {
760  for (int icomp = 0; icomp < fNSigComps; ++icomp)
761  timeModels.push_back(new UnivTimeKG::GammaTimeModel(icomp));
762  } else {
763  cout << "ERROR: invalid time model version" << endl;
764  throw;
765  }
766  }
767 
768 
769  void
771  {
772  for (int icomp = 0; icomp < fNSigComps; ++icomp)
773  delete timeModels[icomp];
774  timeModels.clear();
775  }
776 
777 
778  void
779  Fitter::setRecType(unsigned int type)
780  {
781  // all options are set to useful values in the constructor of this class
782  // they are replaced depending on the type of reconstruction
783 
784  switch (type) {
785 
786  // simulated SD: energy fixed to MC energy
787  case 1:
788  initMode = eMC;
789  break;
790 
791  // real SD events: energy fixed to SD energy
792  case 2:
793  initMode = eSD;
794  break;
795 
796  // real SD/FD events: energy fixed to FD energy
797  case 3:
798  initMode = eFD;
799  break;
800 
801  // MC events: calibration mode
802  case 4:
803  initMode = eMC;
804 
805  coreFixed = false;
806  axisFixed = true;
807  xmaxFixed = true;
808  NmuFixed = false;
809  energyFixed = true;
810  TimeModelOffsetFixed = false;
811 
812  fCalibMode = true;
813  fIterativeFit = false;
814 
815  x0Mode = eCoupled;
816 
817  break;
818 
819  // real golden hybrid events: parameters from FD reconstruction, Nmu fitted, no time fit
820  case 5:
821  initMode = eFD;
822 
823  coreFixed = false;
824  axisFixed = true;
825  xmaxFixed = true;
826  NmuFixed = false;
827  energyFixed = true;
828  TimeModelOffsetFixed = true;
829 
830  fIterativeFit = false;
831 
832  x0Mode = eCoupled;
833 
834  break;
835 
836  // real golden hybrid events: parameters from FD reconstruction, Nmu fitted, fit TimeModelOffset
837  case 6:
838  initMode = eFD;
839 
840  coreFixed = false;
841  axisFixed = true;
842  xmaxFixed = true;
843  NmuFixed = false;
844  energyFixed = true;
845  TimeModelOffsetFixed = false;
846 
847  fCalibMode = true;
848  fIterativeFit = false;
849 
850  x0Mode = eCoupled;
851 
852  break;
853 
854  }
855  }
856 
857 
858  void
860  {
861  fitData.push_back(sdata);
862  }
863 
864 
866  Fitter::getStationFitData(const int stationId)
867  {
868  for (std::vector<StationFitData>::iterator sIt = fitData.begin(); sIt != fitData.end(); ++sIt) {
869  if (sIt->stationId == stationId)
870  return *sIt;
871  }
872  throw;
873  }
874 
875 
876  bool
877  Fitter::isShapeFitCandidate(const int stationId)
878  {
879  StationFitData& s(getStationFitData(stationId));
880  return s.useForShapeFit;
881  }
882 
883 
884  bool
885  Fitter::isLDFFitCandidate(const int stationId)
886  {
887  StationFitData& s(getStationFitData(stationId));
888  return s.useForLDFFit;
889  }
890 
891 
892  bool
893  Fitter::isStartTimeFitCandidate(const int stationId)
894  {
895  StationFitData& s(getStationFitData(stationId));
896  return s.useForStartTimeFit;
897  }
898 
899 
900  // return true if the station was selected for the fit
901  bool
902  Fitter::isCandidateStation(const int stationId)
903  {
904  StationFitData& s(getStationFitData(stationId));
906  }
907 
908 
909  void
910  Fitter::setupMinuit(MnUserParameters& upar)
911  {
912  upar.Add("coreX", initPars.core.GetX(fBaryCS), 50.*meter);
913  upar.Add("coreY", initPars.core.GetY(fBaryCS), 50.*meter);
914  upar.Add("coreZ", initPars.core.GetZ(fBaryCS), 50.*meter);
915 
916  upar.Add("relCoreTime", 0, 25 * nanosecond);
917  upar.SetLimits("relCoreTime", -1e6 * nanosecond, 1e6 * nanosecond);
918 
919  if (fCoreFitLimit > 0) {
920  upar.SetLimits("coreX", upar.Value("coreX") - fCoreFitLimit, upar.Value("coreX") + fCoreFitLimit);
921  upar.SetLimits("coreY", upar.Value("coreY") - fCoreFitLimit, upar.Value("coreY") + fCoreFitLimit);
922  }
923 
924  if (coreFixed) {
925  upar.Fix("coreX");
926  upar.Fix("coreY");
927  upar.Fix("relCoreTime");
928  }
929  upar.Fix("coreZ");
930 
931  upar.Add("theta", initPars.axis.GetTheta(fBaryCS), 1 * degree);
932  upar.Add("phi", initPars.axis.GetPhi(fBaryCS), 1 * degree);
933  if (fAxisFitLimit > 0) {
934  double minTheta = upar.Value("theta") - fAxisFitLimit;
935  if (minTheta < 0)
936  minTheta = 0;
937  upar.SetLimits("theta", minTheta, upar.Value("theta") + fAxisFitLimit);
938  upar.SetLimits("phi", upar.Value("phi") - fAxisFitLimit, upar.Value("phi") + fAxisFitLimit);
939  }
940  if (axisFixed) {
941  upar.Fix("theta");
942  upar.Fix("phi");
943  }
944 
945  // The numeric values of eV and g/cm^2 are very large.
946  // Energy and grammage are rescaled for Minuit such that
947  // the values are roughly on the same order of magnitude.
949  upar.SetLimits("xmax", fXmaxLowerLimit / fGrammageScale, fXmaxUpperLimit / fGrammageScale);
950  if (xmaxFixed)
951  upar.Fix("xmax");
952 
953  upar.Add("Nmu", initPars.Nmu, initPars.NmuUnc);
954  upar.SetLimits("Nmu", 0., 4.);
955  if (NmuFixed)
956  upar.Fix("Nmu");
957 
958  upar.Add("energy", initPars.energy / fEnergyScale, .2 * initPars.energy / fEnergyScale);
959  upar.SetLimits("energy", 0.5 * initPars.energy / fEnergyScale, 1.5 * initPars.energy / fEnergyScale);
960  if (energyFixed)
961  upar.Fix("energy");
962 
963  upar.Add("TimeModelOffset", initPars.TimeModelOffset, 1);
964  upar.SetLimits("TimeModelOffset", -3., 3.);
966  upar.Fix("TimeModelOffset");
967 
968  upar.Add("x0", initPars.x0 / fGrammageScale, 10.);
969  upar.SetLimits("x0", 0., 500);
970  if (x0Mode == eFixed || x0Mode == eCoupled)
971  upar.Fix("x0");
972  }
973 
974 
975  void
977  {
979  fAtmosphere->SetCurrentAtmosphere(atmModel);
981 
982  if (isMCEvent && mcPars.valid) {
983  mcPars.coreCS = AugerCoordinateSystem::Create(mcPars.core, ReferenceEllipsoid::eWGS84, fSiteCS);
984  mcPars.showerCS = CoordinateSystem::RotationY(mcPars.axis.GetTheta(fSiteCS),
985  CoordinateSystem::RotationZ(mcPars.axis.GetPhi(fSiteCS), mcPars.coreCS));
986 
987  const CoordinateSystemPtr rotatedMCCoreCS = CoordinateSystem::RotationZ(mcPars.axis.GetPhi(fSiteCS), mcPars.coreCS);
988 
989  for (std::vector<StationFitData>::iterator sIt = fitData.begin(); sIt != fitData.end(); ++sIt) {
990  // This is needed only if UnviFitterKG is used outside of the Offline framework
991  // since the position is only known in (r,psi) referred to the shower axis.
992  // If used within Offline, the position (utl::Point) can be set directly.
993  if (sIt->isDense) {
994  sIt->position = Point(sIt->denseRho * cos(sIt->densePsi) / cos(mcPars.axis.GetTheta(fSiteCS)),
995  sIt->denseRho * sin(sIt->densePsi), 0, rotatedMCCoreCS);
996  //cout << sIt->stationId << " " << sIt->denseRho << " " << sIt->densePsi/degree << " "
997  //<< sIt->position.GetRho(mcPars.showerCS) << " " << NormalizeAngle(sIt->position.GetPhi(mcPars.showerCS))/degree << endl;
998  }
999  }
1000  }
1001 
1002  if (sdPars.valid) {
1003  sdPars.coreCS = AugerCoordinateSystem::Create(sdPars.core, ReferenceEllipsoid::eWGS84, fSiteCS);
1004  sdPars.showerCS = CoordinateSystem::RotationY(sdPars.axis.GetTheta(fSiteCS),
1005  CoordinateSystem::RotationZ(sdPars.axis.GetPhi(fSiteCS), sdPars.coreCS));
1007  sdPars.xmaxUnc = 40 * gpercm2;
1008  sdPars.Nmu = 1.9;
1009  }
1010 
1011  if (fdPars.valid) {
1012  fdPars.coreCS = AugerCoordinateSystem::Create(fdPars.core, ReferenceEllipsoid::eWGS84, fSiteCS);
1013  fdPars.showerCS = CoordinateSystem::RotationY(fdPars.axis.GetTheta(fSiteCS),
1014  CoordinateSystem::RotationZ(fdPars.axis.GetPhi(fSiteCS), fdPars.coreCS));
1015  fdPars.Nmu = 1.9;
1016  }
1017 
1018  if (initMode == eMC && mcPars.valid)
1019  initPars = mcPars;
1020  else if (initMode == eSD && sdPars.valid)
1021  initPars = sdPars;
1022  else if (initMode == eFD && fdPars.valid)
1023  initPars = fdPars;
1024  else {
1025  cout << "ERROR: invalid initMode" << endl;
1026  throw;
1027  }
1028 
1030  initPars.x0Unc = 20 * gpercm2;
1031  initPars.NmuUnc = 0.3;
1033 
1034  const Point siteOrigin(0, 0, 0, fSiteCS);
1035  Vector barySum(0, 0, 0, fSiteCS);
1036  double weightSum = 0;
1037 
1038  for (std::vector<StationFitData>::const_iterator sIt = fitData.begin(); sIt != fitData.end(); ++sIt) {
1039  const double weight = sqrt(sIt->totalSignal); // GAP 2007-035
1040  weightSum += weight;
1041  barySum += weight * (sIt->position - siteOrigin);
1042  }
1043  barySum /= weightSum;
1044  fBarycenter = siteOrigin + barySum;
1045  fBaryCS = AugerCoordinateSystem::Create(fBarycenter, ReferenceEllipsoid::eWGS84, fSiteCS);
1046 
1047  double hottestStationSignal = 0;
1048  Point hottestStationPosition;
1049  for (std::vector<StationFitData>::iterator sIt = fitData.begin(); sIt != fitData.end(); ++sIt) {
1050  if (sIt->totalSignal > hottestStationSignal) {
1051  hottestStationPosition = sIt->position;
1052  hottestStationSignal = sIt->totalSignal;
1053  if (sIt->isSaturated)
1054  cout << "hottest station " << sIt->stationId << " is saturated" << endl;
1055  }
1056  }
1057 
1058  fHottestStationCS = AugerCoordinateSystem::Create(hottestStationPosition, ReferenceEllipsoid::eWGS84, fBaryCS);
1059 
1060  // recalculate energy with respect to p, QGSJet2.3 reference
1061  if (fUseMCEnergyScale && (initMode == eSD || initMode == eFD)) {
1062  if (initMode == eFD && !sdPars.valid) {
1063  cout << "ERROR: Energy rescaling requires Sd parameters at the moment!" << endl;
1064  throw;
1065  }
1066  // initPars.energy = MCEnergyCalibration(sdPars.showersize, sdPars.axis.GetTheta(fBaryCS), false);
1068  }
1069 
1070  if (fVerbosityLevel > 0) {
1071  cout << "\n"
1072  << "station selection:\n"
1073  << "-------------------------\n";
1074  }
1075 
1076  for (std::vector<StationFitData>::iterator sIt = fitData.begin(); sIt != fitData.end(); ++sIt) {
1077 
1078  const double stationRho = sIt->position.GetRho(initPars.showerCS);
1079 
1080  int nBinsAboveShapeFitLimit = 0;
1081 
1082  double Smaxbin(0);
1083 
1084  if (sIt->trace.size() > 0) {
1085  for (unsigned int curBin = 0; curBin < sIt->trace.size(); ++curBin) {
1086  if (sIt->trace[curBin] >= fMinBinContentForShapeFit)
1087  ++nBinsAboveShapeFitLimit;
1088  if (sIt->trace[curBin] > Smaxbin)
1089  Smaxbin = sIt->trace[curBin];
1090  }
1091 
1092  for (int curBin = sIt->startBin; curBin <= sIt->stopBin; ++curBin) {
1093  sIt->traceSum += sIt->trace[curBin]; // different for saturated stations from total signal
1094  } // when unsaturated traces are used
1095 
1096  double traceCumulative = 0;
1097  for (unsigned int curBin = 0; curBin < sIt->trace.size(); ++curBin) {
1098  traceCumulative += sIt->trace[curBin];
1099  if (!sIt->firstFitBin && traceCumulative >= 0.05 * sIt->traceSum)
1100  sIt->firstFitBin = curBin;
1101  if (!sIt->lastFitBin && traceCumulative >= 0.8 * sIt->traceSum)
1102  sIt->lastFitBin = curBin - 1;
1103  }
1104  }
1105 
1106  sIt->Smaxbin = Smaxbin;
1107 
1108  eventHasSaturation |= sIt->isSaturated;
1109 
1110  // sIt->useForShapeFit = doShapeFit && (!sIt->isSaturated || sIt->useUnsaturatedTrace)
1111  sIt->useForShapeFit =
1112  doShapeFit &&
1113  nBinsAboveShapeFitLimit >= fMinBinsAboveShapeFitLimit &&
1114  stationRho > fLowerRadiusCutShape &&
1115  stationRho < fUpperRadiusCutShape;
1116 
1117  sIt->useForLDFFit =
1118  doLDFFit &&
1119  !sIt->useForShapeFit &&
1120  !sIt->isSaturated &&
1121  stationRho > fLowerRadiusCutLDF &&
1122  stationRho < fUpperRadiusCutLDF;
1123 
1124  sIt->useForStartTimeFit =
1125  doStartTimeFit &&
1126  !sIt->useForShapeFit &&
1127  stationRho > fLowerRadiusCutTime &&
1128  stationRho < fUpperRadiusCutTime &&
1129  (!sIt->isSaturated || doSaturatedStartTimeFit);
1130 
1131  if (sIt->useForLDFFit)
1132  ++fNStationsLDF;
1133  if (sIt->useForShapeFit)
1134  ++fNStationsShape;
1135  if (sIt->useForStartTimeFit)
1137 
1138  if (doMuonTimeFit)
1139  sIt->useForMuonTimeFit = true;
1140 
1141  if (fVerbosityLevel > 0) {
1142  cout << "id " << sIt->stationId
1143  << " r " << showpoint << stationRho // same length for all numbers (shows zero at the end)
1144  << " S " << showpoint << sIt->totalSignal << " "
1145  << (sIt->useForLDFFit ? "ldf " : " ")
1146  << (sIt->useForShapeFit ? "shape " : " ")
1147  << (sIt->useForStartTimeFit ? "time " : " ")
1148  << (sIt->isSaturated ? "saturated " : " ")
1149  << (sIt->useUnsaturatedTrace ? "(use simulated unsaturated trace)" : " ");
1150 
1151  if (sIt->useForMuonTimeFit)
1152  cout << sIt->muonTimes.size() << " muons";
1153 
1154  if (doPartialShapeFit)
1155  cout << " fit bins " << sIt->firstFitBin << " " << sIt->lastFitBin;
1156  cout << endl;
1157  }
1158  }
1159  }
1160 
1161 
1162  bool
1164  {
1165  init();
1166 
1167  if (fVerbosityLevel > 0)
1168  cout << "-------------------------\n";
1169 
1170  bool fitOk = true;
1171  bool hesseOk = true;
1172  MnUserParameters upar;
1173  setupMinuit(upar);
1174 
1175  if (upar.VariableParameters() > 0) {
1176  const int maxSteps = 100000;
1177 
1178  MnMigrad migrad(*fFunc, upar, MnStrategy(fMigradStrategy));
1179  FunctionMinimum* min = 0;
1180 
1181  // can also add and remove constraints during iterative fitting
1182  // just set respective sigma values of the ef.xxxConstraint values
1183 
1184  if (fCalibMode) {
1185 
1186  migrad.Fix("xmax");
1187  migrad.Fix("theta");
1188  migrad.Fix("phi");
1189  migrad.Fix("energy");
1190  migrad.Fix("TimeModelOffset");
1191  migrad.Fix("relCoreTime");
1192 
1193  migrad.Release("coreX");
1194  migrad.Release("coreY");
1195  migrad.Release("Nmu");
1196 
1197  fOnlySignalLikelihood = true;
1198 
1199  min = new FunctionMinimum(migrad(maxSteps, fMigradTol));
1200 
1201  migrad.Fix("Nmu");
1202  migrad.Fix("coreX");
1203  migrad.Fix("coreY");
1204  // migrad.Fix("relCoreTime");
1205 
1206  migrad.Release("relCoreTime");
1207  migrad.Release("TimeModelOffset");
1208 
1209  TimeModelOffsetFixed = false;
1210  fOnlySignalLikelihood = false;
1211 
1212  *min = migrad(maxSteps, fMigradTol);
1213 
1214  } else {
1215 
1216  // warning: fixing of certain parameters is overwritten here
1217  if (fIterativeFit) {
1218 
1219  const bool dbgprint(true);
1220 
1221  coreFixed = false;
1222  axisFixed = false;
1223  xmaxFixed = false;
1224  NmuFixed = false;
1225  energyFixed = false;
1226  TimeModelOffsetFixed = true;
1227 
1228  fUseTimeModelOffset = true;
1229 
1230  const double lgE0 = log10(migrad.Value("energy") * fEnergyScale);
1231  //const double theta0 = migrad.Value("theta");
1232  //const double phi0 = migrad.Value("phi");
1233 
1234  // stage 1: core + energy, energy constrained
1235  // only signal model in use
1236 
1237  // constraining
1238  fEnergyConstraint.mean = pow(10, lgE0);
1239  fEnergyConstraint.sigma = 0.2 * pow(10, lgE0);
1240 
1241  fOnlySignalLikelihood = true;
1242 
1243  // need to add new parametrizations for MC events
1244  // should be general enough to incorporate various interaction models and primary types
1245 
1246  if (!isMCEvent) {
1247 
1248  const double lgE = log10(migrad.Value("energy") * fEnergyScale);
1249  const double theta = migrad.Value("theta");
1250 
1251  const double xmax = FitterUtil::getMeanParametrizedXmaxData(lgE);
1252  const double nmu = FitterUtil::getMeanParametrizedNmuData(lgE, theta, xmax);
1253 
1254  migrad.SetValue("xmax", xmax);
1255  migrad.SetValue("Nmu", nmu);
1256  }
1257 
1258  if (dbgprint) {
1259  cout << "Energy before stage 1: " << log10(migrad.Value("energy") * fEnergyScale) << endl;
1260  cout << "Xmax before stage 1: " << migrad.Value("xmax") << endl;
1261  cout << "Nmu before stage 1: " << migrad.Value("Nmu") << endl;
1262  cout << "Zenith before stage 1: " << migrad.Value("theta") << endl;
1263  cout << "RelCoreTime before stage 1: " << migrad.Value("relCoreTime") << endl;
1264  }
1265 
1266  migrad.Fix("TimeModelOffset");
1267 
1268  migrad.Fix("xmax");
1269  migrad.Fix("Nmu");
1270  migrad.Fix("theta");
1271  migrad.Fix("phi");
1272  migrad.Fix("relCoreTime");
1273 
1274  if (!eventHasSaturation)
1275  migrad.Release("energy");
1276  else
1277  migrad.Fix("energy");
1278 
1279  migrad.Release("coreX");
1280  migrad.Release("coreY");
1281 
1282  min = new FunctionMinimum(migrad(maxSteps, fMigradTol));
1283 
1284  if (dbgprint) {
1285  cout << "Energy after stage 1: " << log10(migrad.Value("energy") * fEnergyScale) << endl;
1286  cout << "Xmax after stage 1: " << migrad.Value("xmax") << endl;
1287  cout << "Nmu after stage 1: " << migrad.Value("Nmu") << endl;
1288  cout << "Zenith after stage 1: " << migrad.Value("theta") << endl;
1289  cout << "RelCoreTime after stage 1: " << migrad.Value("relCoreTime") << endl;
1290  }
1291 
1292  // stage 2: core + energy (updated model values after fitting energy), tighter energy constraint
1293  // only signal model is used
1294 
1295  fEnergyConstraint.mean = migrad.Value("energy") * fEnergyScale;
1297 
1298  if (!isMCEvent) {
1299  const double lgE = log10(migrad.Value("energy") * fEnergyScale);
1300  const double theta = migrad.Value("theta");
1301 
1302  const double xmax = FitterUtil::getMeanParametrizedXmaxData(lgE);
1303  const double nmu = FitterUtil::getMeanParametrizedNmuData(lgE, theta, xmax);
1304 
1305  migrad.SetValue("xmax", xmax);
1306  migrad.SetValue("Nmu", nmu);
1307  }
1308 
1309  if (dbgprint) {
1310  cout << "Energy before stage 2: " << log10(migrad.Value("energy") * fEnergyScale) << endl;
1311  cout << "Xmax before stage 2: " << migrad.Value("xmax") << endl;
1312  cout << "Nmu before stage 2: " << migrad.Value("Nmu") << endl;
1313  cout << "Zenith before stage 2: " << migrad.Value("theta") << endl;
1314  cout << "RelCoreTime after stage 2: " << migrad.Value("relCoreTime") << endl;
1315  }
1316 
1317  migrad.Fix("xmax");
1318  migrad.Fix("Nmu");
1319  migrad.Fix("theta");
1320  migrad.Fix("phi");
1321  migrad.Fix("relCoreTime");
1322 
1323  if (!eventHasSaturation)
1324  migrad.Release("energy");
1325  else
1326  migrad.Fix("energy");
1327 
1328  migrad.Release("coreX");
1329  migrad.Release("coreY");
1330 
1331  *min = migrad(maxSteps, fMigradTol);
1332 
1333  if (dbgprint) {
1334  cout << "Energy after stage 2: " << log10(migrad.Value("energy") * fEnergyScale) << endl;
1335  cout << "Xmax after stage 2: " << migrad.Value("xmax") << endl;
1336  cout << "Nmu after stage 2: " << migrad.Value("Nmu") << endl;
1337  cout << "Zenith after stage 2: " << migrad.Value("theta") << endl;
1338  cout << "RelCoreTime after stage 2: " << migrad.Value("relCoreTime") << endl;
1339  }
1340 
1341  fOnlySignalLikelihood = false;
1342 
1343  // stage 3a: relative core time
1344 
1346 
1347  migrad.Fix("energy");
1348  migrad.Fix("coreX");
1349  migrad.Fix("coreY");
1350  migrad.Fix("Nmu");
1351  migrad.Fix("theta");
1352  migrad.Fix("phi");
1353 
1354  migrad.Release("relCoreTime");
1355 
1356  *min = migrad(maxSteps, fMigradTol);
1357 
1358  // stage3b: xmax + relative core time (+ Nmu model)
1359 
1360  // if (!isMCEvent)
1361  // fUseNmuModel = true;
1362 
1363  migrad.Release("relCoreTime");
1364  migrad.Release("xmax");
1365 
1366  *min = migrad(maxSteps, fMigradTol);
1367 
1368  if (dbgprint) {
1369  cout << "Energy after stage 3: " << log10(migrad.Value("energy") * fEnergyScale) << endl;
1370  cout << "Xmax after stage 3: " << migrad.Value("xmax") << endl;
1371  cout << "Nmu after stage 3: " << migrad.Value("Nmu") << endl;
1372  cout << "Zenith after stage 3: " << migrad.Value("theta") << endl;
1373  cout << "RelCoreTime after stage 3: " << migrad.Value("relCoreTime") << endl;
1374  }
1375 
1376  // stage 4: xmax, geometry, relative core time, geometry constrained
1377 
1378  fThetaConstraint.mean = migrad.Value("theta");
1380 
1381  fPhiConstraint.mean = migrad.Value("phi");
1382  fPhiConstraint.sigma = 1 * degree;
1383 
1384  // fXmaxConstraint.sigma = 0;
1385 
1386  /*if (!isMCEvent) {
1387 
1388  const double lgE = log10(migrad.Value("energy") * fEnergyScale);
1389  const double theta = migrad.Value("theta");
1390  const double xmax = migrad.Value("xmax");
1391 
1392  // double nmu(0);
1393 
1394  // if ((xmax > 700) & (xmax < 900)) // validity range of the model
1395  // nmu = FitterUtil::getMeanParametrizedNmuData(lgE, theta, xmax);
1396  // else
1397  // nmu = FitterUtil::getMeanParametrizedNmuData(lgE, theta);
1398 
1399  // migrad.SetValue("Nmu", nmu);
1400  }*/
1401 
1402  if (dbgprint) {
1403  cout << "Energy before stage 4: " << log10(migrad.Value("energy") * fEnergyScale) << endl;
1404  cout << "Xmax before stage 4: " << migrad.Value("xmax") << endl;
1405  cout << "Nmu before stage 4: " << migrad.Value("Nmu") << endl;
1406  cout << "Zenith before stage 4: " << migrad.Value("theta") << endl;
1407  cout << "RelCoreTime before stage 4: " << migrad.Value("relCoreTime") << endl;
1408  }
1409 
1410  migrad.Fix("Nmu");
1411  migrad.Fix("energy");
1412  migrad.Fix("coreX");
1413  migrad.Fix("coreY");
1414 
1415  migrad.Release("theta");
1416  migrad.Release("phi");
1417 
1418  *min = migrad(maxSteps, fMigradTol);
1419 
1420  if (!isMCEvent && fUseNmuModel) {
1421  fUseNmuModel = false;
1422 
1423  const double lgE = log10(migrad.Value("energy") * fEnergyScale);
1424  const double theta = migrad.Value("theta");
1425  const double xmax = migrad.Value("xmax");
1426 
1427  const double nmu = FitterUtil::getMeanParametrizedNmuData(lgE, theta, xmax);
1428 
1429  migrad.SetValue("Nmu", nmu);
1430  }
1431 
1432  if (dbgprint) {
1433  cout << "Energy after stage 4: " << log10(migrad.Value("energy") * fEnergyScale) << endl;
1434  cout << "Xmax after stage 4: " << migrad.Value("xmax") << endl;
1435  cout << "Nmu after stage 4: " << migrad.Value("Nmu") << endl;
1436  cout << "Zenith after stage 4: " << migrad.Value("theta") << endl;
1437  cout << "RelCoreTime after stage 4: " << migrad.Value("relCoreTime") << endl;
1438  }
1439 
1440  // catching misreconstructions by fixing the energy in previous stages
1441  // if (migrad.Value("xmax") > 1200) {
1442 
1443  // cout << "Warning: Xmax is larger than 1100, trying to recover with fixed energy !!!" << endl;
1444 
1445  // migrad.SetValue("energy", pow(10, lgE0) / fEnergyScale);
1446 
1447  // const double xmax = FitterUtil::getMeanParametrizedXmaxData(lgE0);
1448  // const double nmu = FitterUtil::getMeanParametrizedNmuData(lgE0, theta0, xmax);
1449 
1450  // migrad.SetValue("xmax", xmax);
1451  // migrad.SetValue("Nmu", nmu);
1452  // migrad.SetValue("theta", theta0);
1453  // migrad.SetValue("phi", phi0);
1454 
1455  // fThetaConstraint.sigma = 0;
1456  // fPhiConstraint.sigma = 0;
1457 
1458  // // refitting core with fixed energy
1459 
1460  // migrad.Fix("theta");
1461  // migrad.Fix("phi");
1462  // migrad.Fix("xmax");
1463  // migrad.Fix("relCoreTime");
1464 
1465  // migrad.Release("coreX");
1466  // migrad.Release("coreY");
1467 
1468  // *min = migrad(maxSteps, fMigradTol);
1469 
1470  // // refitting xmax and timing
1471 
1472  // migrad.Fix("coreX");
1473  // migrad.Fix("coreY");
1474 
1475  // // migrad.Release("theta");
1476  // // migrad.Release("phi");
1477  // migrad.Release("xmax");
1478  // migrad.Release("relCoreTime");
1479 
1480  // *min = migrad(maxSteps, fMigradTol);
1481 
1482  // // refitting xmax, timing and geometry
1483 
1484  // fThetaConstraint.mean = theta0;
1485  // fThetaConstraint.sigma = 0.5 / 180. * M_PI;
1486 
1487  // fPhiConstraint.mean = phi0;
1488  // fPhiConstraint.sigma = 0.5 / 180. * M_PI;
1489 
1490  // migrad.Release("theta");
1491  // migrad.Release("phi");
1492  // migrad.Release("xmax");
1493  // migrad.Release("relCoreTime");
1494 
1495  // *min = migrad(maxSteps, fMigradTol);
1496 
1497  // }
1498 
1499  // stage 5: re-fit of Nmu
1500 
1501  fThetaConstraint.sigma = 0;
1502  fPhiConstraint.sigma = 0;
1504 
1505  fOnlySignalLikelihood = true;
1506 
1507  migrad.Fix("energy");
1508  migrad.Fix("coreX");
1509  migrad.Fix("coreY");
1510  migrad.Fix("theta");
1511  migrad.Fix("phi");
1512  migrad.Fix("relCoreTime");
1513  migrad.Fix("xmax");
1514 
1515  migrad.Release("Nmu");
1516 
1517  *min = migrad(maxSteps, fMigradTol);
1518 
1519  if (dbgprint) {
1520  cout << "Energy after stage 5: " << log10(migrad.Value("energy") * fEnergyScale) << endl;
1521  cout << "Xmax after stage 5: " << migrad.Value("xmax") << endl;
1522  cout << "Nmu after stage 5: " << migrad.Value("Nmu") << endl;
1523  cout << "Zenith after stage 5: " << migrad.Value("theta") << endl;
1524  cout << "RelCoreTime after stage 5: " << migrad.Value("relCoreTime") << endl;
1525  }
1526 
1527  fOnlySignalLikelihood = false;
1528 
1529  // stage 6: xmax, geometry, geometry constrained (updated Nmu value)
1530 
1531  fThetaConstraint.mean = migrad.Value("theta");
1533 
1534  fPhiConstraint.mean = migrad.Value("phi");
1535  fPhiConstraint.sigma = 1 * degree;
1536 
1537  migrad.Fix("Nmu");
1538 
1539  migrad.Release("theta");
1540  migrad.Release("phi");
1541  migrad.Release("xmax");
1542 
1543  *min = migrad(maxSteps, fMigradTol);
1544 
1545  if (dbgprint) {
1546  cout << "Energy after stage 6: " << log10(migrad.Value("energy") * fEnergyScale) << endl;
1547  cout << "Xmax after stage 6: " << migrad.Value("xmax") << endl;
1548  cout << "Nmu after stage 6: " << migrad.Value("Nmu") << endl;
1549  cout << "Zenith after stage 6: " << migrad.Value("theta") << endl;
1550  cout << "RelCoreTime after stage 6: " << migrad.Value("relCoreTime") << endl;
1551  }
1552 
1553  // stage 7: re-fit energy as previous last step (using signal and time models)
1554 
1555  fThetaConstraint.sigma = 0;
1556  fPhiConstraint.sigma = 0;
1557 
1558  fEnergyConstraint.mean = migrad.Value("energy") * fEnergyScale;
1560 
1561  migrad.Fix("Nmu");
1562  migrad.Fix("theta");
1563  migrad.Fix("phi");
1564  migrad.Fix("xmax");
1565  migrad.Release("energy");
1566 
1567  *min = migrad(maxSteps, fMigradTol);
1568 
1569  if (dbgprint) {
1570  cout << "Energy after stage 7: " << log10(migrad.Value("energy") * fEnergyScale) << endl;
1571  cout << "Xmax after stage 7: " << migrad.Value("xmax") << endl;
1572  cout << "Nmu after stage 7: " << migrad.Value("Nmu") << endl;
1573  cout << "Zenith after stage 7: " << migrad.Value("theta") << endl;
1574  cout << "RelCoreTime after stage 7: " << migrad.Value("relCoreTime") << endl;
1575  }
1576 
1577  // stage 8: re-fit Nmu as last step (using signal model)
1578 
1579  // fEnergyConstraint.sigma = 0;
1580 
1581  // fOnlySignalLikelihood = true;
1582 
1583  // migrad.Fix("energy");
1584  // migrad.Fix("theta");
1585  // migrad.Fix("phi");
1586  // migrad.Fix("xmax");
1587  // migrad.Release("Nmu");
1588 
1589  // *min = migrad(maxSteps, fMigradTol);
1590 
1591  // fOnlySignalLikelihood = false;
1592 
1593  // if (dbgprint)
1594  // cout << "Xmax after stage 8: " << migrad.Value("xmax") << endl;
1595 
1596  } else
1597  min = new FunctionMinimum(migrad(maxSteps, fMigradTol));
1598  }
1599 
1600  if (fVerbosityLevel > 1)
1601  cout << *min;
1602 
1603  // The likelihood near the minimum is slightly non-parabolic in the x/y direction in rare cases.
1604  // In this case, Minuit overestimates the EDM and pretends it didn't converge
1605  // although the fitted value is fine (checked by hand many cases).
1606  // After fixing the core and running again, the change in the remaining free parameters is very small.
1607  if (!isFitOk(*min) && !fIterativeFit) {
1608  cout << "\n"
1609  "No convergence according to Minuit. Fixing the core position and running again."
1610  << endl;
1611  migrad.Fix("coreX");
1612  migrad.Fix("coreY");
1613  *min = migrad(maxSteps, fMigradTol);
1614  }
1615 
1616  if (fVerbosityLevel > 1)
1617  cout << *min;
1618  fitOk = isFitOk(*min);
1619 
1620  if (fVerbosityLevel > 1)
1621  cout << "\n\n### calculating hesse matrix\n" << endl;
1622  const int verblevel = fVerbosityLevel;
1623  fVerbosityLevel = 0;
1624  MnHesse hesse(fMigradStrategy);
1625  hesse(migrad.Fcnbase(), *min, maxSteps);
1626  fVerbosityLevel = verblevel;
1627  hesseOk = !min->HesseFailed();
1628 
1629  const MnUserParameterState& us = min->UserState();
1630  fFittedMinuitParams = us.Params();
1631  if (fVerbosityLevel > 1)
1632  cout << min->UserCovariance() << endl;
1633 
1634  fittedPars.axis = Vector(1., us.Value("theta"), us.Value("phi"), fBaryCS, Vector::kSpherical);
1635  fittedPars.axisUncTheta = us.Error("theta");
1636  fittedPars.axisUncPhi = us.Error("phi");
1637 
1638  fittedPars.core = Point(us.Value("coreX"), us.Value("coreY"), us.Value("coreZ"), fBaryCS);
1639  fittedPars.coreUncX = us.Error("coreX");
1640  fittedPars.coreUncY = us.Error("coreY");
1641  fittedPars.coretime = initPars.coretime + us.Value("relCoreTime");
1642  fittedPars.coreCS = AugerCoordinateSystem::Create(fittedPars.core, ReferenceEllipsoid::eWGS84, fSiteCS);
1643  fittedPars.showerCS = CoordinateSystem::RotationY(fittedPars.axis.GetTheta(fSiteCS),
1644  CoordinateSystem::RotationZ(fittedPars.axis.GetPhi(fSiteCS), fittedPars.coreCS));
1645 
1646  fittedPars.Nmu = us.Value("Nmu");
1647  fittedPars.NmuUnc = us.Error("Nmu");
1648  fittedPars.energy = us.Value("energy") * fEnergyScale;
1649  fittedPars.energyUnc = us.Error("energy") * fEnergyScale;
1650 
1651  fittedPars.xmax = us.Value("xmax") * fGrammageScale;
1652  fittedPars.xmaxUnc = us.Error("xmax") * fGrammageScale;
1653 
1654  fittedPars.TimeModelOffset = us.Value("TimeModelOffset");
1655  fittedPars.TimeModelOffsetUnc = us.Error("TimeModelOffset");
1656 
1660 
1661  fittedPars.x0 = us.Value("x0") * fGrammageScale;
1662  fittedPars.x0Unc = us.Error("x0") * fGrammageScale;
1663 
1664  if (x0Mode == eCoupled) {
1666  fittedPars.x0Unc = 0;
1667  }
1668 
1670 
1671  // call fcn at the end to set final likelihood values (total + per station) etc...
1672  (*fFunc)(us.Params());
1673 
1674  delete min;
1675 
1676  } else {
1677  // this is done so that fittedPars can be used from outside in the same way
1678  // even if all parameters are fixed (e.g. to check the prediction of the MC values)
1679  fittedPars = initPars;
1680  (*fFunc)(upar.Params());
1681  }
1682 
1683  if (fPrintResults)
1684  printResults();
1685 
1686  return fitOk && hesseOk;
1687  }
1688 
1689 
1690  bool
1691  Fitter::isFitOk(const FunctionMinimum& min)
1692  {
1693  const MnUserParameterState& us = min.UserState();
1694  if (!min.IsValid() || !us.IsValid() || min.IsAboveMaxEdm() || min.HasReachedCallLimit())
1695  return false;
1696 
1697  const vector<double>& pars = us.Params();
1698  for (unsigned int i = 0; i < pars.size(); ++i) {
1699  if (std::isnan(pars[i]))
1700  return false;
1701  }
1702 
1703  return true;
1704  }
1705 
1706 
1707  void
1709  {
1710  const double eoutsc = 1e18;
1711 
1712  cout << endl;
1713 
1714  cout << format("E/eV") << endl;
1715  if (isMCEvent)
1716  cout << format(" MC %.2f * 10^%i") % (mcPars.energy / eoutsc) % log10(eoutsc) << endl;
1717  cout << format(" init %.2f * 10^%i") % (initPars.energy / eoutsc) % log10(eoutsc) << endl;
1718  if (!energyFixed)
1719  cout << format(" fit (%.2f ± %.2f) * 10^%i") % (fittedPars.energy / eoutsc) % (fittedPars.energyUnc / eoutsc) % log10(eoutsc) << endl;
1720  cout << (fEnergyConstraint.sigma > 0 ? "(constrained)" : "");
1721  cout << endl;
1722 
1723 
1724  cout << "Nmu" << endl;
1725  if (isMCEvent)
1726  cout << format(" MC %.2f") % (mcPars.Nmu) << endl;
1727  cout << format(" init %.2f") % (initPars.Nmu) << endl;
1728  if (!NmuFixed) {
1729  cout << format(" fit %.2f ± %.3f") % (fittedPars.Nmu) % (fittedPars.NmuUnc);
1730  if (isMCEvent)
1731  cout << format(" (%+.2f to MC)") % (fittedPars.Nmu - mcPars.Nmu);
1732  cout << endl;
1733  }
1734  cout << endl;
1735 
1736 
1737  cout << "xmax/gcm^-2" << endl;
1738  if (isMCEvent)
1739  cout << format(" MC %.2f") % (mcPars.xmax / gpercm2) << endl;
1740  cout << format(" init %.2f") % (initPars.xmax / gpercm2) << endl;
1741  if (!xmaxFixed) {
1742  cout << format(" fit %.2f ± %.2f") % (fittedPars.xmax / gpercm2) % (fittedPars.xmaxUnc / gpercm2);
1743  if (isMCEvent)
1744  cout << format(" (%+.2f to MC)") % ((fittedPars.xmax - mcPars.xmax) / gpercm2);
1745  cout << endl;
1746  }
1747  cout << endl;
1748 
1749 
1750  if (x0Mode == eFree) {
1751  cout << "x0/gcm^-2" << endl;
1752  if (isMCEvent)
1753  cout << format(" MC %.2f") % (mcPars.x0 / gpercm2) << endl;
1754  cout << format(" init %.2f") % (initPars.x0 / gpercm2) << endl;
1755  cout << format(" fit %.2f ± %.2f") % (fittedPars.x0 / gpercm2) % (fittedPars.x0Unc / gpercm2);
1756  if (isMCEvent)
1757  cout << format(" (%+.2f to MC)") % ((fittedPars.x0 - mcPars.x0) / gpercm2);
1758  cout << endl;
1759  }
1760 
1761 
1762  cout << "core (site) " << endl;
1763  if (isMCEvent)
1764  cout << format(" MC %.2f, %.2f") % mcPars.core.GetX(fSiteCS) % mcPars.core.GetY(fSiteCS) << endl;
1765  cout << format(" init %.2f, %.2f") % initPars.core.GetX(fSiteCS) % initPars.core.GetY(fSiteCS) << endl;
1766  if (!coreFixed) {
1767  cout << format(" fit %.2f ± %.2f, %.2f ± %.2f") % fittedPars.core.GetX(fSiteCS) % fittedPars.coreUncX
1769  if (isMCEvent)
1770  cout << format(" (%.2fm to MC)") % (fittedPars.core - mcPars.core).GetMag();
1771  cout << endl;
1772  }
1773  cout << endl;
1774 
1775 
1776  cout << "core time " << endl;
1777  if (isMCEvent)
1778  cout << format(" MC s %i ns %10.3f") % mcPars.coretime.GetGPSSecond()
1779  % mcPars.coretime.GetGPSNanoSecond() << endl;
1780  cout << format(" init s %i ns %10.3f") % initPars.coretime.GetGPSSecond()
1781  % initPars.coretime.GetGPSNanoSecond() << endl;
1782  if (!coreFixed) {
1783  cout << format(" fit s %i ns %10.3f") % fittedPars.coretime.GetGPSSecond()
1785  if (isMCEvent)
1786  cout << format(" (%.3f ns to MC)") % (fittedPars.coretime - initPars.coretime).GetInterval();
1787  cout << endl;
1788  }
1789  cout << endl;
1790 
1791 
1792  cout << "axis (site)" << endl;
1793  if (isMCEvent)
1794  cout << format(" MC theta %.2f°, phi %.2f°") % (mcPars.axis.GetTheta(fSiteCS) / degree)
1796  cout << format(" init theta %.2f°, phi %.2f°") % (initPars.axis.GetTheta(fSiteCS) / degree)
1798  if (!axisFixed) {
1799  cout << format(" fit theta %.2f ± %.2f, phi %.2f ± %.2f")
1802  if (isMCEvent)
1803  cout << format(" (%.2f° to MC)") % (getAngle(fittedPars.axis, mcPars.axis) / degree);
1804  cout << endl;
1805  }
1806 
1807  cout << "TimeModelOffset (dM_mu)" << endl;
1808  if (!TimeModelOffsetFixed)
1809  cout << format(" fit %.2f ± %.3f") % (fittedPars.TimeModelOffset) % (fittedPars.TimeModelOffsetUnc);
1810  else
1811  cout << "fixed to calibrated value (see code)!";
1812  cout << endl;
1813 
1814  if (fVerbosityLevel > 0) {
1815  cout << "number of stations: LDF " << fNStationsLDF
1816  << " shape " << fNStationsShape << " time " << fNStationsStartTime << endl
1817  << "likelihood: LDF " << fLDFLikelihood
1818  << " shape " << fShapeLikelihood << " time " << fStartTimeLikelihood << endl
1819  << endl
1820  << "likelihood contributions:" << endl
1821  << "id ldf shape time" << endl;
1822 
1823  for (std::vector<StationFitData>::iterator sIt = fitData.begin(); sIt != fitData.end(); ++sIt) {
1824  if (!(sIt->useForLDFFit || sIt->useForShapeFit || sIt->useForStartTimeFit)) continue;
1825  cout << format("%i %.3f %.3f %.3f") % sIt->stationId
1826  % sIt->LDFLikelihood % sIt->ShapeLikelihood
1827  % sIt->StartTimeLikelihood << endl;
1828  }
1829  cout << endl;
1830  }
1831  }
1832 
1833 }
std::vector< double > fFittedMinuitParams
Definition: UnivFitterKG.h:234
void initTimeModel(const unsigned int version)
const double eV
Definition: GalacticUnits.h:35
double Factor(const double energyEM, const EInteractionModel intMod, const ECompositionModel compMod, const double cosTheta)
invisible energy factor, finv=Etot/Eem, given Eem. CosTheta only needed when using data driven estima...
void setupMinuit(ROOT::Minuit2::MnUserParameters &upar)
double NormalizeAngleMinusPiPi(const double x)
Normalize angle to lie between -pi and pi (-180 and 180 deg)
const double degree
constexpr T Sqr(const T &x)
Point object.
Definition: Point.h:32
double GetPhi(const CoordinateSystemPtr &coordinateSystem) const
azimuth (phi) angle in spherical and cylindrical coordinates
Definition: BasicVector.h:254
utl::CoordinateSystemPtr fSiteCS
Definition: UnivFitterKG.h:228
double getDistToFirstInteraction(double hfi, double sHeight, double zenith, double dist, double psi)
Definition: FitterUtil.cc:12
constexpr double cm3
Definition: AugerUnits.h:119
double RelativeTrackLength(const double cosTheta)
std::vector< double > f
Definition: UnivFitterKG.h:157
double ModelFactor(const EInteractionModel interaction, const ECompositionModel composition)
std::vector< double > f
Definition: UnivFitterKG.h:147
double GetTheta(const CoordinateSystemPtr &coordinateSystem) const
zenith (theta) angle in spherical coordinates
Definition: BasicVector.h:248
Class to hold and convert a point in geodetic coordinates.
Definition: UTMPoint.h:40
double getMeanParametrizedXmaxData(double loge)
Definition: FitterUtil.cc:77
utl::CoordinateSystemPtr showerCS
Definition: UnivFitterKG.h:132
void addStationFitData(const StationFitData &sdata)
double operator()(const std::vector< double > &pars) const
constexpr double radian
Definition: AugerUnits.h:130
std::vector< UnivTimeKG::TimeModel * > timeModels
Definition: UnivFitterKG.h:226
std::vector< double > y
Definition: UnivFitterKG.h:156
const double meter
Definition: GalacticUnits.h:29
std::unique_ptr< UnivParamTimeNS::UnivParamTime > fUnivParamTime
Definition: UnivFitterKG.h:222
double ConvertToMCEnergyScale(const double sdenergy)
vector< t2list > out
output of the algorithm: a list of clusters
Definition: XbAlgo.cc:32
double pow(const double x, const unsigned int i)
double GetMag() const
Definition: Vector.h:58
std::unique_ptr< FitFunction > fFunc
Definition: UnivFitterKG.h:235
A TimeStamp holds GPS second and nanosecond for some event.
Definition: TimeStamp.h:110
constexpr double deg
Definition: AugerUnits.h:140
utl::Point fBarycenter
Definition: UnivFitterKG.h:231
fitConstraint fXmaxConstraint
Definition: UnivFitterKG.h:327
minScan2D scanMinimum2D(const int parIndexx, const int parIndexy, const double valx, const double valy, const double deltaX, const double deltaY, const int nSteps)
double operator()(const std::vector< double > &pars) const
boost::shared_ptr< const CoordinateTransformer > CoordinateSystemPtr
Shared pointer for coordinate systems.
double getX0(int version, double xmax, double loge)
Definition: FitterUtil.cc:155
utl::TimeStamp coretime
Definition: UnivFitterKG.h:134
#define max(a, b)
constexpr double s
Definition: AugerUnits.h:163
Reference ellipsoids for UTM transformations.
double operator()(const std::vector< double > &pars) const
double getMeanParametrizedXmax(double loge)
Definition: FitterUtil.cc:54
double GetX(const CoordinateSystemPtr &coordinateSystem) const
Definition: BasicVector.h:206
constexpr double kPi
Definition: MathConstants.h:24
void setRecType(const unsigned int type)
double getFirstParticleArrivalTime(double r, double dx0)
Definition: FitterUtil.cc:25
constexpr double nanosecond
Definition: AugerUnits.h:143
std::unique_ptr< WCDFitFunction > fWCDFunc
Definition: UnivFitterKG.h:236
double getMeanParametrizedNmuData(double loge, double theta)
Definition: FitterUtil.cc:92
minScan1D scanMinimum1D(const int parIndex, const double val, const double delta, const int nSteps)
double GetMeanMuonOffsetDataCalibrated(double r, double lgE, double theta)
Definition: FitterUtil.cc:113
const int sc_mu
Definition: FitterUtil.h:15
std::vector< double > x
Definition: UnivFitterKG.h:155
double Beta(const double energy)
Calculate the electron energy versus the relativistic beta.
double getMeanXmaxBias(double loge, double theta, bool saturated)
Definition: FitterUtil.cc:39
double PlaneFrontTime(const CoordinateSystemPtr showerCS, const Point &corePosition, const Point &position)
Calculate time of arrival of the plan front at point x.
fitConstraint fCoreTimeConstraint
Definition: UnivFitterKG.h:323
if(dataRoot)
Definition: XXMLManager.h:1003
double fMaxBinContentForSatShapeFit
Definition: UnivFitterKG.h:261
utl::CoordinateSystemPtr coreCS
Definition: UnivFitterKG.h:131
double GetMeanMuonOffset(double r, double offset0)
Definition: FitterUtil.cc:144
double GetY(const CoordinateSystemPtr &coordinateSystem) const
Definition: BasicVector.h:209
constexpr double kSpeedOfLight
FitFunction(const Fitter &theEf)
bool isLDFFitCandidate(const int stationId)
double fMinBinContentForSatShapeFit
Definition: UnivFitterKG.h:260
StationFitData & getStationFitData(const int stationId)
unsigned long GetGPSSecond() const
GPS second.
Definition: TimeStamp.h:124
double norm(utl::Vector x)
double GetGPSNanoSecond() const
GPS nanosecond.
Definition: TimeStamp.h:127
bool isCandidateStation(const int stationId)
double operator()(const std::vector< double > &pars) const
const double * FitParameters(const ECompositionModel composition)
double OldSmoothPoissonFactor(const double sigmaFactor)
Definition: UnivFitterKG.cc:60
fitConstraint fCoreConstraint
Definition: UnivFitterKG.h:322
std::unique_ptr< UnivParamNS::UnivParam > fUnivParam
Definition: UnivFitterKG.h:221
std::unique_ptr< UnivCalibConstantsNS::UnivCalibConstants > fUnivCalibConstants
Definition: UnivFitterKG.h:224
std::vector< double > fStartTime
Definition: UnivFitterKG.h:150
constexpr double cm
Definition: AugerUnits.h:117
double MCEnergyCalibration(const double showerSize, const double theta, bool isInfill)
Definition: UnivFitterKG.cc:87
Vector object.
Definition: Vector.h:30
double RelativeTrackLength(const double cosTheta)
Definition: UnivFitterKG.cc:69
double fMinBinContentForShapeFit
Definition: UnivFitterKG.h:258
double SignalUncertaintyFactor(const ESignalVarianceModel model, const double cosTheta)
fitConstraint fThetaConstraint
Definition: UnivFitterKG.h:324
static double getAngle(const utl::Vector &v1, const utl::Vector &v2)
Definition: UnivFitterKG.h:219
utl::CoordinateSystemPtr Get(const std::string &id)
Get a well-known Coordinate System.
fitConstraint fX0Constraint
Definition: UnivFitterKG.h:330
std::unique_ptr< AtmosphereNS::Atmosphere > fAtmosphere
Definition: UnivFitterKG.h:223
double PlaneFrontTime(const CoordinateSystemPtr showerCS, const Point &corePosition, const Point &position)
Definition: UnivFitterKG.cc:79
utl::CoordinateSystemPtr fHottestStationCS
Definition: UnivFitterKG.h:230
double GetZ(const CoordinateSystemPtr &coordinateSystem) const
Definition: BasicVector.h:212
double GetMeanMuonOffsetMCCalibrated(double, double, double)
Definition: FitterUtil.cc:129
constexpr double m
Definition: AugerUnits.h:121
std::vector< double > x
Definition: UnivFitterKG.h:146
constexpr double gram
Definition: AugerUnits.h:195
double LogarithmOfNormalPDF(const double x)
const double gpercm2
Definition: UnivFitterKG.cc:55
std::vector< StationFitData > fitData
Definition: UnivFitterKG.h:233
fitConstraint fPhiConstraint
Definition: UnivFitterKG.h:325
const double gpercm2
Definition: FitterUtil.h:9
fitConstraint fEnergyConstraint
Definition: UnivFitterKG.h:326
bool isFitOk(const ROOT::Minuit2::FunctionMinimum &min)
std::vector< double > fLDF
Definition: UnivFitterKG.h:148
utl::CoordinateSystemPtr fBaryCS
Definition: UnivFitterKG.h:229
double PoissonFactor(const double sigmaFactor)
double fMaxBinContentForShapeFit
Definition: UnivFitterKG.h:259
constexpr double cm2
Definition: AugerUnits.h:118
std::vector< double > fShape
Definition: UnivFitterKG.h:149
bool isStartTimeFitCandidate(const int stationId)
bool isShapeFitCandidate(const int stationId)

, generated on Tue Sep 26 2023.