Skip to content

Commit be5695a

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 2f7204d commit be5695a

File tree

1 file changed

+102
-66
lines changed

1 file changed

+102
-66
lines changed

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

Lines changed: 102 additions & 66 deletions
Original file line numberDiff line numberDiff line change
@@ -50,6 +50,17 @@ struct RejectListStruct {
5050
std::vector<o2::mid::ColumnData> rejectList{}; /// Bad channels
5151
};
5252

53+
/// @brief Useful metadata
54+
struct MDStruct {
55+
long start = 0; /// Start validity
56+
long end = 0; /// End validity
57+
int runNumber = 0; /// Run number
58+
std::string runType; /// Run Type
59+
60+
bool operator<(const MDStruct& other) const { return start < other.start; }
61+
bool operator==(const MDStruct& other) const { return start == other.start; }
62+
};
63+
5364
/// @brief Get timestamp in milliseconds
5465
/// @param timestamp Input timestamp (in s or ms)
5566
/// @return Timestamp in ms
@@ -96,23 +107,33 @@ std::string timeRangeToString(long start, long end)
96107
/// @param end Query objects created not after
97108
/// @param api CDB api
98109
/// @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)
110+
/// @return Vector of metadata in ascending order
111+
std::vector<MDStruct> findObjectsMDInPeriod(long start, long end, const o2::ccdb::CcdbApi& api, const char* path)
101112
{
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-
}
113+
std::vector<MDStruct> mds;
114+
auto out = api.list(path, false, "application/json", getTSMS(end), getTSMS(start));
115+
rapidjson::Document doc;
116+
doc.Parse(out.c_str());
117+
for (auto& obj : doc["objects"].GetArray()) {
118+
MDStruct md;
119+
md.start = obj["validFrom"].GetInt64();
120+
md.end = obj["validUntil"].GetInt64();
121+
md.runNumber = std::atoi(obj["RunNumber"].GetString());
122+
md.runType = obj["RunType"].GetString();
123+
mds.emplace_back(md);
111124
}
112-
ts.erase(std::unique(ts.begin(), ts.end()), ts.end());
125+
mds.erase(std::unique(mds.begin(), mds.end()), mds.end());
113126
// Sort timestamps in ascending order
114-
std::sort(ts.begin(), ts.end());
115-
return ts;
127+
std::sort(mds.begin(), mds.end());
128+
return mds;
129+
}
130+
131+
/// @brief Gets the quality trend graph from the quality canvas
132+
/// @param qcQuality MID QC quality canvas
133+
/// @return Quality trend graph
134+
TGraph* getQualityTrend(const TCanvas* qcQuality)
135+
{
136+
return static_cast<TGraph*>(qcQuality->GetListOfPrimitives()->FindObject("Graph"));
116137
}
117138

