Skip to content

Commit 9640f2d

Browse files
dstoccoalcaliva
authored andcommitted
Improvements on the MID reject list
- Correctly build the reject list even for runs where the issue happens at the very last sampled QC object, just before EOR - Search for switched off boards at the end of the period with bad quality instead of the beginning. This should make sure that we do not miss additional boards that stops sending data - Remove additional time margin at the beginning and end of the run - Get run number from QC metadata
1 parent f0d9f81 commit 9640f2d

File tree

1 file changed

+105
-68
lines changed

1 file changed

+105
-68
lines changed

Detectors/MUON/MID/Calibration/macros/build_rejectlist.C

Lines changed: 105 additions & 68 deletions
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,4 @@
1+
12
// Copyright 2019-2020 CERN and copyright holders of ALICE O2.
23
// See https://alice-o2.web.cern.ch/copyright for details of the copyright holders.
34
// All rights not expressly granted are reserved.
@@ -50,6 +51,17 @@ struct RejectListStruct {
5051
std::vector<o2::mid::ColumnData> rejectList{}; /// Bad channels
5152
};
5253

54+
/// @brief Useful metadata
55+
struct MDStruct {
56+
long start = 0; /// Start validity
57+
long end = 0; /// End validity
58+
int runNumber = 0; /// Run number
59+
std::string runType; /// Run Type
60+
61+
bool operator<(const MDStruct& other) const { return start < other.start; }
62+
bool operator==(const MDStruct& other) const { return start == other.start; }
63+
};
64+
5365
/// @brief Get timestamp in milliseconds
5466
/// @param timestamp Input timestamp (in s or ms)
5567
/// @return Timestamp in ms
@@ -96,23 +108,33 @@ std::string timeRangeToString(long start, long end)
96108
/// @param end Query objects created not after
97109
/// @param api CDB api
98110
/// @param path CDB path
99-
/// @return Vector of start validity of each object sorted in ascending way
100-
std::vector<long> findObjectsTSInPeriod(long start, long end, const o2::ccdb::CcdbApi& api, const char* path)
111+
/// @return Vector of metadata in ascending order
112+
std::vector<MDStruct> findObjectsMDInPeriod(long start, long end, const o2::ccdb::CcdbApi& api, const char* path)
101113
{
102-
std::vector<long> ts;
103-
auto out = api.list(path, false, "text/plain", getTSMS(end), getTSMS(start));
104-
std::stringstream ss(out);
105-
std::string token;
106-
while (ss >> token) {
107-
if (token.find("Validity") != std::string::npos) {
108-
ss >> token;
109-
ts.emplace_back(std::atol(token.c_str()));
110-
}
114+
std::vector<MDStruct> mds;
115+
auto out = api.list(path, false, "application/json", getTSMS(end), getTSMS(start));
116+
rapidjson::Document doc;
117+
doc.Parse(out.c_str());
118+
for (auto& obj : doc["objects"].GetArray()) {
119+
MDStruct md;
120+
md.start = obj["validFrom"].GetInt64();
121+
md.end = obj["validUntil"].GetInt64();
122+
md.runNumber = std::atoi(obj["RunNumber"].GetString());
123+
md.runType = obj["RunType"].GetString();
124+
mds.emplace_back(md);
111125
}
112-
ts.erase(std::unique(ts.begin(), ts.end()), ts.end());
126+
mds.erase(std::unique(mds.begin(), mds.end()), mds.end());
113127
// Sort timestamps in ascending order
114-
std::sort(ts.begin(), ts.end());
115-
return ts;
128+
std::sort(mds.begin(), mds.end());
129+
return mds;
130+
}
131+
132+
/// @brief Gets the quality trend graph from the quality canvas
133+
/// @param qcQuality MID QC quality canvas
134+
/// @return Quality trend graph
135+
TGraph* getQualityTrend(const TCanvas* qcQuality)
136+
{
137+
return static_cast<TGraph*>(qcQuality->GetListOfPrimitives()->FindObject("Graph"));
116138
}
117139

118140
/// @brief Find the first and last time when the quality was good or bad
@@ -121,7 +143,13 @@ std::vector<long> findObjectsTSInPeriod(long start, long end, const o2::ccdb::Cc
121143
/// @return Pair with first and last time
122144
std::pair<uint64_t, uint64_t> findTSRange(TCanvas* qcQuality, bool selectBad = true)
123145
{
124-
auto* gr = static_cast<TGraph*>(qcQuality->GetListOfPrimitives()->FindObject("Graph"));
146+
// Gets the plot with the quality flags
147+
// The flag values are:
148+
// Good: 3.5
149+
// Medium: 2.5
150+
// Bad: 1.5
151+
// Null: 0.5
152+
auto* gr = getQualityTrend(qcQuality);
125153
double xp, yp;
126154
std::pair<uint64_t, uint64_t> range{std::numeric_limits<uint64_t>::max(), 0};
127155
for (int ip = 0; ip < gr->GetN(); ++ip) {
@@ -138,6 +166,32 @@ std::pair<uint64_t, uint64_t> findTSRange(TCanvas* qcQuality, bool selectBad = t
138166
return range;
139167
}
140168

169+
/// @brief Gets the first and last timestamp in the quality
170+
/// @param qcQuality MID QC quality canvas
171+
/// @return Pair with the first and last timestamp in the quality trend
172+
std::pair<uint64_t, uint64_t> getFirstLast(const TCanvas* qcQuality)
173+
{
174+
auto* gr = getQualityTrend(qcQuality);
175+
double xp1, xp2, yp;
176+
gr->GetPoint(0, xp1, yp);
177+
gr->GetPoint(gr->GetN() - 1, xp2, yp);
178+
return {static_cast<uint64_t>(xp1 * 1000), static_cast<uint64_t>(xp2 * 1000)};
179+
}
180+
181+
/// @brief Update the selected range of timestamp
182+
/// @param selectedTSRange Reference to the selected range to be modified
183+
/// @param qcTSRange Range of the MID quality trend
184+
/// @param runRange Run range
185+
void updateRange(std::pair<uint64_t, uint64_t>& selectedTSRange, const std::pair<uint64_t, uint64_t> qcTSRange, const std::pair<uint64_t, uint64_t> runRange)
186+
{
187+
if (selectedTSRange.first == qcTSRange.first) {
188+
selectedTSRange.first = runRange.first;
189+
}
190+
if (selectedTSRange.second == qcTSRange.second) {
191+
selectedTSRange.second = runRange.second;
192+
}
193+
}
194+
141195
/// @brief Find bad channels from the occupancy histograms
142196
/// @param hits Occupancy histogram
143197
/// @param infos Mapping
@@ -180,72 +234,61 @@ std::vector<o2::mid::ColumnData> getRejectList(std::vector<o2::mid::ColumnData>
180234
return badChannels;
181235
}
182236

183-
/// @brief Gets the run duration with a safety marging
184-
/// @param ccdbApi CCDB api
185-
/// @param marging margin in milliseconds
186-
/// @return Pair with the timestamps of start-margin and end+margin for the run
187-
std::pair<int64_t, int64_t> getRunDuration(const o2::ccdb::CcdbApi& ccdbApi, int runNumber, int64_t margin = 120000)
188-
{
189-
auto runRange = o2::ccdb::BasicCCDBManager::getRunDuration(ccdbApi, runNumber);
190-
runRange.first -= margin; // Subtract margin
191-
runRange.second += margin; // Add margin
192-
return runRange;
193-
}
194-
195237
/// @brief Builds the reject list for the selected timestamp
196-
/// @param timestamp Timestamp for query
238+
/// @param md MD structure
197239
/// @param qcdbApi QCDB api
198240
/// @param ccdbApi CCDB api
199241
/// @param outCCDBApi api of the CCDB where the reject list will be uploaded
200242
/// @return Reject list
201-
RejectListStruct build_rejectlist(long timestamp, const o2::ccdb::CcdbApi& qcdbApi, const o2::ccdb::CcdbApi& ccdbApi)
243+
RejectListStruct build_rejectlist(const MDStruct& md, const o2::ccdb::CcdbApi& qcdbApi, const o2::ccdb::CcdbApi& ccdbApi)
202244
{
203-
std::map<std::string, std::string> metadata;
204245
RejectListStruct rl;
205-
auto* qcQuality = qcdbApi.retrieveFromTFileAny<TCanvas>(sPathQCQuality, metadata, getTSMS(timestamp));
246+
if (md.runType != "PHYSICS") {
247+
std::cout << "Run " << md.runNumber << " is of type " << md.runType << ": skip" << std::endl;
248+
return rl;
249+
}
250+
251+
std::map<std::string, std::string> metadata;
252+
auto* qcQuality = qcdbApi.retrieveFromTFileAny<TCanvas>(sPathQCQuality, metadata, getTSMS(md.start));
206253
if (!qcQuality) {
207-
std::cerr << "Cannot find QC quality for " << tsToString(timestamp) << std::endl;
254+
std::cerr << "Cannot find QC quality for " << tsToString(md.start) << std::endl;
208255
return rl;
209256
}
257+
210258
// Find the first and last timestamp where the quality was bad (if any)
211259
auto badTSRange = findTSRange(qcQuality);
212260
if (badTSRange.second == 0) {
213261
std::cout << "All good" << std::endl;
214262
return rl;
215263
}
264+
265+
// Find the first and last timestamp where the quality flag was set
266+
auto qualityTSRange = getFirstLast(qcQuality);
216267
// Search for the last timestamp for which the run quality was good
217268
auto goodTSRange = findTSRange(qcQuality, false);
218-
// Query the CCDB to see to which run the timestamp corresponds
219-
auto oldestTSInQCQuality = (goodTSRange.first == 0) ? badTSRange.first : goodTSRange.first;
220-
auto grpecs = *ccdbApi.retrieveFromTFileAny<o2::parameters::GRPECSObject>("GLO/Config/GRPECS", metadata, getTSMS(oldestTSInQCQuality));
221-
if (!grpecs.isDetReadOut(o2::detectors::DetID::MID)) {
222-
std::cout << "Error: we are probably reading a parallel run" << std::endl;
223-
grpecs.print();
224-
return rl;
225-
}
226-
if (grpecs.getRunType() != o2::parameters::GRPECS::PHYSICS) {
227-
std::cout << "This is not a physics run: skip" << std::endl;
228-
grpecs.print();
229-
return rl;
230-
}
231269

232-
auto runRange = getRunDuration(ccdbApi, grpecs.getRun());
270+
auto runRange = o2::ccdb::BasicCCDBManager::getRunDuration(ccdbApi, md.runNumber);
271+
updateRange(badTSRange, qualityTSRange, runRange);
272+
updateRange(goodTSRange, qualityTSRange, runRange);
233273

234274
// Search for hits histogram in the period where the QC quality was bad
235-
auto tsVector = findObjectsTSInPeriod(badTSRange.first, badTSRange.second, qcdbApi, "qc/MID/MO/QcTaskMIDDigits/Hits");
236-
if (tsVector.empty()) {
275+
auto mdVector = findObjectsMDInPeriod(badTSRange.first, badTSRange.second, qcdbApi, "qc/MID/MO/QcTaskMIDDigits/Hits");
276+
if (mdVector.empty()) {
237277
std::cerr << "Cannot find hits in period " << tsToString(badTSRange.first) << " - " << tsToString(badTSRange.second) << std::endl;
238278
return {};
239279
}
240-
// Focus on the first object found
241-
TH1* occupancy = qcdbApi.retrieveFromTFileAny<TH1F>("qc/MID/MO/QcTaskMIDDigits/Hits", metadata, getTSMS(tsVector.front()));
280+
// Focus on the last object found
281+
// We chose the last instead of the first because it might happen that
282+
// we lose additional boards before the EOR
283+
// If we build the reject list for the first object, we would therefore miss some boards
284+
TH1* occupancy = qcdbApi.retrieveFromTFileAny<TH1F>("qc/MID/MO/QcTaskMIDDigits/Hits", metadata, getTSMS(mdVector.back().start));
242285
o2::mid::GlobalMapper gm;
243286
auto infos = gm.buildStripsInfo();
244287
auto badChannels = findBadChannels(occupancy, infos);
245-
auto badChannelsCCDB = *ccdbApi.retrieveFromTFileAny<std::vector<o2::mid::ColumnData>>("MID/Calib/BadChannels", metadata, getTSMS(timestamp));
288+
auto badChannelsCCDB = *ccdbApi.retrieveFromTFileAny<std::vector<o2::mid::ColumnData>>("MID/Calib/BadChannels", metadata, getTSMS(md.start));
246289
rl.rejectList = getRejectList(badChannels, badChannelsCCDB);
247290
if (rl.rejectList.empty()) {
248-
std::cout << "Warning: reject list was empty. It probably means that an entire board is already masked in calibration for run " << grpecs.getRun() << std::endl;
291+
std::cout << "Warning: reject list was empty. It probably means that an entire board is already masked in calibration for run " << md.runNumber << std::endl;
249292
return rl;
250293
}
251294

@@ -254,21 +297,15 @@ RejectListStruct build_rejectlist(long timestamp, const o2::ccdb::CcdbApi& qcdbA
254297
for (auto& col : rl.rejectList) {
255298
std::cout << col << std::endl;
256299
}
257-
std::cout << "Run number: " << grpecs.getRun() << std::endl;
258-
std::cout << "SOR - EOR: " << timeRangeToString(grpecs.getTimeStart(), grpecs.getTimeEnd()) << std::endl;
300+
std::cout << "Run number: " << md.runNumber << std::endl;
259301
std::cout << "SOT - EOT: " << timeRangeToString(runRange.first, runRange.second) << std::endl;
260302
std::cout << "Good: " << timeRangeToString(goodTSRange.first, goodTSRange.second) << std::endl;
261303
std::cout << "Bad: " << timeRangeToString(badTSRange.first, badTSRange.second) << std::endl;
304+
std::cout << "Fraction bad: " << static_cast<double>(badTSRange.second - badTSRange.first) / static_cast<double>(runRange.second - runRange.first) << std::endl;
262305

263306
// Set the start of the reject list to the last timestamp in which the occupancy was ok
264307
rl.start = goodTSRange.second;
265-
if (goodTSRange.first == 0) {
266-
// If the quality was bad for the full run, set the start of the reject list to the SOR
267-
std::cout << "CAVEAT: no good TS found. Will use SOT instead" << std::endl;
268-
rl.start = runRange.first;
269-
}
270-
// Set the end of the reject list to the end of run
271-
rl.end = runRange.second;
308+
rl.end = badTSRange.second;
272309
return rl;
273310
}
274311

@@ -295,8 +332,8 @@ RejectListStruct load_from_json(const o2::ccdb::CcdbApi& ccdbApi, const char* fi
295332
std::cerr << "Problem parsing " << filename << std::endl;
296333
return rl;
297334
}
298-
auto startRange = getRunDuration(ccdbApi, doc["startRun"].GetInt());
299-
auto endRange = getRunDuration(ccdbApi, doc["endRun"].GetInt());
335+
auto startRange = o2::ccdb::BasicCCDBManager::getRunDuration(ccdbApi, doc["startRun"].GetInt());
336+
auto endRange = o2::ccdb::BasicCCDBManager::getRunDuration(ccdbApi, doc["endRun"].GetInt());
300337
rl.start = startRange.first;
301338
rl.end = endRange.second;
302339
std::cout << "Manual RL validity: " << timeRangeToString(rl.start, rl.end) << std::endl;
@@ -377,7 +414,7 @@ std::vector<RejectListStruct> merge_rejectlists(const RejectListStruct& manualRL
377414
return merged;
378415
}
379416

380-
/// @brief Builds the reject list iin a time range
417+
/// @brief Builds the reject list in a time range
381418
/// @param start Start time for query
382419
/// @param end End time for query
383420
/// @param qcdbUrl QCDB URL
@@ -391,9 +428,9 @@ void build_rejectlist(long start, long end, const char* qcdbUrl = "http://ali-qc
391428
o2::ccdb::CcdbApi ccdbApi;
392429
ccdbApi.init(ccdbUrl);
393430
std::vector<RejectListStruct> rls;
394-
auto objectsTS = findObjectsTSInPeriod(start, end, qcdbApi, sPathQCQuality.c_str());
395-
for (auto ts : objectsTS) {
396-
auto rl = build_rejectlist(ts, qcdbApi, ccdbApi);
431+
auto objectsMD = findObjectsMDInPeriod(start, end, qcdbApi, sPathQCQuality.c_str());
432+
for (auto md : objectsMD) {
433+
auto rl = build_rejectlist(md, qcdbApi, ccdbApi);
397434
if (rl.start != rl.end) {
398435
rls.emplace_back(rl);
399436
}
@@ -417,4 +454,4 @@ void build_rejectlist(long start, long end, const char* qcdbUrl = "http://ali-qc
417454
outCCDBApi.storeAsTFileAny(&rl.rejectList, "MID/Calib/RejectList", metadata, rl.start, rl.end);
418455
}
419456
}
420-
}
457+
}

0 commit comments

Comments
 (0)