Project
Loading...
Searching...
No Matches
PHOSBadMapCalibDevice.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
13#include <fairlogger/Logger.h>
22#include "PHOSBase/Mapping.h"
25
26using namespace o2::phos;
27
29{
30
31 mElowMin = ic.options().get<int>("ElowMin");
32 mElowMax = ic.options().get<int>("ElowMax");
33 mEhighMin = ic.options().get<int>("EhighMin");
34 mEhighMax = ic.options().get<int>("EhighMax");
35
36 short n = o2::phos::Mapping::NCHANNELS - 1792;
37 if (mMode == 0) { // Cell occupancy and time
38 // Create histograms for lowE and high E occupancy and Time
39 mMeanLow.reset(new TH1F("MeanLowE", "Mean low E cut", n, 1792.5, n + 1792.5));
40 mMeanHigh.reset(new TH1F("MeanHighE", "Mean high E cut", n, 1792.5, n + 1792.5));
41 mMeanTime.reset(new TH1F("MeanTimeLow", "MeanTimeLow", n, 1792.5, n + 1792.5));
42 }
43 if (mMode == 1) { // chi2 distribution
44 mChi2.reset(new TH1F("Chi2", "#chi^2", n, 1792.5, n + 1792.5));
45 mChi2norm.reset(new TH1F("Chi2Norm", "#chi^2 normalization", n, 1792.5, n + 1792.5));
46 }
47 if (mMode == 2) { // Pedestals
48 mHGMean.reset(new TH1F("HGMean", "High Gain mean", n, 1792.5, n + 1792.5));
49 mHGRMS.reset(new TH1F("HGRMS", "High Gain RMS", n, 1792.5, n + 1792.5));
50 mHGNorm.reset(new TH1F("HGNorm", "High Gain normalization", n, 1792.5, n + 1792.5));
51 mLGMean.reset(new TH1F("LGMean", "Low Gain mean", n, 1792.5, n + 1792.5));
52 mLGRMS.reset(new TH1F("LGRMS", "Low Gain RMS", n, 1792.5, n + 1792.5));
53 mLGNorm.reset(new TH1F("LGNorm", "Low Gain normalization", n, 1792.5, n + 1792.5));
54 }
55}
56
58{
59 if (mRunStartTime == 0) {
60 mRunStartTime = ctx.services().get<o2::framework::TimingInfo>().creation;
61 mValidityTime = mRunStartTime + 31622400000; // one year validity range
62 }
63
64 // Read previous bad map if not read yet
65 if (!mOldBadMap) {
66 mOldBadMap = ctx.inputs().get<o2::phos::BadChannelsMap*>("prevbdmap").get();
67 }
68
69 // scan Cells stream, collect occupancy
70 if (mMode == 0) { // Cell occupancy and time
71 auto cells = ctx.inputs().get<gsl::span<o2::phos::Cell>>("cells");
72 LOG(detail) << "[PHOSBadMapCalibDevice - run] Received " << cells.size() << " cells, running calibration ...";
73 for (const auto& c : cells) {
74 float e = c.getEnergy();
75 if (e > mElowMin && e < mElowMax) {
76 mMeanLow->Fill(c.getAbsId() - 1792);
77 }
78 if (e > mEhighMin && e < mEhighMax) {
79 mMeanHigh->Fill(c.getAbsId() - 1792);
80 mMeanTime->Fill(c.getAbsId() - 1792, c.getTime());
81 }
82 }
83 } // mMode 0: cell occupancy
84
85 if (mMode == 1) { // Raw data analysis, chi2
86 auto chi2list = ctx.inputs().get<gsl::span<short>>("fitqa");
87 LOG(info) << "[PHOSBadMapCalibDevice - run] Received " << chi2list.size() << " Chi2, running calibration ...";
88 auto b = chi2list.begin();
89 while (b != chi2list.end()) {
90 short absId = *b;
91 ++b;
92 float c = 0.2 * (*b);
93 ++b;
94 mChi2norm->Fill(absId - 1792);
95 mChi2->Fill(absId - 1792, c);
96 }
97 }
98
99 if (mMode == 2) { // Pedestals
100 if (mStatistics <= 0) { // skip the rest of the run
101 return;
102 }
103 if (mStatistics % 100 == 0) {
104 LOG(info) << mStatistics << " left to produce pedestal BadMap";
105 }
106
107 auto cells = ctx.inputs().get<gsl::span<o2::phos::Cell>>("cells");
108 LOG(debug) << "[PHOSBadMapCalibDevice - run] Received " << cells.size() << " cells, running calibration ...";
109 for (const auto& c : cells) {
110 if (c.getHighGain()) {
111 mHGMean->Fill(c.getAbsId() - 1792, c.getEnergy());
112 mHGRMS->Fill(c.getAbsId() - 1792, 1.e+7 * c.getTime());
113 mHGNorm->Fill(c.getAbsId() - 1792, 1.);
114 } else {
115 mLGMean->Fill(c.getAbsId() - 1792);
116 mLGRMS->Fill(c.getAbsId() - 1792, 1.e+7 * c.getTime());
117 mLGNorm->Fill(c.getAbsId() - 1792, 1.);
118 }
119 }
120 --mStatistics;
121 if (mStatistics <= 0) {
122 LOG(info) << "Start calculating bad map";
124 checkBadMap();
125 sendOutput(ctx.outputs());
126 }
127 }
128}
129
131{
132
133 LOG(info) << "[PHOSBadMapCalibDevice - endOfStream]";
134 // calculate stuff here
135 if (mMode == 2 && mStatistics <= 0) { // already calculated, do nothing
136 return;
137 }
138 if (calculateBadMap()) {
139 checkBadMap();
140 sendOutput(ec.outputs());
141 }
142}
143
145{
146
147 // extract CCDB infos and calibration objects, convert it to TMemFile and send them to the output
148 // prepare all info to be sent to CCDB
149 std::string kind;
150 switch (mMode) {
151 case 0:
152 kind = "PHS/BadMap/Occ";
153 break;
154 case 1:
155 kind = "PHS/BadMap/Chi";
156 break;
157 case 2:
158 kind = "PHS/BadMap/Ped";
159 break;
160 default:
161 kind = "";
162 }
163 std::string flName = o2::ccdb::CcdbApi::generateFileName("BadMap");
164 std::map<std::string, std::string> md;
165 o2::ccdb::CcdbObjectInfo info(kind, "BadMap", flName, md, mRunStartTime, mValidityTime);
166 info.setMetaData(md);
167 auto image = o2::ccdb::CcdbApi::createObjectImage(mBadMap.get(), &info);
168
169 LOG(info) << "Sending object " << info.getPath() << "/" << info.getFileName()
170 << " of size " << image->size()
171 << " bytes, valid for " << info.getStartValidityTimestamp()
172 << " : " << info.getEndValidityTimestamp();
173
175 output.snapshot(Output{o2::calibration::Utils::gDataOriginCDBPayload, "PHS_BadMap", subSpec}, *image.get());
176 output.snapshot(Output{o2::calibration::Utils::gDataOriginCDBWrapper, "PHS_BadMap", subSpec}, info);
177
178 // Send change to QC
179 LOG(info) << "[PHOSBadMapCalibDevice - run] Sending QC ";
180 output.snapshot(o2::framework::Output{"PHS", "BADMAPDIFF", 0}, mBadMapDiff);
181}
182
184{
185 mBadMap = std::make_unique<BadChannelsMap>();
186
187 if (mMode == 0) { // occupancy
188 // --check if statistics is sufficient
189 // --prepare map of pairs (number of entries in cell, number of such cells)
190 // --sort according number of entries
191 // --remove pairs in the beginning and the end of the list till variation of mean becomes small
192 if (mMeanLow->Integral() < 1.e+4) {
193 LOG(error) << "Insufficient statistics: " << mMeanLow->Integral() << " entries in lowE histo, do nothing";
194 return false;
195 }
196
197 float nMean, nRMS;
198 calculateLimits(mMeanLow.get(), nMean, nRMS); // for low E occupamcy
199 float nMinLow = std::max(float(0.), nMean - 6 * nRMS);
200 float nMaxLow = nMean + 6 * nRMS;
201 LOG(info) << "Limits for low E histo: " << nMinLow << "<n<" << nMaxLow;
202 for (int i = 1; i <= mMeanLow->GetNbinsX(); i++) {
203 int c = mMeanLow->GetBinContent(i);
204 if (c < nMinLow || c > nMaxLow) {
205 mBadMap->addBadChannel(i + 1792);
206 }
207 }
208 calculateLimits(mMeanHigh.get(), nMean, nRMS); // for high
209 float nMinHigh = std::max(float(0.), nMean - 6 * nRMS);
210 float nMaxHigh = nMean + 6 * nRMS;
211 LOG(info) << "Limits for high E histo: " << nMinHigh << "<n<" << nMaxHigh;
212 for (int i = 1; i <= mMeanHigh->GetNbinsX(); i++) {
213 int c = mMeanHigh->GetBinContent(i);
214 if (c < nMinHigh || c > nMaxHigh) {
215 mBadMap->addBadChannel(i + 1792);
216 }
217 }
218 }
219
220 if (mMode == 1) { // chi2 distribution
221 if (mChi2norm->Integral() < 1.e+4) {
222 LOG(important) << "Insufficient statistics: " << mChi2norm->Integral() << " entries in chi2Norm histo, do nothing";
223 return false;
224 }
225 mChi2->Divide(mChi2norm.get());
226 float nMean, nRMS;
227 calculateLimits(mChi2.get(), nMean, nRMS); // for low E occupamcy
228 float nMinHigh = std::max(float(0.), nMean - 6 * nRMS);
229 float nMaxHigh = nMean + 6 * nRMS;
230 for (int i = 1; i <= mChi2->GetNbinsX(); i++) {
231 int c = mChi2->GetBinContent(i);
232 if (c < nMinHigh || c > nMaxHigh) {
233 mBadMap->addBadChannel(i + 1792);
234 }
235 }
236 } // Chi2
237
238 if (mMode == 2) { // Pedestals
239 if (mHGNorm->Integral() < 2.e+4) {
240 LOG(important) << "Insufficient statistics: " << mHGNorm->Integral() << " entries in mHGNorm histo, do nothing";
241 return false;
242 }
243 float nMean, nRMS;
244 mHGMean->Divide(mHGNorm.get());
245 calculateLimits(mHGMean.get(), nMean, nRMS); // mean HG pedestals
246 float nMinHigh = std::max(float(0.), nMean - 6 * nRMS);
247 float nMaxHigh = nMean + 6 * nRMS;
248 LOG(info) << "Limits for HG mean: " << nMinHigh << " < meanHG < " << nMaxHigh;
249 int nBad = 0;
250 for (int i = 1; i <= mHGMean->GetNbinsX(); i++) {
251 int c = mHGMean->GetBinContent(i);
252 if (c < nMinHigh || c > nMaxHigh) {
253 mBadMap->addBadChannel(i + 1792);
254 nBad++;
255 }
256 }
257 LOG(info) << "HG mean: removed " << nBad << " channels";
258 mLGMean->Divide(mLGNorm.get());
259 calculateLimits(mLGMean.get(), nMean, nRMS); // for low E occupamcy
260 nMinHigh = std::max(float(0.), nMean - 6 * nRMS);
261 nMaxHigh = nMean + 6 * nRMS;
262 LOG(info) << "Limits for LG mean: " << nMinHigh << " < meanHG < " << nMaxHigh;
263 nBad = 0;
264 for (int i = 1; i <= mLGMean->GetNbinsX(); i++) {
265 int c = mLGMean->GetBinContent(i);
266 if (c < nMinHigh || c > nMaxHigh) {
267 mBadMap->addBadChannel(i + 1792);
268 nBad++;
269 }
270 }
271 LOG(info) << " LG mean: removed " << nBad << " channels";
272 mHGRMS->Divide(mHGNorm.get());
273 calculateLimits(mHGRMS.get(), nMean, nRMS); // mean HG pedestals
274 nMinHigh = std::max(float(0.), nMean - 6 * nRMS);
275 nMaxHigh = nMean + 6 * nRMS;
276 LOG(info) << "Limits for HG RMS: " << nMinHigh << " < HG rms < " << nMaxHigh;
277 nBad = 0;
278 for (int i = 1; i <= mHGRMS->GetNbinsX(); i++) {
279 int c = mHGRMS->GetBinContent(i);
280 if (c < nMinHigh || c > nMaxHigh) {
281 mBadMap->addBadChannel(i + 1792);
282 nBad++;
283 }
284 }
285 LOG(info) << " HG RMS: removed " << nBad << " channels";
286 mLGRMS->Divide(mHGNorm.get());
287 calculateLimits(mLGRMS.get(), nMean, nRMS); // for low E occupamcy
288 nMinHigh = std::max(float(0.), nMean - 6 * nRMS);
289 nMaxHigh = nMean + 6 * nRMS;
290 LOG(info) << "Limits for LG RMS: " << nMinHigh << " < LG rms < " << nMaxHigh;
291 nBad = 0;
292 for (int i = 1; i <= mLGRMS->GetNbinsX(); i++) {
293 int c = mLGRMS->GetBinContent(i);
294 if (c < nMinHigh || c > nMaxHigh) {
295 mBadMap->addBadChannel(i + 1792);
296 nBad++;
297 }
298 }
299 LOG(info) << " LG RMS: removed " << nBad << " channels";
300
301 } // Pedestals
302
303 return true;
304}
305void PHOSBadMapCalibDevice::calculateLimits(TH1F* tmp, float& nMean, float& nRMS)
306{
307
308 // --prepare map of pairs (number of entries in cell, number of such cells)
309 // --sort according number of entries
310 // --remove pairs in the beginning and the end of the list till variation of mean becomes small
311
312 std::map<short, int> histo{};
313 for (int i = 1; i <= tmp->GetNbinsX(); i++) {
314 int c = tmp->GetBinContent(i);
315 if (c > 0) {
316 histo[c] = histo[c] + 1;
317 }
318 }
319 float mean = 0, rms = 0, nTot = 0, maxN = 0.;
320 for (const auto& [n, nCells] : histo) {
321 mean += n * nCells;
322 rms += n * n * nCells;
323 nTot += nCells;
324 if (n > maxN) {
325 maxN = n;
326 }
327 }
328 const float eps = 0.05; // maximal variation of mean if remove outlyers
329 // now remove largest entries till mean remains almost the same
330 for (std::map<short, int>::reverse_iterator iter = histo.rbegin(); iter != histo.rend(); ++iter) {
331 float nextMean = mean - iter->first * iter->second;
332 float nextRMS = rms - iter->first * iter->first * iter->second;
333 float nextTot = nTot - iter->second;
334 if (nTot == 0. || nextTot == 0.) {
335 break;
336 }
337 if (mean / nTot - nextMean / nextTot > eps * mean / nTot) {
338 mean = nextMean;
339 rms = nextRMS;
340 nTot = nextTot;
341 } else { // converged
342 break;
343 }
344 }
345 // now remove smallest entries till mean remains almost the same
346 for (std::map<short, int>::iterator iter = histo.begin(); iter != histo.end(); ++iter) {
347 float nextMean = mean - iter->first * iter->second;
348 float nextRMS = rms - iter->first * iter->first * iter->second;
349 float nextTot = nTot - iter->second;
350 if (nTot == 0. || nextTot == 0.) {
351 break;
352 }
353 if (mean / nTot - nextMean / nextTot > eps * mean / nTot) {
354 mean = nextMean;
355 rms = nextRMS;
356 nTot = nextTot;
357 } else { // converged
358 break;
359 }
360 }
361 // Now we have stable mean. calculate limits
362 if (nTot > 0) {
363 nMean = mean / nTot;
364 rms /= nTot;
365 nRMS = rms - nMean * nMean;
366 if (rms > 0) {
367 nRMS = sqrt(nRMS);
368 } else {
369 nRMS = 0.;
370 }
371 } else {
372 nMean = 0.5 * maxN;
373 nRMS = 0.5 * maxN;
374 }
375}
376
378{
379 if (!mOldBadMap) {
380 return;
381 }
382
383 // Compare old to current
384 int nNewBad = 0;
385 int nNewGood = 0;
386 for (short i = o2::phos::Mapping::NCHANNELS; i > 1792; i--) {
387 mBadMapDiff[i] = mBadMap->isChannelGood(i) - mOldBadMap->isChannelGood(i);
388 if (mBadMapDiff[i] > 0) { // new good channel
389 nNewGood++;
390 }
391 if (mBadMapDiff[i] < 0) { // new bad channel
392 nNewBad++;
393 }
394 }
395 LOG(info) << nNewBad + nNewGood << " channels changed: " << nNewGood << " new good ch., " << nNewBad << " new bad ch.";
396 if (nNewBad + nNewGood > kMinorChange) { // serious change, do not update CCDB automatically, use "force" option to overwrite
397 LOG(important) << "too many channels changed: " << nNewGood << " new good ch., " << nNewBad << " new bad ch.";
398 }
399}
400
402{
403
404 std::vector<InputSpec> inputs;
405 if (mode == 0) {
406 inputs.emplace_back("cells", ConcreteDataTypeMatcher{o2::header::gDataOriginPHS, "CELLS"}, o2::framework::Lifetime::Timeframe);
407 inputs.emplace_back("prevbdmap", o2::header::gDataOriginPHS, "PHS_BM", 0, o2::framework::Lifetime::Condition, o2::framework::ccdbParamSpec("PHS/BadMap/Occ"));
408 }
409 if (mode == 1) {
410 inputs.emplace_back("fitqa", ConcreteDataTypeMatcher{o2::header::gDataOriginPHS, "CELLFITQA"}, o2::framework::Lifetime::Timeframe);
411 inputs.emplace_back("prevbdmap", o2::header::gDataOriginPHS, "PHS_BM", 0, o2::framework::Lifetime::Condition, o2::framework::ccdbParamSpec("PHS/BadMap/Chi"));
412 }
413 if (mode == 2) {
414 inputs.emplace_back("cells", ConcreteDataTypeMatcher{o2::header::gDataOriginPHS, "CELLS"}, o2::framework::Lifetime::Timeframe);
415 inputs.emplace_back("prevbdmap", o2::header::gDataOriginPHS, "PHS_BM", 0, o2::framework::Lifetime::Condition, o2::framework::ccdbParamSpec("PHS/BadMap/Ped"));
416 }
417
419 std::vector<OutputSpec> outputs;
420 outputs.emplace_back(o2::header::gDataOriginPHS, "BADMAPDIFF", 0, o2::framework::Lifetime::Sporadic);
421 outputs.emplace_back(ConcreteDataTypeMatcher{clbUtils::gDataOriginCDBPayload, "PHS_BadMap"}, o2::framework::Lifetime::Sporadic);
422 outputs.emplace_back(ConcreteDataTypeMatcher{clbUtils::gDataOriginCDBWrapper, "PHS_BadMap"}, o2::framework::Lifetime::Sporadic);
423 return o2::framework::DataProcessorSpec{"BadMapCalibSpec",
424 inputs,
425 outputs,
426 o2::framework::adaptFromTask<PHOSBadMapCalibDevice>(mode),
428 {"ElowMin", o2::framework::VariantType::Int, 100, {"Low E minimum in ADC counts"}},
429 {"ElowMax", o2::framework::VariantType::Int, 200, {"Low E maximum in ADC counts"}},
430 {"EhighMin", o2::framework::VariantType::Int, 400, {"Low E minimum in ADC counts"}},
431 {"EhighMax", o2::framework::VariantType::Int, 900, {"Low E maximum in ADC counts"}}}};
432}
Utils and constants for calibration and related workflows.
std::ostringstream debug
int32_t i
void output(const std::map< std::string, ChannelStat > &channels)
Definition rawdump.cxx:197
Definition of the Names Generator class.
uint32_t c
Definition RawData.h:2
static std::string generateFileName(const std::string &inp)
Definition CcdbApi.cxx:823
static std::unique_ptr< std::vector< char > > createObjectImage(const T *obj, CcdbObjectInfo *info=nullptr)
Definition CcdbApi.h:103
ConfigParamRegistry const & options()
Definition InitContext.h:33
CCDB container for bad (masked) channels in PHOS.
bool isChannelGood(short channelID) const
Get the status of a certain cell.
static constexpr short NCHANNELS
Number of channels starting from 1.
Definition Mapping.h:42
void calculateLimits(TH1F *h, float &mean, float &rms)
void init(o2::framework::InitContext &ic) final
void sendOutput(DataAllocator &output)
void endOfStream(o2::framework::EndOfStreamContext &ec) final
This is invoked whenever we have an EndOfStream event.
void run(o2::framework::ProcessingContext &pc) final
GLdouble n
Definition glcorearb.h:1982
GLeglImageOES image
Definition glcorearb.h:4021
GLenum mode
Definition glcorearb.h:266
GLboolean GLboolean GLboolean b
Definition glcorearb.h:1233
constexpr o2::header::DataOrigin gDataOriginPHS
Definition DataHeader.h:574
std::vector< ConfigParamSpec > ccdbParamSpec(std::string const &path, int runDependent, std::vector< CCDBMetadata > metadata={}, int qrate=0)
std::vector< ConfigParamSpec > Options
auto get(const std::byte *buffer, size_t=0)
Definition DataHeader.h:454
o2::framework::DataProcessorSpec getBadMapCalibSpec(int mode)
static constexpr o2::header::DataOrigin gDataOriginCDBWrapper
Definition Utils.h:44
static constexpr o2::header::DataOrigin gDataOriginCDBPayload
Definition Utils.h:43
uint32_t SubSpecificationType
Definition DataHeader.h:622
LOG(info)<< "Compressed in "<< sw.CpuTime()<< " s"
std::vector< Cell > cells