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