Skip to content

Commit 3d3ee4d

Browse files
dstoccoshahor02
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 061a310 commit 3d3ee4d

File tree

1 file changed

+96
-66
lines changed

1 file changed

+96
-66
lines changed

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

Lines changed: 96 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
@@ -127,7 +148,7 @@ std::pair<uint64_t, uint64_t> findTSRange(TCanvas* qcQuality, bool selectBad = t
127148
// Medium: 2.5
128149
// Bad: 1.5
129150
// Null: 0.5
130-
auto* gr = static_cast<TGraph*>(qcQuality->GetListOfPrimitives()->FindObject("Graph"));
151+
auto* gr = getQualityTrend(qcQuality);
131152
double xp, yp;
132153
std::pair<uint64_t, uint64_t> range{std::numeric_limits<uint64_t>::max(), 0};
133154
for (int ip = 0; ip < gr->GetN(); ++ip) {
@@ -144,6 +165,32 @@ std::pair<uint64_t, uint64_t> findTSRange(TCanvas* qcQuality, bool selectBad = t
144165
return range;
145166
}
146167

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+
147194
/// @brief Find bad channels from the occupancy histograms
148195
/// @param hits Occupancy histogram
149196
/// @param infos Mapping
@@ -186,72 +233,61 @@ std::vector<o2::mid::ColumnData> getRejectList(std::vector<o2::mid::ColumnData>
186233
return badChannels;
187234
}
188235

189-
/// @brief Gets the run duration with a safety marging
190-
/// @param ccdbApi CCDB api
191-
/// @param marging margin in milliseconds
192-
/// @return Pair with the timestamps of start-margin and end+margin for the run
193-
std::pair<int64_t, int64_t> getRunDuration(const o2::ccdb::CcdbApi& ccdbApi, int runNumber, int64_t margin = 120000)
194-
{
195-
auto runRange = o2::ccdb::BasicCCDBManager::getRunDuration(ccdbApi, runNumber);
196-
runRange.first -= margin; // Subtract margin
197-
runRange.second += margin; // Add margin
198-
return runRange;
199-
}
200-
201236
/// @brief Builds the reject list for the selected timestamp
202-
/// @param timestamp Timestamp for query
237+
/// @param md MD structure
203238
/// @param qcdbApi QCDB api
204239
/// @param ccdbApi CCDB api
205240
/// @param outCCDBApi api of the CCDB where the reject list will be uploaded
206241
/// @return Reject list
207-
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)
208243
{
209-
std::map<std::string, std::string> metadata;
210244
RejectListStruct rl;
211-
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));
212252
if (!qcQuality) {
213-
std::cerr << "Cannot find QC quality for " << tsToString(timestamp) << std::endl;
253+
std::cerr << "Cannot find QC quality for " << tsToString(md.start) << std::endl;
214254
return rl;
215255
}
256+
216257
// Find the first and last timestamp where the quality was bad (if any)
217258
auto badTSRange = findTSRange(qcQuality);
218259
if (badTSRange.second == 0) {
219260
std::cout << "All good" << std::endl;
220261
return rl;
221262
}
263+
264+
// Find the first and last timestamp where the quality flag was set
265+
auto qualityTSRange = getFirstLast(qcQuality);
222266
// Search for the last timestamp for which the run quality was good
223267
auto goodTSRange = findTSRange(qcQuality, false);
224-
// Query the CCDB to see to which run the timestamp corresponds
225-
auto oldestTSInQCQuality = (goodTSRange.first == 0) ? badTSRange.first : goodTSRange.first;
226-
auto grpecs = *ccdbApi.retrieveFromTFileAny<o2::parameters::GRPECSObject>("GLO/Config/GRPECS", metadata, getTSMS(oldestTSInQCQuality));
227-
if (!grpecs.isDetReadOut(o2::detectors::DetID::MID)) {
228-
std::cout << "Error: we are probably reading a parallel run" << std::endl;
229-
grpecs.print();
230-
return rl;
231-
}
232-
if (grpecs.getRunType() != o2::parameters::GRPECS::PHYSICS) {
233-
std::cout << "This is not a physics run: skip" << std::endl;
234-
grpecs.print();
235-
return rl;
236-
}
237268

