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
18// Out of line: see the comment on the declarations in HistogramSpec.h.
19AxisSpec::AxisSpec(std::vector<double> binEdges_, std::optional<std::string> title_, std::optional<std::string> name_)
20 : nBins(std::nullopt),
21 binEdges(std::move(binEdges_)),
22 title(std::move(title_)),
23 name(std::move(name_))
24{
25}
26
27AxisSpec::AxisSpec(int nBins_, double binMin_, double binMax_, std::optional<std::string> title_, std::optional<std::string> name_)
28 : nBins(nBins_),
29 binEdges({binMin_, binMax_}),
30 title(std::move(title_)),
31 name(std::move(name_))
32{
33 if (binMin_ > binMax_) {
34 LOG(fatal) << "Defined ill-defined axis";
35 }
36}
37
38AxisSpec::AxisSpec(ConfigurableAxis binEdges_, std::optional<std::string> title_, std::optional<std::string> name_)
39 : nBins(std::nullopt),
40 binEdges(std::vector<double>(binEdges_)),
41 title(std::move(title_)),
42 name(std::move(name_))
43{
44 if (binEdges.empty()) {
45 return;
46 }
47 if (binEdges[0] != VARIABLE_WIDTH) {
48 nBins = static_cast<int>(binEdges[0]);
49 binEdges.resize(3); // nBins, lowerBound, upperBound, disregard whatever else is stored in vecotr
50 }
51 binEdges.erase(binEdges.begin()); // remove first entry that we assume to be number of bins
52}
53
54HistogramConfigSpec::HistogramConfigSpec(HistType type_, std::vector<AxisSpec> axes_, uint8_t nSteps_)
55 : type(type_),
56 axes(std::move(axes_)),
57 nSteps(nSteps_)
58{
59}
60
61// Out of line: see the comments on the declarations in HistogramSpec.h.
62AxisSpec::~AxisSpec() = default;
63AxisSpec::AxisSpec(AxisSpec const&) = default;
64AxisSpec::AxisSpec(AxisSpec&&) noexcept = default;
65AxisSpec& AxisSpec::operator=(AxisSpec const&) = default;
66AxisSpec& AxisSpec::operator=(AxisSpec&&) noexcept = default;
67
69
70void AxisSpec::makeLogarithmic()
71{
72 if (binEdges.size() > 2) {
73 LOG(fatal) << "Cannot make a variabled bin width axis logaritmic";
74 }
75
76 const double min = binEdges[0];
77 if (min <= 0.) {
78 LOG(fatal) << "Cannot have the first bin limit of the log. axis below 0: " << min;
79 }
80 const double max = binEdges[1];
81 binEdges.clear();
82 const double logmin = std::log10(min);
83 const double logmax = std::log10(max);
84 const int nbins = nBins.value();
85 const double logdelta = (logmax - logmin) / (static_cast<double>(nbins));
86 LOG(debug) << "Making a logaritmic binning from " << min << " to " << max << " with " << nbins << " bins";
87 for (int i = 0; i < nbins + 1; i++) {
88 const auto nextEdge = std::pow(10, logmin + i * logdelta);
89 LOG(debug) << i << "/" << nbins - 1 << ": " << nextEdge;
90 binEdges.push_back(nextEdge);
91 }
92 nBins = std::nullopt;
93}
94
96{
97 // return the number of bins
98 if (nBins.has_value()) {
99 return *nBins;
100 }
101 return binEdges.size() - 1;
102}
103
104// helper function to generate the actual histograms
105template <typename T>
106T* generateHist(const std::string& name, const std::string& title, const std::size_t nDim,
107 const int nBins[], const double lowerBounds[], const double upperBounds[], const int nSteps)
108{
109 if constexpr (std::is_base_of_v<StepTHn, T>) {
110 return new T(name.data(), title.data(), nSteps, nDim, nBins, lowerBounds, upperBounds);
111 } else if constexpr (std::is_base_of_v<THnBase, T>) {
112 return new T(name.data(), title.data(), nDim, nBins, lowerBounds, upperBounds);
113 } else if constexpr (std::is_base_of_v<TH3, T>) {
114 return (nDim != 3) ? nullptr
115 : new T(name.data(), title.data(), nBins[0], lowerBounds[0],
116 upperBounds[0], nBins[1], lowerBounds[1], upperBounds[1],
117 nBins[2], lowerBounds[2], upperBounds[2]);
118 } else if constexpr (std::is_base_of_v<TH2, T>) {
119 return (nDim != 2) ? nullptr
120 : new T(name.data(), title.data(), nBins[0], lowerBounds[0],
121 upperBounds[0], nBins[1], lowerBounds[1], upperBounds[1]);
122 } else if constexpr (std::is_base_of_v<TH1, T>) {
123 return (nDim != 1)
124 ? nullptr
125 : new T(name.data(), title.data(), nBins[0], lowerBounds[0], upperBounds[0]);
126 }
127 return nullptr;
128}
129
130// main function for creating arbitrary histograms
131template <typename T, typename BASE>
132static std::unique_ptr<BASE> createHistFull(const HistogramSpec& histSpec)
133{
134 constexpr std::size_t MAX_DIM{20};
135 const std::size_t nAxes{histSpec.config.axes.size()};
136 if (nAxes == 0 || nAxes > MAX_DIM) {
137 LOGF(fatal, "The histogram specification contains no (or too many) axes.");
138 }
139
140 int nBins[MAX_DIM]{0};
141 double lowerBounds[MAX_DIM]{0.};
142 double upperBounds[MAX_DIM]{0.};
143
144 // first figure out number of bins and dimensions
145 for (std::size_t i = 0; i < nAxes; i++) {
146 nBins[i] = (histSpec.config.axes[i].nBins) ? *histSpec.config.axes[i].nBins : histSpec.config.axes[i].binEdges.size() - 1;
147 lowerBounds[i] = histSpec.config.axes[i].binEdges.front();
148 upperBounds[i] = histSpec.config.axes[i].binEdges.back();
149 }
150
151 // create histogram
152 std::unique_ptr<BASE> hist{generateHist<T>(histSpec.name, histSpec.title, nAxes, nBins, lowerBounds, upperBounds, histSpec.config.nSteps)};
153 if (!hist) {
154 LOGF(fatal, "The number of dimensions specified for histogram %s does not match the type.", histSpec.name);
155 }
156
157 // set axis properties
158 for (std::size_t i = 0; i < nAxes; i++) {
159 TAxis* axis{HistFactory::getAxis(i, hist.get())};
160 if (axis) {
161 if (histSpec.config.axes[i].title) {
162 axis->SetTitle((*histSpec.config.axes[i].title).data());
163 }
164
165 // this helps to have axes not only called 0,1,2... in ndim histos
166 if constexpr (std::is_base_of_v<THnBase, T>) {
167 if (histSpec.config.axes[i].name) {
168 axis->SetName((std::string(axis->GetName()) + "-" + *histSpec.config.axes[i].name).data());
169 }
170 }
171
172 // move the bin edges in case a variable binning was requested
173 if (!histSpec.config.axes[i].nBins) {
174 if (!std::is_sorted(std::begin(histSpec.config.axes[i].binEdges), std::end(histSpec.config.axes[i].binEdges))) {
175 LOGF(fatal, "The bin edges in histogram %s are not in increasing order!", histSpec.name);
176 }
177 axis->Set(nBins[i], histSpec.config.axes[i].binEdges.data());
178 }
179 }
180 }
181 if (histSpec.callSumw2) {
182 hist->Sumw2();
183 }
184 return hist;
185}
186
187template <typename T>
188std::unique_ptr<T> HistFactory::createHist(const HistogramSpec& histSpec)
189{
190 return createHistFull<T, T>(histSpec);
191}
192
193// define histogram callbacks for runtime histogram creation
194#define CREATE_HIST_CASE(HType, BType) \
195 case k##HType: \
196 return std::shared_ptr<BType>(createHistFull<HType, BType>(histSpec));
197
198// runtime version of the above
200{
201 switch (histSpec.config.type) {
202 CREATE_HIST_CASE(TH1D, TH1)
203 CREATE_HIST_CASE(TH1F, TH1)
204 CREATE_HIST_CASE(TH1I, TH1)
205 CREATE_HIST_CASE(TH1L, TH1)
206 CREATE_HIST_CASE(TH1C, TH1)
207 CREATE_HIST_CASE(TH1S, TH1)
208
209 CREATE_HIST_CASE(TH2D, TH2)
210 CREATE_HIST_CASE(TH2F, TH2)
211 CREATE_HIST_CASE(TH2I, TH2)
212 CREATE_HIST_CASE(TH2L, TH2)
213 CREATE_HIST_CASE(TH2C, TH2)
214 CREATE_HIST_CASE(TH2S, TH2)
215
216 CREATE_HIST_CASE(TH3D, TH3)
217 CREATE_HIST_CASE(TH3F, TH3)
218 CREATE_HIST_CASE(TH3I, TH3)
219 CREATE_HIST_CASE(TH3L, TH3)
220 CREATE_HIST_CASE(TH3C, TH3)
221 CREATE_HIST_CASE(TH3S, TH3)
222
223 CREATE_HIST_CASE(THnD, THn)
224 CREATE_HIST_CASE(THnF, THn)
225 CREATE_HIST_CASE(THnI, THn)
226 CREATE_HIST_CASE(THnC, THn)
227 CREATE_HIST_CASE(THnS, THn)
228 CREATE_HIST_CASE(THnL, THn)
229
230 CREATE_HIST_CASE(THnSparseD, THnSparse)
231 CREATE_HIST_CASE(THnSparseF, THnSparse)
232 CREATE_HIST_CASE(THnSparseI, THnSparse)
233 CREATE_HIST_CASE(THnSparseC, THnSparse)
234 CREATE_HIST_CASE(THnSparseS, THnSparse)
235 CREATE_HIST_CASE(THnSparseL, THnSparse)
236
237 CREATE_HIST_CASE(TProfile, TProfile)
238 CREATE_HIST_CASE(TProfile2D, TProfile2D)
239 CREATE_HIST_CASE(TProfile3D, TProfile3D)
240
243 default:
244 throw runtime_error("Histogram type was not specified.");
245 }
246}
247
248// helper function to get the axis via index for any type of root histogram
249template <typename T>
250TAxis* HistFactory::getAxis(const int i, T* hist)
251{
252 if constexpr (std::is_base_of_v<THnBase, T> || std::is_base_of_v<StepTHn, T>) {
253 return hist->GetAxis(i);
254 } else {
255 if (i == 0) {
256 return hist->GetXaxis();
257 } else if (i == 1) {
258 return hist->GetYaxis();
259 } else if (i == 2) {
260 return hist->GetZaxis();
261 } else {
262 return nullptr;
263 }
264 }
265}
266
267// explicitly instantiate createHist templates for all histogram types
268#define EXPIMPL(HType) \
269 template std::unique_ptr<HType> HistFactory::createHist<HType>(const HistogramSpec& histSpec);
294EXPIMPL(THnSparseD);
295EXPIMPL(THnSparseF);
296EXPIMPL(THnSparseI);
297EXPIMPL(THnSparseC);
298EXPIMPL(THnSparseS);
299EXPIMPL(THnSparseL);
300EXPIMPL(TProfile);
301EXPIMPL(TProfile2D);
302EXPIMPL(TProfile3D);
305#undef EXPIMPL
306
307} // namespace o2::framework
std::ostringstream debug
int32_t i
#define CREATE_HIST_CASE(HType, BType)
#define EXPIMPL(HType)
GLsizeiptr size
Definition glcorearb.h:659
GLuint const GLchar * name
Definition glcorearb.h:781
GLint GLint GLsizei GLint GLenum GLenum type
Definition glcorearb.h:275
Defining ITS Vertex explicitly as messageable.
Definition Cartesian.h:288
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
constexpr double VARIABLE_WIDTH
std::optional< int > nBins
Data members.
AxisSpec(std::vector< double > binEdges_, std::optional< std::string > title_=std::nullopt, std::optional< std::string > name_=std::nullopt)
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"