Logo ROOT  
Reference Guide
RHistImpl.hxx
Go to the documentation of this file.
1/// \file ROOT/RHistImpl.hxx
2/// \ingroup Hist ROOT7
3/// \author Axel Naumann <axel@cern.ch>
4/// \date 2015-03-23
5/// \warning This is part of the ROOT 7 prototype! It will change without notice. It might trigger earthquakes. Feedback
6/// is welcome!
7
8/*************************************************************************
9 * Copyright (C) 1995-2015, Rene Brun and Fons Rademakers. *
10 * All rights reserved. *
11 * *
12 * For the licensing terms see $ROOTSYS/LICENSE. *
13 * For the list of contributors see $ROOTSYS/README/CREDITS. *
14 *************************************************************************/
15
16#ifndef ROOT7_RHistImpl
17#define ROOT7_RHistImpl
18
19#include <cassert>
20#include <cctype>
21#include <functional>
22#include "ROOT/RSpan.hxx"
23#include "ROOT/RTupleApply.hxx"
24
25#include "ROOT/RAxis.hxx"
26#include "ROOT/RHistBinIter.hxx"
27#include "ROOT/RHistUtils.hxx"
28#include "ROOT/RLogger.hxx"
29
30class TRootIOCtor;
31
32namespace ROOT {
33namespace Experimental {
34
35template <int DIMENSIONS, class PRECISION, template <int D_, class P_> class... STAT>
36class RHist;
37
38namespace Hist {
39/// Iterator over n dimensional axes - an array of n axis iterators.
40template <int NDIMS>
41using AxisIter_t = std::array<RAxisBase::const_iterator, NDIMS>;
42/// Range over n dimensional axes - a pair of arrays of n axis iterators.
43template <int NDIMS>
44using AxisIterRange_t = std::array<AxisIter_t<NDIMS>, 2>;
45
46/// Kinds of under- and overflow handling.
47enum class EOverflow {
48 kNoOverflow = 0x0, ///< Exclude under- and overflows
49 kUnderflow = 0x1, ///< Include underflows
50 kOverflow = 0x2, ///< Include overflows
51 kUnderOver = 0x3, ///< Include both under- and overflows
52};
53
55{
56 return static_cast<int>(a) & static_cast<int>(b);
57}
58} // namespace Hist
59
60namespace Detail {
61
62/**
63 \class RHistImplPrecisionAgnosticBase
64 Base class for `RHistImplBase` that abstracts out the histogram's `PRECISION`.
65
66 For operations such as painting a histogram, the `PRECISION` (type of the bin
67 content) is not relevant; painting will cast the underlying bin type to double.
68 To facilitate this, `RHistImplBase` itself inherits from the
69 `RHistImplPrecisionAgnosticBase` interface.
70 */
71template <int DIMENSIONS>
73public:
74 /// Type of the coordinates.
76 /// Type of the local per-axis bin indices.
77 using BinArray_t = std::array<int, DIMENSIONS>;
78 /// Range type.
80
86
87 /// Number of dimensions of the coordinates.
88 static constexpr int GetNDim() { return DIMENSIONS; }
89 /// Number of bins of this histogram, including all overflow and underflow
90 /// bins. Simply the product of all axes' total number of bins.
91 virtual int GetNBins() const noexcept = 0;
92 /// Number of bins of this histogram, excluding all overflow and underflow
93 /// bins. Simply the product of all axes' number of regular bins.
94 virtual int GetNBinsNoOver() const noexcept = 0;
95 /// Number of under- and overflow bins of this histogram, excluding all
96 /// regular bins.
97 virtual int GetNOverflowBins() const noexcept = 0;
98
99 /// Get the histogram title.
100 const std::string &GetTitle() const { return fTitle; }
101
102 /// Given the coordinate `x`, determine the index of the bin.
103 virtual int GetBinIndex(const CoordArray_t &x) const = 0;
104 /// Given the coordinate `x`, determine the index of the bin, possibly
105 /// growing axes for which `x` is out of range.
106 virtual int GetBinIndexAndGrow(const CoordArray_t &x) const = 0;
107
108 /// Given the local per-axis bins `x`, determine the index of the bin.
109 virtual int GetBinIndexFromLocalBins(const BinArray_t &x) const = 0;
110 /// Given the index of the bin, determine the local per-axis bins `x`.
111 virtual BinArray_t GetLocalBins(int binidx) const = 0;
112
113 /// Get the center in all dimensions of the bin with index `binidx`.
114 virtual CoordArray_t GetBinCenter(int binidx) const = 0;
115 /// Get the lower edge in all dimensions of the bin with index `binidx`.
116 virtual CoordArray_t GetBinFrom(int binidx) const = 0;
117 /// Get the upper edge in all dimensions of the bin with index `binidx`.
118 virtual CoordArray_t GetBinTo(int binidx) const = 0;
119
120 /// Get the uncertainty of the bin with index `binidx`.
121 virtual double GetBinUncertainty(int binidx) const = 0;
122
123 /// Whether this histogram's statistics provide storage for uncertainties, or
124 /// whether uncertainties are determined as poisson uncertainty of the content.
125 virtual bool HasBinUncertainty() const = 0;
126
127 /// The bin content, cast to double.
128 virtual double GetBinContentAsDouble(int binidx) const = 0;
129
130 /// Get a base-class view on axis with index `iAxis`.
131 ///
132 /// \param iAxis - index of the axis, must be `0 <= iAxis < DIMENSION`.
133 virtual const RAxisBase &GetAxis(int iAxis) const = 0;
134
135 /// Get an `AxisIterRange_t` for the whole histogram,
136 /// excluding under- and overflow.
137 virtual AxisIterRange_t GetRange() const = 0;
138
139private:
140 std::string fTitle; ///< The histogram's title.
141};
142
143/**
144 \class RHistImplBase
145 Interface class for `RHistImpl`.
146
147 `RHistImpl` is templated for a specific configuration of axes. To enable access
148 through `RHist`, `RHistImpl` inherits from `RHistImplBase`, exposing only dimension
149 (`DIMENSION`) and bin type (`PRECISION`).
150 */
151template <class DATA>
152class RHistImplBase: public RHistImplPrecisionAgnosticBase<DATA::GetNDim()> {
153public:
154 /// Type of the statistics (bin content, uncertainties etc).
155 using Stat_t = DATA;
156 /// Type of the coordinates.
157 using CoordArray_t = Hist::CoordArray_t<DATA::GetNDim()>;
158 /// Type of the local per-axis bin indices.
159 using BinArray_t = std::array<int, DATA::GetNDim()>;
160 /// Type of the bin content (and thus weights).
161 using Weight_t = typename DATA::Weight_t;
162
163 /// Type of the `Fill(x, w)` function
165
166private:
167 /// The histogram's bin content, uncertainties etc.
169
170public:
171 RHistImplBase() = default;
172 RHistImplBase(size_t numBins, size_t numOverflowBins): fStatistics(numBins, numOverflowBins) {}
173 RHistImplBase(std::string_view title, size_t numBins, size_t numOverflowBins)
174 : RHistImplPrecisionAgnosticBase<DATA::GetNDim()>(title), fStatistics(numBins, numOverflowBins)
175 {}
176 RHistImplBase(const RHistImplBase &) = default;
178
179 virtual std::unique_ptr<RHistImplBase> Clone() const = 0;
180
181 /// Interface function to fill a vector or array of coordinates with
182 /// corresponding weights.
183 /// \note the size of `xN` and `weightN` must be the same!
184 virtual void FillN(const std::span<const CoordArray_t> xN, const std::span<const Weight_t> weightN) = 0;
185
186 /// Interface function to fill a vector or array of coordinates.
187 virtual void FillN(const std::span<const CoordArray_t> xN) = 0;
188
189 /// Retrieve the pointer to the overridden `Fill(x, w)` function.
190 virtual FillFunc_t GetFillFunc() const = 0;
191
192 /// Get the bin content (sum of weights) for the bin at coordinate `x`.
193 virtual Weight_t GetBinContent(const CoordArray_t &x) const = 0;
194
196
197 /// Get the bin uncertainty for the bin at coordinate x.
198 virtual double GetBinUncertainty(const CoordArray_t &x) const = 0;
199
200 /// Get the number of bins in this histogram, including possible under- and
201 /// overflow bins.
202 int GetNBins() const noexcept final { return fStatistics.size(); }
203
204 /// Get the number of bins in this histogram, excluding possible under- and
205 /// overflow bins.
206 int GetNBinsNoOver() const noexcept final { return fStatistics.sizeNoOver(); }
207
208 /// Get the number of under- and overflow bins of this histogram, excluding all
209 /// regular bins.
210 int GetNOverflowBins() const noexcept final { return fStatistics.sizeUnderOver(); }
211
212 /// Get the bin content (sum of weights) for bin index `binidx`.
213 Weight_t GetBinContent(int binidx) const
214 {
215 assert(binidx != 0);
216 return fStatistics[binidx];
217 }
218
219 /// Get the bin content (sum of weights) for bin index `binidx` (non-const).
221 {
222 assert(binidx != 0);
223 return fStatistics[binidx];
224 }
225
226 /// Const access to statistics.
227 const Stat_t &GetStat() const noexcept { return fStatistics; }
228
229 /// Non-const access to statistics.
230 Stat_t &GetStat() noexcept { return fStatistics; }
231
232 /// Get the bin content (sum of weights) for bin index `binidx`, cast to
233 /// `double`.
234 double GetBinContentAsDouble(int binidx) const final { return (double)GetBinContent(binidx); }
235
236 /// Add `w` to the bin at index `bin`.
237 void AddBinContent(int binidx, Weight_t w)
238 {
239 assert(binidx != 0);
240 fStatistics[binidx] += w;
241 }
242};
243} // namespace Detail
244
245namespace Internal {
246/** \name Histogram traits
247 Helper traits for histogram operations.
248 */
249///\{
250
251/// Specifies if the wanted result is the bin's lower edge, center or higher edge.
252enum class EBinCoord {
253 kBinFrom, ///< Get the lower bin edge
254 kBinCenter, ///< Get the bin center
255 kBinTo ///< Get the bin high edge
256};
257
258/// Status of FindBin(x) and FindAdjustedBin(x)
259enum class EFindStatus {
260 kCanGrow, ///< The coordinate could fit after growing the axis
261 kValid ///< The returned bin index is valid
262};
263
264/// \name Axis tuple operations
265/// Template operations on axis tuple.
266///@{
267
268/// Recursively gets the total number of bins in whole hist, excluding under- and overflow.
269/// Each call gets the current axis' number of bins (excluding under- and overflow) multiplied
270/// by that of the next axis.
271template <int IDX, class AXISTUPLE>
272struct RGetNBinsNoOverCount;
273
274template <class AXES>
275struct RGetNBinsNoOverCount<0, AXES> {
276 int operator()(const AXES &axes) const { return std::get<0>(axes).GetNBinsNoOver(); }
277};
278
279template <int I, class AXES>
281 int operator()(const AXES &axes) const { return std::get<I>(axes).GetNBinsNoOver() * RGetNBinsNoOverCount<I - 1, AXES>()(axes); }
282};
283
284/// Get the number of bins in whole hist, excluding under- and overflow.
285template <class... AXISCONFIG>
286int GetNBinsNoOverFromAxes(AXISCONFIG... axisArgs)
287{
288 using axesTuple = std::tuple<AXISCONFIG...>;
289 return RGetNBinsNoOverCount<sizeof...(AXISCONFIG) - 1, axesTuple>()(axesTuple{axisArgs...});
290}
291
292/// Recursively gets the total number of bins in whole hist, including under- and overflow.
293/// Each call gets the current axis' number of bins (including under- and overflow) multiplied
294/// by that of the next axis.
295template <int IDX, class AXISTUPLE>
296struct RGetNBinsCount;
297
298template <class AXES>
299struct RGetNBinsCount<0, AXES> {
300 int operator()(const AXES &axes) const { return std::get<0>(axes).GetNBins(); }
301};
302
303template <int I, class AXES>
305 int operator()(const AXES &axes) const { return std::get<I>(axes).GetNBins() * RGetNBinsCount<I - 1, AXES>()(axes); }
306};
307
308/// Get the number of bins in whole hist, including under- and overflow.
309template <class... AXISCONFIG>
310int GetNBinsFromAxes(AXISCONFIG... axisArgs)
311{
312 using axesTuple = std::tuple<AXISCONFIG...>;
313 return RGetNBinsCount<sizeof...(AXISCONFIG) - 1, axesTuple>()(axesTuple{axisArgs...});
314}
315
316/// Get the number of under- and overflow bins in whole hist, excluding regular bins.
317template <class... AXISCONFIG>
318int GetNOverflowBinsFromAxes(AXISCONFIG... axisArgs)
319{
320 using axesTuple = std::tuple<AXISCONFIG...>;
321 return RGetNBinsCount<sizeof...(AXISCONFIG) - 1, axesTuple>()(axesTuple{axisArgs...}) - RGetNBinsNoOverCount<sizeof...(AXISCONFIG) - 1, axesTuple>()(axesTuple{axisArgs...});
322}
323
324/// Recursively fills the ranges of all axes, excluding under- and overflow.
325/// Each call fills `range` with `begin()` and `end()` of the current axis, excluding
326/// under- and overflow.
327template <int I, class AXES>
328struct RFillIterRange;
329
330template <class AXES>
331struct RFillIterRange<-1, AXES> {
332 void operator()(Hist::AxisIterRange_t<std::tuple_size<AXES>::value> & /*range*/, const AXES & /*axes*/) const
333 {}
334};
335
336template <int I, class AXES>
338 void operator()(Hist::AxisIterRange_t<std::tuple_size<AXES>::value> &range, const AXES &axes) const
339 {
340 range[0][I] = std::get<I>(axes).begin();
341 range[1][I] = std::get<I>(axes).end();
342 RFillIterRange<I - 1, AXES>()(range, axes);
343 }
344};
345
346/// Recursively gets the number of regular bins just before the current dimension.
347/// Each call gets the previous axis' number of regular bins multiplied
348/// by the number of regular bins before the previous axis.
349template <int I, int NDIMS, typename BINS, class AXES>
350struct RGetNRegularBinsBefore;
351
352template <int NDIMS, typename BINS, class AXES>
353struct RGetNRegularBinsBefore<-1, NDIMS, BINS, AXES> {
354 void operator()(BINS &/*binSizes*/, const AXES &/*axes*/) const
355 {}
356};
357
358template <int I, int NDIMS, typename BINS, class AXES>
360 void operator()(BINS &binSizes, const AXES &axes) const
361 {
362 constexpr const int thisAxis = NDIMS - I - 1;
363 binSizes[thisAxis] = binSizes[thisAxis-1] * std::get<thisAxis-1>(axes).GetNBinsNoOver();
364 RGetNRegularBinsBefore<I - 1, NDIMS, BINS, AXES>()(binSizes, axes);
365 }
366};
367
368/// Recursively gets the total number of regular bins before the current dimension,
369/// when computing a global bin that is in under- or overflow in at least one
370/// dimension. That global bin's local per-axis bin indices are passed through
371/// the `localBins` parameter. These `localBins` were translated to 0-based bins,
372/// which is more convenient for some operations and which are the `virtualBins`
373/// parameter.
374/// Each call gets the current axis' number of regular bins before the global_bin
375/// in the current dimension multiplied by the number of regular bins before the
376/// current axis.
377/// If the global_bin is in under- or overflow in the current dimension (local bin),
378/// there is no need to process further.
379
380// - We want to know how many regular bins lie before the current overflow bin in the
381// histogram's global binning order (which so far I thought was row-major, but now I'm
382// not sure, maybe it's actually column-major... it doesn't matter, we don't need to spell out what is the global binning order anyway).
383
384template <int I, int NDIMS, typename BINS, class AXES>
385struct RComputeGlobalBin;
386
387template <int NDIMS, typename BINS, class AXES>
388struct RComputeGlobalBin<-1, NDIMS, BINS, AXES> {
389 int operator()(int total_regular_bins_before, const AXES &/*axes*/, const BINS &/*virtualBins*/, const BINS &/*binSizes*/, const BINS &/*localBins*/) const
390 {
391 return total_regular_bins_before;
392 }
393};
394
395template <int I, int NDIMS, typename BINS, class AXES>
397 int operator()(int total_regular_bins_before, const AXES &axes, const BINS &virtualBins, const BINS &binSizes, const BINS &localBins) const
398 {
399 // We can tell how many regular bins lie before us on this axis,
400 // accounting for the underflow bin of this axis if it has one.
401 const int num_underflow_bins = static_cast<int>(!std::get<I>(axes).CanGrow());
402 const int num_regular_bins_before =
403 std::max(virtualBins[I] - num_underflow_bins, 0);
404 total_regular_bins_before += num_regular_bins_before * binSizes[I];
405
406 // If we are on an overflow or underflow bin on this axis, we know that
407 // we don't need to look at the remaining axes. Projecting on those
408 // dimensions would only take us into an hyperplane of over/underflow
409 // bins for the current axis, and we know that by construction there
410 // will be no regular bins in there.
411 if (localBins[I] < 1)
412 return total_regular_bins_before;
413
414 return RComputeGlobalBin<I - 1, NDIMS, BINS, AXES>()(total_regular_bins_before, axes, virtualBins, binSizes, localBins);
415 }
416};
417
418/// Recursively compute some quantities needed for `ComputeLocalBins`, namely
419/// the total number of bins per hyperplane (overflow and regular) and the
420/// number of regular bins per hyperplane on the hyperplanes that have them.
421template <int I, int NDIMS, class AXES>
422struct RComputeLocalBinsInitialisation;
423
424template <int NDIMS, class AXES>
425struct RComputeLocalBinsInitialisation<0, NDIMS, AXES> {
426 void operator()(std::array<int, NDIMS-1> /* bins_per_hyperplane */, std::array<int, NDIMS-1> /* regular_bins_per_hyperplane */, const AXES & /*axes*/) const
427 {}
428};
429
430template <int I, int NDIMS, class AXES>
432 void operator()(std::array<int, NDIMS-1>& bins_per_hyperplane, std::array<int, NDIMS-1>& regular_bins_per_hyperplane, const AXES &axes) const
433 {
434 constexpr const int thisAxis = NDIMS - I - 1;
435 bins_per_hyperplane[thisAxis] = Internal::RGetNBinsCount<thisAxis, AXES>()(axes);
436 regular_bins_per_hyperplane[thisAxis] = Internal::RGetNBinsNoOverCount<thisAxis, AXES>()(axes);
437 RComputeLocalBinsInitialisation<I - 1, NDIMS, AXES>()(bins_per_hyperplane, regular_bins_per_hyperplane, axes);
438 }
439};
440
441/// Recursively computes the number of regular bins before the current dimension,
442/// as well as the number of under- and overflow bins left to account for, after
443/// the current dimension. If the latter is equal to 0, there is no need to process
444/// further.
445/// It is computing local bins that are in under- or overflow in at least one
446/// dimension.
447/// Starting at the highest dimension, it examines how many full hyperplanes of
448/// regular bins lie before, then projects on the remaining dimensions.
449
450template <int I, int NDIMS, class AXES>
451struct RComputeLocalBins;
452
453template <int NDIMS, class AXES>
454struct RComputeLocalBins<0, NDIMS, AXES> {
455 void operator()(const AXES &/*axes*/, int &/*unprocessed_previous_overflow_bin*/,
456 int &/*num_regular_bins_before*/, std::array<int, NDIMS-1> /* bins_per_hyperplane */,
457 std::array<int, NDIMS-1> /* regular_bins_per_hyperplane */, int /* curr_bins_per_hyperplane */,
458 int /* curr_regular_bins_per_hyperplane */) const
459 {}
460};
461
462template <int I, int NDIMS, class AXES>
464 void operator()(const AXES &axes, int &unprocessed_previous_overflow_bin,
465 int &num_regular_bins_before, std::array<int, NDIMS-1> bins_per_hyperplane,
466 std::array<int, NDIMS-1> regular_bins_per_hyperplane, int curr_bins_per_hyperplane,
467 int curr_regular_bins_per_hyperplane) const
468 {
469 // Let's start by computing the contribution of the underflow
470 // hyperplane (if any), in which we know there will be no regular bins
471 const int num_underflow_hyperplanes =
472 static_cast<int>(!std::get<I>(axes).CanGrow());
473 const int bins_in_underflow_hyperplane =
474 num_underflow_hyperplanes * bins_per_hyperplane[I-1];
475
476 // Next, from the total number of bins per hyperplane and the number of
477 // regular bins per hyperplane that has them, we deduce the number of
478 // overflow bins per hyperplane that has regular bins.
479 const int overflow_bins_per_regular_hyperplane =
480 bins_per_hyperplane[I-1] - regular_bins_per_hyperplane[I-1];
481
482 // This allows us to answer a key question: are there any under/overflow
483 // bins on the hyperplanes that have regular bins? It may not be the
484 // case if all of their axes are growable, and thus don't have overflow bins.
485 if (overflow_bins_per_regular_hyperplane != 0) {
486 // If so, we start by cutting off the contribution of the underflow
487 // and overflow hyperplanes, to focus specifically on regular bins.
488 const int overflow_bins_in_regular_hyperplanes =
489 std::min(
490 std::max(
491 unprocessed_previous_overflow_bin
492 - bins_in_underflow_hyperplane,
493 0
494 ),
495 overflow_bins_per_regular_hyperplane
496 * std::get<I>(axes).GetNBinsNoOver()
497 );
498
499 // We count how many _complete_ "regular" hyperplanes that leaves
500 // before us, and account for those in our regular bin count.
501 const int num_regular_hyperplanes_before =
502 overflow_bins_in_regular_hyperplanes
503 / overflow_bins_per_regular_hyperplane;
504 num_regular_bins_before +=
505 num_regular_hyperplanes_before
506 * regular_bins_per_hyperplane[I-1];
507
508 // This only leaves the _current_ hyperplane as a possible source of
509 // more regular bins that we haven't accounted for yet. We'll take
510 // those into account while processing previous dimensions.
511 unprocessed_previous_overflow_bin =
512 overflow_bins_in_regular_hyperplanes
513 % overflow_bins_per_regular_hyperplane;
514 } else {
515 // If there are no overflow bins in regular hyperplane, then the
516 // rule changes: observing _one_ overflow bin after the underflow
517 // hyperplane means that _all_ regular hyperplanes on this axis are
518 // already before us.
519 if (unprocessed_previous_overflow_bin >= bins_in_underflow_hyperplane) {
520 num_regular_bins_before +=
521 std::get<I>(axes).GetNBinsNoOver()
522 * regular_bins_per_hyperplane[I-1];
523 }
524
525 // In this case, we're done, because the current bin may only lie
526 // in the underflow or underflow hyperplane of this axis. Which
527 // means that there are no further regular bins to be accounted for
528 // in the current hyperplane.
529 unprocessed_previous_overflow_bin = 0;
530 }
531
532 // No need to continue this loop if we've taken into account all
533 // overflow bins that were associated with regular bins.
534 if (unprocessed_previous_overflow_bin == 0)
535 return;
536
537 return Internal::RComputeLocalBins<I - 1, NDIMS, AXES>()
538 (axes, unprocessed_previous_overflow_bin, num_regular_bins_before, bins_per_hyperplane,
539 regular_bins_per_hyperplane, curr_bins_per_hyperplane, curr_regular_bins_per_hyperplane);
540 }
541};
542
543/// Recursively computes zero-based local bin indices, given...
544///
545/// - A zero-based global bin index
546/// - The number of considered bins on each axis (can be either `GetNBinsNoOver`
547/// or `GetNBins` depending on what you are trying to do)
548/// - A policy of treating all bins as regular (i.e. no negative indices)
549template <int I, int NDIMS, typename BINS, class AXES, class BINTYPE>
550struct RComputeLocalBinsRaw;
551
552template <int NDIMS, typename BINS, class AXES, class BINTYPE>
553struct RComputeLocalBinsRaw<-1, NDIMS, BINS, AXES, BINTYPE> {
554 void operator()(BINS & /*virtualBins*/, const AXES & /*axes*/, int /*zeroBasedGlobalBin*/, BINTYPE /*GetNBinType*/) const
555 {}
556};
557
558template <int I, int NDIMS, typename BINS, class AXES, class BINTYPE>
560 void operator()(BINS &virtualBins, const AXES &axes, int zeroBasedGlobalBin, BINTYPE GetNBinType) const
561 {
562 constexpr const int thisAxis = NDIMS - I - 1;
563 virtualBins[thisAxis] = zeroBasedGlobalBin % (std::get<thisAxis>(axes).*GetNBinType)();
564 RComputeLocalBinsRaw<I - 1, NDIMS, BINS, AXES, BINTYPE>()(virtualBins, axes, zeroBasedGlobalBin / (std::get<thisAxis>(axes).*GetNBinType)(), GetNBinType);
565 }
566};
567
568/// Recursively computes a zero-based global bin index, given...
569///
570/// - A set of zero-based per-axis bin indices
571/// - The number of considered bins on each axis (can be either `GetNBinsNoOver`
572/// or `GetNBins` depending on what you are trying to do)
573/// - A policy of treating all bins qs regular (i.e. no negative indices)
574template <int I, int NDIMS, typename BINS, class AXES, class BINTYPE>
575struct RComputeGlobalBinRaw;
576
577template <int NDIMS, typename BINS, class AXES, class BINTYPE>
578struct RComputeGlobalBinRaw<-1, NDIMS, BINS, AXES, BINTYPE> {
579 int operator()(int globalVirtualBin, const AXES & /*axes*/, const BINS & /*zeroBasedLocalBins*/, int /*binSize*/, BINTYPE /*GetNBinType*/) const
580 {
581 return globalVirtualBin;
582 }
583};
584
585template <int I, int NDIMS, typename BINS, class AXES, class BINTYPE>
587 int operator()(int globalVirtualBin, const AXES &axes, const BINS &zeroBasedLocalBins, int binSize, BINTYPE GetNBinType) const
588 {
589 constexpr const int thisAxis = NDIMS - I - 1;
590 globalVirtualBin += zeroBasedLocalBins[thisAxis] * binSize;
591 binSize *= (std::get<thisAxis>(axes).*GetNBinType)();
592 return Internal::RComputeGlobalBinRaw<I - 1, NDIMS, BINS, AXES, BINTYPE>()(globalVirtualBin, axes, zeroBasedLocalBins, binSize, GetNBinType);
593 }
594};
595
596/// Recursively converts zero-based virtual bins where the underflow bin
597/// has index `0` and the overflow bin has index `N+1` where `N` is the axis'
598/// number of regular bins, to the standard `kUnderflowBin`/`kOverflowBin` for under/overflow
599/// bin indexing convention.
600///
601/// For growable axes, must add 1 to go back to standard indices as their virtual
602/// indexing convention is also 0-based, with zero designating the first regular bin.
603template <int I, int NDIMS, typename BINS, class AXES>
604struct RVirtualBinsToLocalBins;
605
606template <int NDIMS, typename BINS, class AXES>
607struct RVirtualBinsToLocalBins<-1, NDIMS, BINS, AXES> {
608 void operator()(BINS & /*localBins*/, const AXES & /*axes*/, const BINS & /*virtualBins*/) const
609 {}
610};
611
612template <int I, int NDIMS, typename BINS, class AXES>
614 void operator()(BINS &localBins, const AXES &axes, const BINS &virtualBins) const
615 {
616 constexpr const int thisAxis = NDIMS - I - 1;
617 if ((!std::get<thisAxis>(axes).CanGrow()) && (virtualBins[thisAxis] == 0)) {
618 localBins[thisAxis] = RAxisBase::kUnderflowBin;
619 } else if ((!std::get<thisAxis>(axes).CanGrow()) && (virtualBins[thisAxis] == (std::get<thisAxis>(axes).GetNBins() - 1))) {
620 localBins[thisAxis] = RAxisBase::kOverflowBin;
621 } else {
622 const int regular_bin_offset = -static_cast<int>(std::get<thisAxis>(axes).CanGrow());
623 localBins[thisAxis] = virtualBins[thisAxis] - regular_bin_offset;
624 }
625 RVirtualBinsToLocalBins<I - 1, NDIMS, BINS, AXES>()(localBins, axes, virtualBins);
626 }
627};
628
629/// Recursively converts local axis bins from the standard `kUnderflowBin`/`kOverflowBin` for under/overflow
630/// bin indexing convention, to a "virtual bin" convention where the underflow bin
631/// has index `0` and the overflow bin has index `N+1` where `N` is the axis'
632/// number of regular bins.
633///
634/// For growable axes, subtract 1 from regular indices so that the indexing
635/// convention remains zero-based (this means that there will be no "holes" in
636/// global binning, which matters more than the choice of regular index base)
637template <int I, int NDIMS, typename BINS, class AXES>
638struct RLocalBinsToVirtualBins;
639
640template <int NDIMS, typename BINS, class AXES>
641struct RLocalBinsToVirtualBins<-1, NDIMS, BINS, AXES> {
642 void operator()(BINS & /*virtualBins*/, const AXES & /*axes*/, const BINS & /*localBins*/) const
643 {}
644};
645
646template <int I, int NDIMS, typename BINS, class AXES>
648 void operator()(BINS &virtualBins, const AXES &axes, const BINS &localBins) const
649 {
650 constexpr const int thisAxis = NDIMS - I - 1;
651 switch (localBins[thisAxis]) {
653 virtualBins[thisAxis] = 0; break;
655 virtualBins[thisAxis] = std::get<thisAxis>(axes).GetNBins() - 1; break;
656 default:
657 virtualBins[thisAxis] = localBins[thisAxis] - static_cast<int>(std::get<thisAxis>(axes).CanGrow());
658 }
659 RLocalBinsToVirtualBins<I - 1, NDIMS, BINS, AXES>()(virtualBins, axes, localBins);
660 }
661};
662
663/// Find the per-axis local bin indices associated with a certain set of coordinates.
664template <int I, int NDIMS, typename BINS, typename COORD, class AXES>
665struct RFindLocalBins;
666
667template <int NDIMS, typename BINS, typename COORD, class AXES>
668struct RFindLocalBins<-1, NDIMS, BINS, COORD, AXES> {
669 void operator()(BINS & /*localBins*/, const AXES & /*axes*/, const COORD & /*coords*/) const
670 {}
671};
672
673template <int I, int NDIMS, typename BINS, typename COORD, class AXES>
675 void operator()(BINS &localBins, const AXES &axes, const COORD &coords) const
676 {
677 constexpr const int thisAxis = NDIMS - I - 1;
678 localBins[thisAxis] = std::get<thisAxis>(axes).FindBin(coords[thisAxis]);
679 RFindLocalBins<I - 1, NDIMS, BINS, COORD, AXES>()(localBins, axes, coords);
680 }
681};
682
683/// Recursively converts local axis bins from the standard `kUnderflowBin`/`kOverflowBin` for
684/// under/overflow bin indexing convention, to the corresponding bin coordinates.
685template <int I, int NDIMS, typename BINS, typename COORD, class AXES>
686struct RLocalBinsToCoords;
687
688template <int NDIMS, typename BINS, typename COORD, class AXES>
689struct RLocalBinsToCoords<-1, NDIMS, BINS, COORD, AXES> {
690 void operator()(COORD & /*coords*/, const AXES & /*axes*/, const BINS & /*localBins*/, EBinCoord /*kind*/) const
691 {}
692};
693
694template <int I, int NDIMS, typename BINS, typename COORD, class AXES>
696 void operator()(COORD &coords, const AXES &axes, const BINS &localBins, EBinCoord kind) const
697 {
698 constexpr const int thisAxis = NDIMS - I - 1;
699 int axisbin = localBins[thisAxis];
700 switch (kind) {
701 case EBinCoord::kBinFrom: coords[thisAxis] = std::get<thisAxis>(axes).GetBinFrom(axisbin); break;
702 case EBinCoord::kBinCenter: coords[thisAxis] = std::get<thisAxis>(axes).GetBinCenter(axisbin); break;
703 case EBinCoord::kBinTo: coords[thisAxis] = std::get<thisAxis>(axes).GetBinTo(axisbin); break;
704 }
705 RLocalBinsToCoords<I - 1, NDIMS, BINS, COORD, AXES>()(coords, axes, localBins, kind);
706 }
707};
708
709template <class... AXISCONFIG>
710static std::array<const RAxisBase *, sizeof...(AXISCONFIG)> GetAxisView(const AXISCONFIG &... axes) noexcept
711{
712 std::array<const RAxisBase *, sizeof...(AXISCONFIG)> axisViews{{&axes...}};
713 return axisViews;
714}
715
716///\}
717} // namespace Internal
718
719namespace Detail {
720
721template <class DATA, class... AXISCONFIG>
722class RHistImpl final: public RHistImplBase<DATA> {
723 static_assert(sizeof...(AXISCONFIG) == DATA::GetNDim(), "Number of axes must equal histogram dimension");
724
725 friend typename DATA::Hist_t;
726
727public:
732 using typename ImplBase_t::FillFunc_t;
733 template <int NDIMS = DATA::GetNDim()>
735
736private:
737 std::tuple<AXISCONFIG...> fAxes; ///< The histogram's axes
738
739public:
741 RHistImpl(AXISCONFIG... axisArgs);
742 RHistImpl(std::string_view title, AXISCONFIG... axisArgs);
743
744 std::unique_ptr<ImplBase_t> Clone() const override {
745 return std::unique_ptr<ImplBase_t>(new RHistImpl(*this));
746 }
747
748 /// Retrieve the fill function for this histogram implementation, to prevent
749 /// the virtual function call for high-frequency fills.
750 FillFunc_t GetFillFunc() const final {
751 return (FillFunc_t)&RHistImpl::Fill;
752 }
753
754 /// Get the axes of this histogram.
755 const std::tuple<AXISCONFIG...> &GetAxes() const { return fAxes; }
756
757 /// Normalized axes access, converting from actual axis type to base class.
758 const RAxisBase &GetAxis(int iAxis) const final { return *std::apply(Internal::GetAxisView<AXISCONFIG...>, fAxes)[iAxis]; }
759
760 /// Computes a zero-based global bin index, given...
761 ///
762 /// - A set of zero-based per-axis bin indices
763 /// - The number of considered bins on each axis (can be either `GetNBinsNoOver`
764 /// or `GetNBins` depending on what you are trying to do)
765 /// - A policy of treating all bins qs regular (i.e. no negative indices)
766 template <int NDIMS, typename BINTYPE>
767 int ComputeGlobalBinRaw(const BinArray_t& zeroBasedLocalBins, BINTYPE GetNBinType) const {
768 int result = 0;
769 int binSize = 1;
770 return Internal::RComputeGlobalBinRaw<NDIMS - 1, NDIMS, BinArray_t, decltype(fAxes), BINTYPE>()(result, fAxes, zeroBasedLocalBins, binSize, GetNBinType);
771 }
772
773 /// Computes zero-based local bin indices, given...
774 ///
775 /// - A zero-based global bin index
776 /// - The number of considered bins on each axis (can be either `GetNBinsNoOver`
777 /// or `GetNBins` depending on what you are trying to do)
778 /// - A policy of treating all bins as regular (i.e. no negative indices)
779 template <int NDIMS, typename BINTYPE>
780 BinArray_t ComputeLocalBinsRaw(int zeroBasedGlobalBin, BINTYPE GetNBinType) const {
781 BinArray_t result;
782 Internal::RComputeLocalBinsRaw<NDIMS - 1, NDIMS, BinArray_t, decltype(fAxes), BINTYPE>()(result, fAxes, zeroBasedGlobalBin, GetNBinType);
783 return result;
784 }
785
786 /// Converts local axis bins from the standard `kUnderflowBin`/`kOverflowBin` for under/overflow
787 /// bin indexing convention, to a "virtual bin" convention where the underflow bin
788 /// has index `0` and the overflow bin has index `N+1` where `N` is the axis'
789 /// number of regular bins.
790 template <int NDIMS>
792 BinArray_t virtualBins;
793 Internal::RLocalBinsToVirtualBins<NDIMS - 1, NDIMS, BinArray_t, decltype(fAxes)>()(virtualBins, fAxes, localBins);
794 return virtualBins;
795 }
796
797 /// Converts zero-based virtual bins where the underflow bin has
798 /// index `0` and the overflow bin has index `N+1` where `N` is the axis'
799 /// number of regular bins, to the standard `kUnderflowBin`/`kOverflowBin` for under/overflow
800 /// bin indexing convention.
801 template <int NDIMS>
802 BinArray_t VirtualBinsToLocalBins(const BinArray_t& virtualBins) const {
803 BinArray_t localBins = {};
804 Internal::RVirtualBinsToLocalBins<NDIMS - 1, NDIMS, BinArray_t, decltype(fAxes)>()(localBins, fAxes, virtualBins);
805 return localBins;
806 }
807
808 /// Computes the global index of a certain bin on an `NDIMS`-dimensional histogram,
809 /// knowing the local per-axis bin indices as returned by calling `FindBin()` on each axis.
810 template <int NDIMS>
811 int ComputeGlobalBin(BinArray_t& local_bins) const {
812 // Get regular bins out of the way
813 if (std::all_of(local_bins.cbegin(), local_bins.cend(),
814 [](int bin) { return bin >= 1; })) {
815 for (int bin = 0; bin < NDIMS; bin++)
816 local_bins[bin] -= 1;
817 return ComputeGlobalBinRaw<NDIMS>(local_bins, &ROOT::Experimental::RAxisBase::GetNBinsNoOver) + 1;
818 }
819
820 // Convert bin indices to a zero-based coordinate system where the underflow
821 // bin (if any) has coordinate 0 and the overflow bin (if any) has
822 // coordinate N-1, where N is the axis' total number of bins.
823 BinArray_t virtual_bins = LocalBinsToVirtualBins<NDIMS>(local_bins);
824
825 // Deduce what the global bin index would be in this coordinate system that
826 // unifies regular and overflow bins.
827 const int global_virtual_bin = ComputeGlobalBinRaw<NDIMS>(virtual_bins, &ROOT::Experimental::RAxisBase::GetNBins);
828
829 // Move to 1-based and negative indexing
830 const int neg_1based_virtual_bin = -global_virtual_bin - 1;
831
832 // At this point, we have an index that represents a count of all bins, both
833 // regular and overflow, that are located before the current bin when
834 // enumerating histogram bins in row-major order.
835 //
836 // We will next count the number of _regular_ bins which are located before
837 // the current bin, and by removing this offset from the above index, we
838 // will get a count of overflow bins that are located before the current bin
839 // in row-major order. Which is what we want as our overflow bin index.
840 //
841 int total_regular_bins_before = 0;
842
843 // First, we need to know how many regular bins we leave behind us for each
844 // step on each axis, assuming that the bin from which we come was regular.
845 //
846 // If mathematically inclined, you can also think of this as the size of an
847 // hyperplane of regular bins when projecting on lower-numbered dimensions.
848 // See the docs of ComputeLocalBins for more on this worldview.
849 //
850 BinArray_t bin_sizes;
851 bin_sizes[0] = 1;
852 Internal::RGetNRegularBinsBefore<NDIMS - 2, NDIMS, BinArray_t, decltype(fAxes)>()(bin_sizes, fAxes);
853
854 // With that, we can deduce how many regular bins lie before us.
855 total_regular_bins_before = Internal::RComputeGlobalBin<NDIMS - 1, NDIMS, BinArray_t, decltype(fAxes)>()
856 (total_regular_bins_before, fAxes, virtual_bins, bin_sizes, local_bins);
857
858 // Now that we know how many bins lie before us, and how many of those are
859 // regular bins, we can trivially deduce how many overflow bins lie before
860 // us, and emit that as our global overflow bin index.
861 return neg_1based_virtual_bin + total_regular_bins_before;
862 }
863
864 /// Computes the local per-axis bin indices of a certain bin on an `NDIMS`-dimensional histogram,
865 /// knowing the global histogram bin index.
866 template <int NDIMS>
867 BinArray_t ComputeLocalBins(int global_bin) const {
868 // Get regular bins out of the way
869 if (global_bin >= 1) {
870 BinArray_t computed_bins = ComputeLocalBinsRaw<NDIMS>(global_bin - 1, &ROOT::Experimental::RAxisBase::GetNBinsNoOver);
871 for (int bin = 0; bin < NDIMS; ++bin)
872 computed_bins[bin] += 1;
873 return computed_bins;
874 }
875
876 // Convert our negative index to something positive and 0-based, as that is
877 // more convenient to work with. Note, however, that this is _not_
878 // equivalent to the virtual_bin that we had before, because what we have
879 // here is a count of overflow bins, not of all bins...
880 const int corrected_virtual_overflow_bin = -global_bin - 1;
881
882 // ...so we need to retrieve and bring back the regular bin count, and this
883 // is where the fun begins.
884 //
885 // The main difficulty is that the number of regular bins is not fixed as
886 // one slides along a histogram axis. Using a 2D binning case as a simple
887 // motivating example...
888 //
889 // -1 -2 -3 -4 <- No regular bins on the underflow line of axis 1
890 // -5 1 2 -6 <- Some of them on middle lines of axis 1
891 // -7 3 4 -8
892 // -9 -10 -11 -12 <- No regular bins on the overflow line of axis 1
893 //
894 // As we go to higher dimensions, the geometry becomes more complex, but
895 // if we replace "line" with "plane", we get a similar picture in 3D when we
896 // slide along axis 2:
897 //
898 // No regular bins on the Some of them on the No regular bins again
899 // UF plane of axis 2 regular planes of ax.2 on the OF plane of ax.2
900 //
901 // -1 -2 -3 -4 -17 -18 -19 -20 -29 -30 -31 -32
902 // -5 -6 -7 -8 -21 1 2 -22 -33 -34 -35 -36
903 // -9 -10 -11 -12 -23 3 4 -24 -37 -37 -39 -40
904 // -13 -14 -15 -16 -25 -26 -27 -28 -41 -42 -43 -44
905 //
906 // We can generalize this to N dimensions by saying that as we slide along
907 // the last axis of an N-d histogram, we see an hyperplane full of overflow
908 // bins, then some hyperplanes with regular bins in the "middle" surrounded
909 // by overflow bins, then a last hyperplane full of overflow bins.
910 //
911 // From this, we can devise a recursive algorithm to recover the number of
912 // regular bins before the overflow bin we're currently looking at:
913 //
914 // - Start by processing the last histogram axis.
915 // - Ignore the first and last hyperplane on this axis, which only contain
916 // underflow and overflow bins respectively.
917 // - Count how many complete hyperplanes of regular bins lie before us on
918 // this axis, which we can do indirectly in our overflow bin based
919 // reasoning by computing the perimeter of the regular region and dividing
920 // our "regular" overflow bin count by that amount.
921 // - Now we counted previous hyperplanes on this last histogram axis, but
922 // we need to process the hyperplane that our bin is located in, if any.
923 // * For this, we reduce our overflow bin count to a count of
924 // _unaccounted_ overflow bins in the current hyperplane...
925 // * ...which allows us to recursively continue the computation by
926 // processing the next (well, previous) histogram axis in the context
927 // of this hyperplane, in the same manner as above.
928 //
929 // Alright, now that the general plan is sorted out, let's compute some
930 // quantities that we are going to need, namely the total number of bins per
931 // hyperplane (overflow and regular) and the number of regular bins per
932 // hyperplane on the hyperplanes that have them.
933 //
934 std::array<int, NDIMS - 1> bins_per_hyperplane;
935 std::array<int, NDIMS - 1> regular_bins_per_hyperplane;
936 Internal::RComputeLocalBinsInitialisation<NDIMS - 1, NDIMS, decltype(fAxes)>()(bins_per_hyperplane, regular_bins_per_hyperplane, fAxes);
937
938 int curr_bins_per_hyperplane = Internal::RGetNBinsCount<NDIMS - 1, decltype(fAxes)>()(fAxes);
939 int curr_regular_bins_per_hyperplane = Internal::RGetNBinsNoOverCount<NDIMS - 1, decltype(fAxes)>()(fAxes);
940
941 // Given that, we examine each axis, starting from the last one.
942 int unprocessed_previous_overflow_bin = corrected_virtual_overflow_bin;
943 int num_regular_bins_before = 0;
944 Internal::RComputeLocalBins<NDIMS - 1, NDIMS, decltype(fAxes)>()
945 (fAxes, unprocessed_previous_overflow_bin, num_regular_bins_before, bins_per_hyperplane,
946 regular_bins_per_hyperplane, curr_bins_per_hyperplane, curr_regular_bins_per_hyperplane);
947
948 // By the time we reach the first axis, there should only be at most one
949 // full row of regular bins before us:
950 //
951 // -1 1 2 3 -2
952 // ^ ^
953 // | |
954 // | Option 2: one overflow bin before us
955 // |
956 // Option 1: no overflow bin before us
957 //
958 num_regular_bins_before +=
959 unprocessed_previous_overflow_bin * std::get<0>(fAxes).GetNBinsNoOver();
960
961 // Now that we know the number of regular bins before us, we can add this to
962 // to the zero-based overflow bin index that we started with to get a global
963 // zero-based bin index accounting for both under/overflow bins and regular
964 // bins, just like what we had in the ComputeGlobalBin<DATA::GetNDim()>() implementation.
965 const int global_virtual_bin =
966 corrected_virtual_overflow_bin + num_regular_bins_before;
967
968 // We can then easily go back to zero-based "virtual" bin indices...
969 const BinArray_t virtual_bins = ComputeLocalBinsRaw<NDIMS>(global_virtual_bin, &ROOT::Experimental::RAxisBase::GetNBins);
970
971 // ...and from that go back to the -1/-2 overflow bin indexing convention.
972 return VirtualBinsToLocalBins<NDIMS>(virtual_bins);
973 }
974
975 /// Get the bin index for the given coordinates `x`. The use of `RFindLocalBins`
976 /// allows to convert the coordinates to local per-axis bin indices before using
977 /// `ComputeGlobalBin()`.
978 int GetBinIndex(const CoordArray_t &x) const final
979 {
980 BinArray_t localBins = {};
981 Internal::RFindLocalBins<DATA::GetNDim() - 1, DATA::GetNDim(), BinArray_t, CoordArray_t, decltype(fAxes)>()(localBins, fAxes, x);
982 int result = ComputeGlobalBin<DATA::GetNDim()>(localBins);
983 return result;
984 }
985
986 /// Get the bin index for the given coordinates `x`, growing the axes as needed.
987 /// The use of `RFindLocalBins` allows to convert the coordinates to local
988 /// per-axis bin indices before using `ComputeGlobalBin()`.
989 ///
990 /// TODO: implement growable behavior
991 int GetBinIndexAndGrow(const CoordArray_t &x) const final
992 {
994 int ret = 0;
995 BinArray_t localBins = {};
996 while (status == Internal::EFindStatus::kCanGrow) {
997 Internal::RFindLocalBins<DATA::GetNDim() - 1, DATA::GetNDim(), BinArray_t, CoordArray_t, decltype(fAxes)>()(localBins, fAxes, x);
998 ret = ComputeGlobalBin<DATA::GetNDim()>(localBins);
1000 }
1001 return ret;
1002 }
1003
1004 /// Get the bin index for the given local per-axis bin indices `x`, using
1005 /// `ComputeGlobalBin()`.
1006 int GetBinIndexFromLocalBins(const BinArray_t &x) const final
1007 {
1008 BinArray_t localBins = x;
1009 int result = ComputeGlobalBin<DATA::GetNDim()>(localBins);
1010 return result;
1011 }
1012
1013 /// Get the local per-axis bin indices `x` for the given bin index, using
1014 /// `ComputeLocalBins()`.
1015 BinArray_t GetLocalBins(int binidx) const final
1016 {
1017 BinArray_t localBins = ComputeLocalBins<DATA::GetNDim()>(binidx);
1018 return localBins;
1019 }
1020
1021 /// Get the center coordinates of the bin with index `binidx`.
1022 CoordArray_t GetBinCenter(int binidx) const final
1023 {
1024 BinArray_t localBins = ComputeLocalBins<DATA::GetNDim()>(binidx);
1025 CoordArray_t coords;
1026 Internal::RLocalBinsToCoords<DATA::GetNDim() - 1, DATA::GetNDim(), BinArray_t, CoordArray_t, decltype(fAxes)>()(coords, fAxes, localBins, Internal::EBinCoord::kBinCenter);
1027 return coords;
1028 }
1029
1030 /// Get the coordinates of the low limit of the bin with index `binidx`.
1031 CoordArray_t GetBinFrom(int binidx) const final
1032 {
1033 BinArray_t localBins = ComputeLocalBins<DATA::GetNDim()>(binidx);
1034 CoordArray_t coords;
1035 Internal::RLocalBinsToCoords<DATA::GetNDim() - 1, DATA::GetNDim(), BinArray_t, CoordArray_t, decltype(fAxes)>()(coords, fAxes, localBins, Internal::EBinCoord::kBinFrom);
1036 return coords;
1037 }
1038
1039 /// Get the coordinates of the high limit of the bin with index `binidx`.
1040 CoordArray_t GetBinTo(int binidx) const final
1041 {
1042 BinArray_t localBins = ComputeLocalBins<DATA::GetNDim()>(binidx);
1043 CoordArray_t coords;
1044 Internal::RLocalBinsToCoords<DATA::GetNDim() - 1, DATA::GetNDim(), BinArray_t, CoordArray_t, decltype(fAxes)>()(coords, fAxes, localBins, Internal::EBinCoord::kBinTo);
1045 return coords;
1046 }
1047
1048 /// Fill an array of `weightN` to the bins specified by coordinates `xN`.
1049 /// For each element `i`, the weight `weightN[i]` will be added to the bin
1050 /// at the coordinate `xN[i]`
1051 /// \note `xN` and `weightN` must have the same size!
1052 void FillN(const std::span<const CoordArray_t> xN, const std::span<const Weight_t> weightN) final
1053 {
1054#ifndef NDEBUG
1055 if (xN.size() != weightN.size()) {
1056 R__LOG_ERROR(HistLog()) << "Not the same number of points and weights!";
1057 return;
1058 }
1059#endif
1060
1061 for (size_t i = 0; i < xN.size(); ++i) {
1062 Fill(xN[i], weightN[i]);
1063 }
1064 }
1065
1066 /// Fill an array of `weightN` to the bins specified by coordinates `xN`.
1067 /// For each element `i`, the weight `weightN[i]` will be added to the bin
1068 /// at the coordinate `xN[i]`
1069 void FillN(const std::span<const CoordArray_t> xN) final
1070 {
1071 for (auto &&x: xN) {
1072 Fill(x);
1073 }
1074 }
1075
1076 /// Add a single weight `w` to the bin at coordinate `x`.
1077 void Fill(const CoordArray_t &x, Weight_t w = 1.)
1078 {
1079 int bin = GetBinIndexAndGrow(x);
1080 this->GetStat().Fill(x, bin, w);
1081 }
1082
1083 /// Get the content of the bin at position `x`.
1085 {
1086 int bin = GetBinIndex(x);
1087 return ImplBase_t::GetBinContent(bin);
1088 }
1089
1090 /// Return the uncertainties for the given bin index.
1091 double GetBinUncertainty(int binidx) const final { return this->GetStat().GetBinUncertainty(binidx); }
1092
1093 /// Get the bin uncertainty for the bin at coordinate `x`.
1094 double GetBinUncertainty(const CoordArray_t &x) const final
1095 {
1096 const int bin = GetBinIndex(x);
1097 return this->GetBinUncertainty(bin);
1098 }
1099
1100 /// Whether this histogram's statistics provide storage for uncertainties, or
1101 /// whether uncertainties are determined as poisson uncertainty of the content.
1102 bool HasBinUncertainty() const final { return this->GetStat().HasBinUncertainty(); }
1103
1104 /// Get the begin() and end() for each axis.
1105 AxisIterRange_t<DATA::GetNDim()>
1106 GetRange() const final
1107 {
1108 std::array<std::array<RAxisBase::const_iterator, DATA::GetNDim()>, 2> ret;
1109 Internal::RFillIterRange<DATA::GetNDim() - 1, decltype(fAxes)>()(ret, fAxes);
1110 return ret;
1111 }
1112
1113 /// Grow the axis number `iAxis` to fit the coordinate `x`.
1114 ///
1115 /// The histogram (conceptually) combines pairs of bins along this axis until
1116 /// `x` is within the range of the axis.
1117 /// The axis must support growing for this to work (e.g. a `RAxisGrow`).
1118 void GrowAxis(int /*iAxis*/, double /*x*/)
1119 {
1120 // TODO: Implement GrowAxis()
1121 }
1122
1123 /// \{
1124 /// \name Iterator interface
1127 iterator begin() noexcept { return iterator(*this); }
1128 const_iterator begin() const noexcept { return const_iterator(*this); }
1129 iterator end() noexcept { return iterator(*this, this->GetNBinsNoOver()); }
1130 const_iterator end() const noexcept { return const_iterator(*this, this->GetNBinsNoOver()); }
1131 /// \}
1132};
1133
1134template <class DATA, class... AXISCONFIG>
1136{}
1137
1138template <class DATA, class... AXISCONFIG>
1140 : ImplBase_t(Internal::GetNBinsNoOverFromAxes(axisArgs...), Internal::GetNOverflowBinsFromAxes(axisArgs...)), fAxes{axisArgs...}
1141{}
1142
1143template <class DATA, class... AXISCONFIG>
1145 : ImplBase_t(title, Internal::GetNBinsNoOverFromAxes(axisArgs...), Internal::GetNOverflowBinsFromAxes(axisArgs...)), fAxes{axisArgs...}
1146{}
1147
1148#if 0
1149// In principle we can also have a runtime version of RHistImpl, that does not
1150// contain a tuple of concrete axis types but a vector of `RAxisConfig`.
1151template <class DATA>
1152class RHistImplRuntime: public RHistImplBase<DATA> {
1153public:
1154 RHistImplRuntime(std::array<RAxisConfig, DATA::GetNDim()>&& axisCfg);
1155};
1156#endif
1157
1158} // namespace Detail
1159
1160} // namespace Experimental
1161} // namespace ROOT
1162
1163#endif
typedef void(GLAPIENTRYP _GLUfuncptr)(void)
#define R__LOG_ERROR(...)
Definition: RLogger.hxx:362
#define b(i)
Definition: RSha256.hxx:100
Iterates over the bins of a RHist or RHistImpl.
Interface class for RHistImpl.
Definition: RHistImpl.hxx:152
Weight_t & GetBinContent(int binidx)
Get the bin content (sum of weights) for bin index binidx (non-const).
Definition: RHistImpl.hxx:220
int GetNOverflowBins() const noexcept final
Get the number of under- and overflow bins of this histogram, excluding all regular bins.
Definition: RHistImpl.hxx:210
RHistImplBase(const RHistImplBase &)=default
void(RHistImplBase::*)(const CoordArray_t &x, Weight_t w) FillFunc_t
Type of the Fill(x, w) function.
Definition: RHistImpl.hxx:164
virtual double GetBinUncertainty(const CoordArray_t &x) const =0
Get the bin uncertainty for the bin at coordinate x.
void AddBinContent(int binidx, Weight_t w)
Add w to the bin at index bin.
Definition: RHistImpl.hxx:237
int GetNBinsNoOver() const noexcept final
Get the number of bins in this histogram, excluding possible under- and overflow bins.
Definition: RHistImpl.hxx:206
RHistImplBase(RHistImplBase &&)=default
Hist::CoordArray_t< DATA::GetNDim()> CoordArray_t
Type of the coordinates.
Definition: RHistImpl.hxx:157
virtual std::unique_ptr< RHistImplBase > Clone() const =0
DATA Stat_t
Type of the statistics (bin content, uncertainties etc).
Definition: RHistImpl.hxx:155
Stat_t & GetStat() noexcept
Non-const access to statistics.
Definition: RHistImpl.hxx:230
virtual void FillN(const std::span< const CoordArray_t > xN)=0
Interface function to fill a vector or array of coordinates.
Weight_t GetBinContent(int binidx) const
Get the bin content (sum of weights) for bin index binidx.
Definition: RHistImpl.hxx:213
const Stat_t & GetStat() const noexcept
Const access to statistics.
Definition: RHistImpl.hxx:227
Stat_t fStatistics
The histogram's bin content, uncertainties etc.
Definition: RHistImpl.hxx:168
virtual void FillN(const std::span< const CoordArray_t > xN, const std::span< const Weight_t > weightN)=0
Interface function to fill a vector or array of coordinates with corresponding weights.
virtual Weight_t GetBinContent(const CoordArray_t &x) const =0
Get the bin content (sum of weights) for the bin at coordinate x.
std::array< int, DATA::GetNDim()> BinArray_t
Type of the local per-axis bin indices.
Definition: RHistImpl.hxx:159
RHistImplBase(std::string_view title, size_t numBins, size_t numOverflowBins)
Definition: RHistImpl.hxx:173
double GetBinContentAsDouble(int binidx) const final
Get the bin content (sum of weights) for bin index binidx, cast to double.
Definition: RHistImpl.hxx:234
int GetNBins() const noexcept final
Get the number of bins in this histogram, including possible under- and overflow bins.
Definition: RHistImpl.hxx:202
typename DATA::Weight_t Weight_t
Type of the bin content (and thus weights).
Definition: RHistImpl.hxx:161
RHistImplBase(size_t numBins, size_t numOverflowBins)
Definition: RHistImpl.hxx:172
virtual FillFunc_t GetFillFunc() const =0
Retrieve the pointer to the overridden Fill(x, w) function.
Base class for RHistImplBase that abstracts out the histogram's PRECISION.
Definition: RHistImpl.hxx:72
virtual int GetNOverflowBins() const noexcept=0
Number of under- and overflow bins of this histogram, excluding all regular bins.
virtual int GetBinIndex(const CoordArray_t &x) const =0
Given the coordinate x, determine the index of the bin.
std::array< int, DIMENSIONS > BinArray_t
Type of the local per-axis bin indices.
Definition: RHistImpl.hxx:77
RHistImplPrecisionAgnosticBase(RHistImplPrecisionAgnosticBase &&)=default
virtual int GetNBins() const noexcept=0
Number of bins of this histogram, including all overflow and underflow bins.
virtual bool HasBinUncertainty() const =0
Whether this histogram's statistics provide storage for uncertainties, or whether uncertainties are d...
virtual int GetNBinsNoOver() const noexcept=0
Number of bins of this histogram, excluding all overflow and underflow bins.
virtual CoordArray_t GetBinTo(int binidx) const =0
Get the upper edge in all dimensions of the bin with index binidx.
virtual BinArray_t GetLocalBins(int binidx) const =0
Given the index of the bin, determine the local per-axis bins x.
RHistImplPrecisionAgnosticBase(const RHistImplPrecisionAgnosticBase &)=default
const std::string & GetTitle() const
Get the histogram title.
Definition: RHistImpl.hxx:100
Hist::AxisIterRange_t< DIMENSIONS > AxisIterRange_t
Range type.
Definition: RHistImpl.hxx:79
static constexpr int GetNDim()
Number of dimensions of the coordinates.
Definition: RHistImpl.hxx:88
virtual int GetBinIndexAndGrow(const CoordArray_t &x) const =0
Given the coordinate x, determine the index of the bin, possibly growing axes for which x is out of r...
virtual int GetBinIndexFromLocalBins(const BinArray_t &x) const =0
Given the local per-axis bins x, determine the index of the bin.
virtual double GetBinUncertainty(int binidx) const =0
Get the uncertainty of the bin with index binidx.
virtual double GetBinContentAsDouble(int binidx) const =0
The bin content, cast to double.
virtual const RAxisBase & GetAxis(int iAxis) const =0
Get a base-class view on axis with index iAxis.
virtual CoordArray_t GetBinCenter(int binidx) const =0
Get the center in all dimensions of the bin with index binidx.
virtual AxisIterRange_t GetRange() const =0
Get an AxisIterRange_t for the whole histogram, excluding under- and overflow.
virtual CoordArray_t GetBinFrom(int binidx) const =0
Get the lower edge in all dimensions of the bin with index binidx.
void Fill(const CoordArray_t &x, Weight_t w=1.)
Add a single weight w to the bin at coordinate x.
Definition: RHistImpl.hxx:1077
BinArray_t GetLocalBins(int binidx) const final
Get the local per-axis bin indices x for the given bin index, using ComputeLocalBins().
Definition: RHistImpl.hxx:1015
int GetBinIndexAndGrow(const CoordArray_t &x) const final
Get the bin index for the given coordinates x, growing the axes as needed.
Definition: RHistImpl.hxx:991
int ComputeGlobalBinRaw(const BinArray_t &zeroBasedLocalBins, BINTYPE GetNBinType) const
Computes a zero-based global bin index, given...
Definition: RHistImpl.hxx:767
const_iterator end() const noexcept
Definition: RHistImpl.hxx:1130
AxisIterRange_t< DATA::GetNDim()> GetRange() const final
Get the begin() and end() for each axis.
Definition: RHistImpl.hxx:1106
BinArray_t ComputeLocalBins(int global_bin) const
Computes the local per-axis bin indices of a certain bin on an NDIMS-dimensional histogram,...
Definition: RHistImpl.hxx:867
double GetBinUncertainty(const CoordArray_t &x) const final
Get the bin uncertainty for the bin at coordinate x.
Definition: RHistImpl.hxx:1094
const_iterator begin() const noexcept
Definition: RHistImpl.hxx:1128
CoordArray_t GetBinCenter(int binidx) const final
Get the center coordinates of the bin with index binidx.
Definition: RHistImpl.hxx:1022
int GetBinIndexFromLocalBins(const BinArray_t &x) const final
Get the bin index for the given local per-axis bin indices x, using ComputeGlobalBin().
Definition: RHistImpl.hxx:1006
FillFunc_t GetFillFunc() const final
Retrieve the fill function for this histogram implementation, to prevent the virtual function call fo...
Definition: RHistImpl.hxx:750
std::tuple< AXISCONFIG... > fAxes
The histogram's axes.
Definition: RHistImpl.hxx:737
void GrowAxis(int, double)
Grow the axis number iAxis to fit the coordinate x.
Definition: RHistImpl.hxx:1118
Weight_t GetBinContent(const CoordArray_t &x) const final
Get the content of the bin at position x.
Definition: RHistImpl.hxx:1084
int GetBinIndex(const CoordArray_t &x) const final
Get the bin index for the given coordinates x.
Definition: RHistImpl.hxx:978
BinArray_t VirtualBinsToLocalBins(const BinArray_t &virtualBins) const
Converts zero-based virtual bins where the underflow bin has index 0 and the overflow bin has index N...
Definition: RHistImpl.hxx:802
const RAxisBase & GetAxis(int iAxis) const final
Normalized axes access, converting from actual axis type to base class.
Definition: RHistImpl.hxx:758
typename Hist::AxisIterRange_t< NDIMS > AxisIterRange_t
Definition: RHistImpl.hxx:734
int ComputeGlobalBin(BinArray_t &local_bins) const
Computes the global index of a certain bin on an NDIMS-dimensional histogram, knowing the local per-a...
Definition: RHistImpl.hxx:811
typename ImplBase_t::BinArray_t BinArray_t
Definition: RHistImpl.hxx:730
double GetBinUncertainty(int binidx) const final
Return the uncertainties for the given bin index.
Definition: RHistImpl.hxx:1091
bool HasBinUncertainty() const final
Whether this histogram's statistics provide storage for uncertainties, or whether uncertainties are d...
Definition: RHistImpl.hxx:1102
std::unique_ptr< ImplBase_t > Clone() const override
Definition: RHistImpl.hxx:744
RHistBinIter< ImplBase_t > iterator
Definition: RHistImpl.hxx:1126
void FillN(const std::span< const CoordArray_t > xN, const std::span< const Weight_t > weightN) final
Fill an array of weightN to the bins specified by coordinates xN.
Definition: RHistImpl.hxx:1052
BinArray_t ComputeLocalBinsRaw(int zeroBasedGlobalBin, BINTYPE GetNBinType) const
Computes zero-based local bin indices, given...
Definition: RHistImpl.hxx:780
const std::tuple< AXISCONFIG... > & GetAxes() const
Get the axes of this histogram.
Definition: RHistImpl.hxx:755
CoordArray_t GetBinTo(int binidx) const final
Get the coordinates of the high limit of the bin with index binidx.
Definition: RHistImpl.hxx:1040
void FillN(const std::span< const CoordArray_t > xN) final
Fill an array of weightN to the bins specified by coordinates xN.
Definition: RHistImpl.hxx:1069
CoordArray_t GetBinFrom(int binidx) const final
Get the coordinates of the low limit of the bin with index binidx.
Definition: RHistImpl.hxx:1031
BinArray_t LocalBinsToVirtualBins(const BinArray_t &localBins) const
Converts local axis bins from the standard kUnderflowBin/kOverflowBin for under/overflow bin indexing...
Definition: RHistImpl.hxx:791
RHistBinIter< const ImplBase_t > const_iterator
Definition: RHistImpl.hxx:1125
typename ImplBase_t::CoordArray_t CoordArray_t
Definition: RHistImpl.hxx:729
Random const_iterator through bins.
Definition: RAxis.hxx:127
Histogram axis base class.
Definition: RAxis.hxx:44
constexpr static const int kUnderflowBin
Index of the underflow bin, if any.
Definition: RAxis.hxx:229
virtual int GetNBinsNoOver() const noexcept=0
Get the number of bins, excluding under- and overflow.
constexpr static const int kOverflowBin
Index of the overflow bin, if any.
Definition: RAxis.hxx:232
int GetNBins() const noexcept
Get the number of bins, including under- and overflow.
Definition: RAxis.hxx:244
Objects used to configure the different axis types.
Definition: RAxisConfig.hxx:35
Double_t x[n]
Definition: legend1.C:17
basic_string_view< char > string_view
#define I(x, y, z)
EOverflow
Kinds of under- and overflow handling.
Definition: RHistImpl.hxx:47
@ kNoOverflow
Exclude under- and overflows.
@ kUnderOver
Include both under- and overflows.
std::array< AxisIter_t< NDIMS >, 2 > AxisIterRange_t
Range over n dimensional axes - a pair of arrays of n axis iterators.
Definition: RHistImpl.hxx:44
bool operator&(EOverflow a, EOverflow b)
Definition: RHistImpl.hxx:54
std::array< RAxisBase::const_iterator, NDIMS > AxisIter_t
Iterator over n dimensional axes - an array of n axis iterators.
Definition: RHistImpl.hxx:41
EFindStatus
Status of FindBin(x) and FindAdjustedBin(x)
Definition: RHistImpl.hxx:259
@ kValid
The returned bin index is valid.
@ kCanGrow
The coordinate could fit after growing the axis.
int GetNBinsFromAxes(AXISCONFIG... axisArgs)
Get the number of bins in whole hist, including under- and overflow.
Definition: RHistImpl.hxx:310
EBinCoord
Specifies if the wanted result is the bin's lower edge, center or higher edge.
Definition: RHistImpl.hxx:252
@ kBinFrom
Get the lower bin edge.
int GetNOverflowBinsFromAxes(AXISCONFIG... axisArgs)
Get the number of under- and overflow bins in whole hist, excluding regular bins.
Definition: RHistImpl.hxx:318
int GetNBinsNoOverFromAxes(AXISCONFIG... axisArgs)
Get the number of bins in whole hist, excluding under- and overflow.
Definition: RHistImpl.hxx:286
static std::array< const RAxisBase *, sizeof...(AXISCONFIG)> GetAxisView(const AXISCONFIG &... axes) noexcept
Definition: RHistImpl.hxx:710
RLogChannel & HistLog()
Log channel for Hist diagnostics.
Definition: RAxis.cxx:25
tbb::task_arena is an alias of tbb::interface7::task_arena, which doesn't allow to forward declare tb...
int operator()(int globalVirtualBin, const AXES &, const BINS &, int, BINTYPE) const
Definition: RHistImpl.hxx:579
Recursively computes a zero-based global bin index, given...
Definition: RHistImpl.hxx:586
int operator()(int globalVirtualBin, const AXES &axes, const BINS &zeroBasedLocalBins, int binSize, BINTYPE GetNBinType) const
Definition: RHistImpl.hxx:587
int operator()(int total_regular_bins_before, const AXES &, const BINS &, const BINS &, const BINS &) const
Definition: RHistImpl.hxx:389
Recursively gets the total number of regular bins before the current dimension, when computing a glob...
Definition: RHistImpl.hxx:396
int operator()(int total_regular_bins_before, const AXES &axes, const BINS &virtualBins, const BINS &binSizes, const BINS &localBins) const
Definition: RHistImpl.hxx:397
void operator()(std::array< int, NDIMS-1 >, std::array< int, NDIMS-1 >, const AXES &) const
Definition: RHistImpl.hxx:426
Recursively compute some quantities needed for ComputeLocalBins, namely the total number of bins per ...
Definition: RHistImpl.hxx:431
void operator()(std::array< int, NDIMS-1 > &bins_per_hyperplane, std::array< int, NDIMS-1 > &regular_bins_per_hyperplane, const AXES &axes) const
Definition: RHistImpl.hxx:432
Recursively computes zero-based local bin indices, given...
Definition: RHistImpl.hxx:559
void operator()(BINS &virtualBins, const AXES &axes, int zeroBasedGlobalBin, BINTYPE GetNBinType) const
Definition: RHistImpl.hxx:560
void operator()(const AXES &, int &, int &, std::array< int, NDIMS-1 >, std::array< int, NDIMS-1 >, int, int) const
Definition: RHistImpl.hxx:455
Recursively computes the number of regular bins before the current dimension, as well as the number o...
Definition: RHistImpl.hxx:463
void operator()(const AXES &axes, int &unprocessed_previous_overflow_bin, int &num_regular_bins_before, std::array< int, NDIMS-1 > bins_per_hyperplane, std::array< int, NDIMS-1 > regular_bins_per_hyperplane, int curr_bins_per_hyperplane, int curr_regular_bins_per_hyperplane) const
Definition: RHistImpl.hxx:464
void operator()(Hist::AxisIterRange_t< std::tuple_size< AXES >::value > &, const AXES &) const
Definition: RHistImpl.hxx:332
Recursively fills the ranges of all axes, excluding under- and overflow.
Definition: RHistImpl.hxx:337
void operator()(Hist::AxisIterRange_t< std::tuple_size< AXES >::value > &range, const AXES &axes) const
Definition: RHistImpl.hxx:338
void operator()(BINS &, const AXES &, const COORD &) const
Definition: RHistImpl.hxx:669
Find the per-axis local bin indices associated with a certain set of coordinates.
Definition: RHistImpl.hxx:674
void operator()(BINS &localBins, const AXES &axes, const COORD &coords) const
Definition: RHistImpl.hxx:675
Recursively gets the total number of bins in whole hist, including under- and overflow.
Definition: RHistImpl.hxx:304
int operator()(const AXES &axes) const
Definition: RHistImpl.hxx:305
Recursively gets the total number of bins in whole hist, excluding under- and overflow.
Definition: RHistImpl.hxx:280
Recursively gets the number of regular bins just before the current dimension.
Definition: RHistImpl.hxx:359
void operator()(BINS &binSizes, const AXES &axes) const
Definition: RHistImpl.hxx:360
void operator()(COORD &, const AXES &, const BINS &, EBinCoord) const
Definition: RHistImpl.hxx:690
Recursively converts local axis bins from the standard kUnderflowBin/kOverflowBin for under/overflow ...
Definition: RHistImpl.hxx:695
void operator()(COORD &coords, const AXES &axes, const BINS &localBins, EBinCoord kind) const
Definition: RHistImpl.hxx:696
Recursively converts local axis bins from the standard kUnderflowBin/kOverflowBin for under/overflow ...
Definition: RHistImpl.hxx:647
void operator()(BINS &virtualBins, const AXES &axes, const BINS &localBins) const
Definition: RHistImpl.hxx:648
Recursively converts zero-based virtual bins where the underflow bin has index 0 and the overflow bin...
Definition: RHistImpl.hxx:613
void operator()(BINS &localBins, const AXES &axes, const BINS &virtualBins) const
Definition: RHistImpl.hxx:614
auto * a
Definition: textangle.C:12