Logo ROOT  
Reference Guide
 
Loading...
Searching...
No Matches
RRegularAxis.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_RRegularAxis
6#define ROOT_RRegularAxis
7
8#include "RBinIndex.hxx"
9#include "RBinIndexRange.hxx"
10#include "RLinearizedIndex.hxx"
11#include "RSliceSpec.hxx"
12
13#include <cassert>
14#include <cmath>
15#include <cstdint>
16#include <stdexcept>
17#include <string>
18#include <utility>
19
20class TBuffer;
21
22namespace ROOT {
23namespace Experimental {
24
25/**
26A regular axis with equidistant bins in the interval \f$[fLow, fHigh)\f$.
27
28For example, the following creates a regular axis with 10 normal bins between 5 and 15:
29\code
30ROOT::Experimental::RRegularAxis axis(10, {5, 15});
31\endcode
32
33It is possible to disable underflow and overflow bins by passing `enableFlowBins = false`. In that case, arguments
34outside the axis will be silently discarded.
35
36\warning This is part of the %ROOT 7 prototype! It will change without notice. It might trigger earthquakes.
37Feedback is welcome!
38*/
40public:
42
43private:
44 /// The number of normal bins
45 std::uint64_t fNNormalBins;
46 /// The lower end of the axis interval
47 double fLow;
48 /// The upper end of the axis interval
49 double fHigh;
50 /// The cached inverse of the bin width to speed up ComputeLinearizedIndex
51 double fInvBinWidth; //!
52 /// Whether underflow and overflow bins are enabled
54
55public:
56 /// Construct a regular axis object.
57 ///
58 /// \param[in] nNormalBins the number of normal bins, must be > 0
59 /// \param[in] interval the axis interval (lower end inclusive, upper end exclusive), must be finite
60 /// \param[in] enableFlowBins whether to enable underflow and overflow bins
61 RRegularAxis(std::uint64_t nNormalBins, std::pair<double, double> interval, bool enableFlowBins = true)
63 {
64 if (nNormalBins == 0) {
65 throw std::invalid_argument("nNormalBins must be > 0");
66 }
67 if (!std::isfinite(fLow)) {
68 throw std::invalid_argument("low must be a finite value, but is " + std::to_string(fLow));
69 }
70 if (!std::isfinite(fHigh)) {
71 throw std::invalid_argument("high must be a finite value, but is " + std::to_string(fHigh));
72 }
73 if (fLow >= fHigh) {
74 std::string msg = "high must be > low, but " + std::to_string(fLow) + " >= " + std::to_string(fHigh);
75 throw std::invalid_argument(msg);
76 }
78 assert(std::isfinite(fInvBinWidth));
79 }
80
81 std::uint64_t GetNNormalBins() const { return fNNormalBins; }
82 std::uint64_t GetTotalNBins() const { return fEnableFlowBins ? fNNormalBins + 2 : fNNormalBins; }
83 double GetLow() const { return fLow; }
84 double GetHigh() const { return fHigh; }
85 bool HasFlowBins() const { return fEnableFlowBins; }
86
87 /// Compute the low edge of a bin.
88 ///
89 /// \param[in] bin the index, must be \f$< fNNormalBins\f$
90 double ComputeLowEdge(std::uint64_t bin) const
91 {
92 if (bin >= fNNormalBins) {
93 throw std::invalid_argument("bin must be inside the axis");
94 }
95 return fLow + (fHigh - fLow) * bin / fNNormalBins;
96 }
97
98 /// Compute the high edge of a bin.
99 ///
100 /// \param[in] bin the index, must be \f$< fNNormalBins\f$
101 double ComputeHighEdge(std::uint64_t bin) const
102 {
103 if (bin >= fNNormalBins) {
104 throw std::invalid_argument("bin must be inside the axis");
105 }
106 return fLow + (fHigh - fLow) * (bin + 1) / fNNormalBins;
107 }
108
109 friend bool operator==(const RRegularAxis &lhs, const RRegularAxis &rhs)
110 {
111 return lhs.fNNormalBins == rhs.fNNormalBins && lhs.fLow == rhs.fLow && lhs.fHigh == rhs.fHigh &&
112 lhs.fEnableFlowBins == rhs.fEnableFlowBins;
113 }
114
115 /// Compute the linarized index for a single argument.
116 ///
117 /// If flow bins are disabled, the normal bins have indices \f$0\f$ to \f$fNNormalBins - 1\f$. Otherwise the
118 /// underflow bin has index \f$0\$, the indices of all normal bins shift by one, and the overflow bin has index
119 /// \f$fNNormalBins + 1\f$. If the argument is outside the interval \f$[fLow, fHigh)\f$ and the flow bins are
120 /// disabled, the return value is invalid.
121 ///
122 /// \param[in] x the argument
123 /// \return the linearized index that may be invalid
124 RLinearizedIndex ComputeLinearizedIndex(double x) const
125 {
126 bool underflow = x < fLow;
127 // Put NaNs into overflow bin.
128 bool overflow = !(x < fHigh);
129 if (underflow) {
130 return {0, fEnableFlowBins};
131 } else if (overflow) {
132 return {fNNormalBins + 1, fEnableFlowBins};
133 }
134
135 std::uint64_t bin = (x - fLow) * fInvBinWidth;
136 if (bin >= fNNormalBins) {
137 bin = fNNormalBins - 1;
138 }
139 // If the underflow bin is enabled, shift the normal bins by one.
140 if (fEnableFlowBins) {
141 bin += 1;
142 }
143 return {bin, true};
144 }
145
146 /// Get the linearized index for an RBinIndex.
147 ///
148 /// If flow bins are disabled, the normal bins have indices \f$0\f$ to \f$fNNormalBins - 1\f$. Otherwise the
149 /// underflow bin has index \f$0\$, the indices of all normal bins shift by one, and the overflow bin has index
150 /// \f$fNNormalBins + 1\f$.
151 ///
152 /// \param[in] index the RBinIndex
153 /// \return the linearized index that may be invalid
155 {
156 if (index.IsUnderflow()) {
157 return {0, fEnableFlowBins};
158 } else if (index.IsOverflow()) {
159 return {fNNormalBins + 1, fEnableFlowBins};
160 } else if (index.IsInvalid()) {
161 return {0, false};
162 }
163 assert(index.IsNormal());
164 std::uint64_t bin = index.GetIndex();
165 if (bin >= fNNormalBins) {
166 // Index is out of range and invalid.
167 return {bin, false};
168 }
169 // If the underflow bin is enabled, shift the normal bins by one.
170 if (fEnableFlowBins) {
171 bin += 1;
172 }
173 return {bin, true};
174 }
175
176 /// Get the range of all normal bins.
177 ///
178 /// \return the bin index range from the first to the last normal bin, inclusive
183
184 /// Get a range of normal bins.
185 ///
186 /// \param[in] begin the begin of the bin index range (inclusive), must be normal
187 /// \param[in] end the end of the bin index range (exclusive), must be normal and >= begin
188 /// \return a bin index range \f$[begin, end)\f$
190 {
191 if (!begin.IsNormal()) {
192 throw std::invalid_argument("begin must be a normal bin");
193 }
194 if (begin.GetIndex() >= fNNormalBins) {
195 throw std::invalid_argument("begin must be inside the axis");
196 }
197 if (!end.IsNormal()) {
198 throw std::invalid_argument("end must be a normal bin");
199 }
200 if (end.GetIndex() > fNNormalBins) {
201 throw std::invalid_argument("end must be inside or past the axis");
202 }
203 if (!(end >= begin)) {
204 throw std::invalid_argument("end must be >= begin");
205 }
206 return Internal::CreateBinIndexRange(begin, end, 0);
207 }
208
209 /// Get the full range of all bins.
210 ///
211 /// This includes underflow and overflow bins, if enabled.
212 ///
213 /// \return the bin index range of all bins
219
220 /// Slice this axis according to the specification.
221 ///
222 /// Throws an exception if the axis cannot be sliced:
223 /// * A sum operation makes the dimension disappear.
224 /// * The rebin operation must divide the number of normal bins.
225 ///
226 /// \param[in] sliceSpec the slice specification
227 /// \return the sliced axis, with enabled underflow and overflow bins
229 {
230 if (sliceSpec.GetOperationSum() != nullptr) {
231 throw std::runtime_error("sum operation makes dimension disappear");
232 }
233
234 // Figure out the properties of the sliced axis.
235 std::uint64_t nNormalBins = fNNormalBins;
236 double low = fLow;
237 double high = fHigh;
238
239 const auto &range = sliceSpec.GetRange();
240 if (!range.IsInvalid()) {
241 std::uint64_t begin = 0;
242 std::uint64_t end = nNormalBins;
243 if (range.GetBegin().IsNormal()) {
244 begin = range.GetBegin().GetIndex();
245 // Only compute a new lower end of the axis interval if needed.
246 if (begin > 0) {
247 low = ComputeLowEdge(begin);
248 }
249 }
250 if (range.GetEnd().IsNormal()) {
251 end = range.GetEnd().GetIndex();
252 // Only compute a new upper end of the axis interval if needed, to avoid floating-point inaccuracies.
253 if (end < nNormalBins) {
254 high = ComputeHighEdge(end - 1);
255 }
256 }
257 nNormalBins = end - begin;
258 }
259
260 if (auto *opRebin = sliceSpec.GetOperationRebin()) {
261 if (nNormalBins % opRebin->GetNGroup() != 0) {
262 throw std::runtime_error("rebin operation does not divide number of normal bins");
263 }
264 nNormalBins /= opRebin->GetNGroup();
265 }
266
267 // The sliced axis always has flow bins enabled to preserve all entries. This is the least confusing for users,
268 // even if not always strictly necessary.
269 bool enableFlowBins = true;
270 return RRegularAxis(nNormalBins, {low, high}, enableFlowBins);
271 }
272
273 /// %ROOT Streamer function to throw when trying to store an object of this class.
274 void Streamer(TBuffer &) { throw std::runtime_error("unable to store RRegularAxis"); }
275};
276
277} // namespace Experimental
278} // namespace ROOT
279
280#endif
ROOT::Detail::TRangeCast< T, true > TRangeDynCast
TRangeDynCast is an adapter class that allows the typed iteration through a TCollection.
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
A bin index with special values for underflow and overflow bins.
Definition RBinIndex.hxx:23
bool IsNormal() const
A bin index is normal iff it is not one of the special values.
Definition RBinIndex.hxx:80
std::uint64_t GetIndex() const
Return the index for a normal bin.
Definition RBinIndex.hxx:71
static RBinIndex Underflow()
A regular axis with equidistant bins in the interval .
std::uint64_t GetTotalNBins() const
RBinIndexRange GetNormalRange(RBinIndex begin, RBinIndex end) const
Get a range of normal bins.
RRegularAxis Slice(const RSliceSpec &sliceSpec) const
Slice this axis according to the specification.
bool fEnableFlowBins
Whether underflow and overflow bins are enabled.
friend bool operator==(const RRegularAxis &lhs, const RRegularAxis &rhs)
RBinIndexRange GetFullRange() const
Get the full range of all bins.
double ComputeHighEdge(std::uint64_t bin) const
Compute the high edge of a bin.
double fInvBinWidth
The cached inverse of the bin width to speed up ComputeLinearizedIndex.
RRegularAxis(std::uint64_t nNormalBins, std::pair< double, double > interval, bool enableFlowBins=true)
Construct a regular axis object.
double ComputeLowEdge(std::uint64_t bin) const
Compute the low edge of a bin.
std::uint64_t fNNormalBins
The number of normal bins.
double fLow
The lower end of the axis interval.
RBinIndexRange GetNormalRange() const
Get the range of all normal bins.
void Streamer(TBuffer &)
ROOT Streamer function to throw when trying to store an object of this class.
double fHigh
The upper end of the axis interval.
RLinearizedIndex GetLinearizedIndex(RBinIndex index) const
Compute the linarized index for a single argument.
std::uint64_t GetNNormalBins() const
Specification of a slice operation along one dimension.
Buffer base class used for serializing objects.
Definition TBuffer.h:43
Double_t x[n]
Definition legend1.C:17
static RBinIndexRange CreateBinIndexRange(RBinIndex begin, RBinIndex end, std::uint64_t nNormalBins)
Internal function to create RBinIndexRange.
A linearized index that can be invalid.