Project
Loading...
Searching...
No Matches
EMCALCalibExtractor.h
Go to the documentation of this file.
1// Copyright 2019-2020 CERN and copyright holders of ALICE O2.
2// See https://alice-o2.web.cern.ch/copyright for details of the copyright holders.
3// All rights not expressly granted are reserved.
4//
5// This software is distributed under the terms of the GNU General Public
6// License v3 (GPL Version 3), copied verbatim in the file "COPYING".
7//
8// In applying this license CERN does not waive the privileges and immunities
9// granted to it by virtue of its status as an Intergovernmental Organization
10// or submit itself to any jurisdiction.
11
17
18#ifndef EMCALCALIBEXTRACTOR_H_
19#define EMCALCALIBEXTRACTOR_H_
20
21#include <algorithm>
22#include <cmath>
23#include <iostream>
30#include "EMCALBase/Geometry.h"
32#include "EMCALCalib/Pedestal.h"
34#include <boost/histogram.hpp>
35
36#include <TRobustEstimator.h>
37#include <TProfile.h>
38
39#if (defined(WITH_OPENMP) && !defined(__CLING__))
40#include <omp.h>
41#endif
42
43namespace o2
44{
45namespace emcal
46{
47using boostHisto = boost::histogram::histogram<std::tuple<boost::histogram::axis::regular<double, boost::use_default, boost::use_default, boost::use_default>, boost::histogram::axis::integer<>>, boost::histogram::unlimited_storage<std::allocator<char>>>;
49{
50 using slice_t = int;
51 using cell_t = int;
52
54 struct BadChannelCalibInfo {
55 std::map<slice_t, std::array<double, 17664>> energyPerHitMap; // energy/per hit per cell per slice
56 std::map<slice_t, std::array<double, 17664>> nHitsMap; // number of hits per cell per slice
57 std::map<slice_t, std::pair<double, double>> goodCellWindowMap; // for each slice, the emin and the emax of the good cell window
58 std::map<slice_t, std::pair<double, double>> goodCellWindowNHitsMap; // for each slice, the nHitsMin and the mHitsMax of the good cell window
59 };
60
61 struct BadChannelCalibTimeInfo {
62 std::array<double, 17664> sigmaCell; // sigma value of time distribution for single cells
63 double goodCellWindow; // cut value for good cells
64 std::array<double, 17664> fracHitsPreTrigg; // fraction of hits before the main time peak (pre-trigger pile-up)
65 double goodCellWindowFracHitsPreTrigg; // cut value for good cells for pre-trigger pile-up
66 std::array<double, 17664> fracHitsPostTrigg; // fraction of hits after the main time peak (post-trigger pile-up)
67 double goodCellWindowFracHitsPostTrigg; // cut value for good cells for post-trigger pile-up
68 };
69
70 public:
72 {
73 LOG(info) << "initialized EMCALCalibExtractor";
74 try {
75 // Try to access geometry initialized ountside
78 mGeometry = o2::emcal::Geometry::GetInstanceFromRunNumber(300000); // fallback option
79 }
80 // mNcells = mGeometry->GetNCells();
81 };
83
84 int getNsigma() const { return mSigma; }
85 void setNsigma(int ns) { mSigma = ns; }
86
87 void setNThreads(int n) { mNThreads = std::min(n, mNcells); }
88 int getNThreads() const { return mNThreads; }
89
90 void setBCMScaleFactors(EMCALChannelScaleFactors* scalefactors) { mBCMScaleFactors = scalefactors; }
91
95 boostHisto buildHitAndEnergyMeanScaled(double emin, double emax, boostHisto mCellAmplitude);
96
100 template <typename... axes>
101 o2::emcal::BadChannelMap calibrateBadChannels(const boost::histogram::histogram<axes...>& hist, const boost::histogram::histogram<axes...>& histTime = boost::histogram::make_histogram(boost::histogram::axis::variable<>{0., 1.}, boost::histogram::axis::variable<>{0., 1.}))
102 {
103 double time1 = std::chrono::duration_cast<std::chrono::nanoseconds>(std::chrono::high_resolution_clock::now().time_since_epoch()).count();
104 std::map<int, std::pair<double, double>> slices = {{0, {0.1, 0.3}}, {1, {0.3, 0.5}}, {2, {0.5, 1.0}}, {3, {1.0, 4.0}}, {4, {4.0, 39.0}}};
105
106 std::fill(std::begin(mBadCellFracSM), std::end(mBadCellFracSM), 0); // reset all fractions to 0
107 for (unsigned int i = 0; i < mBadCellFracFEC.size(); ++i) {
108 std::fill(std::begin(mBadCellFracFEC[i]), std::end(mBadCellFracFEC[i]), 0);
109 }
110
111 auto histScaled = hist;
112 if (mBCMScaleFactors) {
113 LOG(info) << "Rescaling BCM histo";
114 // rescale the histogram
115 for (int icell = 0; icell < 17644; icell++) {
116 for (int ebin = 0; ebin < hist.axis(0).size(); ebin++) {
117 double lowerE = hist.axis(0).bin(ebin).lower();
118 double upperE = hist.axis(0).bin(ebin).upper();
119 double midE = (lowerE + upperE) / 2.;
120 histScaled.at(ebin, icell) = hist.at(ebin, icell) / mBCMScaleFactors->getScaleVal(icell, midE);
121 }
122 }
123 }
124
125 // get all ofthe calibration information that we need in a struct
126 BadChannelCalibInfo calibrationInformation = buildHitAndEnergyMean(slices, histScaled);
127
128 // only initialize this if the histo is not the default one
129 const bool doIncludeTime = (histTime.axis(0).size() > 1 && EMCALCalibParams::Instance().useTimeInfoForCalib_bc) ? true : false;
130 BadChannelCalibTimeInfo calibrationTimeInfo;
131 if (doIncludeTime) {
132 calibrationTimeInfo = buildTimeMeanAndSigma(histTime);
133 }
134
135 o2::emcal::BadChannelMap mOutputBCM;
136 // now loop through the cells and determine the mask for a given cell
137
138#if (defined(WITH_OPENMP) && !defined(__CLING__))
139 if (mNThreads < 1) {
140 mNThreads = std::min(omp_get_max_threads(), mNcells);
141 }
142 LOG(info) << "Number of threads that will be used = " << mNThreads;
143#pragma omp parallel for num_threads(mNThreads)
144#else
145 LOG(info) << "OPEN MP will not be used for the bad channel calibration";
146 mNThreads = 1;
147#endif
148
149 for (int cellID = 0; cellID < mNcells; cellID++) {
150 LOG(debug) << "analysing cell " << cellID;
151 if (calibrationInformation.energyPerHitMap[0][cellID] == 0) {
152 LOG(debug) << "Cell " << cellID << " is dead.";
154 mBadCellFracSM[mGeometry->GetSuperModuleNumber(cellID)] += 1;
155 mBadCellFracFEC[mGeometry->GetSuperModuleNumber(cellID)][getFECNumberInSM(cellID)] += 1;
156 } else {
157 bool failed = false;
158 for (auto& [sliceIndex, slice] : slices) {
159 auto ranges = calibrationInformation.goodCellWindowMap[sliceIndex];
160 auto rangesNHits = calibrationInformation.goodCellWindowNHitsMap[sliceIndex];
161 auto meanPerCell = calibrationInformation.energyPerHitMap[sliceIndex][cellID];
162 auto meanPerCellNHits = calibrationInformation.nHitsMap[sliceIndex][cellID];
163 LOG(debug) << "Energy Per Hit: Mean per cell is " << meanPerCell << " Good Cell Window: [ " << ranges.first << " , " << ranges.second << " ]";
164 LOG(debug) << "NHits: Mean per cell is " << meanPerCellNHits << " Good Cell Window: [ " << rangesNHits.first << " , " << rangesNHits.second << " ]";
165
166 // for the cut on the mean number of hits we require at least 2 hits on average
167 double meanNHits = 0.5 * (rangesNHits.first + rangesNHits.second);
168 if (meanNHits < EMCALCalibParams::Instance().minNHitsForNHitCut || (std::abs(ranges.first) < 0.001 && std::abs(ranges.second) < 0.001)) {
169 LOG(debug) << "On average, only " << meanNHits << " found in energy interval [" << slice.first << " - " << slice.second << "]. Will do untight cut on upper limit";
170 if (meanPerCellNHits > EMCALCalibParams::Instance().minNHitsForNHitCut * 10) {
171 LOG(debug) << "********* FAILED for number of hits **********";
172 failed = true;
173 break;
174 }
175 // Case were enough statistics is present
176 } else if (meanPerCellNHits < rangesNHits.first || meanPerCellNHits > rangesNHits.second) {
177 LOG(debug) << "********* FAILED for mean NHits **********";
178 failed = true;
179 break;
180 }
181
182 // for the cut on the mean energy per hit we require at least 100 hits, as otherwise the distribution is very instable
183 if (meanNHits > EMCALCalibParams::Instance().minNHitsForMeanEnergyCut && (meanPerCell < ranges.first || meanPerCell > ranges.second)) {
184 LOG(debug) << "********* FAILED for mean energy **********";
185 failed = true;
186 break;
187 }
188 }
189
190 // check if the cell is bad due to timing signal.
191 if (!failed && doIncludeTime) {
192 if (std::abs(calibrationTimeInfo.goodCellWindow) < 0.001) {
193 LOG(warning) << "Good cell window for time distribution is 0. Will skip the cut on time distribution";
194 } else {
195 LOG(debug) << " calibrationTimeInfo.goodCellWindow " << calibrationTimeInfo.goodCellWindow << " calibrationTimeInfo.sigmaCell[cellID] " << calibrationTimeInfo.sigmaCell[cellID];
196 if (calibrationTimeInfo.sigmaCell[cellID] > calibrationTimeInfo.goodCellWindow) {
197 LOG(debug) << "Cell " << cellID << " is flagged due to time distribution";
198 failed = true;
199 } else if (calibrationTimeInfo.fracHitsPreTrigg[cellID] > calibrationTimeInfo.goodCellWindowFracHitsPreTrigg) {
200 LOG(debug) << "Cell " << cellID << " is flagged due to time distribution (pre-trigger)";
201 failed = true;
202 } else if (calibrationTimeInfo.fracHitsPostTrigg[cellID] > calibrationTimeInfo.goodCellWindowFracHitsPostTrigg) {
203 LOG(debug) << "Cell " << cellID << " is flagged due to time distribution (post-trigger)";
204 failed = true;
205 }
206 }
207 }
208
209 if (failed) {
210 LOG(debug) << "Cell " << cellID << " is bad.";
212 mBadCellFracSM[mGeometry->GetSuperModuleNumber(cellID)] += 1;
213 mBadCellFracFEC[mGeometry->GetSuperModuleNumber(cellID)][getFECNumberInSM(cellID)] += 1;
214 } else {
215 LOG(debug) << "Cell " << cellID << " is good.";
217 }
218 }
219 }
220
221 // Check if the fraction of bad+dead cells in a SM is above a certain threshold
222 // If yes, mask the whole SM
223 if (EMCALCalibParams::Instance().fracMaskSMFully_bc < 1) {
224 checkMaskSM(mOutputBCM);
225 }
226 // Same as above for FECs
227 if (EMCALCalibParams::Instance().fracMaskFECFully_bc < 1) {
228 checkMaskFEC(mOutputBCM);
229 }
230
231 double time2 = std::chrono::duration_cast<std::chrono::nanoseconds>(std::chrono::high_resolution_clock::now().time_since_epoch()).count();
232 double diffTransfer = time2 - time1;
233 LOG(info) << "Total time" << diffTransfer << " ns";
234
235 return mOutputBCM;
236 }
237
238 //___________________________________________________________________________________________________
244 template <typename... axes>
245 BadChannelCalibInfo buildHitAndEnergyMean(std::map<slice_t, std::pair<double, double>> sliceMap, boost::histogram::histogram<axes...>& cellAmplitude)
246 {
247 // create the output histo
248 BadChannelCalibInfo outputInfo;
249 std::map<slice_t, std::array<double, mNcells>> outputMapEnergyPerHit;
250 std::map<slice_t, std::array<double, mNcells>> outputMapNHits;
251 // initialize the output maps with 0
252 for (const auto& [sliceIndex, sliceLimits] : sliceMap) {
253 std::array<double, mNcells> energyPerHit, nHits;
254 std::fill(energyPerHit.begin(), energyPerHit.end(), 0.);
255 std::fill(nHits.begin(), nHits.end(), 0.);
256 outputMapEnergyPerHit[sliceIndex] = energyPerHit;
257 outputMapNHits[sliceIndex] = nHits;
258 }
259#if (defined(WITH_OPENMP) && !defined(__CLING__))
260 if (mNThreads < 1) {
261 mNThreads = std::min(omp_get_max_threads(), mNcells);
262 }
263 LOG(info) << "Number of threads that will be used = " << mNThreads;
264#pragma omp parallel for num_threads(mNThreads)
265#else
266 LOG(info) << "OPEN MP will not be used for the bad channel calibration";
267 mNThreads = 1;
268#endif
269 for (int cellID = 0; cellID < mNcells; cellID++) {
270 int binCellID = cellAmplitude.axis(1).index(cellID);
271 auto projectedSlice = o2::utils::ProjectBoostHistoXFast(cellAmplitude, binCellID, binCellID + 1);
272 auto projectedSum = boost::histogram::algorithm::sum(projectedSlice);
273 if (projectedSum == 0) {
274 continue; // check before loop if the cell is dead
275 }
276 for (const auto& [sliceIndex, slice] : sliceMap) {
277 double emin = slice.first;
278 double emax = slice.second;
279 int binXLowSlice = cellAmplitude.axis(0).index(emin);
280 int binXHighSlice = cellAmplitude.axis(0).index(emax);
281 auto slicedHist = o2::utils::ReduceBoostHistoFastSlice1D(projectedSlice, binXLowSlice, binXHighSlice, false);
282 double meanVal = o2::utils::getMeanBoost1D(slicedHist);
283 double sumVal = boost::histogram::algorithm::sum(slicedHist);
284 if (sumVal > 0.) {
285 // fill the output map with the desired slicing etc.
286 outputMapEnergyPerHit[sliceIndex][cellID] = meanVal;
287 outputMapNHits[sliceIndex][cellID] = sumVal;
288 }
289 } // end loop over the slices
290 } // end loop over the cells
291 for (const auto& [sliceIndex, slice] : sliceMap) {
292 Double_t meanPerSlice = 0.0; // mean energy per slice to be compared to the cell
293 Double_t sigmaPerSlice = 0.0; // sigma energy per slice to be compared to the cell
294 TRobustEstimator robustEstimator;
295 auto& means = outputMapEnergyPerHit[sliceIndex];
296 robustEstimator.EvaluateUni(means.size(), means.data(), meanPerSlice, sigmaPerSlice, 0);
297 if (std::abs(meanPerSlice) < 0.001 && std::abs(sigmaPerSlice) < 0.001) {
298 robustEstimator.EvaluateUni(means.size(), means.data(), meanPerSlice, sigmaPerSlice, means.size() * 0.95);
299 }
300
301 Double_t meanPerSlice_NHits = 0.0; // mean energy per slice to be compared to the cell
302 Double_t sigmaPerSlice_NHits = 0.0; // sigma energy per slice to be compared to the cell
303 TRobustEstimator robustEstimatorNHits;
304 auto& meansNHits = outputMapNHits[sliceIndex];
305 robustEstimatorNHits.EvaluateUni(meansNHits.size(), meansNHits.data(), meanPerSlice_NHits, sigmaPerSlice_NHits, 0);
306 if (std::abs(meanPerSlice_NHits) < 0.001 && std::abs(sigmaPerSlice_NHits) < 0.001) {
307 robustEstimator.EvaluateUni(meansNHits.size(), meansNHits.data(), meanPerSlice_NHits, sigmaPerSlice_NHits, meansNHits.size() * 0.95);
308 }
309
310 LOG(debug) << "Energy Per hit: Mean per slice is: " << meanPerSlice << " Sigma Per Slice: " << sigmaPerSlice << " with size " << outputMapEnergyPerHit[sliceIndex].size();
311 LOG(debug) << "NHits: Mean per slice is: " << meanPerSlice_NHits << " Sigma Per Slice: " << sigmaPerSlice_NHits << " with size " << outputMapNHits[sliceIndex].size();
312 // calculate the "good cell window from the mean"
313 double maxVal = meanPerSlice + mSigma * sigmaPerSlice;
314 double minVal = meanPerSlice - mSigma * sigmaPerSlice;
315 double maxValNHits = meanPerSlice_NHits + mSigma * sigmaPerSlice_NHits;
316 double minValNHits = meanPerSlice_NHits - mSigma * sigmaPerSlice_NHits;
317 // store in the output maps
318 outputInfo.goodCellWindowMap[sliceIndex] = {minVal, maxVal};
319 outputInfo.goodCellWindowNHitsMap[sliceIndex] = {minValNHits, maxValNHits};
320 }
321 // now add these to the calib info struct
322 outputInfo.energyPerHitMap = outputMapEnergyPerHit;
323 outputInfo.nHitsMap = outputMapNHits;
324
325 return outputInfo;
326 }
327
328 //____________________________________________
332 template <typename... axes>
333 BadChannelCalibTimeInfo buildTimeMeanAndSigma(const boost::histogram::histogram<axes...>& histCellTime)
334 {
335 BadChannelCalibTimeInfo timeInfo;
336 for (int i = 0; i < mNcells; ++i) {
337 // calculate sigma per cell
338 const int indexLow = histCellTime.axis(1).index(i);
339 const int indexHigh = histCellTime.axis(1).index(i + 1);
340 auto boostHistCellSlice = o2::utils::ProjectBoostHistoXFast(histCellTime, indexLow, indexHigh);
341
342 int maxElementIndex = std::max_element(boostHistCellSlice.begin(), boostHistCellSlice.end()) - boostHistCellSlice.begin() - 1;
343 if (maxElementIndex < 0) {
344 maxElementIndex = 0;
345 }
346 float maxElementCenter = 0.5 * (boostHistCellSlice.axis(0).bin(maxElementIndex).upper() + boostHistCellSlice.axis(0).bin(maxElementIndex).lower());
347 timeInfo.sigmaCell[i] = std::sqrt(o2::utils::getVarianceBoost1D(boostHistCellSlice, -999999, maxElementCenter - 50, maxElementCenter + 50));
348
349 // 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)
350 double sumTrigg = o2::utils::getIntegralBoostHist(boostHistCellSlice, maxElementCenter - 25, maxElementCenter + 25);
351 double sumPreTrigg = o2::utils::getIntegralBoostHist(boostHistCellSlice, maxElementCenter - 500, maxElementCenter - 25);
352 double sumPostTrigg = o2::utils::getIntegralBoostHist(boostHistCellSlice, maxElementCenter + 25, maxElementCenter + 500);
353
354 // calculate fraction of hits of post and pre-trigger to main trigger bunch
355 timeInfo.fracHitsPreTrigg[i] = sumTrigg == 0 ? 0. : sumPreTrigg / sumTrigg;
356 timeInfo.fracHitsPostTrigg[i] = sumTrigg == 0 ? 0. : sumPostTrigg / sumTrigg;
357 }
358
359 // get the mean sigma and the std. deviation of the sigma distribution
360 // those will be the values we cut on
361 double avMean = 0, avSigma = 0;
362 TRobustEstimator robustEstimator;
363 robustEstimator.EvaluateUni(timeInfo.sigmaCell.size(), timeInfo.sigmaCell.data(), avMean, avSigma, 0.5 * timeInfo.sigmaCell.size());
364 // protection for the following case: For low statistics cases, it can happen that more than half of the cells is in one bin
365 // in that case the sigma will be close to zero. In that case, we take 95% of the data to calculate the truncated mean
366 if (std::abs(avMean) < 0.001 && std::abs(avSigma) < 0.001) {
367 robustEstimator.EvaluateUni(timeInfo.sigmaCell.size(), timeInfo.sigmaCell.data(), avMean, avSigma, 0.95 * timeInfo.sigmaCell.size());
368 }
369 // timeInfo.sigmaCell = meanSigma;
370 timeInfo.goodCellWindow = avMean + (avSigma * o2::emcal::EMCALCalibParams::Instance().sigmaTime_bc); // only upper limit needed
371
372 double avMeanPre = 0, avSigmaPre = 0;
373 robustEstimator.EvaluateUni(timeInfo.fracHitsPreTrigg.size(), timeInfo.fracHitsPreTrigg.data(), avMeanPre, avSigmaPre, 0.5 * timeInfo.fracHitsPreTrigg.size());
374 if (std::abs(avMeanPre) < 0.001 && std::abs(avSigmaPre) < 0.001) {
375 robustEstimator.EvaluateUni(timeInfo.fracHitsPreTrigg.size(), timeInfo.fracHitsPreTrigg.data(), avMeanPre, avSigmaPre, 0.95 * timeInfo.fracHitsPreTrigg.size());
376 }
377 timeInfo.goodCellWindowFracHitsPreTrigg = avMeanPre + (avSigmaPre * o2::emcal::EMCALCalibParams::Instance().sigmaTimePreTrigg_bc); // only upper limit needed
378
379 double avMeanPost = 0, avSigmaPost = 0;
380 robustEstimator.EvaluateUni(timeInfo.fracHitsPostTrigg.size(), timeInfo.fracHitsPostTrigg.data(), avMeanPost, avSigmaPost, 0.5 * timeInfo.fracHitsPostTrigg.size());
381 if (std::abs(avMeanPost) < 0.001 && std::abs(avSigmaPost) < 0.001) {
382 robustEstimator.EvaluateUni(timeInfo.fracHitsPostTrigg.size(), timeInfo.fracHitsPostTrigg.data(), avMeanPost, avSigmaPost, 0.95 * timeInfo.fracHitsPostTrigg.size());
383 }
384 timeInfo.goodCellWindowFracHitsPostTrigg = avMeanPost + (avSigmaPost * o2::emcal::EMCALCalibParams::Instance().sigmaTimePostTrigg_bc); // only upper limit needed
385
386 return timeInfo;
387 }
388
389 //____________________________________________
390
396 template <typename... axes>
397 o2::emcal::TimeCalibrationParams calibrateTime(const boost::histogram::histogram<axes...>& hist, double minTime = 0, double maxTime = 1000, double restrictFitRangeToMax = 25)
398 {
399
400 auto histReduced = boost::histogram::algorithm::reduce(hist, boost::histogram::algorithm::shrink(minTime, maxTime), boost::histogram::algorithm::shrink(0, mNcells));
401
403
404 double mean = 0;
405
406 // #if (defined(WITH_OPENMP) && !defined(__CLING__))
407 // if (mNThreads < 1) {
408 // mNThreads = std::min(omp_get_max_threads(), mNcells);
409 // }
410 // LOG(info) << "Number of threads that will be used = " << mNThreads;
411 // #pragma omp parallel for num_threads(mNThreads)
412 // #else
413 // LOG(info) << "OPEN MP will not be used for the time calibration";
414 // mNThreads = 1;
415 // #endif
416
417 for (unsigned int i = 0; i < mNcells; ++i) {
418 // project boost histogram to 1d just for 1 cell
419 const int indexLow = histReduced.axis(1).index(i);
420 const int indexHigh = histReduced.axis(1).index(i + 1);
421 auto boostHist1d = o2::utils::ProjectBoostHistoXFast(histReduced, indexLow, indexHigh);
422
423 LOG(debug) << "calibrate cell time " << i << " of " << mNcells;
424 int maxElementIndex = std::max_element(boostHist1d.begin(), boostHist1d.end()) - boostHist1d.begin() - 1;
425 if (maxElementIndex < 0) {
426 maxElementIndex = 0;
427 }
428 float maxElementCenter = 0.5 * (boostHist1d.axis(0).bin(maxElementIndex).upper() + boostHist1d.axis(0).bin(maxElementIndex).lower());
429 // Restrict fit range to maximum +- restrictFitRangeToMax
430 if (restrictFitRangeToMax > 0) {
431 boostHist1d = boost::histogram::algorithm::reduce(boostHist1d, boost::histogram::algorithm::shrink(maxElementCenter - restrictFitRangeToMax, maxElementCenter + restrictFitRangeToMax));
432 }
433
434 try {
435 auto fitValues = o2::utils::fitBoostHistoWithGaus<double>(boostHist1d);
436 if (maxElementCenter + EMCALCalibParams::Instance().maxAllowedDeviationFromMax < fitValues.at(1) || maxElementCenter - EMCALCalibParams::Instance().maxAllowedDeviationFromMax > fitValues.at(1)) {
437 mean = maxElementCenter;
438 } else {
439 mean = fitValues.at(1);
440 }
441 // add mean to time calib params
442 TCP.addTimeCalibParam(i, mean, false); // highGain calib factor
443 TCP.addTimeCalibParam(i, mean + EMCALCalibParams::Instance().lowGainOffset_tc, true); // lowGain calib factor
444 } catch (o2::utils::FitGausError_t err) {
445 LOG(warning) << createErrorMessageFitGaus(err) << "; for cell " << i << " (Will take the parameter of the previous cell: " << mean << "ns)";
446 TCP.addTimeCalibParam(i, mean, false); // take calib value of last cell; or 400 ns shift default value
447 TCP.addTimeCalibParam(i, mean + EMCALCalibParams::Instance().lowGainOffset_tc, true); // take calib value of last cell; or 400 ns shift default value
448 }
449 }
450 return TCP;
451 }
452
453 //____________________________________________
458 {
459 Pedestal pedestalData;
460 // loop over both low and high gain data as well as normal and LEDMON data
461 for (const auto& isLEDMON : {false, true}) {
462 auto maxChannels = isLEDMON ? mLEDMONs : mNcells;
463 for (const auto& isLG : {false, true}) {
464 for (unsigned short iCell = 0; iCell < maxChannels; ++iCell) {
465 auto [mean, rms] = obj.getValue(iCell, isLG, isLEDMON); // get mean and rms for pedestals
466 if (rms > EMCALCalibParams::Instance().maxPedestalRMS) {
467 mean = mMaxPedestalVal;
468 }
469 pedestalData.addPedestalValue(iCell, std::round(mean), isLG, isLEDMON);
470 }
471 }
472 }
473 return pedestalData;
474 }
475
476 //____________________________________________
482 Pedestal extractPedestals(TProfile* objHG = nullptr, TProfile* objLG = nullptr, bool isLEDMON = false)
483 {
484 Pedestal pedestalData;
485 auto maxChannels = isLEDMON ? mLEDMONs : mNcells;
486 // loop over both low and high gain data
487 for (const auto& isLG : {false, true}) {
488 auto obj = (isLG == true ? objLG : objHG);
489 if (!obj)
490 continue;
491 for (unsigned short iCell = 0; iCell < maxChannels; ++iCell) {
492 short mean = static_cast<short>(std::round(obj->GetBinContent(iCell + 1)));
493 short rms = static_cast<short>(obj->GetBinError(iCell + 1) / obj->GetBinEntries(iCell + 1));
494 if (rms > EMCALCalibParams::Instance().maxPedestalRMS) {
495 mean = mMaxPedestalVal;
496 }
497 pedestalData.addPedestalValue(iCell, mean, isLG, isLEDMON);
498 }
499 }
500 return pedestalData;
501 }
502
503 private:
504 //____________________________________________
507 void checkMaskSM(o2::emcal::BadChannelMap& bcm);
508
511 void checkMaskFEC(o2::emcal::BadChannelMap& bcm);
512
515 unsigned int getFECNumberInSM(int absCellID) const;
516
517 EMCALChannelScaleFactors* mBCMScaleFactors = nullptr;
518 int mSigma = 5;
519 int mNThreads = 1;
520 std::array<float, 20> mBadCellFracSM;
521 std::array<std::array<float, 36>, 20> mBadCellFracFEC;
522
523 o2::emcal::Geometry* mGeometry = nullptr;
524 static constexpr int mNcells = 17664;
525 static constexpr int mLEDMONs = 480;
526 static constexpr short mMaxPedestalVal = 1023;
527
528 ClassDefNV(EMCALCalibExtractor, 1);
529};
530
531} // namespace emcal
532} // namespace o2
533#endif
int32_t i
#define failed(...)
Definition Utils.h:42
std::ostringstream debug
CCDB container for masked cells in EMCAL.
@ DEAD_CELL
Dead cell, no data obtained.
@ BAD_CELL
Bad cell, must be excluded.
@ GOOD_CELL
GOOD cell, can be used without problems.
void addBadChannel(unsigned short channelID, MaskType_t mask)
Add bad cell to the container.
o2::emcal::BadChannelMap calibrateBadChannels(const boost::histogram::histogram< axes... > &hist, const boost::histogram::histogram< axes... > &histTime=boost::histogram::make_histogram(boost::histogram::axis::variable<>{0., 1.}, boost::histogram::axis::variable<>{0., 1.}))
Function to perform the calibration of bad channels.
BadChannelCalibTimeInfo buildTimeMeanAndSigma(const boost::histogram::histogram< axes... > &histCellTime)
calculate the sigma of the time distribution for all cells and caluclate the mean of the sigmas
Pedestal extractPedestals(PedestalProcessorData &obj)
Extract the pedestals from Stat Accumulators.
void setBCMScaleFactors(EMCALChannelScaleFactors *scalefactors)
o2::emcal::TimeCalibrationParams calibrateTime(const boost::histogram::histogram< axes... > &hist, double minTime=0, double maxTime=1000, double restrictFitRangeToMax=25)
Calibrate time for all cells.
Pedestal extractPedestals(TProfile *objHG=nullptr, TProfile *objLG=nullptr, bool isLEDMON=false)
Extract the pedestals from TProfile (for old data)
BadChannelCalibInfo buildHitAndEnergyMean(std::map< slice_t, std::pair< double, double > > sliceMap, boost::histogram::histogram< axes... > &cellAmplitude)
Average energy per hit is caluclated for each cell.
boostHisto buildHitAndEnergyMeanScaled(double emin, double emax, boostHisto mCellAmplitude)
Scaled hits per cell.
float getScaleVal(unsigned int cellID, float E) const
Error handling access to non-initialized geometry.
EMCAL geometry definition.
Definition Geometry.h:40
static Geometry * GetInstanceFromRunNumber(Int_t runNumber, const std::string_view="", const std::string_view mcname="TGeant3", const std::string_view mctitle="")
Instanciate geometry depending on the run number. Mostly used in analysis and MC anchors.
Definition Geometry.cxx:219
Int_t GetSuperModuleNumber(Int_t absId) const
Get cell SM, from absolute ID number.
static Geometry * GetInstance()
Get geometry instance. It should have been set before.
Definition Geometry.cxx:190
Exchange container between PedestalProcessorDevice and PedestalAggregatorDevice.
PedestalValue getValue(unsigned short tower, bool lowGain, bool LEDMON) const
Get mean ADC and RMS for a certain channel.
CCDB container for pedestal values.
Definition Pedestal.h:48
void addPedestalValue(unsigned short cellID, short pedestal, bool isLowGain, bool isLEDMON)
Add pedestal to the container.
Definition Pedestal.cxx:27
void addTimeCalibParam(unsigned short cellID, short time, bool isLowGain)
Add time calibration coefficients to the container.
GLdouble n
Definition glcorearb.h:1982
GLsizeiptr size
Definition glcorearb.h:659
boost::histogram::histogram< std::tuple< boost::histogram::axis::regular< double, boost::use_default, boost::use_default, boost::use_default >, boost::histogram::axis::integer<> >, boost::histogram::unlimited_storage< std::allocator< char > > > boostHisto
auto ProjectBoostHistoXFast(const boost::histogram::histogram< axes... > &hist2d, const int binLow, const int binHigh)
Function to project 2d boost histogram onto x-axis.
FitGausError_t
Error code for invalid result in the fitGaus process.
double getIntegralBoostHist(boost::histogram::histogram< axes... > &hist, double min, double max)
Function to integrate 1d boost histogram in specified range.
auto ReduceBoostHistoFastSlice1D(boost::histogram::histogram< axes... > &hist1d, int binXLow, int binXHigh, bool includeOverflowUnderflow)
double getMeanBoost1D(boost::histogram::histogram< axes... > &inHist1D, const double rangeLow=0, const double rangeHigh=0)
Get the mean of a 1D boost histogram.
double getVarianceBoost1D(boost::histogram::histogram< axes... > &inHist1D, double mean=-999999, const double rangeLow=0, const double rangeHigh=0, const double weight=1)
Get the variance of a 1D boost histogram.
a couple of static helper functions to create timestamp values for CCDB queries or override obsolete ...
LOG(info)<< "Compressed in "<< sw.CpuTime()<< " s"