3 #include <fwk/CentralConfig.h>
5 #include <sdet/SDetector.h>
6 #include <sevt/SEvent.h>
7 #include <sevt/EventTrigger.h>
8 #include <sevt/StationCalibData.h>
9 #include <utl/QuadraticFitter.h>
10 #include <utl/ExponentialFitter.h>
11 #include <utl/String.h>
22 template<
typename T1,
typename T2>
25 operator<<(ostream& os, pair<T1, T2>&
p)
27 return os <<
'[' <<
p.first <<
", " <<
p.second <<
']';
33 IsInRange(
const double x,
const pair<double, double>& r)
35 return r.first < x && x < r.second;
45 topB.GetChild(
"peakFitChi2Accept").GetData(fPeakFitChi2Accept);
46 topB.GetChild(
"peakOnlineToVEMFactor").GetData(fPeakOnlineToVEMFactor);
47 topB.GetChild(
"peakHistogramToVEMFactor").GetData(fPeakHistogramToVEMFactor);
48 topB.GetChild(
"peakOnlineToMIPFactor").GetData(fPeakOnlineToMIPFactor);
49 topB.GetChild(
"peakHistogramToMIPFactor").GetData(fPeakHistogramToMIPFactor);
50 topB.GetChild(
"chargeSigmaThresholdFactors").GetData(fChargeSigmaThresholdFactors);
51 topB.GetChild(
"chargeFitChi2Accept").GetData(fChargeFitChi2Accept);
52 topB.GetChild(
"chargeOnlineToVEMFactor").GetData(fChargeOnlineToVEMFactor);
53 topB.GetChild(
"chargeHistogramToVEMFactor").GetData(fChargeHistogramToVEMFactor);
54 topB.GetChild(
"chargeOnlineToMIPFactor").GetData(fChargeOnlineToMIPFactor);
55 topB.GetChild(
"chargeHistogramToMIPFactor").GetData(fChargeHistogramToMIPFactor);
56 topB.GetChild(
"chargeVEMRangeUub").GetData(fChargeVEMRangeUub);
58 auto shapeFitB = topB.GetChild(
"shapeFitRange");
59 shapeFitB.GetChild(
"beforeCalibrationVersion12").GetData(fShapeFitRangeBefore12);
60 shapeFitB.GetChild(
"sinceCalibrationVersion12").GetData(fShapeFitRangeSince12);
63 info <<
"Parameters:\n"
64 "peakFitRange: " << fPeakFitRange <<
"\n"
65 "peakFitChi2Accept: " << fPeakFitChi2Accept <<
"\n"
66 "peakOnlineToVEMFactor: " << fPeakOnlineToVEMFactor <<
"\n"
67 "peakHistogramToVEMFactor: " << fPeakHistogramToVEMFactor <<
"\n"
68 "peakOnlineToMIPFactor: " << fPeakOnlineToMIPFactor <<
"\n"
69 "peakHistogramToMIPFactor: " << fPeakHistogramToMIPFactor <<
"\n"
70 "chargeSigmaThresholdFactors: " <<
Join(
" ", fChargeSigmaThresholdFactors) <<
"\n"
71 "chargeFitChi2Accept: " << fChargeFitChi2Accept <<
"\n"
72 "chargeOnlineToVEMFactor: " << fChargeOnlineToVEMFactor <<
"\n"
73 "chargeHistogramToVEMFactor: " << fChargeHistogramToVEMFactor <<
"\n"
74 "chargeOnlineToMIPFactor: " << fChargeOnlineToMIPFactor <<
"\n"
75 "chargeHistogramToMIPFactor: " << fChargeHistogramToMIPFactor <<
"\n"
76 "chargeVEMRangeUub: " << fChargeVEMRangeUub;
88 auto& sEvent =
event.GetSEvent();
91 fToldYaCharge =
false;
95 for (
auto& station : sEvent.StationsRange()) {
96 if (!station.HasTriggerData() ||
97 !station.HasCalibData() ||
98 !station.HasGPSData())
101 const auto& trig = station.GetTriggerData();
102 if (trig.IsRandom() ||
103 (trig.GetErrorCode() & 0xff) ||
104 station.GetCalibData().GetVersion() > 32000)
108 if (sEvent.HasTrigger()) {
109 const int trigSecond = sEvent.GetTrigger().GetTime().GetGPSSecond();
110 const int timeDiff = int(station.GetGPSData().GetSecond()) - trigSecond;
111 if (
abs(timeDiff) > 1)
115 const auto& dStation = det::Detector::GetInstance().GetSDetector().GetStation(station);
116 fIsUUB = dStation.IsUUB();
118 CalculatePeakAndCharge(station);
121 if (fIsUUB && station.HasSmallPMTData()) {
122 if (CopySmallPMTCalibData(station))
123 station.GetSmallPMTData().SetIsTubeOk();
125 station.GetSmallPMTData().SetIsTubeOk(
false);
126 if (station.GetSmallPMT().HasCalibData())
127 station.GetSmallPMT().GetCalibData().SetIsTubeOk(
false);
129 warn <<
"Station " << station.GetId() <<
": No valid SmallPMT calibration. "
130 "Setting IsTubeOk as false for SmallPMT.";
141 SdHistogramFitter::CalculatePeakAndCharge(
Station& station)
145 const auto calibVersion = stationCalibData.
GetVersion();
146 const auto& dStation = det::Detector::GetInstance().GetSDetector().GetStation(station);
152 const auto type = pmt.GetType();
160 if (!pmt.HasCalibData())
162 auto& pmtCalibData = pmt.GetCalibData();
164 if (!pmtCalibData.IsTubeOk())
167 if (!pmt.HasRecData())
169 auto& pmtRec = pmt.GetRecData();
171 if (!pmtRec.GetVEMPeak()) {
173 const double onlineFactor =
175 double vemPeak = pmtCalibData.GetOnlinePeak() * onlineFactor;
176 double vemPeakErr = 0;
177 pmtRec.SetOnlineVEMPeak(vemPeak, vemPeakErr);
178 bool vemPeakFromHisto =
false;
181 if (calibVersion > 8) {
182 const auto& peakHistoBinning = dStation.GetMuonPeakHistogramBinning<
short>(type, calibVersion);
183 const int muonPeakHistoSize = pmtCalibData.GetMuonPeakHisto().size();
184 if (!muonPeakHistoSize ||
int(peakHistoBinning.size())-1 != muonPeakHistoSize) {
185 if (!(fToldYaPeak || pmt.HasSimData())) {
186 WARNING(
"According to the LS calibration version there should be a muon peak histogram... Will not tell you again!");
190 const CalibHistogram peakHisto(peakHistoBinning, pmtCalibData.GetMuonPeakHisto());
191 const double histoFactor =
193 const double predictedHistoPeak = vemPeak / histoFactor;
194 if (predictedHistoPeak > 0 && peakHisto.GetMaximum() > 200) {
195 const double baseEstimate =
196 pmtCalibData.GetBaseline() - pmtCalibData.GetMuonPeakHistoOffset();
197 const double base = (fabs(baseEstimate) < 20) ? baseEstimate : 0;
198 const double peakLow = fPeakFitRange.first * predictedHistoPeak;
199 const double peakHigh = fPeakFitRange.second * predictedHistoPeak;
201 if (peakHigh - peakLow >= 5) {
207 peakLow + base, peakHigh + base).GetFitData(qf);
208 pmtRec.GetMuonPeakFitData() = qf;
211 if (peakLow <= fittedPeak && fittedPeak <= peakHigh &&
213 vemPeak = fittedPeak * histoFactor;
215 pmtRec.SetHistogramVEMPeak(vemPeak, vemPeakErr);
216 vemPeakFromHisto =
true;
225 pmtRec.SetVEMPeak(vemPeak, vemPeakErr);
226 pmtRec.SetIsVEMPeakFromHistogram(vemPeakFromHisto);
229 if (!pmtRec.GetVEMCharge()) {
234 const double onlineFactor =
236 double vemCharge = pmtCalibData.GetOnlineCharge() * onlineFactor;
237 double vemChargeErr = 20 * onlineFactor;
238 pmtRec.SetOnlineVEMCharge(vemCharge, vemChargeErr);
239 bool vemChargeFromHisto =
false;
240 double muChargeSlope = 0;
243 if (calibVersion > 8) {
244 const auto& chargeHistoBinning = dStation.GetMuonChargeHistogramBinning<
double>(type, calibVersion);
245 const auto& calibChargeHisto = pmtCalibData.GetMuonChargeHisto();
246 const int chargeHistoSize = calibChargeHisto.size();
248 if (!chargeHistoSize ||
int(chargeHistoBinning.size()) - 1 != chargeHistoSize) {
249 if (!fToldYaCharge) {
250 WARNING(
"According to the LS calibration version there should be a muon charge histogram... Will not tell you again!");
251 fToldYaCharge =
true;
254 const CalibHistogramD chargeHisto(chargeHistoBinning, calibChargeHisto);
256 const int chargeHistoEntries = fIsUUB ?
257 chargeHisto.GetSumEntries() :
258 chargeHisto.GetSumEntries() - calibChargeHisto.back();
260 if (chargeHistoEntries > 1e4) {
261 const double chargeEntropyMinimum =
263 const double chargeEntropy = chargeHisto.GetEntropy();
264 if (chargeEntropy > chargeEntropyMinimum) {
269 const double baseEstimate = pmtCalibData.GetBaseline() *
270 (calibVersion == 13 ? 19 : 20) - pmtCalibData.GetMuonChargeHistoOffset();
271 base = (fabs(baseEstimate) < 20) ? baseEstimate : 0;
274 const auto chargeDensity = chargeHisto.GetDensityVector();
275 const auto chargeDensityError = chargeHisto.GetDensityErrorVector();
277 for (
const auto& thresholdFactor: fChargeSigmaThresholdFactors) {
278 double chargeHumpPos = 0;
279 double chargeHumpPosError = 0;
280 double chargeDipPos = 0;
283 const unsigned int binStart = chargeHisto.GetNBins() - 5;
284 unsigned int humpBin = binStart;
285 double humpDensity = chargeDensity[humpBin];
286 double humpDensityError = chargeDensityError[humpBin];
288 unsigned int humpLimitLow = 0;
289 for (
unsigned int bin = humpBin - 1; bin > 1; --bin) {
290 const double dens1 = chargeDensity[bin];
291 const double dens2 = chargeDensity[bin - 1];
292 const double dens3 = chargeDensity[bin - 2];
293 const double thresh = humpDensity - thresholdFactor * humpDensityError;
294 if (dens1 < thresh && dens2 < thresh && dens3 < thresh) {
298 if (dens1 > humpDensity) {
301 humpDensityError = chargeDensityError.at(bin);
305 const double histoFactor =
309 unsigned int humpLimitHigh = 0;
310 for (
unsigned int bin = humpBin + 1; bin < binStart; ++bin) {
311 double dens1 = chargeDensity[bin];
312 double dens2 = chargeDensity[bin + 1];
313 double dens3 = chargeDensity[bin + 2];
314 double thresh = humpDensity - thresholdFactor * humpDensityError;
315 if (dens1 < thresh && dens2 < thresh && dens3 < thresh) {
322 const double chargeHumpLow = chargeHisto.GetBinCenter(humpLimitLow);
323 const double chargeHumpHigh = chargeHisto.GetBinCenter(humpLimitHigh);
328 pmtRec.GetMuonChargeFitData() = qfHump;
330 if (chargeHumpLow <= humpFit && humpFit <= chargeHumpHigh &&
333 chargeHumpPos = humpFit;
339 <<
"\nQuadratic fit of hump between limits "
343 <<
" failed on this charge histogram:\n";
351 const double start = chargeHumpHigh + 10;
352 const double stop = min(2 * start, 950.);
353 if (start + 10 < stop) {
355 pmtRec.GetMuonChargeSlopeFitData() = ef;
356 const double slope = (chargeHumpPos - base) * histoFactor * ef.
GetSlope();
358 muChargeSlope = slope;
367 if (chargeHumpPos && humpLimitLow > 0) {
368 unsigned int dipBin = humpLimitLow - 1;
369 double dipDensity = chargeDensity.at(dipBin);
370 double dipDensityError = chargeDensityError.at(dipBin);
372 unsigned int dipLimitLow = 0;
373 for (
unsigned int bin = dipBin - 1; bin > 1; --bin) {
374 double dens1 = chargeDensity[bin];
375 double dens2 = chargeDensity[bin - 1];
376 double dens3 = chargeDensity[bin - 2];
377 double thresh = dipDensity + thresholdFactor * dipDensityError;
378 if (dens1 > thresh && dens2 > thresh && dens3 > thresh) {
382 if (dens1 < dipDensity) {
385 dipDensityError = chargeDensityError[bin];
390 unsigned int dipLimitHigh = 0;
391 for (
unsigned int bin = dipBin + 1; bin < humpBin; ++bin) {
392 double dens1 = chargeDensity[bin];
393 double dens2 = chargeDensity[bin + 1];
394 double dens3 = chargeDensity[bin + 2];
395 double thresh = dipDensity + thresholdFactor * dipDensityError;
396 if (dens1 > thresh && dens2 > thresh && dens3 > thresh) {
399 chargeDipPos = chargeHisto.GetBinCenter(dipBin);
405 const double chargeDipLow = chargeHisto.GetBinCenter(dipLimitLow);
406 const double chargeDipHigh = chargeHisto.GetBinCenter(dipLimitHigh);
408 if ((dipLimitHigh - dipLimitLow) > 10) {
413 if (chargeDipLow <= dipFit && dipFit <= chargeDipHigh &&
416 chargeDipPos = dipFit;
420 "\nQuadratic fit of dip between limits "
421 << chargeDipLow <<
" and " << chargeDipHigh
422 <<
" failed on this charge histogram:\n";
430 if (chargeHumpPos && chargeDipPos) {
431 if (chargeHumpPos / chargeDipPos > 1.3) {
432 vemCharge = (chargeHumpPos - base) * histoFactor;
433 vemChargeErr = chargeHumpPosError * histoFactor;
434 pmtRec.SetHistogramVEMCharge(vemCharge, vemChargeErr);
435 vemChargeFromHisto =
true;
446 if (!vemChargeFromHisto &&
452 pmtCalibData.SetIsTubeOk(
false);
454 pmtRec.SetVEMCharge(vemCharge, vemChargeErr);
455 pmtRec.SetIsVEMChargeFromHistogram(vemChargeFromHisto);
456 pmtRec.SetMuonChargeSlope(muChargeSlope);
460 double muDecayTime = 0;
461 double muDecayTimeErr = 0;
462 if (calibVersion > 8) {
464 const auto& muShapeHisto = pmtCalibData.GetMuonShapeHisto();
465 if (muShapeHisto.empty()) {
467 WARNING(
"According to the LS calibration version there should be a muon shape histogram... "
468 "Will not tell you again!");
472 if (!muShapeHisto.empty()) {
477 const auto& shapeHistoBinning = dStation.GetMuonShapeHistogramBinning(calibVersion);
478 const double subtract = muShapeHisto[0];
481 fShapeFitRangeBefore12 :
482 fShapeFitRangeSince12)).GetFit(ef, subtract);
483 pmtRec.GetMuonShapeFitData() = ef;
489 const double decayTime = -1 / slope;
490 if (0 <= decayTime && decayTime < 1000*
nanosecond) {
491 muDecayTime = decayTime;
492 muDecayTimeErr = slopeErr /
Sqr(slope);
501 pmtRec.SetMuonPulseDecayTime(muDecayTime, muDecayTimeErr);
508 SdHistogramFitter::CopySmallPMTCalibData(
Station& station)
512 if (!spmtData.HasCalibData())
517 if (!spmtCalib.IsTubeOk())
522 if (!pmt.HasCalibData())
527 if (!pmtCalib.IsTubeOk())
530 if (!pmt.HasRecData())
532 auto& pmtRec = pmt.GetRecData();
534 const double spmtVemCharge = 1 / (spmtCalib.GetBeta() * spmtCalib.GetCorrectionFactor());
535 const double spmtVemChargeErr =
536 (spmtCalib.GetBetaError() * spmtCalib.GetCorrectionFactor()) *
Sqr(spmtVemCharge);
538 if (std::isnan(spmtVemCharge) || std::isinf(spmtVemCharge) ||
539 spmtVemCharge <= 0 || spmtVemChargeErr <= 0)
542 pmtRec.SetVEMCharge(spmtVemCharge, spmtVemChargeErr);
545 double muonAreaOverPeak = 0;
546 for (
const auto& lpmt : station.PMTsRange()) {
547 if (lpmt.HasCalibData() &&
548 lpmt.GetCalibData().IsTubeOk() &&
550 lpmt.GetRecData().GetVEMPeak() > 0) {
551 const auto& lpmtRec = lpmt.GetRecData();
552 muonAreaOverPeak += lpmtRec.GetVEMCharge() / lpmtRec.GetVEMPeak();
555 if (muonAreaOverPeak > 0)
556 pmtRec.SetVEMPeak(spmtVemCharge / muonAreaOverPeak, 0);
559 warn <<
"Station " << station.
GetId()
560 <<
": Cannot calculate properly SmallPMT VEMpeak. Using default value = 1/3";
562 pmtRec.SetVEMPeak(1./3, 0);
566 info <<
"SmallPMT calibration for station " << station.
GetId() <<
"\n"
567 <<
" beta = " << spmtCalib.GetBeta() <<
" +- " << spmtCalib.GetBetaError()
568 <<
" ---> VEMcharge = " << pmtRec.GetVEMCharge() <<
" +- " << pmtRec.GetVEMChargeError()
569 <<
" (VEMpeak = " << pmtRec.GetVEMPeak() <<
")";
572 pmtRec.SetIsVEMChargeFromHistogram(
false);
573 pmtRec.SetIsVEMPeakFromHistogram(
false);
575 pmtRec.SetMuonChargeSlope(0);
576 pmtRec.SetMuonPulseDecayTime(0, 0);
577 pmtRec.SetGainRatio(1);
int GetId() const
Get the station Id.
constexpr T Sqr(const T &x)
Holds result of the quadratic fit.
PMTCalibData & GetCalibData()
Get object containing PMT calibration data.
double GetExtremePositionError() const
#define INFO(message)
Macro for logging informational messages.
void Init()
Initialise the registry.
Branch GetChild(const std::string &childName) const
Get child of this Branch by child name.
Exception for reporting variable out of valid range.
SmallPMTCalibData & GetCalibData()
oss<< "0b";oss<< ((x >> i)&1);return oss.str();}template< class S, class V > std::string Join(const S &sep, const V &v)
class to hold data at Station level
ExponentialFitter< Histogram > MakeExponentialFitter(const Histogram &histogram, const T &start, const T &stop)
constexpr double nanosecond
double abs(const SVector< n, T > &v)
SmallPMTData & GetSmallPMTData()
#define WARNING(message)
Macro for logging warning messages.
QuadraticFitter< Histogram, ErrorPolicy > MakeQuadraticFitter(const Histogram &h, const ErrorPolicy)
void GetData(bool &b) const
Overloads of the GetData member template function.
sevt::StationCalibData & GetCalibData()
Get calibration data for the station.
double GetCoefficient(unsigned int i) const
ResultFlag
Flag returned by module methods to the RunController.
static CentralConfig * GetInstance()
Use this the first time you get an instance of central configuration.
double GetExtremePosition() const
int GetVersion() const
version of the onboard calibration
bool IsInRange(const double x, const vector< double > &r)
double GetSlopeError() const
const std::string & GetMessage() const
Retrieve the message from the exception.
utl::Branch GetTopBranch(const std::string &id)
Get top branch for moduleConfigLink with given id (XML files)