Back to home page

EIC code displayed by LXR

 
 

    


File indexing completed on 2025-01-18 10:10:44

0001 /// \file ROOT/RHistData.hxx
0002 /// \ingroup HistV7
0003 /// \author Axel Naumann <axel@cern.ch>
0004 /// \date 2015-06-14
0005 /// \warning This is part of the ROOT 7 prototype! It will change without notice. It might trigger earthquakes. Feedback
0006 /// is welcome!
0007 
0008 /*************************************************************************
0009  * Copyright (C) 1995-2015, Rene Brun and Fons Rademakers.               *
0010  * All rights reserved.                                                  *
0011  *                                                                       *
0012  * For the licensing terms see $ROOTSYS/LICENSE.                         *
0013  * For the list of contributors see $ROOTSYS/README/CREDITS.             *
0014  *************************************************************************/
0015 
0016 #ifndef ROOT7_RHistData
0017 #define ROOT7_RHistData
0018 
0019 #include <cmath>
0020 #include <vector>
0021 #include "ROOT/RSpan.hxx"
0022 #include "ROOT/RHistUtils.hxx"
0023 
0024 namespace ROOT {
0025 namespace Experimental {
0026 
0027 template <int DIMENSIONS, class PRECISION, template <int D_, class P_> class... STAT>
0028 class RHist;
0029 
0030 /**
0031  \class RHistStatContent
0032  Basic histogram statistics, keeping track of the bin content and the total
0033  number of calls to Fill().
0034  */
0035 template <int DIMENSIONS, class PRECISION>
0036 class RHistStatContent {
0037 public:
0038    /// The type of a (possibly multi-dimensional) coordinate.
0039    using CoordArray_t = Hist::CoordArray_t<DIMENSIONS>;
0040    /// The type of the weight and the bin content.
0041    using Weight_t = PRECISION;
0042    /// Type of the bin content array.
0043    using Content_t = std::vector<PRECISION>;
0044 
0045    /**
0046     \class RConstBinStat
0047     Const view on a RHistStatContent for a given bin.
0048    */
0049    class RConstBinStat {
0050    public:
0051       RConstBinStat(const RHistStatContent &stat, int index): fContent(stat.GetBinContent(index)) {}
0052       PRECISION GetContent() const { return fContent; }
0053 
0054    private:
0055       PRECISION fContent; ///< The content of this bin.
0056    };
0057 
0058    /**
0059     \class RBinStat
0060     Modifying view on a RHistStatContent for a given bin.
0061    */
0062    class RBinStat {
0063    public:
0064       RBinStat(RHistStatContent &stat, int index): fContent(stat.GetBinContent(index)) {}
0065       PRECISION &GetContent() const { return fContent; }
0066 
0067    private:
0068       PRECISION &fContent; ///< The content of this bin.
0069    };
0070 
0071    using ConstBinStat_t = RConstBinStat;
0072    using BinStat_t = RBinStat;
0073 
0074 private:
0075    /// Number of calls to Fill().
0076    int64_t fEntries = 0;
0077 
0078    /// Bin content.
0079    Content_t fBinContent;
0080 
0081    /// Under- and overflow bin content.
0082    Content_t fOverflowBinContent;
0083 
0084 public:
0085    RHistStatContent() = default;
0086    RHistStatContent(size_t bin_size, size_t overflow_size): fBinContent(bin_size), fOverflowBinContent(overflow_size) {}
0087 
0088    /// Get a reference to the bin corresponding to `binidx` of the correct bin
0089    /// content array
0090    /// i.e. depending if `binidx` is a regular bin or an under- / overflow bin.
0091    Weight_t GetBinArray(int binidx) const
0092    {
0093       if (binidx < 0){
0094          return fOverflowBinContent[-binidx - 1];
0095       } else {
0096          return fBinContent[binidx - 1];
0097       }
0098    }
0099 
0100    /// Get a reference to the bin corresponding to `binidx` of the correct bin
0101    /// content array (non-const)
0102    /// i.e. depending if `binidx` is a regular bin or an under- / overflow bin.
0103    Weight_t& GetBinArray(int binidx)
0104    {
0105       if (binidx < 0){
0106          return fOverflowBinContent[-binidx - 1];
0107       } else {
0108          return fBinContent[binidx - 1];
0109       }
0110    }
0111 
0112    /// Add weight to the bin content at `binidx`.
0113    void Fill(const CoordArray_t & /*x*/, int binidx, Weight_t weight = 1.)
0114    {
0115       GetBinArray(binidx) += weight;
0116       ++fEntries;
0117    }
0118 
0119    /// Get the number of entries filled into the histogram - i.e. the number of
0120    /// calls to Fill().
0121    int64_t GetEntries() const { return fEntries; }
0122 
0123    /// Get the number of bins exluding under- and overflow.
0124    size_t sizeNoOver() const noexcept { return fBinContent.size(); }
0125 
0126    /// Get the number of bins including under- and overflow..
0127    size_t size() const noexcept { return fBinContent.size() + fOverflowBinContent.size(); }
0128 
0129    /// Get the number of bins including under- and overflow..
0130    size_t sizeUnderOver() const noexcept { return fOverflowBinContent.size(); }
0131 
0132    /// Get the bin content for the given bin.
0133    Weight_t operator[](int binidx) const { return GetBinArray(binidx); }
0134    /// Get the bin content for the given bin (non-const).
0135    Weight_t &operator[](int binidx) { return GetBinArray(binidx); }
0136 
0137    /// Get the bin content for the given bin.
0138    Weight_t GetBinContent(int binidx) const { return GetBinArray(binidx); }
0139    /// Get the bin content for the given bin (non-const).
0140    Weight_t &GetBinContent(int binidx) { return GetBinArray(binidx); }
0141 
0142    /// Retrieve the content array.
0143    const Content_t &GetContentArray() const { return fBinContent; }
0144    /// Retrieve the content array (non-const).
0145    Content_t &GetContentArray() { return fBinContent; }
0146 
0147    /// Retrieve the under-/overflow content array.
0148    const Content_t &GetOverflowContentArray() const { return fOverflowBinContent; }
0149    /// Retrieve the under-/overflow content array (non-const).
0150    Content_t &GetOverflowContentArray() { return fOverflowBinContent; }
0151 
0152    /// Merge with other RHistStatContent, assuming same bin configuration.
0153    void Add(const RHistStatContent& other) {
0154       assert(fBinContent.size() == other.fBinContent.size()
0155                && "this and other have incompatible bin configuration!");
0156       assert(fOverflowBinContent.size() == other.fOverflowBinContent.size()
0157                && "this and other have incompatible bin configuration!");
0158       fEntries += other.fEntries;
0159       for (size_t b = 0; b < fBinContent.size(); ++b)
0160          fBinContent[b] += other.fBinContent[b];
0161       for (size_t b = 0; b < fOverflowBinContent.size(); ++b)
0162          fOverflowBinContent[b] += other.fOverflowBinContent[b];
0163    }
0164 };
0165 
0166 /**
0167  \class RHistStatTotalSumOfWeights
0168  Keeps track of the histogram's total sum of weights.
0169  */
0170 template <int DIMENSIONS, class PRECISION>
0171 class RHistStatTotalSumOfWeights {
0172 public:
0173    /// The type of a (possibly multi-dimensional) coordinate.
0174    using CoordArray_t = Hist::CoordArray_t<DIMENSIONS>;
0175    /// The type of the weight and the bin content.
0176    using Weight_t = PRECISION;
0177 
0178    /**
0179     \class RBinStat
0180     No-op; this class does not provide per-bin statistics.
0181    */
0182    class RBinStat {
0183    public:
0184       RBinStat(const RHistStatTotalSumOfWeights &, int) {}
0185    };
0186 
0187    using ConstBinStat_t = RBinStat;
0188    using BinStat_t = RBinStat;
0189 
0190 private:
0191    /// Sum of weights.
0192    PRECISION fSumWeights = 0;
0193 
0194 public:
0195    RHistStatTotalSumOfWeights() = default;
0196    RHistStatTotalSumOfWeights(size_t, size_t) {}
0197 
0198    /// Add weight to the bin content at binidx.
0199    void Fill(const CoordArray_t & /*x*/, int, Weight_t weight = 1.) { fSumWeights += weight; }
0200 
0201    /// Get the sum of weights.
0202    Weight_t GetSumOfWeights() const { return fSumWeights; }
0203 
0204    /// Merge with other RHistStatTotalSumOfWeights data, assuming same bin configuration.
0205    void Add(const RHistStatTotalSumOfWeights& other) {
0206       fSumWeights += other.fSumWeights;
0207    }
0208 };
0209 
0210 /**
0211  \class RHistStatTotalSumOfSquaredWeights
0212  Keeps track of the histogram's total sum of squared weights.
0213  */
0214 template <int DIMENSIONS, class PRECISION>
0215 class RHistStatTotalSumOfSquaredWeights {
0216 public:
0217    /// The type of a (possibly multi-dimensional) coordinate.
0218    using CoordArray_t = Hist::CoordArray_t<DIMENSIONS>;
0219    /// The type of the weight and the bin content.
0220    using Weight_t = PRECISION;
0221 
0222    /**
0223     \class RBinStat
0224     No-op; this class does not provide per-bin statistics.
0225    */
0226    class RBinStat {
0227    public:
0228       RBinStat(const RHistStatTotalSumOfSquaredWeights &, int) {}
0229    };
0230 
0231    using ConstBinStat_t = RBinStat;
0232    using BinStat_t = RBinStat;
0233 
0234 private:
0235    /// Sum of (weights^2).
0236    PRECISION fSumWeights2 = 0;
0237 
0238 public:
0239    RHistStatTotalSumOfSquaredWeights() = default;
0240    RHistStatTotalSumOfSquaredWeights(size_t, size_t) {}
0241 
0242    /// Add weight to the bin content at binidx.
0243    void Fill(const CoordArray_t & /*x*/, int /*binidx*/, Weight_t weight = 1.) { fSumWeights2 += weight * weight; }
0244 
0245    /// Get the sum of weights.
0246    Weight_t GetSumOfSquaredWeights() const { return fSumWeights2; }
0247 
0248    /// Merge with other RHistStatTotalSumOfSquaredWeights data, assuming same bin configuration.
0249    void Add(const RHistStatTotalSumOfSquaredWeights& other) {
0250       fSumWeights2 += other.fSumWeights2;
0251    }
0252 };
0253 
0254 /**
0255  \class RHistStatUncertainty
0256  Histogram statistics to keep track of the Poisson uncertainty per bin.
0257  */
0258 template <int DIMENSIONS, class PRECISION>
0259 class RHistStatUncertainty {
0260 
0261 public:
0262    /// The type of a (possibly multi-dimensional) coordinate.
0263    using CoordArray_t = Hist::CoordArray_t<DIMENSIONS>;
0264    /// The type of the weight and the bin content.
0265    using Weight_t = PRECISION;
0266    /// Type of the bin content array.
0267    using Content_t = std::vector<PRECISION>;
0268 
0269    /**
0270     \class RConstBinStat
0271     Const view on a `RHistStatUncertainty` for a given bin.
0272    */
0273    class RConstBinStat {
0274    public:
0275       RConstBinStat(const RHistStatUncertainty &stat, int index): fSumW2(stat.GetSumOfSquaredWeights(index)) {}
0276       PRECISION GetSumW2() const { return fSumW2; }
0277 
0278       double GetUncertaintyImpl() const { return std::sqrt(std::abs(fSumW2)); }
0279 
0280    private:
0281       PRECISION fSumW2; ///< The bin's sum of square of weights.
0282    };
0283 
0284    /**
0285     \class RBinStat
0286     Modifying view on a `RHistStatUncertainty` for a given bin.
0287    */
0288    class RBinStat {
0289    public:
0290       RBinStat(RHistStatUncertainty &stat, int index): fSumW2(stat.GetSumOfSquaredWeights(index)) {}
0291       PRECISION &GetSumW2() const { return fSumW2; }
0292       // Can never modify this. Set GetSumW2() instead.
0293       double GetUncertaintyImpl() const { return std::sqrt(std::abs(fSumW2)); }
0294 
0295    private:
0296       PRECISION &fSumW2; ///< The bin's sum of square of weights.
0297    };
0298 
0299    using ConstBinStat_t = RConstBinStat;
0300    using BinStat_t = RBinStat;
0301 
0302 private:
0303    /// Uncertainty of the content for each bin excluding under-/overflow.
0304    Content_t fSumWeightsSquared; ///< Sum of squared weights.
0305    /// Uncertainty of the under-/overflow content.
0306    Content_t fOverflowSumWeightsSquared; ///< Sum of squared weights for under-/overflow.
0307 
0308 public:
0309    RHistStatUncertainty() = default;
0310    RHistStatUncertainty(size_t bin_size, size_t overflow_size): fSumWeightsSquared(bin_size), fOverflowSumWeightsSquared(overflow_size) {}
0311 
0312    /// Get a reference to the bin corresponding to `binidx` of the correct bin
0313    /// content array
0314    /// i.e. depending if `binidx` is a regular bin or an under- / overflow bin.
0315    Weight_t GetBinArray(int binidx) const
0316    {
0317       if (binidx < 0){
0318          return fOverflowSumWeightsSquared[-binidx - 1];
0319       } else {
0320          return fSumWeightsSquared[binidx - 1];
0321       }
0322    }
0323 
0324    /// Get a reference to the bin corresponding to `binidx` of the correct bin
0325    /// content array (non-const)
0326    /// i.e. depending if `binidx` is a regular bin or an under- / overflow bin.
0327    Weight_t& GetBinArray(int binidx)
0328    {
0329       if (binidx < 0){
0330          return fOverflowSumWeightsSquared[-binidx - 1];
0331       } else {
0332          return fSumWeightsSquared[binidx - 1];
0333       }
0334    }
0335 
0336    /// Add weight to the bin at `binidx`; the coordinate was `x`.
0337    void Fill(const CoordArray_t & /*x*/, int binidx, Weight_t weight = 1.)
0338    {
0339       GetBinArray(binidx) += weight * weight;
0340    }
0341 
0342    /// Calculate a bin's (Poisson) uncertainty of the bin content as the
0343    /// square-root of the bin's sum of squared weights.
0344    double GetBinUncertaintyImpl(int binidx) const { return std::sqrt(GetBinArray(binidx)); }
0345 
0346    /// Get a bin's sum of squared weights.
0347    Weight_t GetSumOfSquaredWeights(int binidx) const { return GetBinArray(binidx); }
0348    /// Get a bin's sum of squared weights.
0349    Weight_t &GetSumOfSquaredWeights(int binidx) { return GetBinArray(binidx); }
0350 
0351    /// Get the structure holding the sum of squares of weights.
0352    const std::vector<double> &GetSumOfSquaredWeights() const { return fSumWeightsSquared; }
0353    /// Get the structure holding the sum of squares of weights (non-const).
0354    std::vector<double> &GetSumOfSquaredWeights() { return fSumWeightsSquared; }
0355 
0356    /// Get the structure holding the under-/overflow sum of squares of weights.
0357    const std::vector<double> &GetOverflowSumOfSquaredWeights() const { return fOverflowSumWeightsSquared; }
0358    /// Get the structure holding the under-/overflow sum of squares of weights (non-const).
0359    std::vector<double> &GetOverflowSumOfSquaredWeights() { return fOverflowSumWeightsSquared; }
0360 
0361    /// Merge with other `RHistStatUncertainty` data, assuming same bin configuration.
0362    void Add(const RHistStatUncertainty& other) {
0363       assert(fSumWeightsSquared.size() == other.fSumWeightsSquared.size()
0364                && "this and other have incompatible bin configuration!");
0365       assert(fOverflowSumWeightsSquared.size() == other.fOverflowSumWeightsSquared.size()
0366                && "this and other have incompatible bin configuration!");
0367       for (size_t b = 0; b < fSumWeightsSquared.size(); ++b)
0368          fSumWeightsSquared[b] += other.fSumWeightsSquared[b];
0369       for (size_t b = 0; b < fOverflowSumWeightsSquared.size(); ++b)
0370          fOverflowSumWeightsSquared[b] += other.fOverflowSumWeightsSquared[b];
0371    }
0372 };
0373 
0374 /** \class RHistDataMomentUncert
0375   For now do as `RH1`: calculate first (xw) and second (x^2w) moment.
0376 */
0377 template <int DIMENSIONS, class PRECISION>
0378 class RHistDataMomentUncert {
0379 public:
0380    /// The type of a (possibly multi-dimensional) coordinate.
0381    using CoordArray_t = Hist::CoordArray_t<DIMENSIONS>;
0382    /// The type of the weight and the bin content.
0383    using Weight_t = PRECISION;
0384    /// Type of the bin content array.
0385    using Content_t = std::vector<PRECISION>;
0386 
0387    /**
0388     \class RBinStat
0389     No-op; this class does not provide per-bin statistics.
0390    */
0391    class RBinStat {
0392    public:
0393       RBinStat(const RHistDataMomentUncert &, int) {}
0394    };
0395 
0396    using ConstBinStat_t = RBinStat;
0397    using BinStat_t = RBinStat;
0398 
0399 private:
0400    std::array<Weight_t, DIMENSIONS> fMomentXW;
0401    std::array<Weight_t, DIMENSIONS> fMomentX2W;
0402    // FIXME: Add sum(w.x.y)-style stats.
0403 
0404 public:
0405    RHistDataMomentUncert() = default;
0406    RHistDataMomentUncert(size_t, size_t) {}
0407 
0408    /// Add weight to the bin at binidx; the coordinate was x.
0409    void Fill(const CoordArray_t &x, int /*binidx*/, Weight_t weight = 1.)
0410    {
0411       for (int idim = 0; idim < DIMENSIONS; ++idim) {
0412          const PRECISION xw = x[idim] * weight;
0413          fMomentXW[idim] += xw;
0414          fMomentX2W[idim] += x[idim] * xw;
0415       }
0416    }
0417 
0418    // FIXME: Add a way to query the inner data
0419 
0420    /// Merge with other RHistDataMomentUncert data, assuming same bin configuration.
0421    void Add(const RHistDataMomentUncert& other) {
0422       for (size_t d = 0; d < DIMENSIONS; ++d) {
0423          fMomentXW[d] += other.fMomentXW[d];
0424          fMomentX2W[d] += other.fMomentX2W[d];
0425       }
0426    }
0427 };
0428 
0429 /** \class RHistStatRuntime
0430   Interface implementing a pure virtual functions `DoFill()`, `DoFillN()`.
0431   */
0432 template <int DIMENSIONS, class PRECISION>
0433 class RHistStatRuntime {
0434 public:
0435    /// The type of a (possibly multi-dimensional) coordinate.
0436    using CoordArray_t = Hist::CoordArray_t<DIMENSIONS>;
0437    /// The type of the weight and the bin content.
0438    using Weight_t = PRECISION;
0439    /// Type of the bin content array.
0440    using Content_t = std::vector<PRECISION>;
0441 
0442    /**
0443     \class RBinStat
0444     No-op; this class does not provide per-bin statistics.
0445    */
0446    class RBinStat {
0447    public:
0448       RBinStat(const RHistStatRuntime &, int) {}
0449    };
0450 
0451    using ConstBinStat_t = RBinStat;
0452    using BinStat_t = RBinStat;
0453 
0454    RHistStatRuntime() = default;
0455    RHistStatRuntime(size_t, size_t) {}
0456    virtual ~RHistStatRuntime() = default;
0457 
0458    virtual void DoFill(const CoordArray_t &x, int binidx, Weight_t weightN) = 0;
0459    void Fill(const CoordArray_t &x, int binidx, Weight_t weight = 1.) { DoFill(x, binidx, weight); }
0460 };
0461 
0462 namespace Detail {
0463 
0464 /** \class RHistBinStat
0465   Const view on a bin's statistical data. Combines all STATs' BinStat_t views.
0466   */
0467 template <class DATA, class... BASES>
0468 class RHistBinStat: public BASES... {
0469 private:
0470    /// Check whether `double T::GetBinUncertaintyImpl(int)` can be called.
0471    template <class T>
0472    static auto HaveUncertainty(const T *This) -> decltype(This->GetUncertaintyImpl());
0473    /// Fall-back case for check whether `double T::GetBinUncertaintyImpl(int)` can be called.
0474    template <class T>
0475    static char HaveUncertainty(...);
0476 
0477 public:
0478    RHistBinStat(DATA &data, int index): BASES(data, index)... {}
0479 
0480    /// Whether this provides storage for uncertainties, or whether uncertainties
0481    /// are determined as poisson uncertainty of the content.
0482    static constexpr bool HasBinUncertainty()
0483    {
0484       struct AllYourBaseAreBelongToUs: public BASES... {
0485       };
0486       return sizeof(HaveUncertainty<AllYourBaseAreBelongToUs>(nullptr)) == sizeof(double);
0487    }
0488    /// Calculate the bin content's uncertainty for the given bin, using base class information,
0489    /// i.e. forwarding to a base's `GetUncertaintyImpl()`.
0490    template <bool B = true, class = typename std::enable_if<B && HasBinUncertainty()>::type>
0491    double GetUncertainty() const
0492    {
0493       return this->GetUncertaintyImpl();
0494    }
0495    /// Calculate the bin content's uncertainty for the given bin, using Poisson
0496    /// statistics on the absolute bin content. Only available if no base provides
0497    /// this functionality. Requires `GetContent()`.
0498    template <bool B = true, class = typename std::enable_if<B && !HasBinUncertainty()>::type>
0499    double GetUncertainty(...) const
0500    {
0501       auto content = this->GetContent();
0502       return std::sqrt(std::fabs(content));
0503    }
0504 };
0505 
0506 /** \class RHistData
0507   A `RHistImplBase`'s data, provides accessors to all its statistics.
0508   */
0509 template <int DIMENSIONS, class PRECISION, class STORAGE, template <int D_, class P_> class... STAT>
0510 class RHistData: public STAT<DIMENSIONS, PRECISION>... {
0511 private:
0512    /// Check whether `double T::GetBinUncertaintyImpl(int)` can be called.
0513    template <class T>
0514    static auto HaveUncertainty(const T *This) -> decltype(This->GetBinUncertaintyImpl(12));
0515    /// Fall-back case for check whether `double T::GetBinUncertaintyImpl(int)` can be called.
0516    template <class T>
0517    static char HaveUncertainty(...);
0518 
0519 public:
0520    /// Matching `RHist`.
0521    using Hist_t = RHist<DIMENSIONS, PRECISION, STAT...>;
0522 
0523    /// The type of the weight and the bin content.
0524    using Weight_t = PRECISION;
0525 
0526    /// The type of a (possibly multi-dimensional) coordinate.
0527    using CoordArray_t = Hist::CoordArray_t<DIMENSIONS>;
0528 
0529    /// The type of a non-modifying view on a bin.
0530    using ConstHistBinStat_t =
0531       RHistBinStat<const RHistData, typename STAT<DIMENSIONS, PRECISION>::ConstBinStat_t...>;
0532 
0533    /// The type of a modifying view on a bin.
0534    using HistBinStat_t = RHistBinStat<RHistData, typename STAT<DIMENSIONS, PRECISION>::BinStat_t...>;
0535 
0536    /// Number of dimensions of the coordinates.
0537    static constexpr int GetNDim() noexcept { return DIMENSIONS; }
0538 
0539    RHistData() = default;
0540 
0541    /// Constructor providing the number of bins (incl under, overflow) to the
0542    /// base classes.
0543    RHistData(size_t bin_size, size_t overflow_size): STAT<DIMENSIONS, PRECISION>(bin_size, overflow_size)... {}
0544 
0545    /// Fill weight at x to the bin content at binidx.
0546    void Fill(const CoordArray_t &x, int binidx, Weight_t weight = 1.)
0547    {
0548       // Call `Fill()` on all base classes.
0549       // This combines a couple of C++ spells:
0550       // - "STAT": is a template parameter pack of template template arguments. It
0551       //           has multiple (or one or no) elements; each is a template name
0552       //           that needs to be instantiated before it can be used.
0553       // - "...":  template parameter pack expansion; the expression is evaluated
0554       //           for each `STAT`. The expression is
0555       //           `(STAT<DIMENSIONS, PRECISION>::Fill(x, binidx, weight), 0)`.
0556       // - "trigger_base_fill{}":
0557       //           initialization, provides a context in which template parameter
0558       //           pack expansion happens.
0559       // - ", 0":  because `Fill()` returns void it cannot be used as initializer
0560       //           expression. The trailing ", 0" gives it the type of the trailing
0561       //           comma-separated expression - int.
0562       using trigger_base_fill = int[];
0563       (void)trigger_base_fill{(STAT<DIMENSIONS, PRECISION>::Fill(x, binidx, weight), 0)...};
0564    }
0565 
0566    /// Integrate other statistical data into the current data.
0567    ///
0568    /// The implementation assumes that the other statistics were recorded with
0569    /// the same binning configuration, and that the statistics of `OtherData`
0570    /// are a superset of those recorded by the active `RHistData` instance.
0571    template <typename OtherData>
0572    void Add(const OtherData &other)
0573    {
0574       // Call `Add()` on all base classes, using the same tricks as `Fill()`.
0575       using trigger_base_add = int[];
0576       (void)trigger_base_add{(STAT<DIMENSIONS, PRECISION>::Add(other), 0)...};
0577    }
0578 
0579    /// Whether this provides storage for uncertainties, or whether uncertainties
0580    /// are determined as poisson uncertainty of the content.
0581    static constexpr bool HasBinUncertainty()
0582    {
0583       struct AllYourBaseAreBelongToUs: public STAT<DIMENSIONS, PRECISION>... {
0584       };
0585       return sizeof(HaveUncertainty<AllYourBaseAreBelongToUs>(nullptr)) == sizeof(double);
0586    }
0587 
0588    /// Calculate the bin content's uncertainty for the given bin, using base class information,
0589    /// i.e. forwarding to a base's `GetBinUncertaintyImpl(binidx)`.
0590    template <bool B = true, class = typename std::enable_if<B && HasBinUncertainty()>::type>
0591    double GetBinUncertainty(int binidx) const
0592    {
0593       return this->GetBinUncertaintyImpl(binidx);
0594    }
0595    /// Calculate the bin content's uncertainty for the given bin, using Poisson
0596    /// statistics on the absolute bin content. Only available if no base provides
0597    /// this functionality. Requires `GetContent()`.
0598    template <bool B = true, class = typename std::enable_if<B && !HasBinUncertainty()>::type>
0599    double GetBinUncertainty(int binidx, ...) const
0600    {
0601       auto content = this->GetBinContent(binidx);
0602       return std::sqrt(std::fabs(content));
0603    }
0604 
0605    /// Get a view on the statistics values of a bin.
0606    ConstHistBinStat_t GetView(int idx) const { return ConstHistBinStat_t(*this, idx); }
0607    /// Get a (non-const) view on the statistics values of a bin.
0608    HistBinStat_t GetView(int idx) { return HistBinStat_t(*this, idx); }
0609 };
0610 } // namespace Detail
0611 
0612 } // namespace Experimental
0613 } // namespace ROOT
0614 
0615 #endif