Project
Loading...
Searching...
No Matches
PedestalCalibrator.cxx
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
12#include "Framework/Logger.h"
16#include "CPVBase/Geometry.h"
18#include "CCDB/CcdbApi.h"
20
21namespace o2
22{
23namespace cpv
24{
25//=======================PedestalSpectrum============================
26//___________________________________________________________________
27PedestalSpectrum::PedestalSpectrum(uint16_t toleratedGapWidth, float nSigmasZS, float suspiciousPedestalRMS)
28{
29 mToleratedGapWidth = toleratedGapWidth;
30 mZSnSigmas = nSigmasZS;
31 mSuspiciousPedestalRMS = suspiciousPedestalRMS;
32}
33//___________________________________________________________________
35{
36 mIsAnalyzed = false;
37 mNEntries += rhs.mNEntries;
38 for (auto iAmpl = rhs.mSpectrumContainer.begin(); iAmpl != rhs.mSpectrumContainer.end(); iAmpl++) {
39 mSpectrumContainer[iAmpl->first] += iAmpl->second;
40 }
41 return *this; // return the result by reference
42}
43//___________________________________________________________________
44void PedestalSpectrum::fill(uint16_t amplitude)
45{
46 mSpectrumContainer[amplitude]++;
47 mNEntries++;
48 if (mIsAnalyzed) {
49 mIsAnalyzed = false;
50 }
51}
52//___________________________________________________________________
53void PedestalSpectrum::analyze()
54{
55 if (mIsAnalyzed) {
56 return; // already analyzed, nothing to do
57 }
58
59 mNPeaks = 0;
60 if (mNEntries == 0) { // no statistics to analyze
61 mPedestalValue = 0;
62 mPedestalRMS = 0.;
63 mIsAnalyzed = true;
64 return;
65 }
66 // (A)typical amplitude spectrum from 1 channel in pedestal run
67 // ^ counts peak2
68 // | |
69 // | peak1 |
70 // | | |
71 // | | || peak3
72 // | || || |
73 // | ||| |||| |<----non-tolerated gap---->||
74 // -------------------------------------------------------------------------->
75 // 0 10 ^ 20 30 ADC amplitude
76 // tolerated gap
77 //
78 // we want to find all the peaks, determine their mean and rms
79 // and mean and rms of all the distribution
80 // pedestal is calculated from peak with most of statistics in it
81 std::vector<uint16_t> peakLowEdge, peakHighEdge;
82 peakLowEdge.push_back(mSpectrumContainer.begin()->first);
83 peakHighEdge.push_back((--mSpectrumContainer.end())->first);
84 uint32_t peakCounts(0), totalCounts(0);
85 float peakSumA(0.), peakSumA2(0.), totalSumA(0.), totalSumA2(0.);
86 mNPeaks = 0;
87
88 auto iNextAmpl = mSpectrumContainer.begin();
89 iNextAmpl++;
90 for (auto iAmpl = mSpectrumContainer.begin(); iAmpl != mSpectrumContainer.end(); iAmpl++, iNextAmpl++) {
91 peakCounts += iAmpl->second;
92 totalCounts += iAmpl->second;
93 peakSumA += iAmpl->first * iAmpl->second; // mean = sum [A_i * w_i], where A_i is ADC amplitude, w_i is weight = (binCount/totalCount)
94 peakSumA2 += (iAmpl->first * iAmpl->first) * iAmpl->second; // rms = sum [(A_i)^2 * w_i] - mean^2
95 totalSumA += iAmpl->first * iAmpl->second;
96 totalSumA2 += (iAmpl->first * iAmpl->first) * iAmpl->second;
97
98 if (iNextAmpl != mSpectrumContainer.end()) { // is iAmpl not the last bin?
99 if ((iNextAmpl->first - iAmpl->first) > mToleratedGapWidth) { // let's consider |bin1-bin2|<=5 belong to same peak
100 // firts, save peak low and high edge (just for the future cases)
101 peakHighEdge.push_back(iAmpl->first);
102 peakLowEdge.push_back(iNextAmpl->first);
103 mNPeaks++;
104 mMeanOfPeaks.push_back(peakSumA / peakCounts);
105 mRMSOfPeaks.push_back(sqrt(peakSumA2 / peakCounts - mMeanOfPeaks.back() * mMeanOfPeaks.back()));
106 mPeakCounts.push_back(peakCounts);
107 peakSumA = 0.;
108 peakSumA2 = 0.;
109 peakCounts = 0;
110 }
111 } else { // this is last bin
112 peakHighEdge.push_back(iAmpl->first);
113 mMeanOfPeaks.push_back(peakSumA / peakCounts);
114 mRMSOfPeaks.push_back(sqrt(peakSumA2 / peakCounts - mMeanOfPeaks.back() * mMeanOfPeaks.back()));
115 mPeakCounts.push_back(peakCounts);
116 mNPeaks++;
117 }
118 }
119 // last element of mPeakCounts, mMeanOfPeaks and mRMSOfPeaks is total count, mean and rms
120 mMeanOfPeaks.push_back(totalSumA / totalCounts);
121 mRMSOfPeaks.push_back(sqrt(totalSumA2 / totalCounts - mMeanOfPeaks.back() * mMeanOfPeaks.back()));
122 mPeakCounts.push_back(totalCounts);
123
124 // final decision on pedestal value and RMS
125 if (mNPeaks == 1) { // everything seems to be good
126 mPedestalValue = mMeanOfPeaks.back();
127 mPedestalRMS = mRMSOfPeaks.back();
128 } else if (mNPeaks > 1) { // there are some problems with several pedestal peaks
129 uint16_t iPeakWithMaxStat = 0;
130 for (auto i = 0; i < mNPeaks; i++) { // find peak with max statistics
131 if (mPeakCounts[iPeakWithMaxStat] < mPeakCounts[i]) {
132 iPeakWithMaxStat = i;
133 }
134 }
135 mPedestalValue = mMeanOfPeaks[iPeakWithMaxStat]; // mean of peak with max statistics
136 mPedestalRMS = mRMSOfPeaks[iPeakWithMaxStat]; // RMS of peak with max statistics
137 }
138 mIsAnalyzed = true;
139}
140//___________________________________________________________________
142{
143 if (!mIsAnalyzed) {
144 analyze();
145 }
146 return mNPeaks;
147}
148//___________________________________________________________________
149float PedestalSpectrum::getPeakMean(uint16_t iPeak)
150{
151 if (!mIsAnalyzed) {
152 analyze();
153 }
154 if (iPeak > mNPeaks) {
155 return mMeanOfPeaks.back();
156 } else {
157 return mMeanOfPeaks.at(iPeak);
158 }
159}
160//___________________________________________________________________
161float PedestalSpectrum::getPeakRMS(uint16_t iPeak)
162{
163 if (!mIsAnalyzed) {
164 analyze();
165 }
166 if (iPeak > mNPeaks) {
167 return mRMSOfPeaks.back();
168 } else {
169 return mRMSOfPeaks.at(iPeak);
170 }
171}
172//___________________________________________________________________
174{
175 if (!mIsAnalyzed) {
176 analyze();
177 }
178 return mPedestalValue;
179}
180//___________________________________________________________________
181
183{
184 if (!mIsAnalyzed) {
185 analyze();
186 }
187 return mPedestalRMS;
188}
189//___________________________________________________________________
190
191//========================PedestalCalibData==========================
192//___________________________________________________________________
193PedestalCalibData::PedestalCalibData(uint16_t toleratedGapWidth, float nSigmasZS, float suspiciousPedestalRMS)
194{
195 for (int i = 0; i < Geometry::kNCHANNELS; i++) {
196 mPedestalSpectra.emplace_back(toleratedGapWidth, nSigmasZS, suspiciousPedestalRMS);
197 }
198}
199//___________________________________________________________________
200void PedestalCalibData::fill(const gsl::span<const Digit> digits)
201{
202 for (auto& dig : digits) {
203 mPedestalSpectra[dig.getAbsId()].fill(dig.getAmplitude());
204 }
205 mNEvents++;
206}
207//___________________________________________________________________
209{
210 for (int i = 0; i < Geometry::kNCHANNELS; i++) {
212 }
213 mNEvents += prev->mNEvents;
214 LOG(info) << "Merged TimeSlot with previous one. Now we have " << mNEvents << " events.";
215}
216//___________________________________________________________________
218{
219 LOG(info) << "PedestalCalibData::mNEvents = " << mNEvents;
220}
221//___________________________________________________________________
222//=======================PedestalCalibrator==========================
223//___________________________________________________________________
225{
226 LOG(info) << "PedestalCalibrator::PedestalCalibrator() : pedestal calibrator created!";
227}
228//___________________________________________________________________
230{
231 auto& cpvParams = o2::cpv::CPVCalibParams::Instance();
232 mMinEvents = cpvParams.pedMinEvents;
233 mZSnSigmas = cpvParams.pedZSnSigmas;
234 mToleratedGapWidth = cpvParams.pedToleratedGapWidth;
235 mZSnSigmas = cpvParams.pedZSnSigmas;
236 mSuspiciousPedestalRMS = cpvParams.pedSuspiciousPedestalRMS;
237 LOG(info) << "PedestalCalibrator::configParameters() : following parameters configured:";
238 LOG(info) << "mMinEvents = " << mMinEvents;
239 LOG(info) << "mZSnSigmas = " << mZSnSigmas;
240 LOG(info) << "mToleratedGapWidth = " << mToleratedGapWidth;
241 LOG(info) << "mZSnSigmas = " << mZSnSigmas;
242 LOG(info) << "mSuspiciousPedestalRMS = " << mSuspiciousPedestalRMS;
243}
244//___________________________________________________________________
246{
247 mCcdbInfoPedestalsVec.clear();
248 mPedestalsVec.clear();
249 mCcdbInfoDeadChannelsVec.clear();
250 mDeadChannelsVec.clear();
251 mCcdbInfoHighPedChannelsVec.clear();
252 mHighPedChannelsVec.clear();
253 mCcdbInfoThresholdsFEEVec.clear();
254 mThresholdsFEEVec.clear();
255 mCcdbInfoPedEfficienciesVec.clear();
256 mPedEfficienciesVec.clear();
257}
258//___________________________________________________________________
260{
261 PedestalCalibData* calibData = slot.getContainer();
262 LOG(info) << "PedestalCalibrator::finalizeSlot() : finalizing slot "
263 << slot.getTFStart() << " <= TF <= " << slot.getTFEnd() << " with " << calibData->mNEvents << " events.";
264
265 // o2::cpv::Geometry geo; // CPV geometry object
266
267 // o2::cpv::Pedestals - calibration object used at reconstruction
268 // and efficiencies vector
269 // and dead channels list
270 // and thresholds for FEE
271 // and channels with high thresholds (> 511)
273 std::vector<float> efficiencies;
274 std::vector<int> deadChannels;
275 std::vector<int> thresholdsFEE;
276 std::vector<int> highPedChannels;
277
278 short ccId, dil, gas, pad, ped, threshold;
279 int addr, adrThr;
280 float sigma, efficiency;
281
282 for (int i = 0; i < Geometry::kNCHANNELS; i++) {
283 // Pedestals
284 ped = std::floor(calibData->mPedestalSpectra[i].getPedestalValue()) + 1;
285 sigma = calibData->mPedestalSpectra[i].getPedestalRMS();
286 peds->setPedestal(i, ped);
287 peds->setPedSigma(i, sigma);
288
289 // efficiencies
290 efficiency = 1. * calibData->mPedestalSpectra[i].getNEntries() / calibData->mNEvents;
291 efficiencies.push_back(efficiency);
292
293 // dead channels
294 if (efficiency == 0.0) {
295 deadChannels.push_back(i);
296 }
297
298 // FEE Thresholds
299 threshold = ped + std::floor(sigma * mZSnSigmas) + 1;
300 if (threshold > 511) {
301 threshold = 511; // set maximum threshold for suspisious channels
302 highPedChannels.push_back(i);
303 }
304 Geometry::absIdToHWaddress(i, ccId, dil, gas, pad);
305 addr = ccId * 4 * 5 * 64 + dil * 5 * 64 + gas * 64 + pad;
306 adrThr = (addr << 16) + threshold;
307 // to read back: addr = (adrThr >> 16); threshold = (adrThr & 0xffff)
308 thresholdsFEE.push_back(adrThr);
309 }
310
311 mPedestalsVec.push_back(*peds);
312 mPedEfficienciesVec.push_back(efficiencies);
313 mDeadChannelsVec.push_back(deadChannels);
314 mThresholdsFEEVec.push_back(thresholdsFEE);
315 mThresholdsFEEVec.push_back(thresholdsFEE); // push same FEE thresholds 2 times so one of it goes to ccdb with subspec 0 and another with subspec 1 (for normal and DCS ccdb population)
316 mHighPedChannelsVec.push_back(highPedChannels);
317
318 // metadata for o2::cpv::Pedestals
319 std::map<std::string, std::string> metaData;
320 auto className = o2::utils::MemFileHelper::getClassName(*peds);
321 auto fileName = o2::ccdb::CcdbApi::generateFileName(className);
322 auto timeStamp = o2::ccdb::getCurrentTimestamp();
323 mCcdbInfoPedestalsVec.emplace_back("CPV/Calib/Pedestals", className, fileName, metaData, timeStamp, timeStamp + 31536000000); // one year validity time (in milliseconds!)
324
325 // metadata for efficiencies
326 className = o2::utils::MemFileHelper::getClassName(efficiencies);
327 fileName = o2::ccdb::CcdbApi::generateFileName(className);
328 mCcdbInfoPedEfficienciesVec.emplace_back("CPV/PedestalRun/ChannelEfficiencies", className, fileName, metaData, timeStamp, timeStamp + 31536000000); // one year validity time (in milliseconds!)
329
330 // metadata for dead channels
331 className = o2::utils::MemFileHelper::getClassName(deadChannels);
332 fileName = o2::ccdb::CcdbApi::generateFileName(className);
333 mCcdbInfoDeadChannelsVec.emplace_back("CPV/PedestalRun/DeadChannels", className, fileName, metaData, timeStamp, timeStamp + 31536000000); // one year validity time (in milliseconds!)
334
335 // metadata for ThreasholdsVec
336 className = o2::utils::MemFileHelper::getClassName(thresholdsFEE);
337 fileName = o2::ccdb::CcdbApi::generateFileName(className);
338 mCcdbInfoThresholdsFEEVec.emplace_back("CPV/PedestalRun/FEEThresholds", className, fileName, metaData, timeStamp, timeStamp + 31536000000); // one year validity time (in milliseconds!)
339 // push same FEE thresholds 2 times so one of it goes to ccdb with subspec 0 and another with subspec 1 (for normal and DCS ccdb population)
340 mCcdbInfoThresholdsFEEVec.emplace_back("CPV/PedestalRun/FEEThresholds", className, fileName, metaData, timeStamp, timeStamp + 31536000000);
341
342 // metadata for high pedestal (> 511) channels
343 className = o2::utils::MemFileHelper::getClassName(highPedChannels);
344 fileName = o2::ccdb::CcdbApi::generateFileName(className);
345 mCcdbInfoHighPedChannelsVec.emplace_back("CPV/PedestalRun/HighPedChannels", className, fileName, metaData, timeStamp, timeStamp + 31536000000); // one year validity time (in milliseconds!)
346}
347//___________________________________________________________________
349{
350 auto& cont = getSlots();
351 auto& slot = front ? cont.emplace_front(tstart, tend) : cont.emplace_back(tstart, tend);
352 slot.setContainer(std::make_unique<PedestalCalibData>());
353 return slot;
354}
355//___________________________________________________________________
356} // end namespace cpv
357} // end namespace o2
Utils and constants for calibration and related workflows.
int32_t i
TFType getTFEnd() const
Definition TimeSlot.h:47
const Container * getContainer() const
Definition TimeSlot.h:53
TFType getTFStart() const
Definition TimeSlot.h:46
static std::string generateFileName(const std::string &inp)
Definition CcdbApi.cxx:798
static constexpr short kNCHANNELS
Definition Geometry.h:30
static bool absIdToHWaddress(unsigned short absId, short &ccId, short &dil, short &gas, short &pad)
Definition Geometry.cxx:137
PedestalTimeSlot & emplaceNewSlot(bool front, TFType tstart, TFType tend) final
void finalizeSlot(PedestalTimeSlot &slot) final
void fill(uint16_t amplitude)
PedestalSpectrum & operator+=(const PedestalSpectrum &rhs)
float getPeakMean(uint16_t iPeak)
float getPeakRMS(uint16_t iPeak)
PedestalSpectrum(uint16_t toleratedGapWidth=5, float nSigmasZS=3., float suspiciousPedestalRMS=20.)
void setPedestal(short cellID, short c)
Set pedestal.
Definition Pedestals.h:55
void setPedSigma(short cellID, float c)
Definition Pedestals.h:61
long getCurrentTimestamp()
returns the timestamp in long corresponding to "now"
a couple of static helper functions to create timestamp values for CCDB queries or override obsolete ...
void fill(const gsl::span< const o2::cpv::Digit > data)
std::vector< PedestalSpectrum > mPedestalSpectra
PedestalCalibData(uint16_t toleratedGapWidth=5, float nSigmasZS=3., float suspiciousPedestalRMS=20.)
void merge(const PedestalCalibData *prev)
static std::string getClassName(const T &obj)
get the class name of the object
LOG(info)<< "Compressed in "<< sw.CpuTime()<< " s"
std::vector< Digit > digits