Back to home page

EIC code displayed by LXR

 
 

    


File indexing completed on 2025-12-14 10:31:20

0001 /// \file
0002 /// \warning This is part of the %ROOT 7 prototype! It will change without notice. It might trigger earthquakes.
0003 /// Feedback is welcome!
0004 
0005 #ifndef ROOT_RRegularAxis
0006 #define ROOT_RRegularAxis
0007 
0008 #include "RBinIndex.hxx"
0009 #include "RBinIndexRange.hxx"
0010 #include "RLinearizedIndex.hxx"
0011 
0012 #include <cassert>
0013 #include <cstddef>
0014 #include <stdexcept>
0015 #include <string>
0016 #include <utility>
0017 
0018 class TBuffer;
0019 
0020 namespace ROOT {
0021 namespace Experimental {
0022 
0023 /**
0024 A regular axis with equidistant bins in the interval \f$[fLow, fHigh)\f$.
0025 
0026 For example, the following creates a regular axis with 10 normal bins between 5 and 15:
0027 \code
0028 ROOT::Experimental::RRegularAxis axis(10, 5, 15);
0029 \endcode
0030 
0031 It is possible to disable underflow and overflow bins by passing `enableFlowBins = false`. In that case, arguments
0032 outside the axis will be silently discarded.
0033 
0034 \warning This is part of the %ROOT 7 prototype! It will change without notice. It might trigger earthquakes.
0035 Feedback is welcome!
0036 */
0037 class RRegularAxis final {
0038 public:
0039    using ArgumentType = double;
0040 
0041 private:
0042    /// The number of normal bins
0043    std::size_t fNNormalBins;
0044    /// The lower end of the axis interval
0045    double fLow;
0046    /// The upper end of the axis interval
0047    double fHigh;
0048    /// The cached inverse of the bin width to speed up ComputeLinearizedIndex
0049    double fInvBinWidth; //!
0050    /// Whether underflow and overflow bins are enabled
0051    bool fEnableFlowBins;
0052 
0053 public:
0054    /// Construct a regular axis object.
0055    ///
0056    /// \param[in] nNormalBins the number of normal bins, must be > 0
0057    /// \param[in] interval the axis interval (lower end inclusive, upper end exclusive)
0058    /// \param[in] enableFlowBins whether to enable underflow and overflow bins
0059    RRegularAxis(std::size_t nNormalBins, std::pair<double, double> interval, bool enableFlowBins = true)
0060       : fNNormalBins(nNormalBins), fLow(interval.first), fHigh(interval.second), fEnableFlowBins(enableFlowBins)
0061    {
0062       if (nNormalBins == 0) {
0063          throw std::invalid_argument("nNormalBins must be > 0");
0064       }
0065       if (fLow >= fHigh) {
0066          std::string msg = "high must be > low, but " + std::to_string(fLow) + " >= " + std::to_string(fHigh);
0067          throw std::invalid_argument(msg);
0068       }
0069       fInvBinWidth = nNormalBins / (fHigh - fLow);
0070    }
0071 
0072    std::size_t GetNNormalBins() const { return fNNormalBins; }
0073    std::size_t GetTotalNBins() const { return fEnableFlowBins ? fNNormalBins + 2 : fNNormalBins; }
0074    double GetLow() const { return fLow; }
0075    double GetHigh() const { return fHigh; }
0076    bool HasFlowBins() const { return fEnableFlowBins; }
0077 
0078    friend bool operator==(const RRegularAxis &lhs, const RRegularAxis &rhs)
0079    {
0080       return lhs.fNNormalBins == rhs.fNNormalBins && lhs.fLow == rhs.fLow && lhs.fHigh == rhs.fHigh &&
0081              lhs.fEnableFlowBins == rhs.fEnableFlowBins;
0082    }
0083 
0084    /// Compute the linarized index for a single argument.
0085    ///
0086    /// The normal bins have indices \f$0\f$ to \f$fNNormalBins - 1\f$, the underflow bin has index
0087    /// \f$fNNormalBins\f$, and the overflow bin has index \f$fNNormalBins + 1\f$. If the argument is outside the
0088    /// interval \f$[fLow, fHigh)\f$ and the flow bins are disabled, the return value is invalid.
0089    ///
0090    /// \param[in] x the argument
0091    /// \return the linearized index that may be invalid
0092    RLinearizedIndex ComputeLinearizedIndex(double x) const
0093    {
0094       bool underflow = x < fLow;
0095       // Put NaNs into overflow bin.
0096       bool overflow = !(x < fHigh);
0097       if (underflow) {
0098          return {fNNormalBins, fEnableFlowBins};
0099       } else if (overflow) {
0100          return {fNNormalBins + 1, fEnableFlowBins};
0101       }
0102 
0103       std::size_t bin = (x - fLow) * fInvBinWidth;
0104       return {bin, true};
0105    }
0106 
0107    /// Get the linearized index for an RBinIndex.
0108    ///
0109    /// The normal bins have indices \f$0\f$ to \f$fNNormalBins - 1\f$, the underflow bin has index
0110    /// \f$fNNormalBins\f$, and the overflow bin has index \f$fNNormalBins + 1\f$.
0111    ///
0112    /// \param[in] index the RBinIndex
0113    /// \return the linearized index that may be invalid
0114    RLinearizedIndex GetLinearizedIndex(RBinIndex index) const
0115    {
0116       if (index.IsUnderflow()) {
0117          return {fNNormalBins, fEnableFlowBins};
0118       } else if (index.IsOverflow()) {
0119          return {fNNormalBins + 1, fEnableFlowBins};
0120       } else if (index.IsInvalid()) {
0121          return {0, false};
0122       }
0123       assert(index.IsNormal());
0124       std::size_t bin = index.GetIndex();
0125       return {bin, bin < fNNormalBins};
0126    }
0127 
0128    /// Get the range of all normal bins.
0129    ///
0130    /// \return the bin index range from the first to the last normal bin, inclusive
0131    RBinIndexRange GetNormalRange() const
0132    {
0133       return Internal::CreateBinIndexRange(RBinIndex(0), RBinIndex(fNNormalBins), 0);
0134    }
0135 
0136    /// Get a range of normal bins.
0137    ///
0138    /// \param[in] begin the begin of the bin index range (inclusive), must be normal
0139    /// \param[in] end the end of the bin index range (exclusive), must be normal and >= begin
0140    /// \return a bin index range \f$[begin, end)\f$
0141    RBinIndexRange GetNormalRange(RBinIndex begin, RBinIndex end) const
0142    {
0143       if (!begin.IsNormal()) {
0144          throw std::invalid_argument("begin must be a normal bin");
0145       }
0146       if (begin.GetIndex() >= fNNormalBins) {
0147          throw std::invalid_argument("begin must be inside the axis");
0148       }
0149       if (!end.IsNormal()) {
0150          throw std::invalid_argument("end must be a normal bin");
0151       }
0152       if (end.GetIndex() > fNNormalBins) {
0153          throw std::invalid_argument("end must be inside or past the axis");
0154       }
0155       if (!(end >= begin)) {
0156          throw std::invalid_argument("end must be >= begin");
0157       }
0158       return Internal::CreateBinIndexRange(begin, end, 0);
0159    }
0160 
0161    /// Get the full range of all bins.
0162    ///
0163    /// This includes underflow and overflow bins, if enabled.
0164    ///
0165    /// \return the bin index range of all bins
0166    RBinIndexRange GetFullRange() const
0167    {
0168       return fEnableFlowBins ? Internal::CreateBinIndexRange(RBinIndex::Underflow(), RBinIndex(), fNNormalBins)
0169                              : GetNormalRange();
0170    }
0171 
0172    /// %ROOT Streamer function to throw when trying to store an object of this class.
0173    void Streamer(TBuffer &) { throw std::runtime_error("unable to store RRegularAxis"); }
0174 };
0175 
0176 } // namespace Experimental
0177 } // namespace ROOT
0178 
0179 #endif