Logo ROOT  
Reference Guide
 
Loading...
Searching...
No Matches
RHistAutoAxisFiller.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_RHistAutoAxisFiller
6#define ROOT_RHistAutoAxisFiller
7
8#include "RHist.hxx"
9#include "RHistEngine.hxx"
10#include "RWeight.hxx"
11
12#include <algorithm>
13#include <cmath>
14#include <cstddef>
15#include <limits>
16#include <optional>
17#include <stdexcept>
18#include <utility>
19#include <vector>
20
21namespace ROOT {
22namespace Experimental {
23
24/**
25A histogram filler that automatically determines the axis interval.
26
27This class allows filling a regular one-dimensional histogram without specifying an axis interval during construction.
28After a configurable number of buffered entries, or upon request, a RRegularAxis is constructed using the minimum and
29maximum values until that point. This ensures all initial entries are filled into normal bins. Note that this cannot be
30guaranteed for further calls to Fill.
31
32\code
33ROOT::Experimental::RHistAutoAxisFiller<int> filler(20);
34filler.Fill(1.0);
35filler.Fill(1.5);
36filler.Fill(2.0);
37
38// The following will implicitly trigger the histogram creation
39auto &hist = filler.GetHist();
40// hist.GetNEntries() will return 3
41\endcode
42
43\warning This is part of the %ROOT 7 prototype! It will change without notice. It might trigger earthquakes.
44Feedback is welcome!
45*/
46template <typename BinContentType>
48public:
50
51private:
52 /// The filled histogram, after it has been constructed
53 std::optional<RHist<BinContentType>> fHist;
54
55 /// The number of normal bins
56 std::size_t fNNormalBins;
57 /// The maximum buffer size until Flush() is automatically called
58 std::size_t fMaxBufferSize;
59 /// The fraction of the axis interval to use as margin
61
62 using BufferElement = std::conditional_t<SupportsWeightedFilling, std::pair<double, RWeight>, double>;
63
64 /// The buffer of filled entries
65 std::vector<BufferElement> fBuffer;
66 /// The minimum of the filled entries
67 double fMinimum = std::numeric_limits<double>::infinity();
68 /// The maximum of the filled entries
69 double fMaximum = -std::numeric_limits<double>::infinity();
70
71public:
72 /// Create a filler object.
73 ///
74 /// \param[in] nNormalBins the number of normal bins, must be > 0
75 /// \param[in] maxBufferSize the maximum buffer size, must be > 0
76 /// \param[in] marginFraction the fraction of the axis interval to use as margin, must be > 0
77 explicit RHistAutoAxisFiller(std::size_t nNormalBins, std::size_t maxBufferSize = 1024, double marginFraction = 0.05)
79 {
80 if (nNormalBins == 0) {
81 throw std::invalid_argument("nNormalBins must be > 0");
82 }
83 if (maxBufferSize == 0) {
84 throw std::invalid_argument("maxBufferSize must be > 0");
85 }
86 if (marginFraction <= 0) {
87 throw std::invalid_argument("marginFraction must be > 0");
88 }
89 }
90
91 std::size_t GetNNormalBins() const { return fNNormalBins; }
92 std::size_t GetMaxBufferSize() const { return fMaxBufferSize; }
93 double GetMarginFraction() const { return fMarginFraction; }
94
95private:
96 void BufferImpl(double x, RWeight weight)
97 {
98 if constexpr (SupportsWeightedFilling) {
99 fBuffer.emplace_back(x, weight);
100 } else {
101 assert(weight.fValue == 1.0);
102 // Silence compiler warning about unused parameter
103 (void)weight;
104 fBuffer.push_back(x);
105 }
106 fMinimum = std::min(fMinimum, x);
107 fMaximum = std::max(fMaximum, x);
108
109 if (fBuffer.size() >= fMaxBufferSize) {
110 Flush();
111 }
112 }
113
114public:
115 /// Fill an entry into the histogram.
116 ///
117 /// \param[in] x the argument
118 /// \par See also
119 /// the \ref Fill(double x, RWeight weight) "overload for weighted filling"
120 void Fill(double x)
121 {
122 // If the histogram exists, forward the Fill call.
123 if (fHist) {
124 fHist->Fill(x);
125 return;
126 }
127 BufferImpl(x, RWeight(1.0));
128 }
129
130 /// Fill an entry into the histogram with a weight.
131 ///
132 /// This overload is only available for floating-point bin content types (see
133 /// \ref RHistEngine::SupportsWeightedFilling).
134 ///
135 /// \param[in] x the argument
136 /// \param[in] weight the weight for this entry
137 /// \par See also
138 /// the \ref Fill(double x) "overload for unweighted filling"
139 void Fill(double x, RWeight weight)
140 {
141 // If the histogram exists, forward the Fill call.
142 if (fHist) {
143 fHist->Fill(x, weight);
144 return;
145 }
146 BufferImpl(x, weight);
147 }
148
149 /// Flush the buffer of entries and construct the histogram.
150 ///
151 /// Throws an exception if the buffer is empty, the axis interval cannot be determined, or if it would be empty
152 /// because the minimum equals the maximum.
153 void Flush()
154 {
155 if (fHist) {
156 assert(fBuffer.empty() && "buffer should have been emptied");
157 return;
158 }
159
160 if (fBuffer.empty()) {
161 throw std::runtime_error("buffer is empty, cannot create histogram");
162 }
163 if (!std::isfinite(fMinimum) || !std::isfinite(fMaximum)) {
164 throw std::runtime_error("could not determine axis interval");
165 }
166 if (fMinimum == fMaximum) {
167 throw std::runtime_error("axis interval is empty");
168 }
169
170 // Add some margin to the axis interval to make sure the maximum is included in the last bin, but also to
171 // accomodate closeby values.
172 const auto margin = fMarginFraction * (fMaximum - fMinimum);
173 const auto high = fMaximum + margin;
174 const auto low = fMinimum - margin;
175 assert(high > low);
176 fHist.emplace(fNNormalBins, std::make_pair(low, high));
177
178 for (auto &&x : fBuffer) {
179 if constexpr (SupportsWeightedFilling) {
180 fHist->Fill(x.first, x.second);
181 } else {
182 fHist->Fill(x);
183 }
184 }
185 fBuffer.clear();
186 }
187
188 /// Return the constructed histogram.
189 ///
190 /// \see Flush()
192 {
193 Flush();
194 assert(fHist.has_value());
195 return *fHist;
196 }
197};
198
199} // namespace Experimental
200} // namespace ROOT
201
202#endif
ROOT::Detail::TRangeCast< T, true > TRangeDynCast
TRangeDynCast is an adapter class that allows the typed iteration through a TCollection.
A histogram filler that automatically determines the axis interval.
RHistAutoAxisFiller(std::size_t nNormalBins, std::size_t maxBufferSize=1024, double marginFraction=0.05)
Create a filler object.
std::vector< BufferElement > fBuffer
The buffer of filled entries.
std::size_t fNNormalBins
The number of normal bins.
void Fill(double x)
Fill an entry into the histogram.
double fMaximum
The maximum of the filled entries.
double fMarginFraction
The fraction of the axis interval to use as margin.
std::size_t fMaxBufferSize
The maximum buffer size until Flush() is automatically called.
std::conditional_t< SupportsWeightedFilling, std::pair< double, RWeight >, double > BufferElement
double fMinimum
The minimum of the filled entries.
RHist< BinContentType > & GetHist()
Return the constructed histogram.
void Fill(double x, RWeight weight)
Fill an entry into the histogram with a weight.
void BufferImpl(double x, RWeight weight)
std::optional< RHist< BinContentType > > fHist
The filled histogram, after it has been constructed.
void Flush()
Flush the buffer of entries and construct the histogram.
A histogram data structure to bin data along multiple dimensions.
Double_t x[n]
Definition legend1.C:17
A weight for filling histograms.
Definition RWeight.hxx:17