Skip to content

Commit 5a496c9

Browse files
authored
[EMCAL-565] Add cut on pre and post trigger pile-up (#13018)
- The EMCal QC observed a few runs with cells, which have a significant contribution of pre-trigger pile-up. These come from FECs that loose the correct timeing signal during a run and then fire too early or too late, resulting in a second peak - A new cut is introduced that calculates the fraction of pre trigger (-500 - -25ns before the main time peak) and post trigger (25 - 500ns) after the main timing peak - The distribution of this post and pre-trigger pile-up fraction is then used to calculate the mean and sigma. - The cut is chosen quite loose (defined in the CalibParams) in order to only capture the extreme cases
1 parent 3fe2068 commit 5a496c9

File tree

3 files changed

+65
-9
lines changed

3 files changed

+65
-9
lines changed

Common/Utils/include/CommonUtils/BoostHistogramUtils.h

Lines changed: 23 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -714,6 +714,29 @@ auto ReduceBoostHistoFastSliceByValue(boost::histogram::histogram<axes...>& hist
714714
return ReduceBoostHistoFastSlice(hist2d, binXLow, binXHigh, binYLow, binYHigh, includeOverflowUnderflow);
715715
}
716716

717+
/// \brief Function to integrate 1d boost histogram in specified range
718+
/// \param hist 1d boost histogram
719+
/// \param min lower integration range
720+
/// \param max upper integration range
721+
/// \return sum of bin contents in specified range
722+
template <typename... axes>
723+
double getIntegralBoostHist(boost::histogram::histogram<axes...>& hist, double min, double max)
724+
{
725+
// find bins for min and max values
726+
std::array<int, 2> axisLimitsIndex = {hist.axis(0).index(min), hist.axis(0).index(max)};
727+
// over/underflow bin have to be protected
728+
for (auto& bin : axisLimitsIndex) {
729+
if (bin < 0) {
730+
bin = 0;
731+
} else if (bin >= hist.axis(0).size()) {
732+
bin = hist.axis(0).size() - 1;
733+
}
734+
}
735+
// Reduce histogram to desired range
736+
auto slicedHist = ReduceBoostHistoFastSlice1D(hist, axisLimitsIndex[0], axisLimitsIndex[1], false);
737+
return boost::histogram::algorithm::sum(slicedHist);
738+
}
739+
717740
} // namespace utils
718741
} // end namespace o2
719742

Detectors/EMCAL/calibration/include/EMCALCalibration/EMCALCalibExtractor.h

Lines changed: 40 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -58,8 +58,12 @@ class EMCALCalibExtractor
5858
};
5959

6060
struct BadChannelCalibTimeInfo {
61-
std::array<double, 17664> sigmaCell; // sigma value of time distribution for single cells
62-
double goodCellWindow; // cut value for good cells
61+
std::array<double, 17664> sigmaCell; // sigma value of time distribution for single cells
62+
double goodCellWindow; // cut value for good cells
63+
std::array<double, 17664> fracHitsPreTrigg; // fraction of hits before the main time peak (pre-trigger pile-up)
64+
double goodCellWindowFracHitsPreTrigg; // cut value for good cells for pre-trigger pile-up
65+
std::array<double, 17664> fracHitsPostTrigg; // fraction of hits after the main time peak (post-trigger pile-up)
66+
double goodCellWindowFracHitsPostTrigg; // cut value for good cells for post-trigger pile-up
6367
};
6468

6569
public:
@@ -191,6 +195,12 @@ class EMCALCalibExtractor
191195
if (calibrationTimeInfo.sigmaCell[cellID] > calibrationTimeInfo.goodCellWindow) {
192196
LOG(debug) << "Cell " << cellID << " is flagged due to time distribution";
193197
failed = true;
198+
} else if (calibrationTimeInfo.fracHitsPreTrigg[cellID] > calibrationTimeInfo.goodCellWindowFracHitsPreTrigg) {
199+
LOG(debug) << "Cell " << cellID << " is flagged due to time distribution (pre-trigger)";
200+
failed = true;
201+
} else if (calibrationTimeInfo.fracHitsPostTrigg[cellID] > calibrationTimeInfo.goodCellWindowFracHitsPostTrigg) {
202+
LOG(debug) << "Cell " << cellID << " is flagged due to time distribution (post-trigger)";
203+
failed = true;
194204
}
195205
}
196206
}
@@ -321,7 +331,7 @@ class EMCALCalibExtractor
321331
template <typename... axes>
322332
BadChannelCalibTimeInfo buildTimeMeanAndSigma(const boost::histogram::histogram<axes...>& histCellTime)
323333
{
324-
std::array<double, 17664> meanSigma;
334+
BadChannelCalibTimeInfo timeInfo;
325335
for (int i = 0; i < mNcells; ++i) {
326336
// calculate sigma per cell
327337
const int indexLow = histCellTime.axis(1).index(i);
@@ -333,24 +343,45 @@ class EMCALCalibExtractor
333343
maxElementIndex = 0;
334344
}
335345
float maxElementCenter = 0.5 * (boostHistCellSlice.axis(0).bin(maxElementIndex).upper() + boostHistCellSlice.axis(0).bin(maxElementIndex).lower());
336-
meanSigma[i] = std::sqrt(o2::utils::getVarianceBoost1D(boostHistCellSlice, -999999, maxElementCenter - 50, maxElementCenter + 50));
346+
timeInfo.sigmaCell[i] = std::sqrt(o2::utils::getVarianceBoost1D(boostHistCellSlice, -999999, maxElementCenter - 50, maxElementCenter + 50));
347+
348+
// get number of hits within mean+-25ns (trigger bunch), from -500ns to -25ns before trigger bunch (pre-trigger), and for 25ns to 500ns (post-trigger)
349+
double sumTrigg = o2::utils::getIntegralBoostHist(boostHistCellSlice, maxElementCenter - 25, maxElementCenter + 25);
350+
double sumPreTrigg = o2::utils::getIntegralBoostHist(boostHistCellSlice, maxElementCenter - 500, maxElementCenter - 25);
351+
double sumPostTrigg = o2::utils::getIntegralBoostHist(boostHistCellSlice, maxElementCenter + 25, maxElementCenter + 500);
352+
353+
// calculate fraction of hits of post and pre-trigger to main trigger bunch
354+
timeInfo.fracHitsPreTrigg[i] = sumTrigg == 0 ? 0. : sumPreTrigg / sumTrigg;
355+
timeInfo.fracHitsPostTrigg[i] = sumTrigg == 0 ? 0. : sumPostTrigg / sumTrigg;
337356
}
338357

