Back to home page

EIC code displayed by LXR

 
 

    


File indexing completed on 2025-04-19 09:06:49

0001 // -*- C++ -*-
0002 #ifndef RIVET_PERCENTILEPROJECTION_HH
0003 #define RIVET_PERCENTILEPROJECTION_HH
0004 
0005 #include "Rivet/Projections/SingleValueProjection.hh"
0006 #include "Rivet/Tools/RivetYODA.hh"
0007 #include <map>
0008 
0009 namespace Rivet {
0010 
0011   enum class PercentileOrder { INCREASING, DECREASING };
0012 
0013 
0014   /// @brief class for projections that reports the percentile for a
0015   /// given SingleValueProjection when initialized with a Histo1D of the
0016   /// distribution in the SingleValueProjection.
0017   ///
0018   /// @author Leif Lönnblad
0019   class PercentileProjection : public SingleValueProjection {
0020   public:
0021 
0022     using SingleValueProjection::operator =;
0023 
0024     /// Constructor taking a SingleValueProjection and a calibration
0025     /// histogram. If increasing it means that low values corresponds to
0026     /// lower percentiles.
0027     ///
0028     /// @todo Use mkScatter to pass this to the Scatter2D-calibrated version?
0029     PercentileProjection(const SingleValueProjection & sv, const Histo1D& calhist,
0030                          PercentileOrder pctorder=PercentileOrder::DECREASING)
0031       : _calhist("EMPTY"),
0032     _increasing(pctorder == PercentileOrder::INCREASING)
0033     {
0034       setName("PercentileProjection");
0035       declare(sv, "OBSERVABLE");
0036       //if ( !calhist ) return;
0037       MSG_DEBUG("Constructing PercentileProjection from " << calhist.path());
0038       _calhist = calhist.path();
0039       int N = calhist.numBins();
0040       double sum = calhist.sumW();
0041       if ( _increasing ) {
0042         double acc = 0.0;
0043         for (int i = 0; i <= N; ++i) {
0044           acc += calhist.bin(i).sumW();
0045           _table.insert(make_pair(calhist.bin(i).xMax(), 100.0*acc/sum));
0046         }
0047       }
0048       else {
0049         double acc = 0.0;
0050         for (int i = N+1; i > 0; --i) {
0051           acc += calhist.bin(i).sumW();
0052           _table.insert(make_pair(calhist.bin(i).xMin(), 100.0*acc/sum));
0053         }
0054       }
0055       if (getLog().isActive(Log::DEBUG)) {
0056         MSG_DEBUG("Mapping from observable to percentile:");
0057         for (auto p : _table) {
0058           std::cout << std::setw(16) << p.first << " -> "
0059                     << std::setw(16) << p.second << "%" << std::endl;
0060           if (not _increasing and p.second <= 0) break;
0061           if (_increasing and p.second >= 100) break;
0062         }
0063       }
0064     }
0065 
0066 
0067     // Constructor taking a SingleValueProjection and a calibration
0068     // histogram. If increasing it means that low values corresponds to
0069     // lower percentiles.
0070     PercentileProjection(const SingleValueProjection & sv, const Estimate1D& calest,
0071                          PercentileOrder pctorder=PercentileOrder::DECREASING)
0072       : _calhist("EMPTY"),
0073     _increasing(pctorder == PercentileOrder::INCREASING)
0074     {
0075       declare(sv, "OBSERVABLE");
0076 
0077       //if ( !calest ) return;
0078       MSG_DEBUG("Constructing PercentileProjection from " << calest.path());
0079       _calhist = calest.path();
0080       int N = calest.numBins();
0081       double sum = 0.0;
0082       for (const auto &b : calest.bins() )  sum += b.val();
0083 
0084       double acc = 0.0;
0085       if ( _increasing ) {
0086         _table.insert(make_pair(calest.bin(1).xMin(), 100.0*acc/sum));
0087         for ( int i = 0; i < N; ++i ) {
0088           acc += calest.bin(i+1).val();
0089           _table.insert(make_pair(calest.bin(i+1).xMax(), 100.0*acc/sum));
0090         }
0091       }
0092       else {
0093         _table.insert(make_pair(calest.bin(N).xMax(), 100.0*acc/sum));
0094         for (int i = N - 1; i >= 0; --i) {
0095           acc += calest.bin(i+1).val();
0096           _table.insert(make_pair(calest.bin(i+1).xMin(), 100.0*acc/sum));
0097         }
0098       }
0099     }
0100 
0101 
0102     RIVET_DEFAULT_PROJ_CLONE(PercentileProjection);
0103 
0104     /// Import to avoid warnings about overload-hiding
0105     using Projection::operator =;
0106 
0107 
0108     // The projection function takes the assigned SingeValueProjection
0109     // and sets the value of this projection to the corresponding
0110     // percentile. If no calibration has been provided, -1 will be
0111     // returned. If values are outside of the calibration histogram, 0
0112     // or 100 will be returned.
0113     void project(const Event& e) {
0114       clear();
0115       if ( _table.empty() ) return;
0116       auto&  pobs = apply<SingleValueProjection>(e, "OBSERVABLE");
0117       double obs  = pobs();
0118       double pcnt = lookup(obs);
0119       if ( pcnt >= 0.0 ) setValue(pcnt);
0120       MSG_DEBUG("Observable(" << pobs.name() << ")="
0121                 << std::setw(16) << obs
0122                 << "-> Percentile=" << std::setw(16) << pcnt << "%");
0123     }
0124 
0125     // Standard comparison function.
0126     CmpState compare(const Projection& p) const {
0127       const PercentileProjection pp = dynamic_cast<const PercentileProjection&>(p);
0128       return mkNamedPCmp(p, "OBSERVABLE") ||
0129         cmp(_increasing, pp._increasing) ||
0130         cmp(_calhist, pp._calhist);
0131     }
0132 
0133 
0134   protected:
0135 
0136     // The (interpolated) lookup table
0137     double lookup(double obs) const {
0138       auto low = _table.upper_bound(obs);
0139       if ( low == _table.end() ) return _increasing? 100.0: 0.0;
0140       if ( low == _table.begin() ) return _increasing? 0.0: 100.0;
0141       auto high = low--;
0142       return low->second + (obs - low->first)*(high->second - low->second)/
0143         (high->first - low->first);
0144     }
0145 
0146     // Astring identifying the calibration histogram.
0147     string _calhist;
0148 
0149     // A lookup table to find (by interpolation) the percentile given
0150     // the value of the underlying SingleValueProjection.
0151     map<double,double> _table;
0152 
0153     // A flag to say whether the distribution should be integrated from
0154     // below or above.
0155     bool _increasing;
0156 
0157   };
0158 
0159 
0160 }
0161 
0162 #endif