Project
Loading...
Searching...
No Matches
HistogramSpec.cxx
Go to the documentation of this file.
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
14
15namespace o2::framework
16{
17
19{
20 if (binEdges.size() > 2) {
21 LOG(fatal) << "Cannot make a variabled bin width axis logaritmic";
22 }
23
24 const double min = binEdges[0];
25 if (min <= 0.) {
26 LOG(fatal) << "Cannot have the first bin limit of the log. axis below 0: " << min;
27 }
28 const double max = binEdges[1];
29 binEdges.clear();
30 const double logmin = std::log10(min);
31 const double logmax = std::log10(max);
32 const int nbins = nBins.value();
33 const double logdelta = (logmax - logmin) / (static_cast<double>(nbins));
34 LOG(debug) << "Making a logaritmic binning from " << min << " to " << max << " with " << nbins << " bins";
35 for (int i = 0; i < nbins + 1; i++) {
36 const auto nextEdge = std::pow(10, logmin + i * logdelta);
37 LOG(debug) << i << "/" << nbins - 1 << ": " << nextEdge;
38 binEdges.push_back(nextEdge);
39 }
40 nBins = std::nullopt;
41}
42
44{
45 // return the number of bins
46 if (nBins.has_value()) {
47 return *nBins;
48 }
49 return binEdges.size() - 1;
50}
51
52// helper function to generate the actual histograms
53template <typename T>
54T* generateHist(const std::string& name, const std::string& title, const std::size_t nDim,
55 const int nBins[], const double lowerBounds[], const double upperBounds[], const int nSteps)
56{
57 if constexpr (std::is_base_of_v<StepTHn, T>) {
58 return new T(name.data(), title.data(), nSteps, nDim, nBins, lowerBounds, upperBounds);
59 } else if constexpr (std::is_base_of_v<THnBase, T>) {
60 return new T(name.data(), title.data(), nDim, nBins, lowerBounds, upperBounds);
61 } else if constexpr (std::is_base_of_v<TH3, T>) {
62 return (nDim != 3) ? nullptr
63 : new T(name.data(), title.data(), nBins[0], lowerBounds[0],
64 upperBounds[0], nBins[1], lowerBounds[1], upperBounds[1],
65 nBins[2], lowerBounds[2], upperBounds[2]);
66 } else if constexpr (std::is_base_of_v<TH2, T>) {
67 return (nDim != 2) ? nullptr
68 : new T(name.data(), title.data(), nBins[0], lowerBounds[0],
69 upperBounds[0], nBins[1], lowerBounds[1], upperBounds[1]);
70 } else if constexpr (std::is_base_of_v<TH1, T>) {
71 return (nDim != 1)
72 ? nullptr
73 : new T(name.data(), title.data(), nBins[0], lowerBounds[0], upperBounds[0]);
74 }
75 return nullptr;
76}
77
78// main function for creating arbitrary histograms
79template <typename T, typename BASE>
80static std::unique_ptr<BASE> createHistFull(const HistogramSpec& histSpec)
81{
82 constexpr std::size_t MAX_DIM{20};
83 const std::size_t nAxes{histSpec.config.axes.size()};
84 if (nAxes == 0 || nAxes > MAX_DIM) {
85 LOGF(fatal, "The histogram specification contains no (or too many) axes.");
86 }
87
88 int nBins[MAX_DIM]{0};
89 double lowerBounds[MAX_DIM]{0.};
90 double upperBounds[MAX_DIM]{0.};
91
92 // first figure out number of bins and dimensions
93 for (std::size_t i = 0; i < nAxes; i++) {
94 nBins[i] = (histSpec.config.axes[i].nBins) ? *histSpec.config.axes[i].nBins : histSpec.config.axes[i].binEdges.size() - 1;
95 lowerBounds[i] = histSpec.config.axes[i].binEdges.front();
96 upperBounds[i] = histSpec.config.axes[i].binEdges.back();
97 }
98
99 // create histogram
100 std::unique_ptr<BASE> hist{generateHist<T>(histSpec.name, histSpec.title, nAxes, nBins, lowerBounds, upperBounds, histSpec.config.nSteps)};
101 if (!hist) {
102 LOGF(fatal, "The number of dimensions specified for histogram %s does not match the type.", histSpec.name);
103 }
104
105 // set axis properties
106 for (std::size_t i = 0; i < nAxes; i++) {
107 TAxis* axis{HistFactory::getAxis(i, hist.get())};
108 if (axis) {
109 if (histSpec.config.axes[i].title) {
110 axis->SetTitle((*histSpec.config.axes[i].title).data());
111 }
112
113 // this helps to have axes not only called 0,1,2... in ndim histos
114 if constexpr (std::is_base_of_v<THnBase, T>) {
115 if (histSpec.config.axes[i].name) {
116 axis->SetName((std::string(axis->GetName()) + "-" + *histSpec.config.axes[i].name).data());
117 }
118 }
119
120 // move the bin edges in case a variable binning was requested
121 if (!histSpec.config.axes[i].nBins) {
122 if (!std::is_sorted(std::begin(histSpec.config.axes[i].binEdges), std::end(histSpec.config.axes[i].binEdges))) {
123 LOGF(fatal, "The bin edges in histogram %s are not in increasing order!", histSpec.name);
124 }
125 axis->Set(nBins[i], histSpec.config.axes[i].binEdges.data());
126 }
127 }
128 }
129 if (histSpec.callSumw2) {
130 hist->Sumw2();
131 }
132 return hist;
133}
134
135template <typename T>
136std::unique_ptr<T> HistFactory::createHist(const HistogramSpec& histSpec)
137{
138 return createHistFull<T, T>(histSpec);
139}
140
141// define histogram callbacks for runtime histogram creation
142#define CREATE_HIST_CASE(HType, BType) \
143 case k##HType: \
144 return std::shared_ptr<BType>(createHistFull<HType, BType>(histSpec));
145
146// runtime version of the above
148{
149 switch (histSpec.config.type) {
150 CREATE_HIST_CASE(TH1D, TH1)
151 CREATE_HIST_CASE(TH1F, TH1)
152 CREATE_HIST_CASE(TH1I, TH1)
153 CREATE_HIST_CASE(TH1C, TH1)
154 CREATE_HIST_CASE(TH1S, TH1)
155
156 CREATE_HIST_CASE(TH2D, TH2)
157 CREATE_HIST_CASE(TH2F, TH2)
158 CREATE_HIST_CASE(TH2I, TH2)
159 CREATE_HIST_CASE(TH2C, TH2)
160 CREATE_HIST_CASE(TH2S, TH2)
161
162 CREATE_HIST_CASE(TH3D, TH3)
163 CREATE_HIST_CASE(TH3F, TH3)
164 CREATE_HIST_CASE(TH3I, TH3)
165 CREATE_HIST_CASE(TH3C, TH3)
166 CREATE_HIST_CASE(TH3S, TH3)
167
168 CREATE_HIST_CASE(THnD, THn)
169 CREATE_HIST_CASE(THnF, THn)
170 CREATE_HIST_CASE(THnI, THn)
171 CREATE_HIST_CASE(THnC, THn)
172 CREATE_HIST_CASE(THnS, THn)
173 CREATE_HIST_CASE(THnL, THn)
174
175 CREATE_HIST_CASE(THnSparseD, THnSparse)
176 CREATE_HIST_CASE(THnSparseF, THnSparse)
177 CREATE_HIST_CASE(THnSparseI, THnSparse)
178 CREATE_HIST_CASE(THnSparseC, THnSparse)
179 CREATE_HIST_CASE(THnSparseS, THnSparse)
180 CREATE_HIST_CASE(THnSparseL, THnSparse)
181
182 CREATE_HIST_CASE(TProfile, TProfile)
183 CREATE_HIST_CASE(TProfile2D, TProfile2D)
184 CREATE_HIST_CASE(TProfile3D, TProfile3D)
185
188 default:
189 throw runtime_error("Histogram type was not specified.");
190 }
191}
192
193// helper function to get the axis via index for any type of root histogram
194template <typename T>
195TAxis* HistFactory::getAxis(const int i, T* hist)
196{
197 if constexpr (std::is_base_of_v<THnBase, T> || std::is_base_of_v<StepTHn, T>) {
198 return hist->GetAxis(i);
199 } else {
200 if (i == 0) {
201 return hist->GetXaxis();
202 } else if (i == 1) {
203 return hist->GetYaxis();
204 } else if (i == 2) {
205 return hist->GetZaxis();
206 } else {
207 return nullptr;
208 }
209 }
210}
211
212// explicitly instantiate createHist templates for all histogram types
213#define EXPIMPL(HType) \
214 template std::unique_ptr<HType> HistFactory::createHist<HType>(const HistogramSpec& histSpec);
236EXPIMPL(THnSparseD);
237EXPIMPL(THnSparseF);
238EXPIMPL(THnSparseI);
239EXPIMPL(THnSparseC);
240EXPIMPL(THnSparseS);
241EXPIMPL(THnSparseL);
242EXPIMPL(TProfile);
243EXPIMPL(TProfile2D);
244EXPIMPL(TProfile3D);
247#undef EXPIMPL
248
249} // namespace o2::framework
int32_t i
#define CREATE_HIST_CASE(HType, BType)
#define EXPIMPL(HType)
std::ostringstream debug
GLsizeiptr size
Definition glcorearb.h:659
GLuint const GLchar * name
Definition glcorearb.h:781
Defining PrimaryVertex explicitly as messageable.
Definition TFIDInfo.h:20
RuntimeErrorRef runtime_error(const char *)
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)
std::variant< std::shared_ptr< THn >, std::shared_ptr< THnSparse >, std::shared_ptr< TH3 >, std::shared_ptr< TH2 >, std::shared_ptr< TH1 >, std::shared_ptr< TProfile3D >, std::shared_ptr< TProfile2D >, std::shared_ptr< TProfile >, std::shared_ptr< StepTHn > > HistPtr
void makeLogarithmic()
Function to make the axis logarithmic.
std::optional< int > nBins
Data members.
std::vector< double > binEdges
Number of bins (only used for fixed bin width axis)
static HistPtr createHistVariant(const HistogramSpec &histSpec)
static TAxis * getAxis(const int i, T *hist)
static std::unique_ptr< T > createHist(const HistogramSpec &histSpec)
HistogramConfigSpec config
constexpr size_t min
constexpr size_t max
LOG(info)<< "Compressed in "<< sw.CpuTime()<< " s"