Logo ROOT  
Reference Guide
 
Loading...
Searching...
No Matches
RHistEngine.hxx
Go to the documentation of this file.
1/// \file
2/// \warning This is part of the %ROOT 7 prototype! It will change without notice. It might trigger earthquakes.
3/// Feedback is welcome!
4
5#ifndef ROOT_RHistEngine
6#define ROOT_RHistEngine
7
8#include "RAxes.hxx"
9#include "RBinIndex.hxx"
10#include "RHistUtils.hxx"
11#include "RLinearizedIndex.hxx"
12#include "RRegularAxis.hxx"
13#include "RWeight.hxx"
14
15#include <array>
16#include <cassert>
17#include <stdexcept>
18#include <tuple>
19#include <type_traits>
20#include <utility>
21#include <vector>
22
23class TBuffer;
24
25namespace ROOT {
26namespace Experimental {
27
28/**
29A histogram data structure to bin data along multiple dimensions.
30
31Every call to \ref Fill(const A &... args) "Fill" bins the data according to the axis configuration and increments the
32bin content:
33\code
34ROOT::Experimental::RHistEngine<int> hist(10, {5, 15});
35hist.Fill(8.5);
36// hist.GetBinContent(ROOT::Experimental::RBinIndex(3)) will return 1
37\endcode
38
39The class is templated on the bin content type. For counting, as in the example above, it may be an integral type such
40as `int` or `long`. Narrower types such as `unsigned char` or `short` are supported, but may overflow due to their
41limited range and must be used with care. For weighted filling, the bin content type must not be an integral type, but
42a floating-point type such as `float` or `double`, or the special type RBinWithError. Note that `float` has a limited
43significand precision of 24 bits.
44
45An object can have arbitrary dimensionality determined at run-time. The axis configuration is passed as a vector of
46RAxisVariant:
47\code
48std::vector<ROOT::Experimental::RAxisVariant> axes;
49axes.push_back(ROOT::Experimental::RRegularAxis(10, 5, 15));
50axes.push_back(ROOT::Experimental::RVariableBinAxis({1, 10, 100, 1000}));
51ROOT::Experimental::RHistEngine<int> hist(axes);
52// hist.GetNDimensions() will return 2
53\endcode
54
55\warning This is part of the %ROOT 7 prototype! It will change without notice. It might trigger earthquakes.
56Feedback is welcome!
57*/
58template <typename BinContentType>
60 /// The axis configuration for this histogram. Relevant methods are forwarded from the public interface.
62 /// The bin contents for this histogram
63 std::vector<BinContentType> fBinContents;
64
65public:
66 /// Construct a histogram engine.
67 ///
68 /// \param[in] axes the axis objects, must have size > 0
69 explicit RHistEngine(std::vector<RAxisVariant> axes) : fAxes(std::move(axes))
70 {
72 }
73
74 /// Construct a one-dimensional histogram engine with a regular axis.
75 ///
76 /// \param[in] nNormalBins the number of normal bins, must be > 0
77 /// \param[in] interval the axis interval (lower end inclusive, upper end exclusive)
78 /// \par See also
79 /// the
80 /// \ref RRegularAxis::RRegularAxis(std::size_t nNormalBins, std::pair<double, double> interval, bool enableFlowBins)
81 /// "constructor of RRegularAxis"
82 RHistEngine(std::size_t nNormalBins, std::pair<double, double> interval)
84 {
85 }
86
87 /// The copy constructor is deleted.
88 ///
89 /// Copying all bin contents can be an expensive operation, depending on the number of bins. If required, users can
90 /// explicitly call Clone().
92 /// Efficiently move construct a histogram engine.
93 ///
94 /// After this operation, the moved-from object is invalid.
96
97 /// The copy assignment operator is deleted.
98 ///
99 /// Copying all bin contents can be an expensive operation, depending on the number of bins. If required, users can
100 /// explicitly call Clone().
102 /// Efficiently move a histogram engine.
103 ///
104 /// After this operation, the moved-from object is invalid.
106
107 ~RHistEngine() = default;
108
109 const std::vector<RAxisVariant> &GetAxes() const { return fAxes.Get(); }
110 std::size_t GetNDimensions() const { return fAxes.GetNDimensions(); }
111 std::size_t GetTotalNBins() const { return fBinContents.size(); }
112
113 /// Get the content of a single bin.
114 ///
115 /// \code
116 /// ROOT::Experimental::RHistEngine<int> hist({/* two dimensions */});
117 /// std::array<ROOT::Experimental::RBinIndex, 2> indices = {3, 5};
118 /// int content = hist.GetBinContent(indices);
119 /// \endcode
120 ///
121 /// \note Compared to TH1 conventions, the first normal bin has index 0 and underflow and overflow bins are special
122 /// values. See also the class documentation of RBinIndex.
123 ///
124 /// Throws an exception if the number of indices does not match the axis configuration or the bin is not found.
125 ///
126 /// \param[in] indices the array of indices for each axis
127 /// \return the bin content
128 /// \par See also
129 /// the \ref GetBinContent(const A &... args) const "variadic function template overload" accepting arguments
130 /// directly
131 template <std::size_t N>
132 const BinContentType &GetBinContent(const std::array<RBinIndex, N> &indices) const
133 {
134 // We could rely on RAxes::ComputeGlobalIndex to check the number of arguments, but its exception message might
135 // be confusing for users.
136 if (N != GetNDimensions()) {
137 throw std::invalid_argument("invalid number of indices passed to GetBinContent");
138 }
140 if (!index.fValid) {
141 throw std::invalid_argument("bin not found in GetBinContent");
142 }
143 assert(index.fIndex < fBinContents.size());
144 return fBinContents[index.fIndex];
145 }
146
147 /// Get the content of a single bin.
148 ///
149 /// \code
150 /// ROOT::Experimental::RHistEngine<int> hist({/* two dimensions */});
151 /// int content = hist.GetBinContent(ROOT::Experimental::RBinIndex(3), ROOT::Experimental::RBinIndex(5));
152 /// // ... or construct the RBinIndex arguments implicitly from integers:
153 /// content = hist.GetBinContent(3, 5);
154 /// \endcode
155 ///
156 /// \note Compared to TH1 conventions, the first normal bin has index 0 and underflow and overflow bins are special
157 /// values. See also the class documentation of RBinIndex.
158 ///
159 /// Throws an exception if the number of arguments does not match the axis configuration or the bin is not found.
160 ///
161 /// \param[in] args the arguments for each axis
162 /// \return the bin content
163 /// \par See also
164 /// the \ref GetBinContent(const std::array<RBinIndex, N> &indices) const "function overload" accepting
165 /// `std::array`
166 template <typename... A>
167 const BinContentType &GetBinContent(const A &...args) const
168 {
169 std::array<RBinIndex, sizeof...(A)> indices{args...};
170 return GetBinContent(indices);
171 }
172
173 /// Add all bin contents of another histogram.
174 ///
175 /// Throws an exception if the axes configurations are not identical.
176 ///
177 /// \param[in] other another histogram
179 {
180 if (fAxes != other.fAxes) {
181 throw std::invalid_argument("axes configurations not identical in Add");
182 }
183 for (std::size_t i = 0; i < fBinContents.size(); i++) {
184 fBinContents[i] += other.fBinContents[i];
185 }
186 }
187
188 /// Clear all bin contents.
189 void Clear()
190 {
191 for (std::size_t i = 0; i < fBinContents.size(); i++) {
192 fBinContents[i] = {};
193 }
194 }
195
196 /// Clone this histogram engine.
197 ///
198 /// Copying all bin contents can be an expensive operation, depending on the number of bins.
199 ///
200 /// \return the cloned object
202 {
204 for (std::size_t i = 0; i < fBinContents.size(); i++) {
205 h.fBinContents[i] = fBinContents[i];
206 }
207 return h;
208 }
209
210 /// Whether this histogram engine type supports weighted filling.
211 static constexpr bool SupportsWeightedFilling = !std::is_integral_v<BinContentType>;
212
213 /// Fill an entry into the histogram.
214 ///
215 /// \code
216 /// ROOT::Experimental::RHistEngine<int> hist({/* two dimensions */});
217 /// auto args = std::make_tuple(8.5, 10.5);
218 /// hist.Fill(args);
219 /// \endcode
220 ///
221 /// If one of the arguments is outside the corresponding axis and flow bins are disabled, the entry will be silently
222 /// discarded.
223 ///
224 /// Throws an exception if the number of arguments does not match the axis configuration, or if an argument cannot be
225 /// converted for the axis type at run-time.
226 ///
227 /// \param[in] args the arguments for each axis
228 /// \par See also
229 /// the \ref Fill(const A &... args) "variadic function template overload" accepting arguments directly and the
230 /// \ref Fill(const std::tuple<A...> &args, RWeight weight) "overload for weighted filling"
231 template <typename... A>
232 void Fill(const std::tuple<A...> &args)
233 {
234 // We could rely on RAxes::ComputeGlobalIndex to check the number of arguments, but its exception message might
235 // be confusing for users.
236 if (sizeof...(A) != GetNDimensions()) {
237 throw std::invalid_argument("invalid number of arguments to Fill");
238 }
240 if (index.fValid) {
241 assert(index.fIndex < fBinContents.size());
242 fBinContents[index.fIndex]++;
243 }
244 }
245
246 /// Fill an entry into the histogram with a weight.
247 ///
248 /// This overload is not available for integral bin content types (see \ref SupportsWeightedFilling).
249 ///
250 /// \code
251 /// ROOT::Experimental::RHistEngine<float> hist({/* two dimensions */});
252 /// auto args = std::make_tuple(8.5, 10.5);
253 /// hist.Fill(args, ROOT::Experimental::RWeight(0.8));
254 /// \endcode
255 ///
256 /// If one of the arguments is outside the corresponding axis and flow bins are disabled, the entry will be silently
257 /// discarded.
258 ///
259 /// Throws an exception if the number of arguments does not match the axis configuration, or if an argument cannot be
260 /// converted for the axis type at run-time.
261 ///
262 /// \param[in] args the arguments for each axis
263 /// \param[in] weight the weight for this entry
264 /// \par See also
265 /// the \ref Fill(const A &... args) "variadic function template overload" accepting arguments directly and the
266 /// \ref Fill(const std::tuple<A...> &args) "overload for unweighted filling"
267 template <typename... A>
268 void Fill(const std::tuple<A...> &args, RWeight weight)
269 {
270 static_assert(SupportsWeightedFilling, "weighted filling is not supported for integral bin content types");
271
272 // We could rely on RAxes::ComputeGlobalIndex to check the number of arguments, but its exception message might
273 // be confusing for users.
274 if (sizeof...(A) != GetNDimensions()) {
275 throw std::invalid_argument("invalid number of arguments to Fill");
276 }
278 if (index.fValid) {
279 assert(index.fIndex < fBinContents.size());
280 fBinContents[index.fIndex] += weight.fValue;
281 }
282 }
283
284 /// Fill an entry into the histogram.
285 ///
286 /// \code
287 /// ROOT::Experimental::RHistEngine<int> hist({/* two dimensions */});
288 /// hist.Fill(8.5, 10.5);
289 /// \endcode
290 ///
291 /// For weighted filling, pass an RWeight as the last argument:
292 /// \code
293 /// ROOT::Experimental::RHistEngine<float> hist({/* two dimensions */});
294 /// hist.Fill(8.5, 10.5, ROOT::Experimental::RWeight(0.8));
295 /// \endcode
296 /// This is not available for integral bin content types (see \ref SupportsWeightedFilling).
297 ///
298 /// If one of the arguments is outside the corresponding axis and flow bins are disabled, the entry will be silently
299 /// discarded.
300 ///
301 /// Throws an exception if the number of arguments does not match the axis configuration, or if an argument cannot be
302 /// converted for the axis type at run-time.
303 ///
304 /// \param[in] args the arguments for each axis
305 /// \par See also
306 /// the function overloads accepting `std::tuple` \ref Fill(const std::tuple<A...> &args) "for unweighted filling"
307 /// and \ref Fill(const std::tuple<A...> &args, RWeight) "for weighted filling"
308 template <typename... A>
309 void Fill(const A &...args)
310 {
311 auto t = std::forward_as_tuple(args...);
312 if constexpr (std::is_same_v<typename Internal::LastType<A...>::type, RWeight>) {
313 static_assert(SupportsWeightedFilling, "weighted filling is not supported for integral bin content types");
314 static constexpr std::size_t N = sizeof...(A) - 1;
315 if (N != fAxes.GetNDimensions()) {
316 throw std::invalid_argument("invalid number of arguments to Fill");
317 }
318 RWeight weight = std::get<N>(t);
320 if (index.fValid) {
321 assert(index.fIndex < fBinContents.size());
322 fBinContents[index.fIndex] += weight.fValue;
323 }
324 } else {
325 Fill(t);
326 }
327 }
328
329 /// %ROOT Streamer function to throw when trying to store an object of this class.
330 void Streamer(TBuffer &) { throw std::runtime_error("unable to store RHistEngine"); }
331};
332
333} // namespace Experimental
334} // namespace ROOT
335
336#endif
#define h(i)
Definition RSha256.hxx:106
ROOT::Detail::TRangeCast< T, true > TRangeDynCast
TRangeDynCast is an adapter class that allows the typed iteration through a TCollection.
#define N
Option_t Option_t TPoint TPoint const char GetTextMagnitude GetFillStyle GetLineColor GetLineWidth GetMarkerStyle GetTextAlign GetTextColor GetTextSize void char Point_t Rectangle_t WindowAttributes_t index
Option_t Option_t TPoint TPoint const char GetTextMagnitude GetFillStyle GetLineColor GetLineWidth GetMarkerStyle GetTextAlign GetTextColor GetTextSize void char Point_t Rectangle_t WindowAttributes_t Float_t Float_t Float_t Int_t Int_t UInt_t UInt_t Rectangle_t Int_t Int_t Window_t TString Int_t GCValues_t GetPrimarySelectionOwner GetDisplay GetScreen GetColormap GetNativeEvent const char const char dpyName wid window const char font_name cursor keysym reg const char only_if_exist regb h Point_t winding char text const char depth char const char Int_t count const char ColorStruct_t color const char Pixmap_t Pixmap_t PictureAttributes_t attr const char char ret_data h unsigned char height h Atom_t Int_t ULong_t ULong_t unsigned char prop_list Atom_t Atom_t Atom_t Time_t type
Bin configurations for all dimensions of a histogram.
Definition RAxes.hxx:41
std::size_t GetNDimensions() const
Definition RAxes.hxx:56
RLinearizedIndex ComputeGlobalIndexImpl(std::size_t index, const std::tuple< A... > &args) const
Definition RAxes.hxx:86
RLinearizedIndex ComputeGlobalIndex(const std::tuple< A... > &args) const
Compute the global index for all axes.
Definition RAxes.hxx:140
std::size_t ComputeTotalNBins() const
Compute the total number of bins for all axes.
Definition RAxes.hxx:67
const std::vector< RAxisVariant > & Get() const
Definition RAxes.hxx:57
A bin index with special values for underflow and overflow bins.
Definition RBinIndex.hxx:22
A histogram data structure to bin data along multiple dimensions.
void Fill(const A &...args)
Fill an entry into the histogram.
const std::vector< RAxisVariant > & GetAxes() const
RHistEngine< BinContentType > Clone() const
Clone this histogram engine.
RHistEngine< BinContentType > & operator=(const RHistEngine< BinContentType > &)=delete
The copy assignment operator is deleted.
std::size_t GetTotalNBins() const
void Fill(const std::tuple< A... > &args)
Fill an entry into the histogram.
RHistEngine< BinContentType > & operator=(RHistEngine< BinContentType > &&)=default
Efficiently move a histogram engine.
const BinContentType & GetBinContent(const std::array< RBinIndex, N > &indices) const
Get the content of a single bin.
const BinContentType & GetBinContent(const A &...args) const
Get the content of a single bin.
RHistEngine(const RHistEngine< BinContentType > &)=delete
The copy constructor is deleted.
void Add(const RHistEngine< BinContentType > &other)
Add all bin contents of another histogram.
std::size_t GetNDimensions() const
static constexpr bool SupportsWeightedFilling
Whether this histogram engine type supports weighted filling.
void Clear()
Clear all bin contents.
RHistEngine(std::vector< RAxisVariant > axes)
Construct a histogram engine.
Internal::RAxes fAxes
The axis configuration for this histogram. Relevant methods are forwarded from the public interface.
RHistEngine(std::size_t nNormalBins, std::pair< double, double > interval)
Construct a one-dimensional histogram engine with a regular axis.
void Fill(const std::tuple< A... > &args, RWeight weight)
Fill an entry into the histogram with a weight.
RHistEngine(RHistEngine< BinContentType > &&)=default
Efficiently move construct a histogram engine.
void Streamer(TBuffer &)
ROOT Streamer function to throw when trying to store an object of this class.
std::vector< BinContentType > fBinContents
The bin contents for this histogram.
A regular axis with equidistant bins in the interval .
Buffer base class used for serializing objects.
Definition TBuffer.h:43
A linearized index that can be invalid.
A weight for filling histograms.
Definition RWeight.hxx:17