Skip to content

Commit 85bd150

Browse files
authored
[QC-803] Trend only if all input objects are available (#2397)
* added config for trendingTask that enable trending only if all sources are available * added test and proper parsing * fixup! added test and proper parsing --------- Co-authored-by: Michal Tichák <michal.tichak@cern.ch>
1 parent 3bb7634 commit 85bd150

6 files changed

Lines changed: 48 additions & 6 deletions

File tree

Framework/include/QualityControl/TrendingTask.h

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -70,7 +70,8 @@ class TrendingTask : public PostProcessingInterface
7070
static void formatRunNumberXAxis(TH1* background);
7171
static std::string deduceGraphLegendOptions(const TrendingTaskConfig::Graph& graphConfig);
7272

73-
void trendValues(const Trigger& t, repository::DatabaseInterface&);
73+
/// returns true only if all datasources were available to update reductor
74+
bool trendValues(const Trigger& t, repository::DatabaseInterface&);
7475
void generatePlots();
7576
TCanvas* drawPlot(const TrendingTaskConfig::Plot& plotConfig);
7677
void initializeTrend(repository::DatabaseInterface& qcdb);

Framework/include/QualityControl/TrendingTaskConfig.h

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -61,6 +61,7 @@ struct TrendingTaskConfig : PostProcessingConfig {
6161

6262
bool producePlotsOnUpdate{};
6363
bool resumeTrend{};
64+
bool trendIfAllInputs{ false };
6465
std::vector<Plot> plots;
6566
std::vector<DataSource> dataSources;
6667
};

Framework/src/TrendingTask.cxx

Lines changed: 10 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -158,8 +158,8 @@ void TrendingTask::update(Trigger t, framework::ServiceRegistryRef services)
158158
{
159159
auto& qcdb = services.get<repository::DatabaseInterface>();
160160

161-
trendValues(t, qcdb);
162-
if (mConfig.producePlotsOnUpdate) {
161+
const auto allSourcesInvoked = trendValues(t, qcdb);
162+
if (mConfig.producePlotsOnUpdate && (!mConfig.trendIfAllInputs || allSourcesInvoked)) {
163163
generatePlots();
164164
}
165165
}
@@ -172,22 +172,28 @@ void TrendingTask::finalize(Trigger, framework::ServiceRegistryRef)
172172
generatePlots();
173173
}
174174

175-
void TrendingTask::trendValues(const Trigger& t, repository::DatabaseInterface& qcdb)
175+
bool TrendingTask::trendValues(const Trigger& t, repository::DatabaseInterface& qcdb)
176176
{
177177
mTime = activity_helpers::isLegacyValidity(t.activity.mValidity)
178178
? t.timestamp / 1000
179179
: t.activity.mValidity.getMax() / 1000; // ROOT expects seconds since epoch.
180180
mMetaData.runNumber = t.activity.mId;
181+
bool wereAllSourcesInvoked = true;
181182

182183
for (auto& dataSource : mConfig.dataSources) {
183184
if (!reductor_helpers::updateReductor(mReductors[dataSource.name].get(), t, dataSource, qcdb, *this)) {
185+
wereAllSourcesInvoked = false;
184186
ILOG(Error, Support) << "Failed to update reductor for data sources with path '" << dataSource.path
185187
<< "', name '" << dataSource.name
186188
<< "', type '" << dataSource.type << "'." << ENDM;
187189
}
188190
}
189191

190-
mTrend->Fill();
192+
if (!mConfig.trendIfAllInputs || wereAllSourcesInvoked) {
193+
mTrend->Fill();
194+
}
195+
196+
return wereAllSourcesInvoked;
191197
}
192198

193199
void TrendingTask::setUserAxesLabels(TAxis* xAxis, TAxis* yAxis, const std::string& graphAxesLabels)

Framework/src/TrendingTaskConfig.cxx

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -25,6 +25,8 @@ TrendingTaskConfig::TrendingTaskConfig(std::string id, const boost::property_tre
2525
{
2626
producePlotsOnUpdate = config.get<bool>("qc.postprocessing." + id + ".producePlotsOnUpdate", true);
2727
resumeTrend = config.get<bool>("qc.postprocessing." + id + ".resumeTrend", false);
28+
trendIfAllInputs = config.get<bool>("qc.postprocessing." + id + ".trendIfAllInputs", false);
29+
2830
for (const auto& [_, plotConfig] : config.get_child("qc.postprocessing." + id + ".plots")) {
2931
// since QC-1155 we allow for more than one graph in a single plot (canvas). we support both the new and old ways
3032
// of configuring the expected plots.

Framework/test/testTrendingTask.cxx

Lines changed: 31 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -78,6 +78,7 @@ TEST_CASE("test_trending_task")
7878
"active": "true",
7979
"taskName": "TestTrendingTask",
8080
"className": "o2::quality_control::postprocessing::TrendingTask",
81+
"trendIfAllInputs": true,
8182
"moduleName": "QualityControl",
8283
"detectorName": "TST",
8384
"dataSources": [
@@ -133,6 +134,35 @@ TEST_CASE("test_trending_task")
133134
repository->truncate("qc/TST/MO/" + taskName, "*");
134135
repository->truncate("qc/TST/QO", checkName);
135136

137+
// Test "trendIfAllInputs". There should not be anything in DB so we don't have any input sources available
138+
{
139+
auto objectManager = std::make_shared<ObjectsManager>(taskName, "o2::quality_control::postprocessing::TrendingTask", "TST", "");
140+
ServiceRegistry services;
141+
services.registerService<DatabaseInterface>(repository.get());
142+
143+
TrendingTask task;
144+
task.setName(trendingTaskName);
145+
task.setID(trendingTaskID);
146+
task.setObjectsManager(objectManager);
147+
REQUIRE_NOTHROW(task.configure(config));
148+
149+
// test initialize()
150+
REQUIRE_NOTHROW(task.initialize({ TriggerType::UserOrControl, true, { 0, "NONE", "", "", "qc" }, 1 }, services));
151+
REQUIRE(objectManager->getNumberPublishedObjects() == 1);
152+
auto treeMO = objectManager->getMonitorObject(trendingTaskName);
153+
REQUIRE(treeMO != nullptr);
154+
TTree* tree = dynamic_cast<TTree*>(treeMO->getObject());
155+
REQUIRE(tree != nullptr);
156+
REQUIRE(tree->GetEntries() == 0);
157+
158+
// test update()
159+
task.update({ TriggerType::NewObject, false, { 0, "NONE", "", "", "qc", { 2, 100000 } }, 100000 - 1 }, services);
160+
objectManager->stopPublishing(PublicationPolicy::Once);
161+
task.update({ TriggerType::NewObject, false, { 0, "NONE", "", "", "qc", { 100000, 200000 } }, 200000 - 1 }, services);
162+
REQUIRE(objectManager->getNumberPublishedObjects() == 1);
163+
REQUIRE(tree->GetEntries() == 0);
164+
}
165+
136166
// Putting the objects to trend into the database
137167
{
138168
TH1I* histo = new TH1I("testHistoTrending", "testHistoTrending", 10, 0, 10.0);
@@ -220,4 +250,4 @@ TEST_CASE("test_trending_task")
220250
REQUIRE(tree->GetEntries() == 2);
221251
objectManager->stopPublishing(PublicationPolicy::Once);
222252
objectManager->stopPublishing(PublicationPolicy::ThroughStop);
223-
}
253+
}

doc/PostProcessing.md

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -389,6 +389,8 @@ use the boolean flag `"producePlotsOnUpdate"`.
389389

390390
To pick up the last existing trend which matches the specified Activity, set `"resumeTrend"` to `"true"`.
391391

392+
To generate plots only when all input objects are available, set `"trendIfAllInputs"`.
393+
392394
### The SliceTrendingTask class
393395
The `SliceTrendingTask` is a complementary task to the standard `TrendingTask`. This task allows the trending of canvas objects that hold multiple histograms (which have to be of the same dimension, e.g. TH1) and the slicing of histograms. The latter option allows the user to divide a histogram into multiple subsections along one or two dimensions which are trended in parallel to each other. The task has specific reductors for `TH1` and `TH2` objects which are `o2::quality_control_modules::common::TH1SliceReductor` and `o2::quality_control_modules::common::TH2SliceReductor`.
394396

0 commit comments

Comments
 (0)