339358
// get the mean sigma and the std. deviation of the sigma distribution
340359
// those will be the values we cut on
341360
double avMean = 0, avSigma = 0;
342361
TRobustEstimator robustEstimator;
343-
robustEstimator.EvaluateUni(meanSigma.size(), meanSigma.data(), avMean, avSigma, 0.5 * meanSigma.size());
362+
robustEstimator.EvaluateUni(timeInfo.sigmaCell.size(), timeInfo.sigmaCell.data(), avMean, avSigma, 0.5 * timeInfo.sigmaCell.size());
344363
// protection for the following case: For low statistics cases, it can happen that more than half of the cells is in one bin
345364
// in that case the sigma will be close to zero. In that case, we take 95% of the data to calculate the truncated mean
346365
if (std::abs(avMean) < 0.001 && std::abs(avSigma) < 0.001) {
347-
robustEstimator.EvaluateUni(meanSigma.size(), meanSigma.data(), avMean, avSigma, 0.95 * meanSigma.size());
366+
robustEstimator.EvaluateUni(timeInfo.sigmaCell.size(), timeInfo.sigmaCell.data(), avMean, avSigma, 0.95 * timeInfo.sigmaCell.size());
348367
}
349-
350-
BadChannelCalibTimeInfo timeInfo;
351-
timeInfo.sigmaCell = meanSigma;
368+
// timeInfo.sigmaCell = meanSigma;
352369
timeInfo.goodCellWindow = avMean + (avSigma * o2::emcal::EMCALCalibParams::Instance().sigmaTime_bc); // only upper limit needed
353370

371+
double avMeanPre = 0, avSigmaPre = 0;
372+
robustEstimator.EvaluateUni(timeInfo.fracHitsPreTrigg.size(), timeInfo.fracHitsPreTrigg.data(), avMeanPre, avSigmaPre, 0.5 * timeInfo.fracHitsPreTrigg.size());
373+
if (std::abs(avMeanPre) < 0.001 && std::abs(avSigmaPre) < 0.001) {
374+
robustEstimator.EvaluateUni(timeInfo.fracHitsPreTrigg.size(), timeInfo.fracHitsPreTrigg.data(), avMeanPre, avSigmaPre, 0.95 * timeInfo.fracHitsPreTrigg.size());
375+
}
376+
timeInfo.goodCellWindowFracHitsPreTrigg = avMeanPre + (avSigmaPre * o2::emcal::EMCALCalibParams::Instance().sigmaTimePreTrigg_bc); // only upper limit needed
377+
378+
double avMeanPost = 0, avSigmaPost = 0;
379+
robustEstimator.EvaluateUni(timeInfo.fracHitsPostTrigg.size(), timeInfo.fracHitsPostTrigg.data(), avMeanPost, avSigmaPost, 0.5 * timeInfo.fracHitsPostTrigg.size());
380+
if (std::abs(avMeanPost) < 0.001 && std::abs(avSigmaPost) < 0.001) {
381+
robustEstimator.EvaluateUni(timeInfo.fracHitsPostTrigg.size(), timeInfo.fracHitsPostTrigg.data(), avMeanPost, avSigmaPost, 0.95 * timeInfo.fracHitsPostTrigg.size());
382+
}
383+
timeInfo.goodCellWindowFracHitsPostTrigg = avMeanPost + (avSigmaPost * o2::emcal::EMCALCalibParams::Instance().sigmaTimePostTrigg_bc); // only upper limit needed
384+
354385
return timeInfo;
355386
}
356387

Detectors/EMCAL/calibration/include/EMCALCalibration/EMCALCalibParams.h

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -43,6 +43,8 @@ struct EMCALCalibParams : public o2::conf::ConfigurableParamHelper<EMCALCalibPar
4343
float rangeTimeAxisHigh_bc = 500; ///< maximum value of time for histogram range
4444
float minCellEnergyTime_bc = 0.1; ///< minimum energy needed to fill the time histogram
4545
float sigmaTime_bc = 5; ///< sigma value for the upper cut on the time-variance distribution
46+
float sigmaTimePreTrigg_bc = 10.; ///< sigma value for the upper cut on the fraction of cells in the pre-trigger region
47+
float sigmaTimePostTrigg_bc = 10.; ///< sigma value for the upper cut on the fraction of cells in the post-trigger region
4648
unsigned int slotLength_bc = 0; ///< Lenght of the slot before calibration is triggered. If set to 0 calibration is triggered when hasEnoughData returns true
4749
bool UpdateAtEndOfRunOnly_bc = false; ///< switch to enable trigger of calibration only at end of run
4850
float minNHitsForMeanEnergyCut = 100; ///< mean number of hits per cell that is needed to cut on the mean energy per hit. Needed for high energy intervals as outliers can distort the distribution

0 commit comments

Comments
 (0)