File indexing completed on 2026-08-16 09:21:18
0001
0002
0003
0004
0005 #ifndef ROOT_RHistAutoAxisFiller
0006 #define ROOT_RHistAutoAxisFiller
0007
0008 #include "RHist.hxx"
0009 #include "RHistEngine.hxx"
0010 #include "RWeight.hxx"
0011
0012 #include <algorithm>
0013 #include <cassert>
0014 #include <cmath>
0015 #include <cstddef>
0016 #include <cstdint>
0017 #include <limits>
0018 #include <optional>
0019 #include <stdexcept>
0020 #include <type_traits> // for std::conditional_t
0021 #include <utility>
0022 #include <vector>
0023
0024 namespace ROOT {
0025 namespace Experimental {
0026
0027
0028
0029
0030
0031
0032
0033
0034
0035
0036
0037
0038
0039
0040
0041
0042
0043
0044
0045
0046
0047
0048
0049 template <typename BinContentType>
0050 class RHistAutoAxisFiller final {
0051 public:
0052 static constexpr bool SupportsWeightedFilling = RHistEngine<BinContentType>::SupportsWeightedFilling;
0053
0054 private:
0055
0056 std::optional<RHist<BinContentType>> fHist;
0057
0058
0059 std::uint64_t fNNormalBins;
0060
0061 std::size_t fMaxBufferSize;
0062
0063 double fMarginFraction;
0064
0065 using BufferElement = std::conditional_t<SupportsWeightedFilling, std::pair<double, RWeight>, double>;
0066
0067
0068 std::vector<BufferElement> fBuffer;
0069
0070 double fMinimum = std::numeric_limits<double>::infinity();
0071
0072 double fMaximum = -std::numeric_limits<double>::infinity();
0073
0074 public:
0075
0076
0077
0078
0079
0080 explicit RHistAutoAxisFiller(std::uint64_t nNormalBins, std::size_t maxBufferSize = 1024,
0081 double marginFraction = 0.05)
0082 : fNNormalBins(nNormalBins), fMaxBufferSize(maxBufferSize), fMarginFraction(marginFraction)
0083 {
0084 if (nNormalBins == 0) {
0085 throw std::invalid_argument("nNormalBins must be > 0");
0086 }
0087 if (maxBufferSize == 0) {
0088 throw std::invalid_argument("maxBufferSize must be > 0");
0089 }
0090 if (marginFraction <= 0) {
0091 throw std::invalid_argument("marginFraction must be > 0");
0092 }
0093 }
0094
0095 std::uint64_t GetNNormalBins() const { return fNNormalBins; }
0096 std::size_t GetMaxBufferSize() const { return fMaxBufferSize; }
0097 double GetMarginFraction() const { return fMarginFraction; }
0098
0099 private:
0100 void BufferImpl(double x, RWeight weight)
0101 {
0102 if constexpr (SupportsWeightedFilling) {
0103 fBuffer.emplace_back(x, weight);
0104 } else {
0105 assert(weight.fValue == 1.0);
0106
0107 (void)weight;
0108 fBuffer.push_back(x);
0109 }
0110 fMinimum = std::min(fMinimum, x);
0111 fMaximum = std::max(fMaximum, x);
0112
0113 if (fBuffer.size() >= fMaxBufferSize) {
0114 Flush();
0115 }
0116 }
0117
0118 public:
0119
0120
0121
0122
0123
0124 void Fill(double x)
0125 {
0126
0127 if (fHist) {
0128 fHist->Fill(x);
0129 return;
0130 }
0131 BufferImpl(x, RWeight(1.0));
0132 }
0133
0134
0135
0136
0137
0138
0139
0140
0141
0142
0143 void Fill(double x, RWeight weight)
0144 {
0145
0146 if (fHist) {
0147 fHist->Fill(x, weight);
0148 return;
0149 }
0150 BufferImpl(x, weight);
0151 }
0152
0153
0154
0155
0156
0157 void Flush()
0158 {
0159 if (fHist) {
0160 assert(fBuffer.empty() && "buffer should have been emptied");
0161 return;
0162 }
0163
0164 if (fBuffer.empty()) {
0165 throw std::runtime_error("buffer is empty, cannot create histogram");
0166 }
0167 if (!std::isfinite(fMinimum) || !std::isfinite(fMaximum)) {
0168 throw std::runtime_error("could not determine axis interval");
0169 }
0170 if (fMinimum == fMaximum) {
0171 throw std::runtime_error("axis interval is empty");
0172 }
0173
0174
0175
0176 const auto margin = fMarginFraction * (fMaximum - fMinimum);
0177 const auto high = fMaximum + margin;
0178 const auto low = fMinimum - margin;
0179 assert(high > low);
0180 fHist.emplace(fNNormalBins, std::make_pair(low, high));
0181
0182 for (auto &&x : fBuffer) {
0183 if constexpr (SupportsWeightedFilling) {
0184 fHist->Fill(x.first, x.second);
0185 } else {
0186 fHist->Fill(x);
0187 }
0188 }
0189 fBuffer.clear();
0190 }
0191
0192
0193
0194
0195 RHist<BinContentType> &GetHist()
0196 {
0197 Flush();
0198 assert(fHist.has_value());
0199 return *fHist;
0200 }
0201 };
0202
0203 }
0204 }
0205
0206 #endif