Skip to content

Commit 86f9f99

Browse files
Generic post-processing task for quality objects (#1689)
* Added generic post-processing task for quality objects - the task provides trending of user-defined quality flags as well as a summary in human-readable format in a dedicated canvas - added task and task configuration helper class - added example in postprocessing.json - added task description in PostProcessing documentation * Combine features of QualityTask and QualityObserver Some of the decisions I took: - I used the dataSources key to list all the input objects groups - The aggregated quality is treated like any other quality. To reproduce the previous behaviour one can put it first in the global list of input objects groups. - All input objects may have additional comments which depend on the quality, which allows to still get the old behaviour for the aggregated quality, but also for any other (which would be asked for anyway at some point, I believe). - the inputObjects list contain separate JSON objects with all the possible keys for easier extensibility of configuration while letting users skip some optional fields. - when a QO cannot be retrieved, we still print the corresponding line, so this fact is known - input object groups get both a title and a name. The name is used for paths in QCDB to corresponding trends and histograms - observeDetails and qualityDetailChoice was reduced to ignoreQualitiesDetails, since an empty list would be in fact equal to "observeDetails" : "true" with all qualities listed, so does not using this setting at all. The parameter is per group and an actual JSON list is used, to avoid errors in parsing. - timestamps are kept separate to configuration, since they are state, not configuration. * fix sharing the same quality across multiple groups * add missing picture --------- Co-authored-by: Piotr Konopka <piotr.jan.konopka@cern.ch>
1 parent 4031cc8 commit 86f9f99

13 files changed

Lines changed: 810 additions & 0 deletions

File tree

Framework/include/QualityControl/Quality.h

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -113,6 +113,8 @@ class Quality
113113
/// \return reason, if exists
114114
const CommentedFlagReasons& getReasons() const;
115115

116+
static Quality fromString(const std::string& str);
117+
116118
private:
117119
unsigned int mLevel; /// 0 is no quality, 1 is best quality, then it only goes downhill...
118120
std::string mName;

Framework/postprocessing.json

Lines changed: 53 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -207,6 +207,59 @@
207207
"stopTrigger": [
208208
"userorcontrol", "10 minutes"
209209
]
210+
},
211+
"ExampleQualityTask": {
212+
"active": "true",
213+
"className": "o2::quality_control_modules::common::QualityTask",
214+
"moduleName": "QualityControl",
215+
"detectorName": "TST",
216+
"qualityGroups": [
217+
{
218+
"name" : "global",
219+
"title" : "GLOBAL TST QUALITY",
220+
"path": "TST/QO",
221+
"ignoreQualitiesDetails" : ["Null", "Good", "Medium", "Bad"],
222+
"inputObjects": [
223+
{
224+
"name" : "QcCheck",
225+
"title" : "Aggregated TST Quality",
226+
"messageBad" : "Inform XYZ on-call immediately",
227+
"messageMedium": "Add bookkeeping entry",
228+
"messageGood": "All checks are OK",
229+
"messageNull": "Some histograms are empty!!!"
230+
}
231+
]
232+
},
233+
{
234+
"name" : "details",
235+
"title" : "TST DETAILS",
236+
"path": "TST/QO",
237+
"ignoreQualitiesDetails" : [],
238+
"inputObjects": [
239+
{
240+
"name" : "QcCheck",
241+
"title" : ""
242+
},
243+
{
244+
"name" : "someNumbersCheck",
245+
"title" : ""
246+
},
247+
{
248+
"name" : "XYZCheck",
249+
"title" : ""
250+
}
251+
]
252+
}
253+
],
254+
"initTrigger": [
255+
"userorcontrol"
256+
],
257+
"updateTrigger": [
258+
"10 seconds"
259+
],
260+
"stopTrigger": [
261+
"userorcontrol"
262+
]
210263
}
211264
}
212265
}

Framework/src/Quality.cxx

