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