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
122144std ::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