Lines changed: 15 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -19,6 +19,7 @@
1919
#include <iostream>
2020
#include <utility>
2121
#include <Common/Exceptions.h>
22+
#include <boost/algorithm/string.hpp>
2223

2324
namespace o2::quality_control::core
2425
{
@@ -101,4 +102,18 @@ const CommentedFlagReasons& Quality::getReasons() const
101102
{
102103
return mReasons;
103104
}
105+
106+
Quality Quality::fromString(const std::string& str)
107+
{
108+
if (str == Quality::Good.getName()) {
109+
return Quality::Good;
110+
} else if (str == Quality::Medium.getName()) {
111+
return Quality::Medium;
112+
} else if (str == Quality::Bad.getName()) {
113+
return Quality::Bad;
114+
} else {
115+
return Quality::Null;
116+
}
117+
}
118+
104119
} // namespace o2::quality_control::core

Modules/Common/CMakeLists.txt

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -14,6 +14,8 @@ target_sources(O2QcCommon
1414
src/WorstOfAllAggregator.cxx
1515
src/TRFCollectionTask.cxx
1616
src/TRFCollectionTaskConfig.cxx
17+
src/QualityTask.cxx
18+
src/QualityTaskConfig.cxx
1719
src/NonEmpty.cxx
1820
src/MeanIsAbove.cxx
1921
src/TH1Reductor.cxx
@@ -41,6 +43,7 @@ add_root_dictionary(O2QcCommon
4143
HEADERS include/Common/NonEmpty.h
4244
include/Common/WorstOfAllAggregator.h
4345
include/Common/TRFCollectionTask.h
46+
include/Common/QualityTask.h
4447
include/Common/MeanIsAbove.h
4548
include/Common/TH1Reductor.h
4649
include/Common/TH2Reductor.h
Lines changed: 82 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,82 @@
1+
{
2+
"qc": {
3+
"config": {
4+
"database": {
5+
"implementation": "CCDB",
6+
"host": "ccdb-test.cern.ch:8080",
7+
"username": "not_applicable",
8+
"password": "not_applicable",
9+
"name": "not_applicable"
10+
},
11+
"Activity": {
12+
"number": "42",
13+
"type": "2",
14+
"periodName": "LHC42x", "": "Period name / Production tag - e.g. LHC22c, LHC22c1b_test",
15+
"passName": "spass", "": "Pass type - e.g. spass, cpass1",
16+
"provenance": "qc", "": "Provenance - qc or qc_mc depending whether it is normal data or monte carlo data"
17+
},
18+
"monitoring": {
19+
"url": "infologger:///debug?qc"
20+
},
21+
"consul": {
22+
"url": ""
23+
},
24+
"conditionDB": {
25+
"url": "ccdb-test.cern.ch:8080"
26+
}
27+
},
28+
"postprocessing": {
29+
"ExampleQualityTask": {
30+
"active": "true",
31+
"className": "o2::quality_control::postprocessing::QualityTask",
32+
"moduleName": "QualityControl",
33+
"detectorName": "TST",
34+
"customization": [
35+
{
36+
"name": "AggregatedQualityName",
37+
"value": "Aggregator/AggregatedQuality"
38+
},
39+
{
40+
"name": "MessageGood",
41+
"value": "All checks are OK"
42+
},
43+
{
44+
"name": "MessageMedium",
45+
"value": "Add bookkeeping entry"
46+
},
47+
{
48+
"name": "MessageBad",
49+
"value": "Inform XYZ on-call immediately"
50+
},
51+
{
52+
"name": "MessageNull",
53+
"value": "Some histograms are empty!!!"
54+
}
55+
],
56+
"dataSources": [
57+
{
58+
"type": "repository",
59+
"path": "TST/QO",
60+
"names": [
61+
"Check1", "Check2", "Check3"
62+
]
63+
},
64+
{
65+
"type": "repository",
66+
"path": "TST/QO/Aggregator",
67+
"name": "AggregatedQuality"
68+
}
69+
],
70+
"initTrigger": [
71+
"userorcontrol"
72+
],
73+
"updateTrigger": [
74+
"60 seconds"
75+
],
76+
"stopTrigger": [
77+
"userorcontrol", "10 minutes"
78+
]
79+
}
80+
}
81+
}
82+
}

Modules/Common/include/Common/LinkDef.h

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -11,6 +11,7 @@
1111
#pragma link C++ class o2::quality_control_modules::common::QualityReductor + ;
1212
#pragma link C++ class o2::quality_control_modules::common::EverIncreasingGraph + ;
1313
#pragma link C++ class o2::quality_control_modules::common::TRFCollectionTask + ;
14+
#pragma link C++ class o2::quality_control_modules::common::QualityTask + ;
1415
#pragma link C++ class o2::quality_control_modules::common::WorstOfAllAggregator + ;
1516
#pragma link C++ class o2::quality_control_modules::common::IncreasingEntries + ;
1617
#pragma link C++ class o2::quality_control_modules::common::TH1SliceReductor + ;
Lines changed: 111 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,111 @@
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+
12+
///
13+
/// \file QualityTask.h
14+
/// \author Andrea Ferrero
15+
/// \brief Post-processing of quality flags
16+
///
17+
18+
#ifndef QUALITYCONTROL_QUALITYTASK_H
19+
#define QUALITYCONTROL_QUALITYTASK_H
20+
21+
#include "QualityControl/PostProcessingInterface.h"
22+
#include "Common/QualityTaskConfig.h"
23+
#include "QualityControl/Quality.h"
24+
#include <TH1F.h>
25+
#include <TGraph.h>
26+
#include <TCanvas.h>
27+
#include <TText.h>
28+
#include <string>
29+
#include <map>
30+
31+
namespace o2::quality_control::core
32+
{
33+
class QualityObject;
34+
}
35+
36+
namespace o2::quality_control::repository
37+
{
38+
class DatabaseInterface;
39+
}
40+
41+
namespace o2::quality_control::postprocessing
42+
{
43+
struct Trigger;
44+
}
45+
46+
namespace o2::quality_control_modules::common
47+
{
48+
49+
/// \brief A post-processing task which shows and trends a given list of quality flags
50+
///
51+
/// A post-processing task which shows and trends a given list of quality flags.
52+
/// The list of quality objects to be monitored is passed through the task's dataSources.
53+
/// The task produces the following output:
54+
/// * A canvas with the value of the quality objects in human-readable format.
55+
/// The aggregated quality, whose name can be specified via configuration keys,
56+
/// is shown at the top of the canvas.
57+
/// Configurable messages can also be associated to the various possible values of
58+
/// the aggregated quality (Good/Medium/Bad/Null)
59+
/// * An histogram with the distribution of the values for each quality object
60+
/// * A trend plot for each of the quality objects, showing the evolution of the values over time
61+
///
62+
/// \author Andrea Ferrero
63+
class QualityTask : public quality_control::postprocessing::PostProcessingInterface
64+
{
65+
public:
66+
/// \brief helper class to trend the values of a given Quality Object
67+
struct QualityTrendGraph : public TCanvas {
68+
QualityTrendGraph(std::string name, std::string title);
69+
void update(uint64_t time, o2::quality_control::core::Quality q);
70+
static std::string distributionName(const std::string& groupName, const std::string& qualityName);
71+
static std::string trendName(const std::string& groupName, const std::string& qualityName);
72+
73+
std::unique_ptr<TGraph> mGraph;
74+
std::unique_ptr<TGraph> mGraphHist;
75+
std::array<std::unique_ptr<TText>, 4> mLabels;
76+
};
77+
78+
QualityTask() = default;
79+
~QualityTask() override = default;
80+
81+
void configure(const boost::property_tree::ptree& config) override;
82+
void initialize(quality_control::postprocessing::Trigger, framework::ServiceRegistryRef) override;
83+
void update(quality_control::postprocessing::Trigger, framework::ServiceRegistryRef) override;
84+
void finalize(quality_control::postprocessing::Trigger, framework::ServiceRegistryRef) override;
85+
86+
private:
87+
std::pair<std::shared_ptr<quality_control::core::QualityObject>, bool> getQO(
88+
quality_control::repository::DatabaseInterface& qcdb, const quality_control::postprocessing::Trigger& t, const std::string& fullPath, const std::string& group);
89+
90+
private:
91+
/// \brief configuration parameters
92+
QualityTaskConfig mConfig;
93+
/// \brief latest creation timestamp of each tracked QO
94+
std::unordered_map<std::string /* full path */, uint64_t> mLatestTimestamps;
95+
/// \brief colors associated to each quality state (Good/Medium/Bad/Null)
96+
std::unordered_map<std::string, int> mColors;
97+
/// \brief numerical IDs associated to each quality state (Good/Medium/Bad/Null)
98+
std::unordered_map<std::string, int> mQualityIDs;
99+
/// \brief messages associated to each quality state (Good/Medium/Bad/Null)
100+
std::unordered_map<std::string, std::string> mCheckerMessages;
101+
/// \brief Quality Objects histograms
102+
std::unordered_map<std::string, std::unique_ptr<TH1F>> mHistograms;
103+
/// \brief Quality Objects trends
104+
std::unordered_map<std::string, std::unique_ptr<QualityTrendGraph>> mTrends;
105+
/// \brief canvas with human-readable quality states and messages
106+
std::unique_ptr<TCanvas> mQualityCanvas;
107+
};
108+
109+
} // namespace o2::quality_control_modules::common
110+
111+
#endif // QUALITYCONTROL_QUALITYTASK_H
Lines changed: 60 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,60 @@
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+
12+
///
13+
/// \file QualityTaskConfig.h
14+
/// \author Andrea Ferrero
15+
///
16+
17+
#ifndef QUALITYCONTROL_QUALITYTASKCONFIG_H
18+
#define QUALITYCONTROL_QUALITYTASKCONFIG_H
19+
20+
#include <vector>
21+
#include <unordered_map>
22+
#include <string>
23+
#include "QualityControl/PostProcessingConfig.h"
24+
#include "QualityControl/Quality.h"
25+
26+
namespace o2::quality_control_modules::common
27+
{
28+
29+
// todo pretty print
30+
/// \brief QualityTask configuration structure
31+
struct QualityTaskConfig : quality_control::postprocessing::PostProcessingConfig {
32+
QualityTaskConfig() = default;
33+
QualityTaskConfig(std::string name, const boost::property_tree::ptree& config);
34+
~QualityTaskConfig() = default;
35+
36+
struct QualityConfig {
37+
std::string name;
38+
std::string title;
39+
std::unordered_map<std::string /* quality */, std::string /* message */> messages = {
40+
{ quality_control::core::Quality::Null.getName(), "" },
41+
{ quality_control::core::Quality::Bad.getName(), "" },
42+
{ quality_control::core::Quality::Medium.getName(), "" },
43+
{ quality_control::core::Quality::Good.getName(), "" }
44+
};
45+
};
46+
47+
struct QualityGroup {
48+
std::string name;
49+
std::string title;
50+
std::string path;
51+
std::vector<quality_control::core::Quality> ignoreQualitiesDetails{};
52+
std::vector<QualityConfig> inputObjects{};
53+
};
54+
55+
std::vector<QualityGroup> qualityGroups;
56+
};
57+
58+
} // namespace o2::quality_control_modules::common
59+
60+
#endif // QUALITYCONTROL_QUALITYTASKCONFIG_H

0 commit comments

Comments
 (0)