10 #include <sevt/SEvent.h>
11 #include <sevt/Header.h>
13 #include <sevt/StationRecData.h>
14 #include <sevt/Station.h>
15 #include <sevt/PMTCalibData.h>
16 #include <sevt/PMTRecData.h>
18 #include <sdet/SDetector.h>
19 #include <sdet/Station.h>
21 #include <fwk/CentralConfig.h>
22 #include <fwk/RunController.h>
23 #include <utl/Reader.h>
24 #include <utl/PhysicalConstants.h>
25 #include <utl/PhysicalFunctions.h>
26 #include <utl/ErrorLogger.h>
31 using namespace SdSignalRecoveryKLT;
39 namespace SdSignalRecoveryKLT {
47 double kAlphaSat[] = { 1, 0.301299, 0.0720609, 0.0203313, 0.00631851, 0.00151839 };
48 double kBetaSat[] = { 0, 4485.13, 8180.03, 9846.53, 10744.6, 11420.6 };
57 const double sqrt2 =
sqrt(2.);
58 const double sigma2 = 2*sigma;
60 (erf(exp((x - i1)/sigma2)/sqrt2) - erf(exp((x - i2)/sigma2)/sqrt2));
68 return (value < 974.5) ? 2.17 - 8.908e-4 * value :
69 1.28 + value*(2.63e-5 - 4.808e-9 * value);
78 (value < 878) ? 4.645444 + value*(-0.0134195 + 0.0000105245 * value) :
79 2.1 * (1 - exp(-7.2e-4 * value)) +
pow(value, -3.8);
87 const double sigma_fit = 0.17*(1 - exp(-5.21*x)) + 0.068;
88 const double sigma_sys = 0.05*exp(2.325*x);
89 const double total_sigma =
sqrt(
Sqr(sigma_fit)
91 return (total_sigma < 0.10) ? 0.10 : total_sigma;
99 return 0.44*
pow(x, 7.12) + 0.036;
115 for (
unsigned int i = 0; i < Length(
kAlphaSat); ++i)
117 for (
unsigned int i = 0; i < Length(
kBetaSat); ++i)
127 CentralConfig::GetInstance()->
GetTopBranch(
"SdSignalRecovery");
138 nlBranchPl.
GetChild(
"intervals").
GetData(fNonLinearityPlusSigma.fSignalLimits);
143 const Branch nlBranchMi = topB.
GetChild(
"nonLinearityMinusSigma");
145 nlBranchMi.
GetChild(
"intervals").
GetData(fNonLinearityMinusSigma.fSignalLimits);
158 return eContinueLoop;
160 auto& sEvent =
event.GetSEvent();
164 int nSaturatedStations = 0;
165 for (
auto& station : sEvent.StationsRange()) {
167 if (!station.HasRecData())
170 const auto& dStation = det::Detector::GetInstance().GetSDetector().GetStation(station);
174 if (dStation.IsUUB())
177 const unsigned int saturationValue = dStation.GetSaturationValue();
179 if (station.IsLowGainSaturation()) {
181 ++nSaturatedStations;
183 info <<
"\nRecover saturated station " << station.GetId() <<
':';
186 double recoveredSignal = 0;
187 double signalError = 0;
190 for (
const auto& pmt : station.PMTsRange()) {
192 if (!pmt.HasRecData() ||
193 !pmt.GetRecData().HasVEMTrace() ||
194 !pmt.GetCalibData().IsTubeOk() ||
195 !pmt.GetCalibData().IsLowGainOk())
199 info <<
"\n PMT" << pmt.GetId() <<
" is not saturated";
200 recoveredSignal += pmt.GetRecData().GetTotalCharge();
201 signalError +=
Sqr(pmt.GetRecData().GetTotalChargeError());
206 SetNonLinearityCurve(fNonLinearity);
207 if (!RecoverSignal(pmt, sbest, saturationValue)) {
208 info <<
"\n PMT" << pmt.GetId() <<
" signal "
209 << pmt.GetRecData().GetTotalCharge() <<
" VEM not recovered";
212 if (SetNonLinearityCurve(fNonLinearityPlusSigma)) {
213 if (!RecoverSignal(pmt, sPlusSigma, saturationValue)) {
214 info <<
"\n PMT" << pmt.GetId() <<
" could not calculate nL signal+sigma";
220 if (SetNonLinearityCurve(fNonLinearityMinusSigma)) {
221 if (!RecoverSignal(pmt, sMinusSigma, saturationValue)) {
222 info <<
"\n PMT" << pmt.GetId() <<
" could not calculate nL signal-sigma";
237 info <<
"\n PMT" << pmt.GetId() <<
": signal "
238 << pmt.GetRecData().GetTotalCharge() <<
" recovered to "
241 recoveredSignal += sbest.
fSignal;
249 info <<
"\n No PMTs!";
253 recoveredSignal /= noOfPMTs;
257 const double recoveredSignalError =
sqrt(signalError) / noOfPMTs;
258 info <<
"\n Signal in station " << station.GetId()
259 <<
" successfully recovered from " << sRec.
GetTotalSignal() <<
" to "
260 << recoveredSignal <<
" +- " << recoveredSignalError <<
" VEM";
266 const auto& mess = info.str();
270 if (nSaturatedStations)
271 ++RunController::GetInstance().GetRunData().GetNamedCounters()[
"SdSignalRecovery/SaturatedEvents"];
279 const int saturationValue)
283 copy(vemtrace.
Begin(), vemtrace.
End(), fgVEMTrace);
286 for (
unsigned int i = 0; i < lowGainTrace.GetSize(); ++i)
287 if (lowGainTrace[i] == saturationValue) {
303 WARNING(
"Negative undershoot");
313 sfi.
fChi2 = SaturationFitDriver(sfi);
316 sfi.
fAmpl = ComputeAmplitude(sfi);
323 double pmtSignal = 0;
324 double satSignal = 0;
326 const double vemSignal = fgVEMTrace[i];
327 satSignal += vemSignal;
333 if (lowGainTrace[i] == saturationValue) {
338 pmtSignal += vemSignal;
342 const double peakOverCharge = sfi.
fVEMPeak / vemCharge;
343 sfi.
fSignal = pmtSignal * peakOverCharge;
344 satSignal *= peakOverCharge;
346 WARNING(
"NAN value in recovered signal");
358 warn <<
"Recovered signal " << sfi.
fSignal
359 <<
" smaller than the saturated one " << satSignal;
371 warn <<
"chi2/ndof = " << sfi.
fChi2 / sfi.
fNdof <<
" is too large";
390 minuit.mnexcm(
"SET PRINTOUT", argList, 1, errFlag);
391 minuit.mnexcm(
"SET NOWARNINGS", argList, 0, errFlag);
392 minuit.SetPrintLevel(-1);
395 minuit.mnexcm(
"SET ERRORDEF", argList, 1, errFlag);
407 const double sigmaParamLow = sigmaParam - 0.75;
408 const double sigmaParamHigh = sigmaParam + 0.75;
409 minuit.DefineParameter(1,
"sigma", sigmaParam, 0.01,
410 (sigmaParamLow > 0) ? sigmaParamLow:0,
419 minuit.DefineParameter(5,
"firstSatBin", sfi.
fFirstSatBin, 0, 0, 0);
420 minuit.DefineParameter(6,
"lastSatBin", sfi.
fLastSatBin, 0, 0, 0);
422 minuit.FixParameter(0);
424 minuit.mnexcm(
"CALI", argList, 1, errFlag);
427 minuit.mnexcm(
"MINIMIZE", argList, 2, errFlag);
431 minuit.mnexcm(
"MINOS", argList, 2, errFlag);
438 minuit.GetParameter(2, sfi.
fx0, sfi.
fx0Err);
443 x0 < sfi.fFirstSatBin || x0 > sfi.
fLastSatBin + 2) {
444 WARNING(
"Fit results are out of bounds.");
447 warn <<
"Sanity checks failed: ampl=" << sfi.
fAmpl
448 <<
" sigma=" << sfi.
fSigma
461 double* par,
const int flag)
464 double& amplitude = par[0];
465 const double sigma = par[1];
466 const double x0 = par[2];
467 const double underValue = par[3];
468 const double calibCt = par[4];
469 const unsigned int firstSatBin = (
unsigned int)(par[5]);
470 const unsigned int lastSatBin = (
unsigned int)(par[6]);
472 static unsigned int firstBin;
473 static double maximum;
474 static vector<double> bSignalNotSat;
475 static vector<int> bPosition;
476 static unsigned int nBins;
479 bSignalNotSat.clear();
482 unsigned int maxposition = 0;
483 maximum = fgVEMTrace[0];
487 const double vem = fgVEMTrace[i];
490 if (firstBin > firstSatBin)
491 firstBin = firstSatBin;
499 for (
unsigned int i = lastSatBin+1; i <
kTraceLength; ++i)
505 if (maxposition && fgVEMTrace[maxposition-1] <
kMinCounts) {
506 bSignalNotSat.push_back(fgVEMTrace[maxposition]);
507 bPosition.push_back(
int(maxposition) - firstBin);
510 for (
unsigned int i = 0; i <= firstBin; ++i) {
511 const double t = fgVEMTrace[i];
513 bSignalNotSat.push_back(t);
514 bPosition.push_back(
int(i) - firstBin);
518 for (
unsigned int i = lastSatBin+1; i <= lastBin; ++i) {
519 const double t = fgVEMTrace[i];
521 bSignalNotSat.push_back(t);
522 bPosition.push_back(
int(i) - firstBin);
526 nBins = bSignalNotSat.size();
530 for (
int iterations = 0; iterations < 10; ++iterations) {
532 const double ampl = amplitude / calibCt;
538 if (y < kMaxMoyal && y > 0)
544 if (y < kMaxMoyal && y > 0)
552 const unsigned int n = tin.size();
554 for (
unsigned int i = 0; i < n/2; ++i) {
555 const double tin_i = tin[i];
556 const double tin_i1 = tin[i+1];
558 betasum +=
kBetaSat[i] * (fabs(tin_i1 - tin_i));
561 for (
unsigned int i = 1; i < n/2; ++i) {
562 const int ni = n - i;
563 const double tin_ni = tin[ni];
564 const double tin_ni1 = tin[ni - 1];
566 betasum +=
kBetaSat[i-1] * (fabs(tin_ni - tin_ni1));
569 amplitude = (underValue - betasum*0.5) * calibCt / alphasum;
575 for (
unsigned int i = 0; i < nBins; ++i) {
576 const double landFunc = amplitude *
Moyal((bPosition[i] - x0) / sigma);
577 const double sns = bSignalNotSat[i];
578 chi2 +=
Sqr(sns - landFunc) / sns;
596 const double ampl = sfi.
fAmpl / dynAnOverPeak;
599 ERROR(
"This should not happen!");
620 const unsigned int n = tin.size();
621 for (
unsigned int i = 0; i < n/2; ++i) {
622 const double tin_i = tin[i];
623 const double tin_i1 = tin[i+1];
625 betasum +=
kBetaSat[i] * (fabs(tin_i1 - tin_i));
628 for (
unsigned int i = 1; i < n/2; ++i) {
629 const int ni = n - i;
630 const double tin_ni = tin[ni];
631 const double tin_ni1 = tin[ni - 1];
633 betasum +=
kBetaSat[i-1] * (fabs(tin_ni - tin_ni1));
643 const int saturationValue)
650 vector<int> histoDynBefore(saturationValue + 1, 0);
651 vector<int> histoAnBefore(saturationValue + 1, 0);
653 const unsigned int firstUnderBin = 100;
654 for (
unsigned int j = 0; j < firstUnderBin; ++j) {
655 ++histoDynBefore[dynodeTrace[j]];
656 ++histoAnBefore[anodeTrace[j]];
659 vector<int> histoDynAfter(saturationValue + 1, 0);
660 vector<int> histoAnAfter(saturationValue + 1, 0);
662 const unsigned int lastUnderBin = 668;
663 for (
unsigned int j = lastUnderBin; j <
kTraceLength; ++j) {
664 ++histoDynAfter[dynodeTrace[j]];
665 ++histoAnAfter[anodeTrace[j]];
668 int xMaxDynBefore = 0;
669 int maxDynBefore = histoDynBefore[0];
670 int xMaxAnBefore = 0;
671 int maxAnBefore = histoAnBefore[0];
672 int xMaxDynAfter = 0;
673 int maxDynAfter = histoDynAfter[0];
675 int maxAnAfter = histoAnAfter[0];
677 for (
int j = 1; j <= saturationValue; ++j) {
678 if (histoAnBefore[j] > maxAnBefore) {
679 maxAnBefore = histoAnBefore[j];
682 if (histoAnAfter[j] > maxAnAfter) {
683 maxAnAfter = histoAnAfter[j];
686 if (histoDynBefore[j] > maxDynBefore) {
687 maxDynBefore = histoDynBefore[j];
690 if (histoDynAfter[j] > maxDynAfter) {
691 maxDynAfter = histoDynAfter[j];
697 int sumDynBefore = 0;
702 const double maxBaselineVar = 4;
703 for (
unsigned int j = 0; j < firstUnderBin; ++j) {
704 const int dyn = dynodeTrace[j];
705 if (
abs(dyn - xMaxDynBefore) < maxBaselineVar) {
709 const int an = anodeTrace[j];
710 if (
abs(an - xMaxAnBefore) < maxBaselineVar) {
716 const double baseDynBefore = k_Dyn ? double(sumDynBefore)/k_Dyn : 0;
717 const double baseAnBefore = k_An ? double(sumAnBefore)/k_An : 0;
726 for (
unsigned int j = lastUnderBin; j <
kTraceLength; ++j) {
727 const int dyn = dynodeTrace[j];
729 if (
abs(dyn - xMaxDynAfter) < maxBaselineVar) {
738 const int an = anodeTrace[j];
739 if (
abs(an - xMaxAnAfter) < maxBaselineVar) {
745 const double baseDynAfter = k_Dyn ? double(sumDynAfter)/k_Dyn : 0;
746 const double baseAnAfter = k_An ? double(sumAnAfter)/k_An : 0;
748 if (
abs(interval1 - interval2) > 150) {
749 WARNING(
"Undershoot value could not be computed due to after pulse baseline instability");
753 const double anodeUndershoot = baseAnBefore - baseAnAfter;
754 const double dynodeUndershoot = baseDynBefore - baseDynAfter;
757 double dynodeCharge = 0;
758 double anodeCharge = 0;
760 bool isDynSaturated =
false;
761 const int saturationLimit = saturationValue - 3;
763 const int dyn = dynodeTrace[j];
764 if (dyn == saturationValue)
765 isDynSaturated =
true;
766 if (dyn > saturationLimit)
768 if (dyn - baseDynBefore > 1)
769 dynodeCharge += dyn - baseDynBefore;
770 if (anodeTrace[j] - baseAnBefore > 1)
771 anodeCharge += anodeTrace[j] - baseAnBefore;
773 if (!isDynSaturated) {
774 ERROR(
"No high gain saturation for this PMT");
783 if (dynodeUndershoot <= 0 && anodeUndershoot <= 0) {
785 info <<
"Negative undershoot values: anode " << anodeUndershoot <<
", dynode "
790 const bool useDynode = (dynodeUndershoot > 0);
792 const double lE_RecAnodeCharge2 = (dynodeUndershoot < 30 && useDynode) ?
793 143.68 *
pow(dynodeUndershoot, 1.5316) :
794 21276.60 * (anodeUndershoot - 0.06227);
796 const double to_RecAnodeCharge = (anodeUndershoot <= 1 && useDynode) ?
797 770 * (dynodeUndershoot - (1.35e-4*dynodeCharge + 0.055*nSatDyn)) - 222 :
798 20000*anodeUndershoot - 2216;
800 double recSignal = 0;
802 switch (fRecoverUnsaturatedSignal) {
804 recSignal = 0.5*(lE_RecAnodeCharge2 + to_RecAnodeCharge);
807 recSignal = to_RecAnodeCharge;
810 recSignal = lE_RecAnodeCharge2;
815 if (recSignal < anodeCharge)
816 recSignal = anodeCharge;
double GetVEMCharge() const
Branch GetTopBranch() const
Class to access station level reconstructed data.
static void SaturationFitFnc(int &nPar, double *const grad, double &value, double *par, const int flag)
utl::TraceD & GetVEMTrace(const StationConstants::SignalComponent source=StationConstants::eTotal)
Traces calibrated in VEM Peak.
constexpr T Sqr(const T &x)
class to hold data at PMT level
unsigned int fFirstSatBin
double X0Parametrization(const double value)
PMTRecData & GetRecData()
Get object containing PMT reconstructed data.
std::vector< double > fBeta
#define INFO(message)
Macro for logging informational messages.
double RecoverSignalUndershoot(const utl::TraceI &dynodeTrace, const utl::TraceI &anodeTrace, const int saturationValue) const
fwk::VModule::ResultFlag Init()
Initialize: invoked at beginning of run (NOT beginning of event)
std::vector< double > fAlpha
double ComputeAmplitude(SaturationFitInterface &sfi) const
Branch GetChild(const std::string &childName) const
Get child of this Branch by child name.
double pow(const double x, const unsigned int i)
int GetFADCSaturatedBins(const sdet::PMTConstants::PMTGain gain=sdet::PMTConstants::eHighGain) const
fwk::VModule::ResultFlag Run(evt::Event &event)
Run: invoked once per event.
Class representing a document branch.
double SaturationFitDriver(SaturationFitInterface &sfi) const
class to hold reconstructed data at PMT level
double ErrorParametrization(const double x)
bool SetNonLinearityCurve(const NonLinearity &nL)
double abs(const SVector< n, T > &v)
double GetTotalSignal() const
Total integrated signal in VEM unit, averaged over pmts.
template double InverseMoyal<+1 >(const double y, const double eps)
#define WARNING(message)
Macro for logging warning messages.
void GetData(bool &b) const
Overloads of the GetData member template function.
utl::TraceI & GetFADCTrace(const sdet::PMTConstants::PMTGain gain=sdet::PMTConstants::eHighGain, const StationConstants::SignalComponent source=StationConstants::eTotal)
ResultFlag
Flag returned by module methods to the RunController.
const unsigned int kTraceLength
double NonLinearityUncertainty(const double x)
std::vector< double > fSignalLimits
double Moyal(const double x)
Moyal function.
double AmplitudeFunction(const double i1, const double i2, const double sigma, const double x)
#define ERROR(message)
Macro for logging error messages.
template double InverseMoyal<-1 >(const double y, const double eps)
double GetVEMPeak() const
double SigmaParametrization(const double value)
static double fgVEMTrace[768]
double GetGainRatio() const
void SetRecoveredSignal(const double recSignal, const double recSignalErr)
Total recovered signal in VEM unit, averaged over pmts.