118139
/// @brief Find the first and last time when the quality was good or bad
@@ -121,7 +142,13 @@ std::vector<long> findObjectsTSInPeriod(long start, long end, const o2::ccdb::Cc
121142
/// @return Pair with first and last time
122143
std::pair<uint64_t, uint64_t> findTSRange(TCanvas* qcQuality, bool selectBad = true)
123144
{
124-
auto* gr = static_cast<TGraph*>(qcQuality->GetListOfPrimitives()->FindObject("Graph"));
145+
// Gets the plot with the quality flags
146+
// The flag values are:
147+
// Good: 3.5
148+
// Medium: 2.5
149+
// Bad: 1.5
150+
// Null: 0.5
151+
auto* gr = getQualityTrend(qcQuality);
125152
double xp, yp;
126153
std::pair<uint64_t, uint64_t> range{std::numeric_limits<uint64_t>::max(), 0};
127154
for (int ip = 0; ip < gr->GetN(); ++ip) {
@@ -138,6 +165,32 @@ std::pair<uint64_t, uint64_t> findTSRange(TCanvas* qcQuality, bool selectBad = t
138165
return range;
139166
}
140167

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

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-
195236
/// @brief Builds the reject list for the selected timestamp
196-
/// @param timestamp Timestamp for query
237+
/// @param md MD structure
197238
/// @param qcdbApi QCDB api
198239
/// @param ccdbApi CCDB api
199240
/// @param outCCDBApi api of the CCDB where the reject list will be uploaded
200241
/// @return Reject list
201-
RejectListStruct build_rejectlist(long timestamp, const o2::ccdb::CcdbApi& qcdbApi, const o2::ccdb::CcdbApi& ccdbApi)
242+
RejectListStruct build_rejectlist(const MDStruct& md, const o2::ccdb::CcdbApi& qcdbApi, const o2::ccdb::CcdbApi& ccdbApi)
202243
{
203-
std::map<std::string, std::string> metadata;
204244
RejectListStruct rl;
205-
auto* qcQuality = qcdbApi.retrieveFromTFileAny<TCanvas>(sPathQCQuality, metadata, getTSMS(timestamp));
245+
if (md.runType != "PHYSICS") {
246+
std::cout << "Run " << md.runNumber << " is of type " << md.runType << ": skip" << std::endl;
247+
return rl;
248+
}
249+
250+
std::map<std::string, std::string> metadata;
251+
auto* qcQuality = qcdbApi.retrieveFromTFileAny<TCanvas>(sPathQCQuality, metadata, getTSMS(md.start));
206252
if (!qcQuality) {
207-
std::cerr << "Cannot find QC quality for " << tsToString(timestamp) << std::endl;
253+
std::cerr << "Cannot find QC quality for " << tsToString(md.start) << std::endl;
208254
return rl;
209255
}
256+
210257
// Find the first and last timestamp where the quality was bad (if any)
211258
auto badTSRange = findTSRange(qcQuality);
212259
if (badTSRange.second == 0) {
213260
std::cout << "All good" << std::endl;
214261
return rl;
215262
}
263+
264+
// Find the first and last timestamp where the quality flag was set
265+
auto qualityTSRange = getFirstLast(qcQuality);
216266
// Search for the last timestamp for which the run quality was good
217267
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-
}
231268

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

234273
// 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()) {
274+
auto mdVector = findObjectsMDInPeriod(badTSRange.first, badTSRange.second, qcdbApi, "qc/MID/MO/QcTaskMIDDigits/Hits");
275+
if (mdVector.empty()) {
237276
std::cerr << "Cannot find hits in period " << tsToString(badTSRange.first) << " - " << tsToString(badTSRange.second) << std::endl;
238277
return {};
239278
}
240-
// Focus on the first object found
241-
TH1* occupancy = qcdbApi.retrieveFromTFileAny<TH1F>("qc/MID/MO/QcTaskMIDDigits/Hits", metadata, getTSMS(tsVector.front()));
279+
// Focus on the last object found
280+
// We chose the last instead of the first because it might happen that
281+
// we lose additional boards before the EOR
282+
// If we build the reject list for the first object, we would therefore miss some boards
283+
TH1* occupancy = qcdbApi.retrieveFromTFileAny<TH1F>("qc/MID/MO/QcTaskMIDDigits/Hits", metadata, getTSMS(mdVector.back().start));
242284
o2::mid::GlobalMapper gm;
243285
auto infos = gm.buildStripsInfo();
244286
auto badChannels = findBadChannels(occupancy, infos);
245-
auto badChannelsCCDB = *ccdbApi.retrieveFromTFileAny<std::vector<o2::mid::ColumnData>>("MID/Calib/BadChannels", metadata, getTSMS(timestamp));
287+
auto badChannelsCCDB = *ccdbApi.retrieveFromTFileAny<std::vector<o2::mid::ColumnData>>("MID/Calib/BadChannels", metadata, getTSMS(md.start));
246288
rl.rejectList = getRejectList(badChannels, badChannelsCCDB);
247289
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;
290+
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;
249291
return rl;
250292
}
251293

@@ -254,21 +296,15 @@ RejectListStruct build_rejectlist(long timestamp, const o2::ccdb::CcdbApi& qcdbA
254296
for (auto& col : rl.rejectList) {
255297
std::cout << col << std::endl;
256298
}
257-
std::cout << "Run number: " << grpecs.getRun() << std::endl;
258-
std::cout << "SOR - EOR: " << timeRangeToString(grpecs.getTimeStart(), grpecs.getTimeEnd()) << std::endl;
299+
std::cout << "Run number: " << md.runNumber << std::endl;
259300
std::cout << "SOT - EOT: " << timeRangeToString(runRange.first, runRange.second) << std::endl;
260301
std::cout << "Good: " << timeRangeToString(goodTSRange.first, goodTSRange.second) << std::endl;
261302
std::cout << "Bad: " << timeRangeToString(badTSRange.first, badTSRange.second) << std::endl;
303+
std::cout << "Fraction bad: " << static_cast<double>(badTSRange.second - badTSRange.first) / static_cast<double>(runRange.second - runRange.first) << std::endl;
262304

263305
// Set the start of the reject list to the last timestamp in which the occupancy was ok
264306
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;
307+
rl.end = badTSRange.second;
272308
return rl;
273309
}
274310

@@ -295,8 +331,8 @@ RejectListStruct load_from_json(const o2::ccdb::CcdbApi& ccdbApi, const char* fi
295331
std::cerr << "Problem parsing " << filename << std::endl;
296332
return rl;
297333
}
298-
auto startRange = getRunDuration(ccdbApi, doc["startRun"].GetInt());
299-
auto endRange = getRunDuration(ccdbApi, doc["endRun"].GetInt());
334+
auto startRange = o2::ccdb::BasicCCDBManager::getRunDuration(ccdbApi, doc["startRun"].GetInt());
335+
auto endRange = o2::ccdb::BasicCCDBManager::getRunDuration(ccdbApi, doc["endRun"].GetInt());
300336
rl.start = startRange.first;
301337
rl.end = endRange.second;
302338
std::cout << "Manual RL validity: " << timeRangeToString(rl.start, rl.end) << std::endl;
@@ -391,9 +427,9 @@ void build_rejectlist(long start, long end, const char* qcdbUrl = "http://ali-qc
391427
o2::ccdb::CcdbApi ccdbApi;
392428
ccdbApi.init(ccdbUrl);
393429
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);
430+
auto objectsMD = findObjectsMDInPeriod(start, end, qcdbApi, sPathQCQuality.c_str());
431+
for (auto md : objectsMD) {
432+
auto rl = build_rejectlist(md, qcdbApi, ccdbApi);
397433
if (rl.start != rl.end) {
398434
rls.emplace_back(rl);
399435
}

0 commit comments

Comments
 (0)