diff --git a/Framework/include/QualityControl/SliceTrendingTaskConfig.h b/Framework/include/QualityControl/SliceTrendingTaskConfig.h index bef6f87355..f9d8c43576 100644 --- a/Framework/include/QualityControl/SliceTrendingTaskConfig.h +++ b/Framework/include/QualityControl/SliceTrendingTaskConfig.h @@ -71,6 +71,7 @@ struct SliceTrendingTaskConfig : PostProcessingConfig { bool producePlotsOnUpdate; bool resumeTrend; + std::string trendingTimestamp; std::vector plots; std::vector dataSources; }; diff --git a/Framework/include/QualityControl/TrendingTaskConfig.h b/Framework/include/QualityControl/TrendingTaskConfig.h index 86181e8840..1ad8adac9e 100644 --- a/Framework/include/QualityControl/TrendingTaskConfig.h +++ b/Framework/include/QualityControl/TrendingTaskConfig.h @@ -62,6 +62,7 @@ struct TrendingTaskConfig : PostProcessingConfig { bool producePlotsOnUpdate{}; bool resumeTrend{}; bool trendIfAllInputs{ false }; + std::string trendingTimestamp; std::vector plots; std::vector dataSources; }; diff --git a/Framework/src/SliceTrendingTask.cxx b/Framework/src/SliceTrendingTask.cxx index bb7ecaafea..eaba14cd61 100644 --- a/Framework/src/SliceTrendingTask.cxx +++ b/Framework/src/SliceTrendingTask.cxx @@ -136,9 +136,14 @@ void SliceTrendingTask::finalize(Trigger t, framework::ServiceRegistryRef) void SliceTrendingTask::trendValues(const Trigger& t, repository::DatabaseInterface& qcdb) { - mTime = activity_helpers::isLegacyValidity(t.activity.mValidity) - ? t.timestamp / 1000 - : t.activity.mValidity.getMax() / 1000; // ROOT expects seconds since epoch. + if (mConfig.trendingTimestamp == "trigger") { + // ROOT expects seconds since epoch. + mTime = t.timestamp / 1000; + } else if (mConfig.trendingTimestamp == "validFrom") { + mTime = t.activity.mValidity.getMin() / 1000; + } else { // validUntil + mTime = t.activity.mValidity.getMax() / 1000; + } mMetaData.runNumber = t.activity.mId; for (auto& dataSource : mConfig.dataSources) { mNumberPads[dataSource.name] = 0; diff --git a/Framework/src/SliceTrendingTaskConfig.cxx b/Framework/src/SliceTrendingTaskConfig.cxx index be931087e3..d5648b67e9 100644 --- a/Framework/src/SliceTrendingTaskConfig.cxx +++ b/Framework/src/SliceTrendingTaskConfig.cxx @@ -28,6 +28,7 @@ SliceTrendingTaskConfig::SliceTrendingTaskConfig(const std::string& id, { producePlotsOnUpdate = config.get("qc.postprocessing." + id + ".producePlotsOnUpdate", true); resumeTrend = config.get("qc.postprocessing." + id + ".resumeTrend", false); + trendingTimestamp = config.get("qc.postprocessing." + id + ".trendingTimestamp", "validUntil"); for (const auto& plotConfig : config.get_child("qc.postprocessing." + id + ".plots")) { plots.push_back({ plotConfig.second.get("name"), plotConfig.second.get("title", ""), diff --git a/Framework/src/TrendingTask.cxx b/Framework/src/TrendingTask.cxx index b999f8541a..6752412bf4 100644 --- a/Framework/src/TrendingTask.cxx +++ b/Framework/src/TrendingTask.cxx @@ -174,9 +174,14 @@ void TrendingTask::finalize(Trigger, framework::ServiceRegistryRef) bool TrendingTask::trendValues(const Trigger& t, repository::DatabaseInterface& qcdb) { - mTime = activity_helpers::isLegacyValidity(t.activity.mValidity) - ? t.timestamp / 1000 - : t.activity.mValidity.getMax() / 1000; // ROOT expects seconds since epoch. + if (mConfig.trendingTimestamp == "trigger") { + // ROOT expects seconds since epoch. + mTime = t.timestamp / 1000; + } else if (mConfig.trendingTimestamp == "validFrom") { + mTime = t.activity.mValidity.getMin() / 1000; + } else { // validUntil + mTime = t.activity.mValidity.getMax() / 1000; + } mMetaData.runNumber = t.activity.mId; bool wereAllSourcesInvoked = true; diff --git a/Framework/src/TrendingTaskConfig.cxx b/Framework/src/TrendingTaskConfig.cxx index 8d484151ba..3528db29c0 100644 --- a/Framework/src/TrendingTaskConfig.cxx +++ b/Framework/src/TrendingTaskConfig.cxx @@ -26,6 +26,7 @@ TrendingTaskConfig::TrendingTaskConfig(std::string id, const boost::property_tre producePlotsOnUpdate = config.get("qc.postprocessing." + id + ".producePlotsOnUpdate", true); resumeTrend = config.get("qc.postprocessing." + id + ".resumeTrend", false); trendIfAllInputs = config.get("qc.postprocessing." + id + ".trendIfAllInputs", false); + trendingTimestamp = config.get("qc.postprocessing." + id + ".trendingTimestamp", "validUntil"); for (const auto& [_, plotConfig] : config.get_child("qc.postprocessing." + id + ".plots")) { // since QC-1155 we allow for more than one graph in a single plot (canvas). we support both the new and old ways diff --git a/doc/PostProcessing.md b/doc/PostProcessing.md index 1a0e25fb66..8b038d4d6d 100644 --- a/doc/PostProcessing.md +++ b/doc/PostProcessing.md @@ -289,6 +289,7 @@ some additional parameters. "detectorName": "TST", "resumeTrend": "false", "producePlotsOnUpdate": "true", + "trendingTimestamp": "validUntil", "dataSources": [], "plots": [], "initTrigger": [ "once" ], @@ -391,6 +392,9 @@ To pick up the last existing trend which matches the specified Activity, set `"r To generate plots only when all input objects are available, set `"trendIfAllInputs"`. +`"trendingTimestamp"` allows to select which timestamp should be used as the trending point. +The available options are `"trigger"` (timestamp provided by the trigger), `"validFrom"` (validity start in activity provided by the trigger), `"validUntil"` (validity end in activity provided by the trigger, default). + ### The SliceTrendingTask class 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`.