2 #include <evt/ShowerRecData.h>
3 #include <evt/ShowerSRecData.h>
4 #include <evt/ShowerFRecData.h>
5 #include <evt/ShowerSimData.h>
7 #include <sevt/SEvent.h>
8 #include <sevt/StationRecData.h>
9 #include <sevt/EventTrigger.h>
10 #include <sevt/Station.h>
11 #include <sevt/StationConstants.h>
13 #include <fevt/FEvent.h>
14 #include <fevt/Header.h>
16 #include <fevt/Telescope.h>
17 #include <fevt/EyeHeader.h>
18 #include <fevt/EyeRecData.h>
20 #include <det/Detector.h>
22 #include <sdet/SDetector.h>
23 #include <sdet/SDetectorConstants.h>
24 #include <sdet/Station.h>
25 #include <sdet/STimeVariance.h>
27 #include <fdet/FDetector.h>
29 #include <fdet/Telescope.h>
31 #include <fwk/LocalCoordinateSystem.h>
32 #include <fwk/CentralConfig.h>
33 #include <fwk/RunController.h>
35 #include <utl/CoordinateSystem.h>
36 #include <utl/PhysicalConstants.h>
37 #include <utl/ErrorLogger.h>
38 #include <utl/TabulatedFunctionErrors.h>
39 #include <utl/TimeStamp.h>
40 #include <utl/AxialVector.h>
42 #include <utl/Reader.h>
44 #include <utl/NumericalErrorPropagator.h>
45 #include <utl/String.h>
48 #include <Minuit2/MnMinimize.h>
49 #include <Minuit2/MnHesse.h>
50 #include <Minuit2/FCNBase.h>
51 #include <Minuit2/FunctionMinimum.h>
52 #include <Minuit2/MnUserParameters.h>
53 #include <Minuit2/MnUserCovariance.h>
54 #include <Minuit2/MnPrint.h>
59 #include <boost/range/iterator_range.hpp>
62 using namespace LDFFinderKG;
70 using CLHEP::HepRotation;
73 #define OUT(_x_) if ((_x_) <= fInfoLevel) cerr
76 namespace LDFFinderKG {
85 const auto npar = result.fPar.size();
86 for (
size_t i = 0; i <
npar; ++i) {
87 if (std::isnan(result.fPar[i]))
89 for (
size_t j = i; j <
npar; ++j)
90 if (std::isnan(result.fCov(i, j)))
103 label <<
"S" << refdist/
meter;
104 if (refdist < 1000*
meter)
114 static const char*
const labels[] = {
"beta",
"gamma",
"mu",
"tau" };
115 return Is(iShape).InRange(0, 3) ? labels[iShape] :
"UNKNOWN COMPONENT!!!";
123 const vector<double>& axisParameters) :
124 fCore(coreX, coreY, 0,
gBaryCS),
125 fAxisParameters(axisParameters)
129 Transform(vector<double>& output,
const vector<double>& input)
132 const double& u = fAxisParameters[0];
133 const double& v = fAxisParameters[1];
134 const double& rCore = fAxisParameters[2];
135 const double& ctCore = fAxisParameters[3];
136 const double& newCoreX = input[0];
137 const double& newCoreY = input[1];
139 const double w =
sqrt(1 - u*u - v*v);
144 const double newRCore = newAxis.
GetMag();
146 if (output.size() != 4)
147 output = vector<double>(4);
165 const double cosTheta,
const double rho)
180 const ShowerSRecData& recShower =
event.GetRecShower().GetSRecShower();
183 <<
"***** Final reconstructed shower data *****\n"
199 const double rc = 1 / curv;
213 <<
" Ropt = " << rOpt/meter <<
" m\n";
215 ++RunController::GetInstance().GetRunData().GetNamedCounters()[
216 "LDFFinder/" + (boost::format(
"%|.5|") % recShower.
GetLDFRecStage()).str()
224 auto topB = CentralConfig::GetInstance()->GetTopBranch(
"LDFFinderKG");
226 topB.GetChild(
"infoLevel").GetData(fInfoLevel);
229 const auto arrayType = topB.GetChild(
"arrayType").Get<
string>();
230 if (arrayType ==
"SD1500")
232 else if (arrayType ==
"SD750")
234 else if (arrayType ==
"SD433")
237 ERROR(
"Unknown array type");
243 const auto sigVariance = topB.GetChild(
"signalVariance").Get<
string>();
244 if (sigVariance ==
"eGAP2012_012")
246 else if (sigVariance ==
"eGAP2014_035")
249 ERROR(
"Unknown signal variance");
253 fLDFFitConfig.fUseAdditionalGPSTimeVariance =
254 topB.GetChild(
"useAdditionalGPSTimeVariance").Get<
bool>();
257 const auto ldfType = topB.GetChild(
"ldfType").Get<
string>();
259 const double ldfReferenceDistance = topB.GetChild(
"ldfReferenceDistance").Get<
double>();
261 const auto ldfParameters = topB.GetChild(
"ldfParameters").Get<vector<double>>();
263 const auto ldfUncertaintyParameters =
264 topB.GetChild(
"ldfUncertaintyParameters").Get<vector<double>>();
266 fLDFFitConfig.fLDF =
LDF(ldfType, ldfReferenceDistance, ldfParameters, ldfUncertaintyParameters);
267 fLDFFitConfig.fLDFShapeTreatment.resize(fLDFFitConfig.fLDF.GetNShapeParameters(),
eModeled);
272 auto energyBranch = topB.GetChild(
"energyCalibration");
274 fEnergyConversion.fCicReferenceAngle = energyBranch.GetChild(
"referenceAngle").Get<
double>();
275 fEnergyConversion.fCicReferenceS38 = energyBranch.GetChild(
"referenceS38").Get<
double>();
276 energyBranch.GetChild(
"s38Range").GetData(fEnergyConversion.fCicS38Range);
277 const auto& r = fEnergyConversion.fCicS38Range;
278 if (r.first <= 0 || r.second <= 0 || r.first > r.second) {
279 ERROR(
"Invalid <s38Range>!");
282 fEnergyConversion.SetCICParameters(
283 energyBranch.GetChild(
"attenuationPar1").Get<vector<double>>(),
284 energyBranch.GetChild(
"attenuationPar2").Get<vector<double>>(),
285 energyBranch.GetChild(
"attenuationPar3").Get<vector<double>>()
288 fEnergyConversion.fEnergyConstant = energyBranch.GetChild(
"energyS38Const").Get<
double>();
289 fEnergyConversion.fEnergySlope = energyBranch.GetChild(
"energyS38Slope").Get<
double>();
292 auto silentsBranch = topB.GetChild(
"silentStations");
293 silentsBranch.GetChild(
"maxLDFValue").GetData(fSilentsVars.fMaxLDFValue);
294 silentsBranch.GetChild(
"maxDistance").GetData(fSilentsVars.fMaxDistance);
295 silentsBranch.GetChild(
"minNumberOfStations").GetData(fSilentsVars.fMinNumberOfStations);
298 const auto coreType = topB.GetChild(
"coreType").Get<
string>();
299 if (coreType ==
"MC")
301 else if (coreType ==
"Hybrid")
303 else if (coreType ==
"Fit")
306 ERROR(
"Unknown core type");
311 fLDFFitConfig.fFixCore = (fCoreType !=
eFit);
313 topB.GetChild(
"fixedAxis").GetData(fFixedAxis);
315 topB.GetChild(
"globalFit").GetData(fGlobalFit);
317 topB.GetChild(
"maxTheta").GetData(fMaxTheta);
319 const auto minimizationMethod = topB.GetChild(
"minimizationMethod").Get<
string>();
320 fUseMaxLikelihood = (minimizationMethod ==
"MaxLike");
322 topB.GetChild(
"maxChi2").GetData(fMaxChi2);
324 topB.GetChild(
"useSilentStations").GetData(fLDFFitConfig.fUseSilentStations);
326 topB.GetChild(
"useSilentStationsFromOtherGrids").GetData(fUseSilentStationsFromOtherGrids);
328 topB.GetChild(
"silentMaxRadius").GetData(fLDFFitConfig.fSilentMaxRadius);
330 topB.GetChild(
"silentRadiusTransition").GetData(fLDFFitConfig.fSilentRadiusTransition);
332 topB.GetChild(
"silentSignalThreshold").GetData(fLDFFitConfig.fSilentSignalThreshold);
334 topB.GetChild(
"useSaturationRecovery").GetData(fLDFFitConfig.fUseSaturationRecovery);
336 topB.GetChild(
"recoveryThreshold").GetData(fLDFFitConfig.fRecoveryThreshold);
338 topB.GetChild(
"maxBaryToCoreDistance").GetData(fMaxBaryToCoreDistance);
339 if (fMaxBaryToCoreDistance <= 0) {
340 ERROR(
"<maxBaryToCoreDistance> must be > 0");
344 topB.GetChild(
"RoptN").GetData(fRoptN);
348 auto stage0B = topB.GetChild(
"stage0");
349 stage0B.GetChild(
"minNumberOfStations").GetData(fStage0.fMinNumberOfStations);
350 stage0B.GetChild(
"useCorePosition").GetData(fStage0.fUseCorePosition);
352 auto stage1B = topB.GetChild(
"stage1");
353 stage1B.GetChild(
"minNumberOfStations").GetData(fStage1.fMinNumberOfStations);
355 auto stage2B = topB.GetChild(
"stage2");
356 stage2B.GetChild(
"minNumberRelaxBeta").GetData(fStage2.fMinNumberRelaxBeta);
357 stage2B.GetChild(
"fixBetaRange").GetData(fStage2.fFixBetaRange);
358 stage2B.GetChild(
"fixBetaLeverArmRange").GetData(fStage2.fFixBetaLeverArmRange);
359 stage2B.GetChild(
"minNumberRelaxGamma").GetData(fStage2.fMinNumberRelaxGamma);
360 stage2B.GetChild(
"fixGammaRange").GetData(fStage2.fFixGammaRange);
361 stage2B.GetChild(
"fixGammaLeverArmRange").GetData(fStage2.fFixGammaLeverArmRange);
363 auto stage3B = topB.GetChild(
"stage3");
364 stage3B.GetChild(
"minNumberOfStations").GetData(fStage3.fMinNumberOfStations);
365 stage3B.GetChild(
"minNumberForFullCurvatureFit").GetData(fStage3.fMinNumberForFullCurvatureFit);
366 stage3B.GetChild(
"maxAxisAngleDifference").GetData(fStage3.fMaxAxisAngleDifference);
367 stage3B.GetChild(
"outliersRejection").GetData(fStage3.fOutliersRejection);
371 const auto&
p = fEnergyConversion.fCicParameters;
373 " LDF type: " << fLDFFitConfig.fLDF.GetType() <<
"\n"
375 " Minimization method: " << (fUseMaxLikelihood ?
"Maximum-Likelihood" :
"Chi2") <<
"\n"
378 for (
unsigned int ix = 0, nx = Length(
p)+1; ix < nx; ++ix) {
383 for (
unsigned int iy = 0; iy < 3; ++iy) {
387 info <<
" + " << p[ix-1][iy] <<
"*y";
398 "x = -(sin^2(theta) - sin^2(38deg)), "
399 "y = lg(s / S38_ref), "
400 "s = min(max(S38, " << fEnergyConversion.fCicS38Range.first <<
"), "
401 << fEnergyConversion.fCicS38Range.second <<
"), "
402 "S38_ref = " << fEnergyConversion.fCicReferenceS38 <<
" VEM\n"
403 " energy conversion: E = " << fEnergyConversion.fEnergyConstant <<
" eV * "
404 "pow(S38 / VEM, " << fEnergyConversion.fEnergySlope <<
")\n"
405 " Ropt fitting: " << (fRoptN < 2 ?
"off" :
"on");
417 if (!(event.
HasSEvent() &&
event.HasRecShower() &&
418 event.GetRecShower().HasSRecShower()))
419 return eContinueLoop;
421 const auto& sEvent =
event.GetSEvent();
423 auto& showerRec =
event.GetRecShower().GetSRecShower();
429 for (
const auto& station : sEvent.StationsRange())
430 if (station.IsCandidate()) {
432 if (station.IsLowGainSaturation())
434 }
else if (station.IsSilent())
438 <<
"# candidate stations = " << nStations
439 <<
" (" << nSaturated <<
" saturated), " << nSilent <<
" silent\n";
443 if (nStations < fStage0.fMinNumberOfStations) {
445 <<
"Not enough stations.\n";
446 return eContinueLoop;
450 fBarycenter = showerRec.GetBarycenter();
451 fBaryTime = showerRec.GetBarytime();
452 gBaryCS = showerRec.GetBarycenterCoordinateSystem();
467 if (!FixCore(core, coreTime, showerAxis, event))
468 return eContinueLoop;
470 if (fCoreType !=
eFit) {
471 showerRec.SetAxis(showerAxis);
472 showerRec.SetCorePosition(core);
475 showerRec.SetCurvature(0, 0);
480 if (theta > fMaxTheta) {
482 <<
" theta = " << theta/
degree <<
" is > than limit "
483 << fMaxTheta/
degree <<
" [deg], skipping...\n";
484 return eContinueLoop;
487 const auto& siteCS = det::Detector::GetInstance().GetSiteCoordinateSystem();
488 const auto& eventTime = sEvent.GetTrigger().GetTime();
491 <<
" barycenter = (" <<
String::Make(fBarycenter, siteCS,
meter,
", ") <<
") m (site)\n"
492 " bary time = " << (fBaryTime - eventTime).GetInterval()/
nanosecond <<
" ns (to event time)\n"
493 " axis = (" <<
String::Make(showerAxis, siteCS, 1,
", ") <<
") (site)\n"
495 " theta = " << theta/
degree <<
" deg (bary)\n"
496 " phi = " << phi/
degree <<
" deg (bary)\n";
499 <<
" local/site zenith angle diff = "
505 cbest.
fPar[eU] = sin(theta) * cos(phi);
506 cbest.
fPar[
eV] = sin(theta) * sin(phi);
507 cbest.
fPar[eRCore] = 0;
508 cbest.
fPar[eCTCore] = 0;
511 auto stationFitData = MakeStationFitData(sEvent);
512 bool hasSaturatedStation =
false;
513 for (
const auto& station : stationFitData) {
514 if (station.fIsSaturated) {
515 hasSaturatedStation =
true;
522 best.
fRecStage = ShowerSRecData::kLDFEstimate;
525 <<
" - LDF shape & core fixed\n";
527 FitLDFSimplified(best, config, cbest.GetAxis(), stationFitData);
529 if (nStations < fStage1.fMinNumberOfStations) {
530 SetRecData(event, best, cbest);
531 OutputResults(event);
536 for (
int useSilents = fLDFFitConfig.fUseSilentStations; useSilents >= 0; --useSilents) {
540 const string stationType = useSilents ?
"candidate+silents" :
"candidates";
550 <<
"Stage " << result.
fRecStage <<
": fit "
552 <<
" - LDF shape fixed [" << stationType <<
"]\n";
555 fBadSilents = CleanSilentStation(result, config, cbest.GetAxis(), stationFitData);
557 if (!FitLDF(result, config, cbest.GetAxis(), stationFitData))
560 result.
fRecStage = useSilents ? ShowerSRecData::kLDFSilents : ShowerSRecData::kLDF;
570 (nStations < fStage2.fMinNumberRelaxBeta ||
571 FixBeta(result, cbest.GetAxis(), stationFitData)) ?
eModeled :
eFitted;
573 (nStations < fStage2.fMinNumberRelaxGamma ||
574 FixGamma(result, cbest.GetAxis(), stationFitData)) ?
eModeled :
eFitted;
579 <<
"Stage " << result.
fRecStage <<
": fit " << stationType
580 <<
" for shower size, core"
584 if (FitLDF(result, config, cbest.GetAxis(), stationFitData)) {
585 const bool fixBeta = FixBeta(result, cbest.GetAxis(), stationFitData);
586 const bool fixGamma = FixGamma(result, cbest.GetAxis(), stationFitData);
589 result.
fRecStage = (useSilents ? ShowerSRecData::kLDFSilents : ShowerSRecData::kLDF) +
601 if (FitLDF(result, config, cbest.GetAxis(), stationFitData)) {
602 result.
fRecStage = (useSilents ? ShowerSRecData::kLDFSilents : ShowerSRecData::kLDF) +
621 if (nStations < fStage3.fMinNumberOfStations) {
622 SetRecData(event, best, cbest);
623 OutputResults(event);
630 const double rCoreModel =
631 ParameterizedRc(cres.GetAxis().GetCosTheta(
gBaryCS),
635 <<
"Fit for axis with fixed curvature radius = " << rCoreModel/
kilometer <<
" km\n";
637 fFixedCurvature =
true;
638 cres.
fPar[eRCore] = rCoreModel;
639 if (FitCurvature(cres, best.
GetCore(), stationFitData)) {
642 if (nStations >= fStage3.fMinNumberForFullCurvatureFit) {
644 <<
"Fit for" << (!fFixedAxis ?
" axis and ":
" ") <<
"shower-front curvature.\n";
646 fFixedCurvature =
false;
647 cres.
fPar[eRCore] = rCoreModel;
648 if (FitCurvature(cres, best.
GetCore(), stationFitData))
651 OUT(eIntermediate) <<
" Curvature fit failed.\n";
655 if (fStage3.fOutliersRejection &&
656 nStations > fStage3.fMinNumberForFullCurvatureFit) {
659 <<
" Performing outlier search and rejection\n";
661 for (
const auto& station1 : stationFitData) {
663 if (!station1.fSignal)
666 vector<StationFitData> stationData;
668 for (
const auto& station2 : stationFitData) {
669 if (!station2.fSignal || station1.fId == station2.fId)
671 stationData.push_back(station2);
674 cres.
fPar[eRCore] = rCoreModel;
675 if (FitCurvature(cres, best.
GetCore(), stationData)) {
680 if (prevChi2Probability < 1e-100 ||
681 (newChi2Probability > 1e-100 && newChi2Probability/prevChi2Probability > 2)) {
684 <<
" Removed one outlier:\n"
685 " previous chi2 probability = " << prevChi2Probability <<
"\n"
687 " previous CTCore = " << cbest.
fPar[eCTCore]/
meter <<
" +/- " << cbest.
fCov.Std(eCTCore)/
meter <<
" m\n"
688 " new chi2 probability = " << newChi2Probability <<
"\n"
690 " new CTCore = " << cres.
fPar[eCTCore]/
meter <<
" +/- " << cres.
fCov.Std(eCTCore)/
meter <<
" m\n";
698 const double openingAngle =
Angle(cbest.GetAxis(), cinit.GetAxis());
702 " axis diff = " << openingAngle/
degree <<
" deg (to plain-front fit)\n"
704 " CTCore = " << cbest.
fPar[eCTCore]/meter <<
" +/- " << cbest.
fCov.Std(eCTCore)/meter <<
" m\n";
706 if (openingAngle > fStage3.fMaxAxisAngleDifference || std::isnan(openingAngle)) {
708 <<
" Opening-angle axis difference is above the limit.\n";
712 const double newTheta = cbest.GetTheta();
713 if (newTheta > fMaxTheta) {
715 <<
" theta = " << newTheta/
degree <<
" deg is > than limit " << fMaxTheta/
degree <<
" deg, skipping...\n";
716 return eContinueLoop;
720 if (cbest.
fPar[eRCore] > 0) {
728 const string stationType = (useSilents ?
"candidate+silents" :
"candidates");
731 (useSilents ? ShowerSRecData::kLDFSilents : ShowerSRecData::kLDF) +
741 <<
" [" << stationType <<
"]\n";
743 if (FitLDF(lres, config, cbest.GetAxis(), stationFitData)) {
753 propagator(cbest.
fPar, outputCov, input, inputCov);
756 for (
int i = 0; i < 4; ++i)
757 for (
int j = i; j < 4; ++j)
758 if (cbest.
fCov(i, j) > 0)
759 cbest.
fCov(i, j) += outputCov(i, j);
761 const double openingAngle =
Angle(cbest.GetAxis(), cinit.GetAxis());
766 if (openingAngle > fStage3.fMaxAxisAngleDifference || std::isnan(openingAngle)) {
768 <<
" Opening-angle axis difference is above the limit.\n";
775 ShowerSRecData::kLDFGlobalFit +
781 <<
"Stage " << lres.
fRecStage <<
": global fit [" << stationType <<
"]\n";
784 if (FitGlobal(cres, lres, config, stationFitData)) {
795 <<
"Ropt determination:\n";
799 const double finalBeta = best.
fPar[eShapeParameters + 0];
805 const double deltap = (stopp - startp) / (fRoptN - 1);
811 for (
int i = 0; i < fRoptN; ++i) {
814 double& beta = result.
fPar[eShapeParameters + 0];
815 const double p = startp + i*deltap;
818 FitLDF(result, thisConfig, cbest.GetAxis(), stationFitData);
819 const double beta = result.
fPar[eShapeParameters + 0];
824 const auto halfN = fRoptN / 2;
825 const double s1 = rOptFitter.GetShowerSizeVector()[halfN-1];
826 const double s2 = rOptFitter.GetShowerSizeVector()[halfN];
827 const double b1 = rOptFitter.GetBetaVector()[halfN-1];
828 const double b2 = rOptFitter.GetBetaVector()[halfN];
829 const double dS1000_dBeta = (s2 - s1) / (b2 - b1);
831 auto& shRec =
event.GetRecShower().GetSRecShower();
832 shRec.SetBetaSystematics(betaFixSigma);
833 shRec.SetShowerSizeSystematics(fabs(betaFixSigma * dS1000_dBeta));
836 if (rOptFitter.GetResult(rOpt))
837 shRec.SetLDFOptimumDistance(rOpt);
840 SetRecData(event, best, cbest);
841 OutputResults(event);
860 const auto& previousAxis =
event.GetRecShower().GetSRecShower().GetAxis();
862 ERROR(
"No previous axis found.");
871 ERROR(
"The event is not a simulated shower.");
874 const auto& simShower =
event.GetSimShower();
875 axis = -simShower.GetDirection();
876 coreReference = simShower.GetPosition();
877 refTime = simShower.GetTimeStamp();
883 ERROR(
"The event has no FD shower.");
887 const auto& fEvent =
event.GetFEvent();
889 double bestErrorEllipse = 0;
892 for (
const auto& eye :
893 boost::make_iterator_range(fEvent.EyesBegin(ComponentSelector::eHasData),
894 fEvent.EyesEnd(ComponentSelector::eHasData))) {
897 if (!eye.HasRecData())
900 const auto& eyeRec = eye.GetRecData();
901 if (eyeRec.GetSDPFitNDof() <= 0 || eyeRec.GetTimeFitNDof() <= 0)
904 if (!eyeRec.HasFRecShower())
906 showerFRec = &eyeRec.GetFRecShower();
908 const auto& dEye = det::Detector::GetInstance().GetFDetector().GetEye(eye);
909 const auto& eyeCS = dEye.GetEyeCoordinateSystem();
910 const auto eyePos = dEye.GetPosition();
913 const double rp = eyeRec.GetRp();
914 const double rpErr = eyeRec.GetRpError();
915 const double t0 = eyeRec.GetTZero();
916 const double chi0 = eyeRec.GetChiZero();
917 const double chi0Err = eyeRec.GetChiZeroError();
918 const double sdpPhiErr = eyeRec.GetSDPPhiError();
919 const double rhoChi0Rp = eyeRec.GetRpChi0Correlation();
920 const double distEyeCore = vecEyeCore.GetMag();
925 const double sinChi0 = sin(chi0);
926 const double errorInSDP =
sqrt(
927 Sqr(rpErr / sinChi0) +
928 Sqr((chi0Err * distEyeCore) / (cos(chi0) * sinChi0)) +
929 rhoChi0Rp * rpErr * chi0Err
933 const double errorPerpSDP = distEyeCore * sin(sdpPhiErr);
936 const double coreErrorEllipse = errorInSDP * errorPerpSDP *
kPi;
940 if (bestErrorEllipse && bestErrorEllipse < coreErrorEllipse)
943 bestErrorEllipse = coreErrorEllipse;
947 const Vector vertical(0,0,1, eyeCS);
948 const double alpha = 0.5*kPi -
Angle(vertical, vecEyeCore);
949 const double cosBeta =
CosAngle(axis, vecEyeCore);
953 refTime = eye.GetHeader().GetTimeStamp() +
963 if (fCoreType !=
eFit) {
965 core = coreReference -
966 (localNormal * (coreReference - fBarycenter)) / (localNormal*axis) * axis;
968 const double d = (core - fBarycenter).GetMag();
969 if (d > fMaxBaryToCoreDistance) {
971 err <<
"Bary-centric distance to core " << d/
kilometer <<
" km is above the limit.";
980 <<
" using barycenter as initial core\n";
1001 const Vector& showerAxis,
1002 const vector<StationFitData>&
data)
1005 size_t nStations = 0;
1006 for (
const auto& station : data) {
1007 if (!station.fSignal || (station.fIsSaturated && !station.fRecoveredSignalErr))
1012 if (nStations < 5) {
1014 <<
"FixBeta = 1: nStations = " << nStations <<
'\n';
1018 int nStationsInRange = 0;
1019 double maxDistance = 0;
1021 const auto core = result.
GetCore();
1023 for (
const auto& station : data) {
1025 if (!station.fSignal || (station.fIsSaturated && !station.fRecoveredSignalErr))
1028 const double r =
RPerp(showerAxis, station.fPos - core);
1030 if (fStage2.fFixBetaRange[0] < r && r < fStage2.fFixBetaRange[1]) {
1033 for (
const auto&
s : data) {
1034 const double rr =
RPerp(showerAxis,
s.fPos - core);
1036 if (fStage2.fFixBetaRange[0] < rr && rr < fStage2.fFixBetaRange[1]) {
1037 const double distance = fabs(r - rr);
1038 if (distance > maxDistance)
1039 maxDistance = distance;
1045 const bool fixBeta = !(
1046 (nStationsInRange > 1 && maxDistance > fStage2.fFixBetaLeverArmRange[0]) ||
1047 (nStationsInRange > 2 && maxDistance > fStage2.fFixBetaLeverArmRange[1]) ||
1048 (nStationsInRange > 3 && maxDistance > fStage2.fFixBetaLeverArmRange[2])
1052 <<
"FixBeta = " << fixBeta <<
": "
1053 "nStations (InRange) = " << nStations <<
" (" << nStationsInRange <<
"), "
1054 "maxDistance = " << maxDistance/
meter <<
" m\n";
1063 const Vector& showerAxis,
1064 const vector<StationFitData>&
data)
1067 size_t nStations = 0;
1068 for (
const auto& station : data) {
1069 if (!station.fSignal || (station.fIsSaturated && !station.fRecoveredSignalErr))
1074 if (nStations < 5) {
1076 <<
"FixGamma = 1: nStations = " << nStations <<
'\n';
1080 int nStationsInRange = 0;
1081 double maxDistance = 0;
1082 const auto core = result.
GetCore();
1083 for (
const auto& station : data) {
1084 if (!station.fSignal || (station.fIsSaturated && !station.fRecoveredSignalErr))
1087 const double r =
RPerp(showerAxis, station.fPos - core);
1089 if (fStage2.fFixGammaRange[0] < r && r < fStage2.fFixGammaRange[1]) {
1093 for (
const auto&
s : data) {
1095 const double rr =
RPerp(showerAxis,
s.fPos - core);
1097 if (fStage2.fFixGammaRange[0] < rr && rr < fStage2.fFixGammaRange[1]) {
1098 const double distance = fabs(r - rr);
1099 if (distance > maxDistance)
1100 maxDistance = distance;
1106 const bool fixGamma = !(
1107 (nStationsInRange > 1 && maxDistance > fStage2.fFixGammaLeverArmRange[0]) ||
1108 (nStationsInRange > 2 && maxDistance > fStage2.fFixGammaLeverArmRange[1]) ||
1109 (nStationsInRange > 3 && maxDistance > fStage2.fFixGammaLeverArmRange[2])
1113 <<
"FixGamma = " << fixGamma <<
": "
1114 "nStations (InRange) = " << nStations <<
" (" << nStationsInRange <<
"), "
1115 "maxDistance = " << maxDistance/
meter <<
" m\n";
1127 auto& recShower =
event.GetRecShower().GetSRecShower();
1129 const auto& sDetector = det::Detector::GetInstance().GetSDetector();
1131 const auto& ldf = fLDFFitConfig.fLDF;
1135 const auto& core = lres.
GetCore();
1136 const auto& coreCS = LocalCoordinateSystem::Create(core);
1137 const auto& axis = cres.GetAxis();
1138 const double cosTheta = axis.GetCosTheta(coreCS);
1140 auto& sEvent =
event.GetSEvent();
1142 const double rCurv = cres.
fPar[eRCore];
1143 const bool haveCurvature = (rCurv != 0);
1144 const Point showerOrigin = core + rCurv * axis;
1145 const double cTCore = cres.
fPar[eCTCore];
1147 const double theta = axis.GetTheta(coreCS);
1148 const double phi = axis.GetPhi(coreCS);
1150 CoordinateSystem::RotationY(
1152 CoordinateSystem::RotationZ(
1159 double coreCovSP[2][2];
1167 for (
int i : { 0, 1 }) {
1168 const auto& r_i = r[i];
1169 auto& cc_i = coreCovSP[i];
1170 for (
int j : { 0, 1 }) {
1171 const auto& r_j = r[j];
1172 auto& cc_ij = cc_i[j];
1174 for (
int k : { 0, 1 }) {
1175 const auto& r_ik = r_i[k];
1176 for (
int m : { 0, 1 })
1177 cc_ij += r_ik * r_j[
m] * lres.
fCov(1+k, 1+
m);
1183 const auto& timeVariance = sdet::STimeVariance::GetInstance();
1184 Accumulator::MinMax<double> minMaxRho(1000*
kilometer, 0);
1185 Accumulator::SampleStandardDeviation timeStat;
1187 for (
auto& station : sEvent.StationsRange()) {
1188 if (!station.HasRecData())
1191 const auto& sPos = sDetector.GetStation(station).GetPosition();
1192 const double x = sPos.GetX(showerPlaneCS);
1193 const double y = sPos.GetY(showerPlaneCS);
1194 const double rho =
std::sqrt(x*x + y*y);
1196 if (station.IsCandidate())
1199 const double rhoErr =
1200 std::sqrt(
Sqr(x) * coreCovSP[0][0] +
Sqr(y) * coreCovSP[1][1] + 2*x*y * coreCovSP[0][1]) / rho;
1202 auto& sRec = station.GetRecData();
1203 const double signal = sRec.GetTotalSignal();
1204 const double funcval = showerSize * ldf(rho, ldfShapePars);
1206 sRec.SetAzimuthShowerPlane(sPos.GetPhi(showerPlaneCS));
1207 sRec.SetTotalSignal(signal, sigma);
1208 sRec.SetLDFResidual((signal - funcval)/sigma);
1209 sRec.SetSPDistance(rho, rhoErr);
1211 if (haveCurvature) {
1212 const double measuredTime = (sRec.GetSignalStartTime() - fBaryTime).GetInterval();
1213 const Vector stationToOrigin = showerOrigin - sPos;
1214 const double rStation = stationToOrigin.
GetMag();
1215 const double predictedTime = (rStation + cTCore - rCurv) /
kSpeedOfLight;
1216 const double cosThetaStation = stationToOrigin.
GetZ(coreCS) / rStation;
1217 double sigma2 =
GetTimeVariance(fLDFFitConfig, timeVariance, signal, sRec, cosThetaStation, rho);
1218 if (fLDFFitConfig.fUseAdditionalGPSTimeVariance)
1219 sigma2 += sRec.GetGPSTimeVariance();
1220 const double residual = (measuredTime - predictedTime) /
std::sqrt(sigma2);
1221 sRec.SetResidual(residual);
1222 if (station.IsCandidate())
1228 if (!recShower.HasLDF())
1229 recShower.MakeLDF();
1230 auto& tabulatedLDF = recShower.GetLDF();
1231 tabulatedLDF.Clear();
1234 const double x0 = log(1);
1235 const double x1 = log(10000);
1236 const int nLDFPoints = 20;
1238 for (
int i = 0; i < nLDFPoints; ++i) {
1239 const double z = double(i) / (nLDFPoints - 1);
1240 const double rho = exp((1 - z)*x0 + z*x1);
1241 const double funcval = showerSize * ldf(rho, ldfShapePars);
1243 tabulatedLDF.PushBack(rho, 0, funcval, sigma);
1248 if (haveCurvature) {
1249 const double rCurvErr = cres.
fCov.Std(eRCore);
1250 const double cTOffsetErr = cres.
fCov.Std(eCTCore);
1251 const double cTOffset = cres.
fPar[eCTCore];
1252 recShower.SetCurvature(1/rCurv, rCurvErr/
Sqr(rCurv));
1253 recShower.SetCurvatureTimeOffset(cTOffset, cTOffsetErr);
1257 const double timeMean = timeStat.GetAverage();
1258 const double timeSpread = timeStat.GetStandardDeviation();
1259 recShower.SetTimeResidualMean(timeMean);
1260 recShower.SetTimeResidualSpread(timeSpread);
1262 recShower.SetAngleChi2(cres.
fChi2, cres.
fNdof);
1263 const double u = cres.
fPar[eU];
1264 const double v = cres.
fPar[
eV];
1265 const double w =
sqrt(1 - u*u - v*v);
1266 const double suu = cres.
fCov[eU];
1267 const double suv = cres.
fCov(eU,
eV);
1268 const double svv = cres.
fCov[
eV];
1270 const double suw = -(suu*u + suv*v) / w;
1271 const double svw = -(suv*u + svv*v) / w;
1272 const double sww = (u*u*suu + 2*u*v*suv + v*v*svv) / (w*w);
1274 recShower.SetParameter(eShowerAxisX, u);
1275 recShower.SetParameter(eShowerAxisY, v);
1276 recShower.SetParameter(eShowerAxisZ, w);
1277 recShower.SetParameterCovariance(eShowerAxisX, eShowerAxisX, suu);
1278 recShower.SetParameterCovariance(eShowerAxisY, eShowerAxisY, svv);
1279 recShower.SetParameterCovariance(eShowerAxisZ, eShowerAxisZ, sww);
1280 recShower.SetParameterCovariance(eShowerAxisX, eShowerAxisY, suv);
1281 recShower.SetParameterCovariance(eShowerAxisX, eShowerAxisZ, suw);
1282 recShower.SetParameterCovariance(eShowerAxisY, eShowerAxisZ, svw);
1284 recShower.SetAxis(axis);
1289 const TimeInterval cdiff = recShower.GetAxis() * (recShower.GetCorePosition() - core);
1291 recShower.SetCurvature(0, 0);
1292 recShower.SetCoreTime(newCoreTime, recShower.GetCoreTimeError());
1297 vector<double> ldfShapeParsErr;
1298 for (
size_t i = 0, n = fLDFFitConfig.fLDF.GetNShapeParameters(); i < n; ++i)
1299 ldfShapeParsErr.push_back(lres.
fCov.Std(eShapeParameters + i));
1300 recShower.SetNumberOfActiveStations(timeStat.GetN());
1302 switch (fArrayType) {
1304 recShower.SetShowerSizeType(ShowerSRecData::eS1000);
1307 recShower.SetShowerSizeType(ShowerSRecData::eS450);
1310 recShower.SetShowerSizeType(ShowerSRecData::eS300);
1316 recShower.SetShowerSize(showerSize, showerSizeErr);
1317 recShower.SetCorePosition(core);
1318 const double coreXErr = lres.
fCov.Std(
eCoreX);
1319 const double coreYErr = lres.
fCov.Std(
eCoreY);
1320 recShower.SetCoreError(
Vector(coreXErr, coreYErr, 0,
gBaryCS));
1321 recShower.SetCorrelationXY((coreXErr > 0 && coreYErr > 0) ?
1323 recShower.SetBeta(ldfShapePars[0], ldfShapeParsErr[0]);
1324 if (ldfShapePars.size() > 1)
1325 recShower.SetGamma(ldfShapePars[1], ldfShapeParsErr[1]);
1327 recShower.SetGamma(0, 0);
1328 if (fLDFFitConfig.fLDF.GetType() ==
"NKGFermi")
1329 recShower.SetNKGFermiParameters(ldfShapePars[2], ldfShapePars[3]);
1330 recShower.SetLDFChi2(lres.
fChi2, lres.
fNdof);
1333 recShower.SetCicRefAngle(fEnergyConversion.fCicReferenceAngle);
1334 recShower.SetS38(fEnergyConversion.GetS38(showerSize, cosTheta));
1337 double energyErr = 0;
1338 double energySys = 0;
1339 fEnergyConversion.GetEnergy(cosTheta, showerSize, showerSizeErr,
1340 recShower.GetShowerSizeSystematics(),
1341 energy, energyErr, energySys);
1345 <<
" theta = " << theta/
degree <<
" is outside the range of the CIC. The energy is not valid.\n";
1347 recShower.SetEnergy(energy, energyErr);
1348 recShower.SetEnergyLDFSystematics(energySys);
1349 recShower.SetLDFRecStage(lres.
fRecStage);
1351 for (
const auto sId : fBadSilents) {
1352 if (sEvent.HasStation(sId))
1361 vector<StationFitData>
1365 vector<StationFitData> sFitData;
1367 const auto& sDetector = det::Detector::GetInstance().GetSDetector();
1369 for (
const auto& station : sEvent.StationsRange()) {
1371 if (station.IsCandidate()) {
1372 current.
fId = station.GetId();
1373 current.
fPos = sDetector.GetStation(station).GetPosition();
1375 const auto& sRec = station.GetRecData();
1376 current.
fSignal = sRec.GetTotalSignal();
1380 current.
fT50 = sRec.GetT50();
1381 current.
fGPSTimeVariance = fLDFFitConfig.fUseAdditionalGPSTimeVariance ? sRec.GetGPSTimeVariance() : 0;
1382 sFitData.push_back(current);
1383 }
else if (station.IsSilent() ||
1384 (fUseSilentStationsFromOtherGrids &&
1386 !station.HasRecData() &&
1388 current.
fId = station.GetId();
1389 current.
fPos = sDetector.GetStation(station).GetPosition();
1396 sFitData.push_back(current);
1408 const Vector& showerAxis,
1409 const vector<StationFitData>&
data)
1414 const auto core = result.
GetCore();
1430 double rhoClosest = kRefDist;
1431 double signalClosest = 1;
1434 for (
const auto& station : data) {
1435 if (!station.fSignal)
1438 const double rho =
RPerp(showerAxis, station.fPos - core);
1439 const double distance = fabs(rho - kRefDist);
1441 if (distance < minDistance) {
1442 minDistance = distance;
1444 signalClosest = station.fSignal;
1473 for (
const auto& station : data) {
1474 const double s = station.fSignal;
1479 const double rho =
RPerp(showerAxis, station.fPos - core);
1480 const double f = config.
fLDF(rho, shape);
1502 FitLDF(result, thisConfig, showerAxis, data);
1510 const Vector& showerAxis,
1511 const vector<StationFitData>&
data)
1514 using namespace ROOT::Minuit2;
1516 MnUserParameters pars;
1518 pars.Add(
"showerSize", result.
fPar[0], 1.0);
1519 pars.SetLowerLimit(
"showerSize", 0);
1520 pars.Add(
"coreX", result.
fPar[1], 200*
meter);
1521 pars.Add(
"coreY", result.
fPar[2], 200*
meter);
1537 MnMinimize
m(fUseMaxLikelihood ?
1538 static_cast<const FCNBase&>(likeFcn) :
1539 static_cast<const FCNBase&>(chi2Fcn), pars, 1);
1541 FunctionMinimum fmin =
m(10000);
1543 if (fmin.IsAboveMaxEdm() || fmin.HasReachedCallLimit() || !fmin.IsValid()) {
1545 <<
"\n**************** Minimize FAILED ****************\n"
1547 <<
"**************** Minimize FAILED ****************\n\n";
1553 msg <<
"Found minimum after " << fmin.NFcn() <<
" evaluations";
1563 size_t nCandidates = 0;
1564 for (
const auto& station : data) {
1565 if (station.fSignal > 0)
1569 const auto& params = fmin.UserParameters().Params();
1574 shape[i] = params[eShapeParameters + i];
1576 for (
const auto& station : data) {
1577 if (station.fIsSaturated) {
1578 if (station.fRecoveredSignal > 0 && station.fRecoveredSignalErr > 0) {
1579 const Vector coreToStation = station.fPos - core;
1580 const double rho =
RPerp(showerAxis, coreToStation);
1583 const double prediction = params[
eShowerSize]*config.
fLDF(rho, shape);
1585 prediction < (station.fSignal - 5*
sqrt(prediction))) {
1587 msg <<
"Saturation recovery rejected - fit again without\n"
1588 " 2nd derivative of LDF = " << secDerivative <<
" [Max: " << config.
fRecoveryThreshold <<
"]\n"
1589 " LDF prediction = " << prediction <<
" VEM [Min: " << (station.fSignal - 5*
sqrt(prediction)) <<
" VEM]\n"
1598 msg <<
"Found minimum after " << fmin.NFcn() <<
" evaluations";
1611 hesse(m.Fcnbase(), fmin, 10000);
1613 if (!fmin.IsValid() || fmin.HesseFailed()) {
1615 <<
"\n**************** Hesse FAILED ****************\n"
1617 <<
"**************** Hesse FAILED ****************\n\n";
1621 if (fInfoLevel >= eMinuit)
1623 <<
"\n**************** Minuit Output ****************\n"
1625 <<
"**************** Minuit Output ****************\n\n";
1628 result.
fPar = fmin.UserParameters().Params();
1630 const auto modeledShape =
1634 result.
fPar[3+i] = modeledShape[i];
1636 const auto nVar = pars.VariableParameters();
1641 for (
size_t i = 0; i < nVar; ++i)
1642 for (
size_t j = 0; j < nVar; ++j)
1643 result.
fCov(m.ExtOfInt(i), m.ExtOfInt(j)) = fmin.UserCovariance()(i,j);
1645 const double minValue = fmin.Fval();
1646 if (fUseMaxLikelihood) {
1654 result.
fChi2 = minValue;
1658 for (
const auto& station : data)
1659 if (station.fSignal > 0)
1661 result.
fNdof -= nVar;
1663 const double reducedChi2 = (result.
fNdof > 0) ? result.
fChi2/result.
fNdof : 0;
1665 const auto core = result.
GetCore();
1669 <<
" chi2 = " << result.
fChi2 <<
" / " << result.
fNdof <<
"\n"
1674 OUT(eIntermediate) <<
"\n"
1675 " " <<
GetShapeLabel(i) <<
" = " << result.
fPar[eShapeParameters + i] <<
" +/- " << result.
fCov.Std(eShapeParameters + i);
1676 OUT(eIntermediate) <<
'\n';
1678 if (reducedChi2 > fMaxChi2) {
1680 <<
" chi2 / Ndof = " << reducedChi2 <<
" exceeds limit " << fMaxChi2 <<
'\n';
1684 const double d = (core - fBarycenter).GetMag();
1685 if (d > fMaxBaryToCoreDistance) {
1687 <<
" Distance to core " << d/
km <<
" km exceeds limit.\n";
1702 const double sec1 = 1/cosTheta - 1;
1706 const double x =
Sqr(cosTheta)-
Sqr(0.81932);
1707 const double attenuationFactor = 1 + x*(1.55 - 1.14*x);
1708 const double s35 = (attenuationFactor > 0) ? showerSize/attenuationFactor : showerSize;
1709 const double s = log(s35);
1710 const double eta = 0.1963;
1711 const double mu = -0.0135;
1712 const double zeta = 0.0002866;
1713 const double sDependence = eta + s*(mu + zeta*
s);
1715 const double a = -1.068;
1716 const double b = 0.5059;
1717 const double thetaDependence = 1 + sec1*(a + b*sec1);
1719 const double curvature = sDependence * thetaDependence /
kilometer;
1721 return curvature ? 1/curvature : 0;
1723 const double x =
Sqr(cosTheta) -
Sqr(0.78821);
1724 const double attenuationFactor = 1 + x*(0.87 - 1.49*x);
1725 const double s38 = (attenuationFactor > 0) ? showerSize/attenuationFactor : showerSize;
1726 const double s = log(s38);
1727 const double eta = 0.1785;
1728 const double mu = -0.02149;
1729 const double zeta = 0.0016;
1730 const double sDependence = eta + s*(mu + zeta*
s);
1732 const double a = -1.047;
1733 const double b = 0.473;
1734 const double thetaDependence = 1 + sec1*(a + b*sec1);
1736 const double curvature = sDependence * thetaDependence /
kilometer;
1738 return curvature ? 1/curvature : 0;
1757 const vector<StationFitData>&
data)
1760 using namespace ROOT::Minuit2;
1762 MnUserParameters pars;
1770 const double u = result.
fPar[eU];
1771 const double v = result.
fPar[
eV];
1772 const double w =
sqrt(1 - u*u - v*v);
1773 pars.Add(
"pu", u/w, 0.01);
1774 pars.Add(
"pv", v/w, 0.01);
1775 pars.Add(
"rCore", result.
fPar[eRCore], 10*
meter);
1776 pars.SetLowerLimit(
"rCore", 0);
1777 pars.Add(
"cTCore", result.
fPar[eCTCore], 10*
meter);
1784 if (fFixedCurvature)
1789 MnMinimize
m(chi2Fcn, pars, 1);
1791 FunctionMinimum fmin =
m(10000);
1793 if (fmin.IsAboveMaxEdm() || fmin.HasReachedCallLimit() || !fmin.IsValid()) {
1795 <<
"\n**************** Minimize FAILED ****************\n"
1797 <<
"**************** Minimize FAILED ****************\n\n";
1803 msg <<
"Found minimum after " << fmin.NFcn() <<
" evaluations";
1808 hesse(m.Fcnbase(), fmin, 10000);
1810 if (!fmin.IsValid() || fmin.HesseFailed()) {
1812 <<
"\n**************** Hesse FAILED ****************\n"
1814 <<
"**************** Hesse FAILED ****************\n\n";
1818 if (fInfoLevel >= eMinuit)
1820 <<
"\n**************** Minuit Output ****************\n"
1822 <<
"**************** Minuit Output ****************\n\n";
1825 const auto& params = fmin.UserParameters().Params();
1826 const double pu = params[0];
1827 const double pv = params[1];
1828 const double pw =
sqrt(1 + pu*pu + pv*pv);
1829 result.
fPar[eU] = pu/pw;
1831 result.
fPar[eRCore] = params[eRCore];
1832 result.
fPar[eCTCore] = params[eCTCore];
1834 if (!fFixedCurvature && result.
fPar[eRCore] > 100*
kilometer) {
1836 <<
" curvature radius too large: " << result.
fPar[eRCore]/
kilometer <<
" km\n";
1840 if (!fFixedCurvature && result.
fPar[eRCore] < 1*
kilometer) {
1842 <<
" curvature radius too small: " << result.
fPar[eRCore]/
kilometer <<
" km\n";
1846 const auto nVar = pars.VariableParameters();
1851 for (
size_t i = 0; i < nVar; ++i)
1852 for (
size_t j = 0; j < nVar; ++j)
1853 cov(m.ExtOfInt(i), m.ExtOfInt(j)) = fmin.UserCovariance()(i, j);
1855 const double pupv = pu*pv;
1856 const double pwi3 = 1/(pw*pw*pw);
1858 { (1 + pv*pv)*pwi3, -pupv*pwi3, 0, 0 },
1859 { -pupv*pwi3, (1 + pu*pu)*pwi3, 0, 0 },
1864 for (
size_t i = 0; i < 4; ++i) {
1866 for (
size_t j = i; j < 4; ++j) {
1868 auto& c_ij = result.
fCov(i, j);
1870 for (
size_t k = 0; k < 4; ++k) {
1871 const auto& jac_ik = jac_i[k];
1872 for (
size_t m = 0; m < 4; ++
m)
1873 c_ij += jac_ik * jac_j[m] * cov(k, m);
1878 result.
fChi2 = fmin.Fval();
1881 for (
const auto& sf : data)
1884 result.
fNdof -= nVar;
1894 std::vector<StationFitData>& data)
1897 vector<int> badStations;
1899 int nrCandidates = 0;
1900 for (
const auto& station : data) {
1901 if (station.fSignal > 0)
1904 if (nrCandidates < fSilentsVars.fMinNumberOfStations)
1907 const std::vector<double> shape(ldfres.
fPar.begin()+3, ldfres.
fPar.end());
1909 for (
auto sIt = data.begin(); sIt != data.end(); ) {
1910 if (!sIt->fSignal) {
1911 const Vector coreToStation = sIt->fPos - core;
1912 const double rho =
RPerp(axis, coreToStation);
1913 const double ldfValue = ldfres.
fPar[0] * config.
fLDF(rho, shape);
1914 if (rho < fSilentsVars.fMaxDistance &&
1915 ldfValue > fSilentsVars.fMaxLDFValue) {
1916 badStations.push_back(sIt->fId);
1917 sIt = data.erase(sIt);
1930 const vector<StationFitData>& data)
1933 using namespace ROOT::Minuit2;
1935 MnUserParameters pars;
1937 pars.Add(
"u", cres.
fPar[0], 0.01);
1938 pars.Add(
"v", cres.
fPar[1], 0.01);
1939 pars.Add(
"rCore", cres.
fPar[2], 10*
meter);
1940 pars.SetLowerLimit(
"rCore", 0);
1941 pars.Add(
"cTCore", cres.
fPar[3], 10*
meter);
1948 if (fFixedCurvature)
1951 pars.Add(
"showerSize", lres.
fPar[0], 1.0);
1952 pars.SetLowerLimit(
"showerSize", 0);
1953 pars.Add(
"coreX", lres.
fPar[1], 200*
meter);
1954 pars.Add(
"coreY", lres.
fPar[2], 200*
meter);
1968 MnMinimize
m(likeFcn, pars, 2);
1970 FunctionMinimum fmin =
m();
1972 if (fmin.IsAboveMaxEdm() || fmin.HasReachedCallLimit() || !fmin.IsValid()) {
1974 <<
"\n**************** Minimize FAILED ****************\n"
1976 <<
"**************** Minimize FAILED ****************\n\n";
1982 msg <<
"Found minimum after " << fmin.NFcn() <<
" evaluations";
1987 hesse(m.Fcnbase(), fmin);
1989 if (!fmin.IsValid() || fmin.HesseFailed() || !fmin.HasAccurateCovar()) {
1991 <<
"\n**************** Hesse FAILED ****************\n"
1993 <<
"**************** Hesse FAILED ****************\n\n";
1997 if (fInfoLevel >= eMinuit)
1999 <<
"\n**************** Minuit Output ****************\n"
2001 <<
"**************** Minuit Output ****************\n\n";
2004 const auto nPar = fmin.UserParameters().Params().size();
2005 for (
size_t i = 0; i <
nPar; ++i) {
2007 cres.
fPar[i] = fmin.UserParameters().Params()[i];
2009 lres.
fPar[i-4] = fmin.UserParameters().Params()[i];
2015 lres.
fPar[3+i] = modeledShape[i];
2017 if (!fFixedCurvature && cres.
fPar[eRCore] > 100*
kilometer) {
2019 <<
" curvature radius too large.\n";
2023 const auto core = lres.
GetCore();
2024 const double d = (core - fBarycenter).GetMag();
2025 if (d > fMaxBaryToCoreDistance) {
2027 <<
" Distance to core " << d/
km <<
" km exceeds limit.\n";
2031 const auto nVar = pars.VariableParameters();
2037 for (
size_t i = 0; i < nVar; ++i)
2038 for (
size_t j = 0; j < nVar; ++j) {
2039 const auto iext = m.ExtOfInt(i);
2040 const auto jext = m.ExtOfInt(j);
2041 if (iext < 4 && jext < 4)
2042 cres.
fCov(iext, jext) = fmin.UserCovariance()(i, j);
2043 if (iext >= 4 && jext >= 4)
2044 lres.
fCov(iext-4, jext-4) = fmin.UserCovariance()(i, j);
2057 for (
const auto& station : data)
2058 if (station.fSignal > 0)
2061 for (
size_t i = 4; i <
nPar; ++i)
2062 if (!pars.Parameter(i).IsFixed())
2069 for (
const auto& station : data)
2070 if (station.fSignal > 0)
2073 for (
size_t i = 0; i < 4; ++i)
2074 if (!pars.Parameter(i).IsFixed())
2078 const double reducedChi2 = (lres.
fNdof > 0) ? lres.
fChi2/lres.
fNdof : 0;
2080 if (reducedChi2 > fMaxChi2) {
2082 <<
" ldf chi2 / Ndof = " << reducedChi2 <<
" exceeds limit " << fMaxChi2 <<
'\n';
2088 <<
" curv Chi2 = " << cres.
fChi2 <<
" / " << cres.
fNdof <<
"\n"
2091 " CTCore = " << cres.
fPar[eCTCore]/
meter <<
" +/- " << cres.
fCov.Std(eCTCore)/
meter <<
" m\n"
2092 " ldf chi2 = " << lres.
fChi2 <<
" / " << lres.
fNdof <<
"\n"
2096 OUT(eIntermediate) <<
"\n"
2097 " " <<
GetShapeLabel(i) <<
" = " << lres.
fPar[eShapeParameters + i] <<
" +/- " << lres.
fCov.Std(eShapeParameters + i);
2098 OUT(eIntermediate) <<
'\n';
Class to access station level reconstructed data.
TMatrixD jacobian(TVectorD(*f)(TVectorD, const modeltype), TVectorD x, TVectorD dx, const modeltype mtype)
std::string Make(const Geo &g, const CS &cs, const double unit=1, const std::string &sep=" ")
double GetCorrelationXY() const
void OutputResults(const evt::Event &event) const
double GetCurvatureError() const
bool FixBeta(const LDFFitResult &result, const utl::Vector &showerAxis, const std::vector< StationFitData > &data) const
constexpr T Sqr(const T &x)
double Angle(const double theta1, const double phi1, const double theta2, const double phi2)
double GetAngleNdof() const
double GetPhi(const CoordinateSystemPtr &coordinateSystem) const
azimuth (phi) angle in spherical and cylindrical coordinates
double GetCurvature() const
gaussian curvature = 1 / Rc
IsProxy< T > Is(const T &x)
Interface class to access to the SD Reconstruction of a Shower.
std::vector< StationFitData > MakeStationFitData(const sevt::SEvent &sEvent) const
Init station data used by LDF fit.
Interface class to access to the SD part of an event.
double GetBetaError() const
double GetTheta(const CoordinateSystemPtr &coordinateSystem) const
zenith (theta) angle in spherical coordinates
bool FitLDF(LDFFitResult &result, LDFFitConfig &config, const utl::Vector &showerAxis, const std::vector< StationFitData > &data) const
bool FixGamma(const LDFFitResult &result, const utl::Vector &showerAxis, const std::vector< StationFitData > &data) const
Criterion if gamma can be fitted analogue to beta must be checked/updated.
double RPerp(const utl::Vector &axis, const utl::Vector &station)
void FitLDFSimplified(LDFFitResult &result, LDFFitConfig &config, const utl::Vector &showerAxis, const std::vector< StationFitData > &data) const
Early estimate of shower size.
double GetAngleChi2() const
double GetCosTheta(const CoordinateSystemPtr &coordinateSystem) const
cos of zenith (theta) angle
bool HasSimShower() const
void SetRecData(evt::Event &event, const LDFFitResult &lresult, const CurvFitResult &cresult) const
const utl::Vector & GetCoreError() const
#define INFO(message)
Macro for logging informational messages.
double GetShowerSize() const
Base class for exceptions trying to access non-existing components.
double BetaUncertainty(const double showerSize) const
double InverseNormalCDF(const double p)
Inverse of the comulative normal distribution. Taken from http://home.online.no/~pjacklam/notes/invno...
std::vector< double > ShapeModel(const double cosTheta, const double showerSize) const
double NormalCDF(const double x)
double GetEnergyError() const
A TimeStamp holds GPS second and nanosecond for some event.
utl::CoordinateSystemPtr gBaryCS
boost::shared_ptr< const CoordinateTransformer > CoordinateSystemPtr
Shared pointer for coordinate systems.
const char * GetShapeLabel(const int iShape)
fwk::VModule::ResultFlag Run(evt::Event &event) override
Run: invoked once per event.
std::vector< double > fPar
boost::tuple< double, double, double > Triple
Coordinate triple for easy getting or setting of coordinates.
utl::Point GetCore() const
double GetX(const CoordinateSystemPtr &coordinateSystem) const
constexpr double nanosecond
double GetGPSTimeVariance() const
double GetTimeResidualSpread() const
double GetLDFRecStage() const
double SecondDerivative(const double r, const std::vector< double > &shape) const
double GetTimeVariance(const LDFFitConfig &fconf, const sdet::STimeVariance &timeVariance, const double signal, const StationRecData &sRec, const double cosTheta, const double rho)
bool FitGlobal(CurvFitResult &cres, LDFFitResult &lres, const LDFFitConfig &config, const std::vector< StationFitData > &data) const
double GetThetaError() const
const utl::Vector & GetAxis() const
string GetShowerSizeLabel(const LDFFitConfig &config)
double GetPhiError() const
double FitCurvature(CurvFitResult &result, const utl::Point &core, const std::vector< StationFitData > &data) const
utl::CovarianceMatrix fCov
bool FixCore(utl::Point &core, utl::TimeStamp &coreTime, utl::Vector &showerAxis, const evt::Event &event) const
fwk::VModule::ResultFlag Init() override
Initialize: invoked at beginning of run (NOT beginning of event)
const vector< double > fAxisParameters
std::vector< ParameterTreatment > fLDFShapeTreatment
bool fUseAdditionalGPSTimeVariance
double fRecoveryThreshold
double GetY(const CoordinateSystemPtr &coordinateSystem) const
constexpr double kSpeedOfLight
double GetGammaError() const
A TimeInterval is used to represent time elapsed between two events.
ResultFlag
Flag returned by module methods to the RunController.
double GetLDFOptimumDistance() const
double SignalUncertainty(const ESignalVarianceModel model, const double cosTheta, const double signal)
bool HasNaN(const T &result)
double GetCorrelationThetaPhi() const
double fRecoveredSignalErr
double GetReferenceDistance() const
std::vector< double > fPar
constexpr double kilometer
Interface class to access to Fluorescence reconstruction of a Shower.
double GetShowerSizeError() const
bool fUseSaturationRecovery
double CosAngle(const Vector &l, const Vector &r)
const utl::Point & GetCorePosition() const
utl::CovarianceMatrix fCov
unsigned int GetNShapeParameters() const
double GetZ(const CoordinateSystemPtr &coordinateSystem) const
double Chi2Probability(const double chi2, const double ndof)
#define ERROR(message)
Macro for logging error messages.
double GetTimeResidualMean() const
const utl::Point & GetCorePosition() const
Shower core as reconstructed by the FD or FD eye.
double GetShowerSizeSystematics() const
std::vector< int > CleanSilentStation(const LDFFitResult &ldfres, const LDFFitConfig &config, const utl::Vector &showerAxis, std::vector< StationFitData > &stationFitData) const
double ParameterizedRc(const double cosTheta, const double showerSize) const
std::vector< double > GetLDFShapeParameters() const
CoreShiftPropagator(const double coreX, const double coreY, const vector< double > &axisParameters)
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