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.
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
std::ostringstream debug
static std::string generateFileName(const std::string &inp)
Definition CcdbApi.cxx:798
static std::unique_ptr< std::vector< char > > createObjectImage(const T *obj, CcdbObjectInfo *info=nullptr)
Definition CcdbApi.h:103
long getEndValidityTimestamp() const
const std::string & getPath() const
void setMetaData(const std::map< std::string, std::string > &md)
long getStartValidityTimestamp() const
const std::string & getFileName() const
ConfigParamRegistry const & options()
Definition InitContext.h:33
decltype(auto) get(R binding, int part=0) const
DataAllocator & outputs()
The data allocator is used to allocate memory for the output data.
InputRecord & inputs()
The inputs associated with this processing context.
ServiceRegistryRef services()
The services registry associated with this processing context.
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:620
LOG(info)<< "Compressed in "<< sw.CpuTime()<< " s"
std::vector< Cell > cells