238-
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);
239272

240273
// Search for hits histogram in the period where the QC quality was bad
241-
auto tsVector = findObjectsTSInPeriod(badTSRange.first, badTSRange.second, qcdbApi, "qc/MID/MO/QcTaskMIDDigits/Hits");
242-
if (tsVector.empty()) {
274+
auto mdVector = findObjectsMDInPeriod(badTSRange.first, badTSRange.second, qcdbApi, "qc/MID/MO/QcTaskMIDDigits/Hits");
275+
if (mdVector.empty()) {
243276
std::cerr << "Cannot find hits in period " << tsToString(badTSRange.first) << " - " << tsToString(badTSRange.second) << std::endl;
244277
return {};
245278
}
246-
// Focus on the first object found
247-
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));
248284
o2::mid::GlobalMapper gm;
249285
auto infos = gm.buildStripsInfo();
250286
auto badChannels = findBadChannels(occupancy, infos);
251-
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));
252288
rl.rejectList = getRejectList(badChannels, badChannelsCCDB);
253289
if (rl.rejectList.empty()) {
254-
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;
255291
return rl;
256292
}
257293

@@ -260,21 +296,15 @@ RejectListStruct build_rejectlist(long timestamp, const o2::ccdb::CcdbApi& qcdbA
260296
for (auto& col : rl.rejectList) {
261297
std::cout << col << std::endl;
262298
}
263-
std::cout << "Run number: " << grpecs.getRun() << std::endl;
264-
std::cout << "SOR - EOR: " << timeRangeToString(grpecs.getTimeStart(), grpecs.getTimeEnd()) << std::endl;
299+
std::cout << "Run number: " << md.runNumber << std::endl;
265300
std::cout << "SOT - EOT: " << timeRangeToString(runRange.first, runRange.second) << std::endl;
266301
std::cout << "Good: " << timeRangeToString(goodTSRange.first, goodTSRange.second) << std::endl;
267302
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;
268304

269305
// Set the start of the reject list to the last timestamp in which the occupancy was ok
270306
rl.start = goodTSRange.second;
271-
if (goodTSRange.first == 0) {
272-
// If the quality was bad for the full run, set the start of the reject list to the SOR
273-
std::cout << "CAVEAT: no good TS found. Will use SOT instead" << std::endl;
274-
rl.start = runRange.first;
275-
}
276-
// Set the end of the reject list to the end of run
277-
rl.end = runRange.second;
307+
rl.end = badTSRange.second;
278308
return rl;
279309
}
280310

@@ -301,8 +331,8 @@ RejectListStruct load_from_json(const o2::ccdb::CcdbApi& ccdbApi, const char* fi
301331
std::cerr << "Problem parsing " << filename << std::endl;
302332
return rl;
303333
}
304-
auto startRange = getRunDuration(ccdbApi, doc["startRun"].GetInt());
305-
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());
306336
rl.start = startRange.first;
307337
rl.end = endRange.second;
308338
std::cout << "Manual RL validity: " << timeRangeToString(rl.start, rl.end) << std::endl;
@@ -397,9 +427,9 @@ void build_rejectlist(long start, long end, const char* qcdbUrl = "http://ali-qc
397427
o2::ccdb::CcdbApi ccdbApi;
398428
ccdbApi.init(ccdbUrl);
399429
std::vector<RejectListStruct> rls;
400-
auto objectsTS = findObjectsTSInPeriod(start, end, qcdbApi, sPathQCQuality.c_str());
401-
for (auto ts : objectsTS) {
402-
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);
403433
if (rl.start != rl.end) {
404434
rls.emplace_back(rl);
405435
}

0 commit comments

Comments
 (0)