From a1964448c6a1265e7a52c1176a93e6048f66ce1f Mon Sep 17 00:00:00 2001 From: Piotr Konopka Date: Wed, 18 Jun 2025 15:35:14 +0200 Subject: [PATCH] QC-1290 Possibility to have evenly-spaced trends against run numbers This commits adds runNumberStr branch to trends in TrendingTask and SliceTrendingTask to allow for creating trends with evenly-spaced data points, where run rumbers work as labels. --- Framework/include/QualityControl/SliceTrendingTask.h | 4 ++++ Framework/include/QualityControl/TrendingTask.h | 6 +++++- Framework/src/SliceTrendingTask.cxx | 2 ++ Framework/src/TrendingTask.cxx | 3 ++- Modules/Common/src/TH1SliceReductor.cxx | 6 +++--- doc/PostProcessing.md | 2 +- 6 files changed, 17 insertions(+), 6 deletions(-) diff --git a/Framework/include/QualityControl/SliceTrendingTask.h b/Framework/include/QualityControl/SliceTrendingTask.h index fe909f5c9e..5f2bb62e0d 100644 --- a/Framework/include/QualityControl/SliceTrendingTask.h +++ b/Framework/include/QualityControl/SliceTrendingTask.h @@ -65,8 +65,12 @@ class SliceTrendingTask : public PostProcessingInterface void finalize(Trigger, framework::ServiceRegistryRef) final; private: + static constexpr size_t MaxRunNumberStringLength = 6; struct MetaData { + // we store run numbers both as an integer and as a string to allow users to select whether they need + // a trend in integer or label domain (the latter will contain evenly-spaced data points) Int_t runNumber = 0; + char runNumberStr[MaxRunNumberStringLength + 1] = { 0 }; // 6 characters + null terminator }; struct TitleSettings { std::string observableX; diff --git a/Framework/include/QualityControl/TrendingTask.h b/Framework/include/QualityControl/TrendingTask.h index 26f3b01624..9b37bee237 100644 --- a/Framework/include/QualityControl/TrendingTask.h +++ b/Framework/include/QualityControl/TrendingTask.h @@ -56,11 +56,15 @@ class TrendingTask : public PostProcessingInterface void finalize(Trigger, framework::ServiceRegistryRef) override; private: + static constexpr size_t MaxRunNumberStringLength = 6; struct { + // we store run numbers both as an integer and as a string to allow users to select whether they need + // a trend in integer or label domain (the latter will contain evenly-spaced data points) Long64_t runNumber = 0; + char runNumberStr[MaxRunNumberStringLength + 1] = { 0 }; // 6 characters + null terminator static const char* getBranchLeafList() { - return "runNumber/L"; + return "runNumber/L:runNumberStr/C"; } } mMetaData; diff --git a/Framework/src/SliceTrendingTask.cxx b/Framework/src/SliceTrendingTask.cxx index e7638c70f0..16c28d6968 100644 --- a/Framework/src/SliceTrendingTask.cxx +++ b/Framework/src/SliceTrendingTask.cxx @@ -145,6 +145,8 @@ void SliceTrendingTask::trendValues(const Trigger& t, mTime = t.activity.mValidity.getMax() / 1000; } mMetaData.runNumber = t.activity.mId; + std::snprintf(mMetaData.runNumberStr, MaxRunNumberStringLength + 1, "%d", t.activity.mId); + for (auto& dataSource : mConfig.dataSources) { mNumberPads[dataSource.name] = 0; mSources[dataSource.name]->clear(); diff --git a/Framework/src/TrendingTask.cxx b/Framework/src/TrendingTask.cxx index db98dca175..1f6ed5accf 100644 --- a/Framework/src/TrendingTask.cxx +++ b/Framework/src/TrendingTask.cxx @@ -184,8 +184,9 @@ bool TrendingTask::trendValues(const Trigger& t, repository::DatabaseInterface& mTime = t.activity.mValidity.getMax() / 1000; } mMetaData.runNumber = t.activity.mId; - bool wereAllSourcesInvoked = true; + std::snprintf(mMetaData.runNumberStr, MaxRunNumberStringLength + 1, "%d", t.activity.mId); + bool wereAllSourcesInvoked = true; for (auto& dataSource : mConfig.dataSources) { if (!reductor_helpers::updateReductor(mReductors[dataSource.name].get(), t, dataSource, qcdb, *this)) { wereAllSourcesInvoked = false; diff --git a/Modules/Common/src/TH1SliceReductor.cxx b/Modules/Common/src/TH1SliceReductor.cxx index d36f3082ce..00ebd0d3f6 100644 --- a/Modules/Common/src/TH1SliceReductor.cxx +++ b/Modules/Common/src/TH1SliceReductor.cxx @@ -134,15 +134,15 @@ void TH1SliceReductor::GetTH1StatsY(TH1* hist, float stats[3], // Safety measures. if (lowerBin <= 0 || upperBin <= 0) { - ILOG(Error, Support) << "Error: Negative bin in TH1ReducterTPC::GetTH1StatsY" << ENDM; + ILOG(Error, Support) << "Error: Negative bin in TH1SliceReductor::GetTH1StatsY" << ENDM; exit(0); } if (upperBin < lowerBin) { - ILOG(Error, Support) << "Error: Upper bin smaller than lower bin in TH1ReducterTPC::GetTH1StatsY" << ENDM; + ILOG(Error, Support) << "Error: Upper bin smaller than lower bin in TH1SliceReductor::GetTH1StatsY" << ENDM; exit(0); } if (nTotalBins < iterateBins) { - ILOG(Error, Support) << "Error: Bin region bigger than total amount of bins TH1ReducterTPC::GetTH1StatsY" << ENDM; + ILOG(Error, Support) << "Error: Bin region bigger than total amount of bins TH1SliceReductor::GetTH1StatsY" << ENDM; exit(0); } diff --git a/doc/PostProcessing.md b/doc/PostProcessing.md index add28a74be..6d5fb08730 100644 --- a/doc/PostProcessing.md +++ b/doc/PostProcessing.md @@ -287,7 +287,7 @@ In such case, to reduce a Monitor Object or Quality Object, one has to inherit R All the values are stored in a **TTree**. Each data source forms a separate branch, with its leaves being the individual values. -Additionally added columns include a `time` branch and a `metadata` branch (now consisting only of `runNumber`). +Additionally added columns include a `time` branch and a `metadata` branch, consisting of `runNumber` (integer) and `runNumberStr` (string/label). The TTree is stored back to the **QC database** each time it is updated. In addition, the class exposes the [`TTree::Draw`](https://root.cern/doc/master/classTTree.html#a73450649dc6e54b5b94516c468523e45) interface, which allows to instantaneously generate **plots** with trends, correlations or histograms that are also sent to the QC database.