From 9813b2ae1003cb176401e1d5fc2cb18ab233e7d3 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Mario=20Kr=C3=BCger?= Date: Fri, 14 May 2021 20:49:09 +0200 Subject: [PATCH 1/8] DPL Analysis: store created histograms in unique_ptrs --- Framework/Core/include/Framework/HistogramRegistry.h | 10 +++++----- Framework/Core/src/HistogramRegistry.cxx | 2 +- 2 files changed, 6 insertions(+), 6 deletions(-) diff --git a/Framework/Core/include/Framework/HistogramRegistry.h b/Framework/Core/include/Framework/HistogramRegistry.h index b7ec8f4d189f8..e652e4c586111 100644 --- a/Framework/Core/include/Framework/HistogramRegistry.h +++ b/Framework/Core/include/Framework/HistogramRegistry.h @@ -36,7 +36,7 @@ struct HistFactory { // create histogram of type T with the axes defined in HistogramSpec template - static std::shared_ptr createHist(const HistogramSpec& histSpec) + static std::unique_ptr createHist(const HistogramSpec& histSpec) { constexpr std::size_t MAX_DIM{10}; const std::size_t nAxes{histSpec.config.axes.size()}; @@ -57,7 +57,7 @@ struct HistFactory { } // create histogram - std::shared_ptr hist{generateHist(histSpec.name, histSpec.title, nAxes, nBins, lowerBounds, upperBounds, histSpec.config.nSteps)}; + std::unique_ptr hist{generateHist(histSpec.name, histSpec.title, nAxes, nBins, lowerBounds, upperBounds, histSpec.config.nSteps)}; if (!hist) { LOGF(FATAL, "The number of dimensions specified for histogram %s does not match the type.", histSpec.name); return nullptr; @@ -65,7 +65,7 @@ struct HistFactory { // set axis properties for (std::size_t i = 0; i < nAxes; i++) { - TAxis* axis{getAxis(i, hist)}; + TAxis* axis{getAxis(i, hist.get())}; if (axis) { if (histSpec.config.axes[i].title) { axis->SetTitle((*histSpec.config.axes[i].title).data()); @@ -98,7 +98,7 @@ struct HistFactory { template static HistPtr createHistVariant(const HistogramSpec& histSpec) { - if (auto hist = castToVariant(createHist(histSpec))) { + if (auto hist = castToVariant(std::move(createHist(histSpec)))) { return *hist; } else { throw runtime_error("Histogram was not created properly."); @@ -117,7 +117,7 @@ struct HistFactory { // helper function to get the axis via index for any type of root histogram template - static TAxis* getAxis(const int i, std::shared_ptr& hist) + static TAxis* getAxis(const int i, T* hist) { if constexpr (std::is_base_of_v || std::is_base_of_v) { return hist->GetAxis(i); diff --git a/Framework/Core/src/HistogramRegistry.cxx b/Framework/Core/src/HistogramRegistry.cxx index f833f2ec8f9ce..88ca417bc9084 100644 --- a/Framework/Core/src/HistogramRegistry.cxx +++ b/Framework/Core/src/HistogramRegistry.cxx @@ -194,7 +194,7 @@ void HistogramRegistry::print(bool showAxisDetails) nDim = hist->GetDimension(); } for (int d = 0; d < nDim; ++d) { - TAxis* axis = HistFactory::getAxis(d, hist); + TAxis* axis = HistFactory::getAxis(d, hist.get()); LOGF(INFO, "- Axis %d: %-20s (%d bins)", d, axis->GetTitle(), axis->GetNbins()); } } From 4b7dca708792f91be2359206378274a13517b75a Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Mario=20Kr=C3=BCger?= Date: Fri, 14 May 2021 20:56:58 +0200 Subject: [PATCH 2/8] DPL Analysis: move HistFactory to HistogramSpec header --- .../include/Framework/HistogramRegistry.h | 167 ------------------ .../Core/include/Framework/HistogramSpec.h | 167 ++++++++++++++++++ 2 files changed, 167 insertions(+), 167 deletions(-) diff --git a/Framework/Core/include/Framework/HistogramRegistry.h b/Framework/Core/include/Framework/HistogramRegistry.h index e652e4c586111..e781066ae2452 100644 --- a/Framework/Core/include/Framework/HistogramRegistry.h +++ b/Framework/Core/include/Framework/HistogramRegistry.h @@ -20,178 +20,11 @@ #include "Framework/OutputSpec.h" #include "Framework/SerializationMethods.h" #include "Framework/TableBuilder.h" -#include "Framework/RuntimeError.h" #define HIST(name) CONST_STR(name) namespace o2::framework { -//************************************************************************************************** -/** - * Static helper class to generate histograms from the specifications. - * Also provides functions to obtain pointer to the created histogram casted to the correct alternative of the std::variant HistPtr that is used in HistogramRegistry. - */ -//************************************************************************************************** -struct HistFactory { - - // create histogram of type T with the axes defined in HistogramSpec - template - static std::unique_ptr createHist(const HistogramSpec& histSpec) - { - constexpr std::size_t MAX_DIM{10}; - const std::size_t nAxes{histSpec.config.axes.size()}; - if (nAxes == 0 || nAxes > MAX_DIM) { - LOGF(FATAL, "The histogram specification contains no (or too many) axes."); - return nullptr; - } - - int nBins[MAX_DIM]{0}; - double lowerBounds[MAX_DIM]{0.}; - double upperBounds[MAX_DIM]{0.}; - - // first figure out number of bins and dimensions - for (std::size_t i = 0; i < nAxes; i++) { - nBins[i] = (histSpec.config.axes[i].nBins) ? *histSpec.config.axes[i].nBins : histSpec.config.axes[i].binEdges.size() - 1; - lowerBounds[i] = histSpec.config.axes[i].binEdges.front(); - upperBounds[i] = histSpec.config.axes[i].binEdges.back(); - } - - // create histogram - std::unique_ptr hist{generateHist(histSpec.name, histSpec.title, nAxes, nBins, lowerBounds, upperBounds, histSpec.config.nSteps)}; - if (!hist) { - LOGF(FATAL, "The number of dimensions specified for histogram %s does not match the type.", histSpec.name); - return nullptr; - } - - // set axis properties - for (std::size_t i = 0; i < nAxes; i++) { - TAxis* axis{getAxis(i, hist.get())}; - if (axis) { - if (histSpec.config.axes[i].title) { - axis->SetTitle((*histSpec.config.axes[i].title).data()); - } - - // this helps to have axes not only called 0,1,2... in ndim histos - if constexpr (std::is_base_of_v) { - if (histSpec.config.axes[i].name) { - axis->SetName((std::string(axis->GetName()) + "-" + *histSpec.config.axes[i].name).data()); - } - } - - // move the bin edges in case a variable binning was requested - if (!histSpec.config.axes[i].nBins) { - if (!std::is_sorted(std::begin(histSpec.config.axes[i].binEdges), std::end(histSpec.config.axes[i].binEdges))) { - LOGF(FATAL, "The bin edges in histogram %s are not in increasing order!", histSpec.name); - return nullptr; - } - axis->Set(nBins[i], histSpec.config.axes[i].binEdges.data()); - } - } - } - if (histSpec.callSumw2) { - hist->Sumw2(); - } - return hist; - } - - // create histogram and return it casted to the correct alternative held in HistPtr variant - template - static HistPtr createHistVariant(const HistogramSpec& histSpec) - { - if (auto hist = castToVariant(std::move(createHist(histSpec)))) { - return *hist; - } else { - throw runtime_error("Histogram was not created properly."); - } - } - - // runtime version of the above - static HistPtr createHistVariant(const HistogramSpec& histSpec) - { - if (histSpec.config.type == HistType::kUndefinedHist) { - throw runtime_error("Histogram type was not specified."); - } else { - return HistogramCreationCallbacks.at(histSpec.config.type)(histSpec); - } - } - - // helper function to get the axis via index for any type of root histogram - template - static TAxis* getAxis(const int i, T* hist) - { - if constexpr (std::is_base_of_v || std::is_base_of_v) { - return hist->GetAxis(i); - } else { - if (i == 0) { - return hist->GetXaxis(); - } else if (i == 1) { - return hist->GetYaxis(); - } else if (i == 2) { - return hist->GetZaxis(); - } else { - return nullptr; - } - } - } - - private: - static const std::map> HistogramCreationCallbacks; - - // helper function to generate the actual histograms - template - static T* generateHist(const std::string& name, const std::string& title, const std::size_t nDim, - const int nBins[], const double lowerBounds[], const double upperBounds[], const int nSteps = 1) - { - if constexpr (std::is_base_of_v) { - return new T(name.data(), title.data(), nSteps, nDim, nBins, lowerBounds, upperBounds); - } else if constexpr (std::is_base_of_v) { - return new T(name.data(), title.data(), nDim, nBins, lowerBounds, upperBounds); - } else if constexpr (std::is_base_of_v) { - return (nDim != 3) ? nullptr - : new T(name.data(), title.data(), nBins[0], lowerBounds[0], - upperBounds[0], nBins[1], lowerBounds[1], upperBounds[1], - nBins[2], lowerBounds[2], upperBounds[2]); - } else if constexpr (std::is_base_of_v) { - return (nDim != 2) ? nullptr - : new T(name.data(), title.data(), nBins[0], lowerBounds[0], - upperBounds[0], nBins[1], lowerBounds[1], upperBounds[1]); - } else if constexpr (std::is_base_of_v) { - return (nDim != 1) - ? nullptr - : new T(name.data(), title.data(), nBins[0], lowerBounds[0], upperBounds[0]); - } - return nullptr; - } - - // helper function to cast the actual histogram type (e.g. TH2F) to the correct interface type (e.g. TH2) that is stored in the HistPtr variant - template - static std::optional castToVariant(std::shared_ptr obj) - { - if (obj->InheritsFrom(T::Class())) { - return std::static_pointer_cast(obj); - } - return std::nullopt; - } - - template - static std::optional castToVariant(std::shared_ptr obj) - { - if (auto hist = castToVariant(obj)) { - return hist; - } - return castToVariant(obj); - } - - static std::optional castToVariant(std::shared_ptr obj) - { - if (obj) { - // TProfile3D is TH3, TProfile2D is TH2, TH3 is TH1, TH2 is TH1, TProfile is TH1 - return castToVariant(obj); - } - return std::nullopt; - } -}; - //************************************************************************************************** /** * Static helper class to fill existing root histograms of any type. diff --git a/Framework/Core/include/Framework/HistogramSpec.h b/Framework/Core/include/Framework/HistogramSpec.h index b391dc8b91802..a2adecd0f1ea1 100644 --- a/Framework/Core/include/Framework/HistogramSpec.h +++ b/Framework/Core/include/Framework/HistogramSpec.h @@ -30,6 +30,7 @@ #include "Framework/StepTHn.h" #include "Framework/Configurable.h" #include "Framework/StringHelpers.h" +#include "Framework/RuntimeError.h" namespace o2::framework { @@ -199,5 +200,171 @@ struct HistogramSpec { bool callSumw2{}; // wether or not hist needs heavy error structure produced by Sumw2() }; +//************************************************************************************************** +/** + * Static helper class to generate histograms from the specifications. + * Also provides functions to obtain pointer to the created histogram casted to the correct alternative of the std::variant HistPtr that is used in HistogramRegistry. + */ +//************************************************************************************************** +struct HistFactory { + + // create histogram of type T with the axes defined in HistogramSpec + template + static std::unique_ptr createHist(const HistogramSpec& histSpec) + { + constexpr std::size_t MAX_DIM{10}; + const std::size_t nAxes{histSpec.config.axes.size()}; + if (nAxes == 0 || nAxes > MAX_DIM) { + LOGF(FATAL, "The histogram specification contains no (or too many) axes."); + return nullptr; + } + + int nBins[MAX_DIM]{0}; + double lowerBounds[MAX_DIM]{0.}; + double upperBounds[MAX_DIM]{0.}; + + // first figure out number of bins and dimensions + for (std::size_t i = 0; i < nAxes; i++) { + nBins[i] = (histSpec.config.axes[i].nBins) ? *histSpec.config.axes[i].nBins : histSpec.config.axes[i].binEdges.size() - 1; + lowerBounds[i] = histSpec.config.axes[i].binEdges.front(); + upperBounds[i] = histSpec.config.axes[i].binEdges.back(); + } + + // create histogram + std::unique_ptr hist{generateHist(histSpec.name, histSpec.title, nAxes, nBins, lowerBounds, upperBounds, histSpec.config.nSteps)}; + if (!hist) { + LOGF(FATAL, "The number of dimensions specified for histogram %s does not match the type.", histSpec.name); + return nullptr; + } + + // set axis properties + for (std::size_t i = 0; i < nAxes; i++) { + TAxis* axis{getAxis(i, hist.get())}; + if (axis) { + if (histSpec.config.axes[i].title) { + axis->SetTitle((*histSpec.config.axes[i].title).data()); + } + + // this helps to have axes not only called 0,1,2... in ndim histos + if constexpr (std::is_base_of_v) { + if (histSpec.config.axes[i].name) { + axis->SetName((std::string(axis->GetName()) + "-" + *histSpec.config.axes[i].name).data()); + } + } + + // move the bin edges in case a variable binning was requested + if (!histSpec.config.axes[i].nBins) { + if (!std::is_sorted(std::begin(histSpec.config.axes[i].binEdges), std::end(histSpec.config.axes[i].binEdges))) { + LOGF(FATAL, "The bin edges in histogram %s are not in increasing order!", histSpec.name); + return nullptr; + } + axis->Set(nBins[i], histSpec.config.axes[i].binEdges.data()); + } + } + } + if (histSpec.callSumw2) { + hist->Sumw2(); + } + return hist; + } + + // create histogram and return it casted to the correct alternative held in HistPtr variant + template + static HistPtr createHistVariant(const HistogramSpec& histSpec) + { + if (auto hist = castToVariant(std::move(createHist(histSpec)))) { + return *hist; + } else { + throw runtime_error("Histogram was not created properly."); + } + } + + // runtime version of the above + static HistPtr createHistVariant(const HistogramSpec& histSpec) + { + if (histSpec.config.type == HistType::kUndefinedHist) { + throw runtime_error("Histogram type was not specified."); + } else { + return HistogramCreationCallbacks.at(histSpec.config.type)(histSpec); + } + } + + // helper function to get the axis via index for any type of root histogram + template + static TAxis* getAxis(const int i, T* hist) + { + if constexpr (std::is_base_of_v || std::is_base_of_v) { + return hist->GetAxis(i); + } else { + if (i == 0) { + return hist->GetXaxis(); + } else if (i == 1) { + return hist->GetYaxis(); + } else if (i == 2) { + return hist->GetZaxis(); + } else { + return nullptr; + } + } + } + + private: + static const std::map> HistogramCreationCallbacks; + + // helper function to generate the actual histograms + template + static T* generateHist(const std::string& name, const std::string& title, const std::size_t nDim, + const int nBins[], const double lowerBounds[], const double upperBounds[], const int nSteps = 1) + { + if constexpr (std::is_base_of_v) { + return new T(name.data(), title.data(), nSteps, nDim, nBins, lowerBounds, upperBounds); + } else if constexpr (std::is_base_of_v) { + return new T(name.data(), title.data(), nDim, nBins, lowerBounds, upperBounds); + } else if constexpr (std::is_base_of_v) { + return (nDim != 3) ? nullptr + : new T(name.data(), title.data(), nBins[0], lowerBounds[0], + upperBounds[0], nBins[1], lowerBounds[1], upperBounds[1], + nBins[2], lowerBounds[2], upperBounds[2]); + } else if constexpr (std::is_base_of_v) { + return (nDim != 2) ? nullptr + : new T(name.data(), title.data(), nBins[0], lowerBounds[0], + upperBounds[0], nBins[1], lowerBounds[1], upperBounds[1]); + } else if constexpr (std::is_base_of_v) { + return (nDim != 1) + ? nullptr + : new T(name.data(), title.data(), nBins[0], lowerBounds[0], upperBounds[0]); + } + return nullptr; + } + + // helper function to cast the actual histogram type (e.g. TH2F) to the correct interface type (e.g. TH2) that is stored in the HistPtr variant + template + static std::optional castToVariant(std::shared_ptr obj) + { + if (obj->InheritsFrom(T::Class())) { + return std::static_pointer_cast(obj); + } + return std::nullopt; + } + + template + static std::optional castToVariant(std::shared_ptr obj) + { + if (auto hist = castToVariant(obj)) { + return hist; + } + return castToVariant(obj); + } + + static std::optional castToVariant(std::shared_ptr obj) + { + if (obj) { + // TProfile3D is TH3, TProfile2D is TH2, TH3 is TH1, TH2 is TH1, TProfile is TH1 + return castToVariant(obj); + } + return std::nullopt; + } +}; + } // namespace o2::framework #endif // FRAMEWORK_HISTOGRAMSPEC_H_ From ec9f43331e9602bda56251856616d423a225eb48 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Mario=20Kr=C3=BCger?= Date: Fri, 14 May 2021 21:20:17 +0200 Subject: [PATCH 3/8] avoid cloning histograms in CorrelatinContainer --- Analysis/Core/src/CorrelationContainer.cxx | 15 +++++++-------- 1 file changed, 7 insertions(+), 8 deletions(-) diff --git a/Analysis/Core/src/CorrelationContainer.cxx b/Analysis/Core/src/CorrelationContainer.cxx index 96eaaa7187819..2f943b57162e9 100644 --- a/Analysis/Core/src/CorrelationContainer.cxx +++ b/Analysis/Core/src/CorrelationContainer.cxx @@ -26,13 +26,13 @@ #include "TCanvas.h" #include "TF1.h" #include "THn.h" -#include "Framework/HistogramRegistry.h" +#include "Framework/HistogramSpec.h" using namespace o2::framework; -ClassImp(CorrelationContainer) +ClassImp(CorrelationContainer); - const Int_t CorrelationContainer::fgkCFSteps = 11; +const Int_t CorrelationContainer::fgkCFSteps = 11; CorrelationContainer::CorrelationContainer() : TNamed(), mPairHist(nullptr), @@ -94,11 +94,10 @@ CorrelationContainer::CorrelationContainer(const char* name, const char* objTitl LOGF(info, "Creating CorrelationContainer"); - // TODO Remove Clone() pending change in HistogramRegistry - mPairHist = (StepTHnF*)HistFactory::createHist({"mPairHist", "d^{2}N_{ch}/d#varphid#eta", {HistType::kStepTHnF, {axisList[0], axisList[1], axisList[2], axisList[3], axisList[4], axisList[5]}, fgkCFSteps}})->Clone(); - mTriggerHist = (StepTHnF*)HistFactory::createHist({"mTriggerHist", "d^{2}N_{ch}/d#varphid#eta", {HistType::kStepTHnF, {axisList[2], axisList[3], axisList[5]}, fgkCFSteps}})->Clone(); - mTrackHistEfficiency = (StepTHnD*)HistFactory::createHist({"mTrackHistEfficiency", "Tracking efficiency", {HistType::kStepTHnD, {axisList[6], axisList[7], {4, -0.5, 3.5, "species"}, axisList[3], axisList[8]}, fgkCFSteps}})->Clone(); - mEventCount = (TH2F*)(HistFactory::createHist({"mEventCount", ";step;centrality;count", {HistType::kTH2F, {{fgkCFSteps + 2, -2.5, -0.5 + fgkCFSteps, "step"}, axisList[3]}}})->Clone()); + mPairHist = HistFactory::createHist({"mPairHist", "d^{2}N_{ch}/d#varphid#eta", {HistType::kStepTHnF, {axisList[0], axisList[1], axisList[2], axisList[3], axisList[4], axisList[5]}, fgkCFSteps}}).release(); + mTriggerHist = HistFactory::createHist({"mTriggerHist", "d^{2}N_{ch}/d#varphid#eta", {HistType::kStepTHnF, {axisList[2], axisList[3], axisList[5]}, fgkCFSteps}}).release(); + mTrackHistEfficiency = HistFactory::createHist({"mTrackHistEfficiency", "Tracking efficiency", {HistType::kStepTHnD, {axisList[6], axisList[7], {4, -0.5, 3.5, "species"}, axisList[3], axisList[8]}, fgkCFSteps}}).release(); + mEventCount = HistFactory::createHist({"mEventCount", ";step;centrality;count", {HistType::kTH2F, {{fgkCFSteps + 2, -2.5, -0.5 + fgkCFSteps, "step"}, axisList[3]}}}).release(); } //_____________________________________________________________________________ From 288774bac1d404ee06c7789007d6de6c2edd2b8c Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Mario=20Kr=C3=BCger?= Date: Sat, 15 May 2021 10:42:12 +0200 Subject: [PATCH 4/8] try to fix gcc compilation --- Framework/Core/include/Framework/HistogramSpec.h | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Framework/Core/include/Framework/HistogramSpec.h b/Framework/Core/include/Framework/HistogramSpec.h index a2adecd0f1ea1..48c692b6cc307 100644 --- a/Framework/Core/include/Framework/HistogramSpec.h +++ b/Framework/Core/include/Framework/HistogramSpec.h @@ -272,7 +272,7 @@ struct HistFactory { template static HistPtr createHistVariant(const HistogramSpec& histSpec) { - if (auto hist = castToVariant(std::move(createHist(histSpec)))) { + if (auto hist = castToVariant(std::shared_ptr(std::move(createHist(histSpec))))) { return *hist; } else { throw runtime_error("Histogram was not created properly."); From 65ea6f732a6f295d331a4f9480dc4478590f5083 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Mario=20Kr=C3=BCger?= Date: Sat, 15 May 2021 12:31:51 +0200 Subject: [PATCH 5/8] make pointer type explicit --- Framework/Core/include/Framework/HistogramSpec.h | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Framework/Core/include/Framework/HistogramSpec.h b/Framework/Core/include/Framework/HistogramSpec.h index 48c692b6cc307..e0e7e60f82a44 100644 --- a/Framework/Core/include/Framework/HistogramSpec.h +++ b/Framework/Core/include/Framework/HistogramSpec.h @@ -272,7 +272,7 @@ struct HistFactory { template static HistPtr createHistVariant(const HistogramSpec& histSpec) { - if (auto hist = castToVariant(std::shared_ptr(std::move(createHist(histSpec))))) { + if (auto hist = castToVariant(std::shared_ptr(std::move(createHist(histSpec))))) { return *hist; } else { throw runtime_error("Histogram was not created properly."); From 2e60d947a6c14641fe04a24a4cdb275aa7c7c0b3 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Mario=20Kr=C3=BCger?= Date: Sat, 15 May 2021 14:07:08 +0200 Subject: [PATCH 6/8] move not needed --- Framework/Core/include/Framework/HistogramSpec.h | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Framework/Core/include/Framework/HistogramSpec.h b/Framework/Core/include/Framework/HistogramSpec.h index e0e7e60f82a44..eeeb5fc486a25 100644 --- a/Framework/Core/include/Framework/HistogramSpec.h +++ b/Framework/Core/include/Framework/HistogramSpec.h @@ -272,7 +272,7 @@ struct HistFactory { template static HistPtr createHistVariant(const HistogramSpec& histSpec) { - if (auto hist = castToVariant(std::shared_ptr(std::move(createHist(histSpec))))) { + if (auto hist = castToVariant(createHist(histSpec))) { return *hist; } else { throw runtime_error("Histogram was not created properly."); From 3bdb421a194f3455633faf476a03255a83e40bcb Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Mario=20Kr=C3=BCger?= Date: Sat, 15 May 2021 15:18:46 +0200 Subject: [PATCH 7/8] try with lvalue --- Framework/Core/include/Framework/HistogramSpec.h | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/Framework/Core/include/Framework/HistogramSpec.h b/Framework/Core/include/Framework/HistogramSpec.h index eeeb5fc486a25..58f22e5b8adfc 100644 --- a/Framework/Core/include/Framework/HistogramSpec.h +++ b/Framework/Core/include/Framework/HistogramSpec.h @@ -272,7 +272,8 @@ struct HistFactory { template static HistPtr createHistVariant(const HistogramSpec& histSpec) { - if (auto hist = castToVariant(createHist(histSpec))) { + std::shared_ptr origHist = createHist(histSpec); + if (auto hist = castToVariant(origHist)) { return *hist; } else { throw runtime_error("Histogram was not created properly."); From d747b042390e4d8222c3d292a814fd9e19733cd3 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Mario=20Kr=C3=BCger?= Date: Sun, 16 May 2021 15:06:12 +0200 Subject: [PATCH 8/8] move HistFactory back for now --- Analysis/Core/src/CorrelationContainer.cxx | 2 +- .../include/Framework/HistogramRegistry.h | 167 +++++++++++++++++ .../Core/include/Framework/HistogramSpec.h | 175 +----------------- 3 files changed, 172 insertions(+), 172 deletions(-) diff --git a/Analysis/Core/src/CorrelationContainer.cxx b/Analysis/Core/src/CorrelationContainer.cxx index 2f943b57162e9..ff28029d6ff9c 100644 --- a/Analysis/Core/src/CorrelationContainer.cxx +++ b/Analysis/Core/src/CorrelationContainer.cxx @@ -26,7 +26,7 @@ #include "TCanvas.h" #include "TF1.h" #include "THn.h" -#include "Framework/HistogramSpec.h" +#include "Framework/HistogramRegistry.h" using namespace o2::framework; diff --git a/Framework/Core/include/Framework/HistogramRegistry.h b/Framework/Core/include/Framework/HistogramRegistry.h index e781066ae2452..0e84387777d1c 100644 --- a/Framework/Core/include/Framework/HistogramRegistry.h +++ b/Framework/Core/include/Framework/HistogramRegistry.h @@ -25,6 +25,173 @@ namespace o2::framework { + +//************************************************************************************************** +/** + * Static helper class to generate histograms from the specifications. + * Also provides functions to obtain pointer to the created histogram casted to the correct alternative of the std::variant HistPtr that is used in HistogramRegistry. + */ +//************************************************************************************************** +struct HistFactory { + + // create histogram of type T with the axes defined in HistogramSpec + template + static std::unique_ptr createHist(const HistogramSpec& histSpec) + { + constexpr std::size_t MAX_DIM{10}; + const std::size_t nAxes{histSpec.config.axes.size()}; + if (nAxes == 0 || nAxes > MAX_DIM) { + LOGF(FATAL, "The histogram specification contains no (or too many) axes."); + return nullptr; + } + + int nBins[MAX_DIM]{0}; + double lowerBounds[MAX_DIM]{0.}; + double upperBounds[MAX_DIM]{0.}; + + // first figure out number of bins and dimensions + for (std::size_t i = 0; i < nAxes; i++) { + nBins[i] = (histSpec.config.axes[i].nBins) ? *histSpec.config.axes[i].nBins : histSpec.config.axes[i].binEdges.size() - 1; + lowerBounds[i] = histSpec.config.axes[i].binEdges.front(); + upperBounds[i] = histSpec.config.axes[i].binEdges.back(); + } + + // create histogram + std::unique_ptr hist{generateHist(histSpec.name, histSpec.title, nAxes, nBins, lowerBounds, upperBounds, histSpec.config.nSteps)}; + if (!hist) { + LOGF(FATAL, "The number of dimensions specified for histogram %s does not match the type.", histSpec.name); + return nullptr; + } + + // set axis properties + for (std::size_t i = 0; i < nAxes; i++) { + TAxis* axis{getAxis(i, hist.get())}; + if (axis) { + if (histSpec.config.axes[i].title) { + axis->SetTitle((*histSpec.config.axes[i].title).data()); + } + + // this helps to have axes not only called 0,1,2... in ndim histos + if constexpr (std::is_base_of_v) { + if (histSpec.config.axes[i].name) { + axis->SetName((std::string(axis->GetName()) + "-" + *histSpec.config.axes[i].name).data()); + } + } + + // move the bin edges in case a variable binning was requested + if (!histSpec.config.axes[i].nBins) { + if (!std::is_sorted(std::begin(histSpec.config.axes[i].binEdges), std::end(histSpec.config.axes[i].binEdges))) { + LOGF(FATAL, "The bin edges in histogram %s are not in increasing order!", histSpec.name); + return nullptr; + } + axis->Set(nBins[i], histSpec.config.axes[i].binEdges.data()); + } + } + } + if (histSpec.callSumw2) { + hist->Sumw2(); + } + return hist; + } + + // create histogram and return it casted to the correct alternative held in HistPtr variant + template + static HistPtr createHistVariant(const HistogramSpec& histSpec) + { + if (auto hist = castToVariant(createHist(histSpec))) { + return *hist; + } else { + throw runtime_error("Histogram was not created properly."); + } + } + + // runtime version of the above + static HistPtr createHistVariant(const HistogramSpec& histSpec) + { + if (histSpec.config.type == HistType::kUndefinedHist) { + throw runtime_error("Histogram type was not specified."); + } else { + return HistogramCreationCallbacks.at(histSpec.config.type)(histSpec); + } + } + + // helper function to get the axis via index for any type of root histogram + template + static TAxis* getAxis(const int i, T* hist) + { + if constexpr (std::is_base_of_v || std::is_base_of_v) { + return hist->GetAxis(i); + } else { + if (i == 0) { + return hist->GetXaxis(); + } else if (i == 1) { + return hist->GetYaxis(); + } else if (i == 2) { + return hist->GetZaxis(); + } else { + return nullptr; + } + } + } + + private: + static const std::map> HistogramCreationCallbacks; + + // helper function to generate the actual histograms + template + static T* generateHist(const std::string& name, const std::string& title, const std::size_t nDim, + const int nBins[], const double lowerBounds[], const double upperBounds[], const int nSteps = 1) + { + if constexpr (std::is_base_of_v) { + return new T(name.data(), title.data(), nSteps, nDim, nBins, lowerBounds, upperBounds); + } else if constexpr (std::is_base_of_v) { + return new T(name.data(), title.data(), nDim, nBins, lowerBounds, upperBounds); + } else if constexpr (std::is_base_of_v) { + return (nDim != 3) ? nullptr + : new T(name.data(), title.data(), nBins[0], lowerBounds[0], + upperBounds[0], nBins[1], lowerBounds[1], upperBounds[1], + nBins[2], lowerBounds[2], upperBounds[2]); + } else if constexpr (std::is_base_of_v) { + return (nDim != 2) ? nullptr + : new T(name.data(), title.data(), nBins[0], lowerBounds[0], + upperBounds[0], nBins[1], lowerBounds[1], upperBounds[1]); + } else if constexpr (std::is_base_of_v) { + return (nDim != 1) + ? nullptr + : new T(name.data(), title.data(), nBins[0], lowerBounds[0], upperBounds[0]); + } + return nullptr; + } + + // helper function to cast the actual histogram type (e.g. TH2F) to the correct interface type (e.g. TH2) that is stored in the HistPtr variant + template + static std::optional castToVariant(std::shared_ptr obj) + { + if (obj->InheritsFrom(T::Class())) { + return std::static_pointer_cast(obj); + } + return std::nullopt; + } + + template + static std::optional castToVariant(std::shared_ptr obj) + { + if (auto hist = castToVariant(obj)) { + return hist; + } + return castToVariant(obj); + } + + static std::optional castToVariant(std::shared_ptr obj) + { + if (obj) { + // TProfile3D is TH3, TProfile2D is TH2, TH3 is TH1, TH2 is TH1, TProfile is TH1 + return castToVariant(obj); + } + return std::nullopt; + } +}; + //************************************************************************************************** /** * Static helper class to fill existing root histograms of any type. diff --git a/Framework/Core/include/Framework/HistogramSpec.h b/Framework/Core/include/Framework/HistogramSpec.h index 58f22e5b8adfc..c6af69a2e42fe 100644 --- a/Framework/Core/include/Framework/HistogramSpec.h +++ b/Framework/Core/include/Framework/HistogramSpec.h @@ -11,6 +11,10 @@ #ifndef FRAMEWORK_HISTOGRAMSPEC_H_ #define FRAMEWORK_HISTOGRAMSPEC_H_ +#include +#include +#include + #include #include #include @@ -23,10 +27,6 @@ #include #include -#include -#include -#include - #include "Framework/StepTHn.h" #include "Framework/Configurable.h" #include "Framework/StringHelpers.h" @@ -200,172 +200,5 @@ struct HistogramSpec { bool callSumw2{}; // wether or not hist needs heavy error structure produced by Sumw2() }; -//************************************************************************************************** -/** - * Static helper class to generate histograms from the specifications. - * Also provides functions to obtain pointer to the created histogram casted to the correct alternative of the std::variant HistPtr that is used in HistogramRegistry. - */ -//************************************************************************************************** -struct HistFactory { - - // create histogram of type T with the axes defined in HistogramSpec - template - static std::unique_ptr createHist(const HistogramSpec& histSpec) - { - constexpr std::size_t MAX_DIM{10}; - const std::size_t nAxes{histSpec.config.axes.size()}; - if (nAxes == 0 || nAxes > MAX_DIM) { - LOGF(FATAL, "The histogram specification contains no (or too many) axes."); - return nullptr; - } - - int nBins[MAX_DIM]{0}; - double lowerBounds[MAX_DIM]{0.}; - double upperBounds[MAX_DIM]{0.}; - - // first figure out number of bins and dimensions - for (std::size_t i = 0; i < nAxes; i++) { - nBins[i] = (histSpec.config.axes[i].nBins) ? *histSpec.config.axes[i].nBins : histSpec.config.axes[i].binEdges.size() - 1; - lowerBounds[i] = histSpec.config.axes[i].binEdges.front(); - upperBounds[i] = histSpec.config.axes[i].binEdges.back(); - } - - // create histogram - std::unique_ptr hist{generateHist(histSpec.name, histSpec.title, nAxes, nBins, lowerBounds, upperBounds, histSpec.config.nSteps)}; - if (!hist) { - LOGF(FATAL, "The number of dimensions specified for histogram %s does not match the type.", histSpec.name); - return nullptr; - } - - // set axis properties - for (std::size_t i = 0; i < nAxes; i++) { - TAxis* axis{getAxis(i, hist.get())}; - if (axis) { - if (histSpec.config.axes[i].title) { - axis->SetTitle((*histSpec.config.axes[i].title).data()); - } - - // this helps to have axes not only called 0,1,2... in ndim histos - if constexpr (std::is_base_of_v) { - if (histSpec.config.axes[i].name) { - axis->SetName((std::string(axis->GetName()) + "-" + *histSpec.config.axes[i].name).data()); - } - } - - // move the bin edges in case a variable binning was requested - if (!histSpec.config.axes[i].nBins) { - if (!std::is_sorted(std::begin(histSpec.config.axes[i].binEdges), std::end(histSpec.config.axes[i].binEdges))) { - LOGF(FATAL, "The bin edges in histogram %s are not in increasing order!", histSpec.name); - return nullptr; - } - axis->Set(nBins[i], histSpec.config.axes[i].binEdges.data()); - } - } - } - if (histSpec.callSumw2) { - hist->Sumw2(); - } - return hist; - } - - // create histogram and return it casted to the correct alternative held in HistPtr variant - template - static HistPtr createHistVariant(const HistogramSpec& histSpec) - { - std::shared_ptr origHist = createHist(histSpec); - if (auto hist = castToVariant(origHist)) { - return *hist; - } else { - throw runtime_error("Histogram was not created properly."); - } - } - - // runtime version of the above - static HistPtr createHistVariant(const HistogramSpec& histSpec) - { - if (histSpec.config.type == HistType::kUndefinedHist) { - throw runtime_error("Histogram type was not specified."); - } else { - return HistogramCreationCallbacks.at(histSpec.config.type)(histSpec); - } - } - - // helper function to get the axis via index for any type of root histogram - template - static TAxis* getAxis(const int i, T* hist) - { - if constexpr (std::is_base_of_v || std::is_base_of_v) { - return hist->GetAxis(i); - } else { - if (i == 0) { - return hist->GetXaxis(); - } else if (i == 1) { - return hist->GetYaxis(); - } else if (i == 2) { - return hist->GetZaxis(); - } else { - return nullptr; - } - } - } - - private: - static const std::map> HistogramCreationCallbacks; - - // helper function to generate the actual histograms - template - static T* generateHist(const std::string& name, const std::string& title, const std::size_t nDim, - const int nBins[], const double lowerBounds[], const double upperBounds[], const int nSteps = 1) - { - if constexpr (std::is_base_of_v) { - return new T(name.data(), title.data(), nSteps, nDim, nBins, lowerBounds, upperBounds); - } else if constexpr (std::is_base_of_v) { - return new T(name.data(), title.data(), nDim, nBins, lowerBounds, upperBounds); - } else if constexpr (std::is_base_of_v) { - return (nDim != 3) ? nullptr - : new T(name.data(), title.data(), nBins[0], lowerBounds[0], - upperBounds[0], nBins[1], lowerBounds[1], upperBounds[1], - nBins[2], lowerBounds[2], upperBounds[2]); - } else if constexpr (std::is_base_of_v) { - return (nDim != 2) ? nullptr - : new T(name.data(), title.data(), nBins[0], lowerBounds[0], - upperBounds[0], nBins[1], lowerBounds[1], upperBounds[1]); - } else if constexpr (std::is_base_of_v) { - return (nDim != 1) - ? nullptr - : new T(name.data(), title.data(), nBins[0], lowerBounds[0], upperBounds[0]); - } - return nullptr; - } - - // helper function to cast the actual histogram type (e.g. TH2F) to the correct interface type (e.g. TH2) that is stored in the HistPtr variant - template - static std::optional castToVariant(std::shared_ptr obj) - { - if (obj->InheritsFrom(T::Class())) { - return std::static_pointer_cast(obj); - } - return std::nullopt; - } - - template - static std::optional castToVariant(std::shared_ptr obj) - { - if (auto hist = castToVariant(obj)) { - return hist; - } - return castToVariant(obj); - } - - static std::optional castToVariant(std::shared_ptr obj) - { - if (obj) { - // TProfile3D is TH3, TProfile2D is TH2, TH3 is TH1, TH2 is TH1, TProfile is TH1 - return castToVariant(obj); - } - return std::nullopt; - } -}; - } // namespace o2::framework #endif // FRAMEWORK_HISTOGRAMSPEC_H_