diff --git a/include/YODA/Counter.h b/include/YODA/Counter.h --- a/include/YODA/Counter.h +++ b/include/YODA/Counter.h @@ -1,279 +1,279 @@ // -*- C++ -*- // // This file is part of YODA -- Yet more Objects for Data Analysis // Copyright (C) 2008-2016 The YODA collaboration (see AUTHORS for details) // #ifndef YODA_Counter_h #define YODA_Counter_h #include "YODA/AnalysisObject.h" #include "YODA/Dbn0D.h" #include "YODA/Scatter1D.h" #include "YODA/Exceptions.h" #include <vector> #include <string> #include <map> namespace YODA { /// A weighted counter. class Counter : public AnalysisObject { public: /// @name Constructors //@{ /// Default constructor Counter(const std::string& path="", const std::string& title="") : AnalysisObject("Counter", path, title) { } /// @brief Constructor accepting an explicit Dbn0D. /// /// Intended both for internal persistency and user use. Counter(const Dbn0D& dbn, const std::string& path="", const std::string& title="") : AnalysisObject("Counter", path, title), _dbn(dbn) { } /// @brief Constructor accepting a double (treated as the weight of a single fill). /// /// Intended for user convenience only, so Counter can be treated as a number. Counter(double w, const std::string& path="", const std::string& title="") : AnalysisObject("Counter", path, title) { _dbn.fill(w); } /// Copy constructor with optional new path /// @todo Don't copy the path? Counter(const Counter& c, const std::string& path=""); /// Assignment operator Counter& operator = (const Counter& c) { setPath(c.path()); setTitle(c.title()); _dbn = c._dbn; return *this; } /// Make a copy on the stack Counter clone() const { return Counter(*this); } /// Make a copy on the heap, via 'new' Counter* newclone() const { return new Counter(*this); } //@} /// Fill dimension of this data object size_t dim() const { return 0; } /// @name Modifiers //@{ /// Fill histo by value and weight - void fill(double weight=1.0, double fraction=1.0) { + virtual void fill(double weight=1.0, double fraction=1.0) { _dbn.fill(weight, fraction); } /// @brief Reset the histogram. /// /// Keep the binning but set all bin contents and related quantities to zero virtual void reset() { _dbn.reset(); } /// Rescale as if all fill weights had been different by factor @a scalefactor. void scaleW(double scalefactor) { setAnnotation("ScaledBy", annotation<double>("ScaledBy", 1.0) * scalefactor); _dbn.scaleW(scalefactor); } //@} /// @name Data access //@{ /// Get the number of fills unsigned long numEntries() const { return _dbn.numEntries(); } /// Get the effective number of fills double effNumEntries() const { return _dbn.effNumEntries(); } /// Get the sum of weights double sumW() const { return _dbn.sumW(); } /// Get the sum of squared weights double sumW2() const { return _dbn.sumW2(); } /// Get the value double val() const { return sumW(); } /// Get the uncertainty on the value /// @todo Implement on Dbn0D and feed through to this and Dbn1D, 2D, etc. // double err() const { return _dbn.err(); } double err() const { return sqrt(sumW2()); } /// Get the relative uncertainty on the value /// @todo Implement on Dbn0D and feed through to this and Dbn1D, 2D, etc. // double err() const { return _dbn.err(); } double relErr() const { /// @todo Throw excp if sumW2 is 0? return sumW2() != 0 ? err()/sumW() : 0; } //@} /// @name Internal state access and modification (mainly for persistency use) //@{ /// Get the internal distribution object const Dbn0D& dbn() const { return _dbn; } /// Set the internal distribution object: CAREFUL! void setDbn(const Dbn0D& dbn) { _dbn = dbn; } // /// Set the whole object state // void setState(const Dbn0D& dbn, const AnalysisObject::Annotations& anns=AnalysisObject::Annotations()) { // setDbn(dbn); // setAnnotations(anns); // } //@} /// @name Adding and subtracting counters //@{ /// Add another counter to this Counter& operator += (const Counter& toAdd) { _dbn += toAdd._dbn; return *this; } /// Subtract another counter from this Counter& operator -= (const Counter& toSubtract) { _dbn -= toSubtract._dbn; return *this; } /// Increment as if by a fill of weight = 1 /// @note This is post-increment only, i.e. cn++ not ++cn Counter& operator ++ () { *this += 1; return *this; } /// Increment as if by a fill of weight = -1 /// @note This is post-decrement only, i.e. cn-- not --cn Counter& operator -- () { *this -= 1; return *this; } /// Scale by a double (syntactic sugar for @c scaleW(s)) Counter& operator *= (double s) { scaleW(s); return *this; } /// Inverse-scale by a double (syntactic sugar for @c scaleW(1/s)) Counter& operator /= (double s) { scaleW(1/s); return *this; } //@} private: /// @name Data //@{ /// Contained 0D distribution Dbn0D _dbn; //@} }; /// @name Combining counters: global operators //@{ /// Add two counters inline Counter add(const Counter& first, const Counter& second) { Counter tmp = first; tmp += second; return tmp; } /// Add two counters inline Counter operator + (const Counter& first, const Counter& second) { return add(first, second); } /// Subtract two counters inline Counter subtract(const Counter& first, const Counter& second) { Counter tmp = first; tmp -= second; return tmp; } /// Subtract two counters inline Counter operator - (const Counter& first, const Counter& second) { return subtract(first, second); } /// Divide two counters, with an uncorrelated error treatment /// @todo Or just return a Point1D? Scatter1D divide(const Counter& numer, const Counter& denom); /// Divide two counters, with an uncorrelated error treatment /// @todo Or just return a Point1D? inline Scatter1D operator / (const Counter& numer, const Counter& denom) { return divide(numer, denom); } /// @todo Add divide functions/operators on pointers /// @brief Calculate an efficiency ratio of two counters /// /// Note that an efficiency is not the same thing as a standard division of two /// histograms: the errors must be treated as correlated /// /// @todo Or just return a Point1D? Scatter1D efficiency(const Counter& accepted, const Counter& total); //@} } #endif diff --git a/include/YODA/Histo1D.h b/include/YODA/Histo1D.h --- a/include/YODA/Histo1D.h +++ b/include/YODA/Histo1D.h @@ -1,519 +1,519 @@ // -*- C++ -*- // // This file is part of YODA -- Yet more Objects for Data Analysis // Copyright (C) 2008-2016 The YODA collaboration (see AUTHORS for details) // #ifndef YODA_Histo1D_h #define YODA_Histo1D_h #include "YODA/AnalysisObject.h" #include "YODA/HistoBin1D.h" #include "YODA/Dbn1D.h" #include "YODA/Scatter2D.h" #include "YODA/Axis1D.h" #include "YODA/Exceptions.h" #include <vector> #include <string> #include <map> namespace YODA { /// Convenience typedef typedef Axis1D<HistoBin1D, Dbn1D> Histo1DAxis; /// A one-dimensional histogram. class Histo1D : public AnalysisObject { public: /// Convenience typedefs typedef Histo1DAxis Axis; typedef Axis::Bins Bins; typedef HistoBin1D Bin; /// @name Constructors //@{ /// Default constructor Histo1D(const std::string& path="", const std::string& title="") : AnalysisObject("Histo1D", path, title), _axis() { } /// Constructor giving range and number of bins. Histo1D(size_t nbins, double lower, double upper, const std::string& path="", const std::string& title="") : AnalysisObject("Histo1D", path, title), _axis(nbins, lower, upper) { } /// @brief Constructor giving explicit bin edges. /// /// For n bins, binedges.size() == n+1, the last one being the upper bound /// of the last bin Histo1D(const std::vector<double>& binedges, const std::string& path="", const std::string& title="") : AnalysisObject("Histo1D", path, title), _axis(binedges) { } /// Constructor accepting an explicit collection of bins. Histo1D(const std::vector<Bin>& bins, const std::string& path="", const std::string& title="") : AnalysisObject("Histo1D", path, title), _axis(bins) { } /// Copy constructor with optional new path /// @todo Also allow title setting from the constructor? Histo1D(const Histo1D& h, const std::string& path=""); /// Constructor from a Scatter2D's binning, with optional new path /// @todo Also allow title setting from the constructor? Histo1D(const Scatter2D& s, const std::string& path=""); /// Constructor from a Profile1D's binning, with optional new path /// @todo Also allow title setting from the constructor? Histo1D(const Profile1D& p, const std::string& path=""); /// @brief State-setting constructor /// /// Intended principally for internal persistency use. Histo1D(const std::vector<HistoBin1D>& bins, const Dbn1D& dbn_tot, const Dbn1D& dbn_uflow, const Dbn1D& dbn_oflow, const std::string& path="", const std::string& title="") : AnalysisObject("Histo1D", path, title), _axis(bins, dbn_tot, dbn_uflow, dbn_oflow) { } /// Assignment operator Histo1D& operator = (const Histo1D& h1) { AnalysisObject::operator = (h1); //< AO treatment of paths etc. _axis = h1._axis; return *this; } /// Make a copy on the stack Histo1D clone() const { return Histo1D(*this); } /// Make a copy on the heap, via 'new' Histo1D* newclone() const { return new Histo1D(*this); } //@} /// Fill dimension of this data object size_t dim() const { return 1; } /// @name Modifiers //@{ /// @brief Reset the histogram. /// /// Keep the binning but set all bin contents and related quantities to zero virtual void reset() { _axis.reset(); } /// Fill histo by value and weight, optionally as a fractional fill virtual void fill(double x, double weight=1.0, double fraction=1.0); /// Fill histo bin i with the given weight, optionally as a fractional fill - void fillBin(size_t i, double weight=1.0, double fraction=1.0); + virtual void fillBin(size_t i, double weight=1.0, double fraction=1.0); /// Rescale as if all fill weights had been different by factor @a scalefactor. void scaleW(double scalefactor) { setAnnotation("ScaledBy", annotation<double>("ScaledBy", 1.0) * scalefactor); _axis.scaleW(scalefactor); } /// Normalize the (visible) histo area to the @a normto value. /// /// If @a includeoverflows is true, the original normalisation is computed with /// the overflow bins included, so that the resulting visible normalisation can /// be less than @a normto. This is probably what you want. void normalize(double normto=1.0, bool includeoverflows=true) { const double oldintegral = integral(includeoverflows); if (oldintegral == 0) throw WeightError("Attempted to normalize a histogram with null area"); /// @todo Check that this is the desired behaviour scaleW(normto / oldintegral); } /// Merge together the bin range with indices from @a from to @a to, inclusive void mergeBins(size_t from, size_t to) { _axis.mergeBins(from, to); } /// Merge every group of n bins, starting from the LHS void rebinBy(unsigned int n, size_t begin=0, size_t end=UINT_MAX) { _axis.rebinBy(n, begin, end); } /// Overloaded alias for rebinBy void rebin(unsigned int n, size_t begin=0, size_t end=UINT_MAX) { rebinBy(n, begin, end); } /// Rebin to the given list of bin edges void rebinTo(const std::vector<double>& newedges) { _axis.rebinTo(newedges); } /// Overloaded alias for rebinTo void rebin(const std::vector<double>& newedges) { rebinTo(newedges); } //@} public: /// @name Bin accessors //@{ /// Number of bins on this axis (not counting under/overflow) size_t numBins() const { return bins().size(); } /// Low edge of this histo's axis double xMin() const { return _axis.xMin(); } /// High edge of this histo's axis double xMax() const { return _axis.xMax(); } /// All bin edges on this histo's axis /// /// @note This only returns the finite edges, i.e. -inf and +inf are removed /// @todo Make the +-inf stripping controllable by a default-valued bool arg const std::vector<double> xEdges() const { return _axis.xEdges(); } /// Access the bin vector std::vector<YODA::HistoBin1D>& bins() { return _axis.bins(); } /// Access the bin vector (const version) const std::vector<YODA::HistoBin1D>& bins() const { return _axis.bins(); } /// Access a bin by index (non-const version) HistoBin1D& bin(size_t index) { return _axis.bins()[index]; } /// Access a bin by index (const version) const HistoBin1D& bin(size_t index) const { return _axis.bins()[index]; } /// Access a bin index by coordinate /// @todo Convert to ssize_t? int binIndexAt(double x) { return _axis.binIndexAt(x); } /// Access a bin by coordinate (const version) const HistoBin1D& binAt(double x) const { return _axis.binAt(x); } /// Access summary distribution, including gaps and overflows (non-const version) Dbn1D& totalDbn() { return _axis.totalDbn(); } /// Access summary distribution, including gaps and overflows (const version) const Dbn1D& totalDbn() const { return _axis.totalDbn(); } /// Set summary distribution, mainly for persistency: CAREFUL! void setTotalDbn(const Dbn1D& dbn) { _axis.setTotalDbn(dbn); } /// Access underflow (non-const version) Dbn1D& underflow() { return _axis.underflow(); } /// Access underflow (const version) const Dbn1D& underflow() const { return _axis.underflow(); } /// Set underflow distribution, mainly for persistency: CAREFUL! void setUnderflow(const Dbn1D& dbn) { _axis.setUnderflow(dbn); } /// Access overflow (non-const version) Dbn1D& overflow() { return _axis.overflow(); } /// Access overflow (const version) const Dbn1D& overflow() const { return _axis.overflow(); } /// Set overflow distribution, mainly for persistency: CAREFUL! void setOverflow(const Dbn1D& dbn) { _axis.setOverflow(dbn); } /// Add a new bin specifying its lower and upper bound void addBin(double from, double to) { _axis.addBin(from, to); } /// Add new bins by specifying a vector of edges void addBins(std::vector<double> edges) { _axis.addBins(edges); } // /// Add new bins specifying a beginning and end of each of them // void addBins(std::vector<std::pair<double,double> > edges) { // _axis.addBins(edges); // } /// Add a new bin, perhaps already populated: CAREFUL! void addBin(const HistoBin1D& b) { _axis.addBin(b); } /// @brief Bins addition operator /// /// Add multiple bins without resetting void addBins(const Bins& bins) { _axis.addBins(bins); } /// Remove a bin void eraseBin(size_t index) { _axis.eraseBin(index); } //@} /// @name Whole histo data //@{ /// Get the total area (sumW) of the histogram double integral(bool includeoverflows=true) const { return sumW(includeoverflows); } /// @brief Get the integrated area of the histogram between bins @a binindex1 and @a binindex2. /// /// @note The area of bin @a binindex2 _is_ included in the returned /// value. To include the underflow and overflow areas, you should add them /// explicitly with the underflow() and overflow() methods. /// /// @todo Allow int bin index args for type compatibility with binIndexAt()? double integralRange(size_t binindex1, size_t binindex2) const { assert(binindex2 >= binindex1); if (binindex1 >= numBins()) throw RangeError("binindex1 is out of range"); if (binindex2 >= numBins()) throw RangeError("binindex2 is out of range"); double rtn = 0; for (size_t i = binindex1; i < binindex2; ++i) { rtn += bin(i).sumW(); } return rtn; } /// @brief Get the integrated area of the histogram up to bin @a binindex. /// /// @note The area of bin @a binindex _is_ included in the returned /// value. To not include the underflow, set includeunderflow=false. /// /// @todo Allow int bin index args for type compatibility with binIndexAt()? double integralTo(size_t binindex, bool includeunderflow=true) const { double rtn = includeunderflow ? underflow().sumW() : 0; rtn += integralRange(0, binindex); return rtn; } /// Get the number of fills unsigned long numEntries(bool includeoverflows=true) const; /// Get the effective number of fills double effNumEntries(bool includeoverflows=true) const; /// Get sum of weights in histo double sumW(bool includeoverflows=true) const; /// Get sum of squared weights in histo double sumW2(bool includeoverflows=true) const; /// Get the mean in x double xMean(bool includeoverflows=true) const; /// Get the variance in x double xVariance(bool includeoverflows=true) const; /// Get the standard deviation in x double xStdDev(bool includeoverflows=true) const { if (includeoverflows) return _axis.totalDbn().xStdDev(); return std::sqrt(xVariance(includeoverflows)); } /// Get the standard error in x double xStdErr(bool includeoverflows=true) const; /// Get the RMS in x double xRMS(bool includeoverflows=true) const; //@} /// @name Adding and subtracting histograms //@{ /// @brief Add another histogram to this one /// /// @note Adding histograms will unset any ScaledBy attribute from prevous calls to scaleW or normalize. Histo1D& operator += (const Histo1D& toAdd) { if (hasAnnotation("ScaledBy")) rmAnnotation("ScaledBy"); _axis += toAdd._axis; return *this; // if (!hasAnnotation("ScaledBy") && !toAdd.hasAnnotation("ScaledBy")) { // _axis += toAdd._axis; // } else { // // Undo scaling of both histograms // double scaledBy = annotation<double>("ScaledBy", 1.0); // _axis.scaleW(1.0/scaledBy); // double toAddScaledBy = toAdd.annotation<double>("ScaledBy", 1.0); // Axis1D<HistoBin1D, Dbn1D> toAddAxis = toAdd._axis; // toAddAxis.scaleW(1.0/toAddScaledBy); // _axis += toAddAxis; // // Re-apply combined scaling // double newScaledBy = scaledBy*toAddScaledBy/(scaledBy+toAddScaledBy); // _axis.scaleW(newScaledBy); // setAnnotation("ScaledBy", newScaledBy); // } /// @todo What about if one histo sets ScaledBy, and the other doesn't?!? Aaaargh // return *this; } /// @brief Subtract another histogram from this one /// /// @note Subtracting histograms will unset any ScaledBy attribute from prevous calls to scaleW or normalize. Histo1D& operator -= (const Histo1D& toSubtract) { if (hasAnnotation("ScaledBy")) rmAnnotation("ScaledBy"); _axis -= toSubtract._axis; return *this; } //@} protected: /// Access a bin by coordinate (non-const version) HistoBin1D& binAt(double x) { return _axis.binAt(x); } private: /// @name Bin data //@{ /// Definition of bin edges and contents Axis1D<HistoBin1D, Dbn1D> _axis; //@} }; /// @name Combining histos: global operators //@{ /// Add two histograms inline Histo1D add(const Histo1D& first, const Histo1D& second) { Histo1D tmp = first; if (first.path() != second.path()) tmp.setPath(""); tmp += second; return tmp; } /// Add two histograms inline Histo1D operator + (const Histo1D& first, const Histo1D& second) { return add(first, second); } /// Subtract two histograms inline Histo1D subtract(const Histo1D& first, const Histo1D& second) { Histo1D tmp = first; if (first.path() != second.path()) tmp.setPath(""); tmp -= second; return tmp; } /// Subtract two histograms inline Histo1D operator - (const Histo1D& first, const Histo1D& second) { return subtract(first, second); } /// @todo Add multiply(H1, H1) -> Scatter2D? /// Divide two histograms, with an uncorrelated error treatment /// /// @todo Wouldn't it be nice to be able to supply a correlation matrix or function as optional arg? /// /// @note The two histos must have _exactly_ the same binning. Scatter2D divide(const Histo1D& numer, const Histo1D& denom); /// Divide two histograms, with an uncorrelated error treatment /// /// @note The two histos must have _exactly_ the same binning. inline Scatter2D operator / (const Histo1D& numer, const Histo1D& denom) { return divide(numer, denom); } /// @todo Add functions/operators on pointers /// @brief Calculate a histogrammed efficiency ratio of two histograms /// /// @note The two histos must have _exactly_ the same binning. /// /// @note An efficiency is not the same thing as a standard division of two /// histograms: the errors are treated as correlated via binomial statistics. Scatter2D efficiency(const Histo1D& accepted, const Histo1D& total); /// @brief Calculate the asymmetry (a-b)/(a+b) of two histograms /// /// @note The two histos must have _exactly_ the same binning. inline Scatter2D asymm(const Histo1D& a, const Histo1D& b) { return (a-b) / (a+b); } /// @brief Convert a Histo1D to a Scatter2D representing the integral of the histogram /// /// @note The integral histo errors are calculated as sqrt(binvalue), as if they /// are uncorrelated. This is not in general true for integral histograms, so if you /// need accurate errors you should explicitly monitor bin-to-bin correlations. /// /// The includeunderflow param chooses whether the underflow bin is included /// in the integral numbers as an offset. /// /// @todo Rename/alias as mkIntegral Scatter2D toIntegralHisto(const Histo1D& h, bool includeunderflow=true); /// @brief Convert a Histo1D to a Scatter2D where each bin is a fraction of the total /// /// @note This sounds weird: let's explain a bit more! Sometimes we want to /// take a histo h, make an integral histogram H from it, and then divide H by /// the total integral of h, such that every bin in H represents the /// cumulative efficiency of that bin as a fraction of the total. I.e. an /// integral histo, scaled by 1/total_integral and with binomial errors. /// /// The includeunderflow param behaves as for toIntegral, and applies to both /// the initial integration and the integral used for the scaling. The /// includeoverflow param applies only to obtaining the scaling factor. /// /// @todo Rename/alias as mkIntegralEff Scatter2D toIntegralEfficiencyHisto(const Histo1D& h, bool includeunderflow=true, bool includeoverflow=true); //@} } #endif diff --git a/include/YODA/Histo2D.h b/include/YODA/Histo2D.h --- a/include/YODA/Histo2D.h +++ b/include/YODA/Histo2D.h @@ -1,512 +1,512 @@ // -*- C++ -*- // // This file is part of YODA -- Yet more Objects for Data Analysis // Copyright (C) 2008-2016 The YODA collaboration (see AUTHORS for details) // #ifndef YODA_Histo2D_h #define YODA_Histo2D_h #include "YODA/AnalysisObject.h" #include "YODA/HistoBin2D.h" #include "YODA/Dbn2D.h" #include "YODA/Axis2D.h" #include "YODA/Scatter3D.h" #include "YODA/Exceptions.h" #include <vector> namespace YODA { // Forward declaration class Profile2D; class Scatter3D; /// Convenience typedef typedef Axis2D<HistoBin2D, Dbn2D> Histo2DAxis; /// A two-dimensional histogram. class Histo2D : public AnalysisObject { public: /// Convenience typedefs typedef Histo2DAxis Axis; typedef Axis::Bins Bins; typedef HistoBin2D Bin; typedef Axis::Outflows Outflows; /// @name Constructors //@{ /// Default constructor Histo2D(const std::string& path="", const std::string& title="") : AnalysisObject("Histo2D", path, title), _axis() { } /// Constructor giving range and number of bins. Histo2D(size_t nbinsX, double lowerX, double upperX, size_t nbinsY, double lowerY, double upperY, const std::string& path="", const std::string& title="") : AnalysisObject("Histo2D", path, title), _axis(nbinsX, std::make_pair(lowerX, upperX), nbinsY, std::make_pair(lowerY, upperY)) { } /// Constructor accepting the bin edges on X and Y axis. Histo2D(const std::vector<double>& xedges, const std::vector<double>& yedges, const std::string& path="", const std::string& title="") : AnalysisObject("Histo2D", path, title), _axis(xedges, yedges) { } /// Constructor accepting an explicit collection of bins. Histo2D(const std::vector<Bin>& bins, const std::string& path="", const std::string& title="") : AnalysisObject("Histo2D", path, title), _axis(bins) { } /// Copy constructor with optional new path /// @todo Also allow title setting from the constructor? Histo2D(const Histo2D& h, const std::string& path=""); /// A constructor from a Scatter3D's binning, with optional new path /// @todo Also allow title setting from the constructor? Histo2D(const Scatter3D& s, const std::string& path=""); /// Constructor from a Profile2D's binning, with optional new path /// @todo Also allow title setting from the constructor? Histo2D(const Profile2D& h, const std::string& path=""); /// @brief State-setting constructor /// /// Mainly intended for internal persistency use. Histo2D(const std::vector<HistoBin2D>& bins, const Dbn2D& totalDbn, const Outflows& outflows, const std::string& path="", const std::string& title="") : AnalysisObject("Histo2D", path, title), _axis(bins, totalDbn, outflows) { } /// Assignment operator Histo2D& operator = (const Histo2D& h2) { AnalysisObject::operator = (h2); //< AO treatment of paths etc. _axis = h2._axis; return *this; } /// Make a copy on the stack Histo2D clone() const { return Histo2D(*this); } /// Make a copy on the heap, via 'new' Histo2D* newclone() const { return new Histo2D(*this); } //@} /// Fill dimension of this data object size_t dim() const { return 2; } /// @name Modifiers //@{ /// Fill histo with weight at (x,y) - void fill(double x, double y, double weight=1.0, double fraction=1.0); + virtual void fill(double x, double y, double weight=1.0, double fraction=1.0); /// Fill histo x-y bin i with the given weight - void fillBin(size_t i, double weight=1.0, double fraction=1.0); + virtual void fillBin(size_t i, double weight=1.0, double fraction=1.0); /// @brief Reset the histogram. /// /// Keep the binning but set all bin contents and related quantities to zero void reset() { _axis.reset(); } /// Rescale as if all fill weights had been different by factor @a scalefactor. void scaleW(double scalefactor) { setAnnotation("ScaledBy", annotation<double>("ScaledBy", 1.0) * scalefactor); _axis.scaleW(scalefactor); } /// Normalize the (visible) histo "volume" to the @a normto value. /// /// If @a includeoverflows is true, the original normalisation is computed with /// the overflow bins included, so that the resulting visible normalisation can /// be less than @a normto. This is probably what you want. void normalize(double normto=1.0, bool includeoverflows=true) { const double oldintegral = integral(includeoverflows); if (oldintegral == 0) throw WeightError("Attempted to normalize a histogram with null area"); /// @todo Check that this is the desired behaviour scaleW(normto / oldintegral); } /// Scale the dimensions void scaleXY(double scaleX = 1.0, double scaleY = 1.0) { _axis.scaleXY(scaleX, scaleY); } /// @brief Bin addition operator /// /// Add a bin to an axis described by its x and y ranges. void addBin(Axis::EdgePair1D xrange, Axis::EdgePair1D yrange) { _axis.addBin(xrange, yrange); } /// @brief Bin addition operator /// /// Add a bin, possibly already populated void addBin(const Bin& bin) { _axis.addBin(bin); } /// @brief Bins addition operator /// /// Add multiple bins from edge cuts without resetting void addBins(const Axis::Edges& xcuts, const Axis::Edges& ycuts) { _axis.addBins(xcuts, ycuts); } /// @brief Bins addition operator /// /// Add multiple bins without resetting void addBins(const Bins& bins) { _axis.addBins(bins); } // /// Adding bins /// @todo TODO // void addBin(const std::vector<std::pair<std::pair<double,double>, std::pair<double,double> > > coords) { // _axis.addBin(coords); // } // /// Adding bins which is not so eloquent /// @todo TODO // void addBin(double lowX, double lowY, double highX, double highY) { // _axis.addBin(lowX, lowY, highX, highY); // } // /// Merge the bins /// @todo TODO // void mergeBins(size_t from, size_t to) { // _axis.mergeBins(from, to); // } /// Rebin the whole histo by a @a factorX in the X direction and /// @a factorY in the Y direction /// @todo TODO // void rebin(size_t factorX, size_t factorY){ // _axis.rebin(factorX, factorY); // } void eraseBin(size_t index) { _axis.eraseBin(index); } //@} public: /// @name Bin accessors //@{ /// Low x edge of this histo's axis double xMin() const { return _axis.xMin(); } /// High x edge of this histo's axis double xMax() const { return _axis.xMax(); } /// Low y edge of this histo's axis double yMin() const { return _axis.yMin(); } /// High y edge of this histo's axis double yMax() const { return _axis.yMax(); } /// Access the bin vector (non-const version) std::vector<YODA::HistoBin2D>& bins() { return _axis.bins(); } /// Access the bin vector (const version) const std::vector<YODA::HistoBin2D>& bins() const { return _axis.bins(); } /// Access a bin by index (non-const version) HistoBin2D& bin(size_t index) { return _axis.bin(index); } /// Access a bin by index (const version) const HistoBin2D& bin(size_t index) const { return _axis.bin(index); } /// Access a bin index by coordinate int binIndexAt(double x, double y) { return _axis.binIndexAt(x, y); } /// Access a bin by coordinate (const version) const HistoBin2D& binAt(double x, double y) const { return _axis.binAt(x, y); } /// Number of bins size_t numBins() const { return _axis.numBins(); } /// Number of bins along the x axis size_t numBinsX() const { return _axis.numBinsX(); } /// Number of bins along the y axis size_t numBinsY() const { return _axis.numBinsY(); } /// Access summary distribution, including gaps and overflows (non-const version) Dbn2D& totalDbn() { return _axis.totalDbn(); } /// Access summary distribution, including gaps and overflows (const version) const Dbn2D& totalDbn() const { return _axis.totalDbn(); } /// Set summary distribution, including gaps and overflows void setTotalDbn(const Dbn2D& dbn) { _axis.setTotalDbn(dbn); } // /// @brief Access an outflow (non-const) // /// // /// Two indices are used, for x and y: -1 = underflow, 0 = in-range, and +1 = overflow. // /// (0,0) is not a valid overflow index pair, since it is in range for both x and y. // Dbn2D& outflow(int ix, int iy) { // std::cout << "Histo2D::outflow\n"; // return _axis.outflow(ix, iy); // } // /// @brief Access an outflow (const) // /// // /// Two indices are used, for x and y: -1 = underflow, 0 = in-range, and +1 = overflow. // /// (0,0) is not a valid overflow index pair, since it is in range for both x and y. // const Dbn2D& outflow(int ix, int iy) const { // return _axis.outflow(ix, iy); // } //@} /// @name Whole histo data //@{ /// Get the total volume of the histogram double integral(bool includeoverflows=true) const { return sumW(includeoverflows); } /// Get the number of fills unsigned long numEntries(bool includeoverflows=true) const; /// Get the effective number of fills double effNumEntries(bool includeoverflows=true) const; /// Get the sum of weights in histo double sumW(bool includeoverflows=true) const; /// Get the sum of squared weights in histo double sumW2(bool includeoverflows=true) const; /// Get the mean x double xMean(bool includeoverflows=true) const; /// Get the mean y double yMean(bool includeoverflows=true) const; /// Get the variance in x double xVariance(bool includeoverflows=true) const; /// Get the variance in y double yVariance(bool includeoverflows=true) const; /// Get the standard deviation in x double xStdDev(bool includeoverflows=true) const { return std::sqrt(xVariance(includeoverflows)); } /// Get the standard deviation in y double yStdDev(bool includeoverflows=true) const { return std::sqrt(yVariance(includeoverflows)); } /// Get the standard error in x double xStdErr(bool includeoverflows=true) const; /// Get the standard error in y double yStdErr(bool includeoverflows=true) const; /// Get the RMS in x double xRMS(bool includeoverflows=true) const; /// Get the RMS in y double yRMS(bool includeoverflows=true) const; //@} /// @name Adding and subtracting histograms //@{ /// @brief Add another histogram to this one /// /// @note Adding histograms will unset any ScaledBy attribute from prevous calls to scaleW or normalize. Histo2D& operator += (const Histo2D& toAdd) { if (hasAnnotation("ScaledBy")) rmAnnotation("ScaledBy"); _axis += toAdd._axis; return *this; } /// @brief Subtract another histogram from this one /// /// @note Subtracting histograms will unset any ScaledBy attribute from prevous calls to scaleW or normalize. Histo2D& operator -= (const Histo2D& toSubtract) { if (hasAnnotation("ScaledBy")) rmAnnotation("ScaledBy"); _axis -= toSubtract._axis; return *this; } bool operator == (const Histo2D& other) const { return _axis == other._axis; } bool operator != (const Histo2D& other) const { return ! operator == (other); } //@} // /// @name Slicing operators // //@{ // /// @brief Create a Histo2D for the bin slice parallel to the x axis at the specified y coordinate // /// // /// Note that the created histogram will not have correctly filled underflow and overflow bins. // /// @todo It's not really *at* the specified y coord: it's for the corresponding bin row. // /// @todo Change the name! // Histo2D cutterX(double atY, const std::string& path="", const std::string& title=""); // /// @brief Create a Histo2D for the bin slice parallel to the y axis at the specified x coordinate // /// // /// Note that the created histogram will not have correctly filled underflow and overflow bins. // /// @todo It's not really *at* the specified x coord: it's for the corresponding bin row. // /// @todo Change the name! // Histo2D cutterY(double atX, const std::string& path="", const std::string& title=""); // /// X-wise Profile1D creator from Histo2D // Profile1D mkProfileX(); // /// Y-wise Profile1D creator from Histo2D // Profile1D mkProfileY(); // //@} protected: /// Access a bin by coordinate (non-const version) HistoBin2D& binAt(double x, double y) { return _axis.binAt(x, y); } private: /// @name Bin data //@{ /// Definition of bin edges and contents Axis2D<HistoBin2D, Dbn2D> _axis; //@} }; /// @name Combining histos: global operators //@{ /// Add two histograms inline Histo2D add(const Histo2D& first, const Histo2D& second) { Histo2D tmp = first; if (first.path() != second.path()) tmp.setPath(""); tmp += second; return tmp; } /// Add two histograms inline Histo2D operator + (const Histo2D& first, const Histo2D& second) { return add(first, second); } /// Subtract two histograms inline Histo2D subtract(const Histo2D& first, const Histo2D& second) { Histo2D tmp = first; if (first.path() != second.path()) tmp.setPath(""); tmp -= second; return tmp; } /// Subtract two histograms inline Histo2D operator - (const Histo2D& first, const Histo2D& second) { return subtract(first, second); } /// @todo Add multiply(H2, H2) -> Scatter3D? /// @brief Divide two histograms, with an uncorrelated error treatment /// /// @todo Wouldn't it be nice to be able to supply a correlation matrix or function as optional arg? /// /// @note The two histos must have _exactly_ the same binning. Scatter3D divide(const Histo2D& numer, const Histo2D& denom); /// Divide two histograms, with an uncorrelated error treatment /// /// @note The two histos must have _exactly_ the same binning. inline Scatter3D operator / (const Histo2D& numer, const Histo2D& denom) { return divide(numer, denom); } /// @brief Calculate a histogrammed efficiency ratio of two histograms /// /// @note The two histos must have _exactly_ the same binning. /// /// @note An efficiency is not the same thing as a standard division of two /// histograms: the errors are treated as correlated via binomial statistics. Scatter3D efficiency(const Histo2D& accepted, const Histo2D& total); /// @brief Calculate the asymmetry (a-b)/(a+b) of two histograms /// /// @note The two histos must have _exactly_ the same binning. inline Scatter3D asymm(const Histo2D& a, const Histo2D& b) { return (a-b) / (a+b); } //@} } #endif diff --git a/include/YODA/Profile1D.h b/include/YODA/Profile1D.h --- a/include/YODA/Profile1D.h +++ b/include/YODA/Profile1D.h @@ -1,402 +1,402 @@ // -*- C++ -*- // // This file is part of YODA -- Yet more Objects for Data Analysis // Copyright (C) 2008-2016 The YODA collaboration (see AUTHORS for details) // #ifndef YODA_Profile1D_h #define YODA_Profile1D_h #include "YODA/AnalysisObject.h" #include "YODA/ProfileBin1D.h" #include "YODA/Scatter2D.h" #include "YODA/Dbn2D.h" #include "YODA/Axis1D.h" #include "YODA/Exceptions.h" #include <vector> #include <string> #include <map> namespace YODA { // Forward declarations class Histo1D; class Scatter2D; /// Convenience typedef typedef Axis1D<ProfileBin1D, Dbn2D> Profile1DAxis; /// A one-dimensional profile histogram. class Profile1D : public AnalysisObject { public: /// Convenience typedefs typedef Profile1DAxis Axis; typedef Axis::Bins Bins; typedef ProfileBin1D Bin; /// @name Constructors //@{ /// Default constructor Profile1D(const std::string& path="", const std::string& title="") : AnalysisObject("Profile1D", path, title), _axis() { } /// Constructor giving range and number of bins Profile1D(size_t nxbins, double xlower, double xupper, const std::string& path="", const std::string& title="") : AnalysisObject("Profile1D", path, title), _axis(nxbins, xlower, xupper) { } /// Constructor giving explicit bin edges /// /// For n bins, binedges.size() == n+1, the last one being the upper bound /// of the last bin Profile1D(const std::vector<double>& xbinedges, const std::string& path="", const std::string& title="") : AnalysisObject("Profile1D", path, title), _axis(xbinedges) { } /// Copy constructor with optional new path /// @todo Also allow title setting from the constructor? Profile1D(const Profile1D& p, const std::string& path=""); /// Constructor from a Scatter2D's binning, with optional new path /// @todo Also allow title setting from the constructor? Profile1D(const Scatter2D& s, const std::string& path=""); /// Constructor from a Histo1D's binning, with optional new path /// @todo Also allow title setting from the constructor? Profile1D(const Histo1D& h, const std::string& path=""); /// @brief State-setting constructor. /// /// Intended principally for internal persistency use. Profile1D(const std::vector<ProfileBin1D>& bins, const Dbn2D& dbn_tot, const Dbn2D& dbn_uflow, const Dbn2D& dbn_oflow, const std::string& path="", const std::string& title="") : AnalysisObject("Profile1D", path, title), _axis(bins, dbn_tot, dbn_uflow, dbn_oflow) { } /// Assignment operator Profile1D& operator = (const Profile1D& p1) { AnalysisObject::operator = (p1); //< AO treatment of paths etc. _axis = p1._axis; return *this; } /// Make a copy on the stack Profile1D clone() const { return Profile1D(*this); } /// Make a copy on the heap, via 'new' Profile1D* newclone() const { return new Profile1D(*this); } //@} /// Fill dimension of this data object size_t dim() const { return 1; } /// @name Modifiers //@{ /// Fill histo by value and weight - void fill(double x, double y, double weight=1.0, double fraction=1.0); + virtual void fill(double x, double y, double weight=1.0, double fraction=1.0); /// Fill histo x bin i with the given y value and weight - void fillBin(size_t i, double y, double weight=1.0, double fraction=1.0); + virtual void fillBin(size_t i, double y, double weight=1.0, double fraction=1.0); /// @brief Reset the histogram /// /// Keep the binning but set all bin contents and related quantities to zero void reset() { _axis.reset(); } /// Rescale as if all fill weights had been different by factor @a scalefactor. void scaleW(double scalefactor) { _axis.scaleW(scalefactor); } /// Rescale as if all y values had been different by factor @a scalefactor. void scaleY(double scalefactor) { _axis.totalDbn().scaleY(scalefactor); _axis.overflow().scaleY(scalefactor); _axis.underflow().scaleY(scalefactor); for (size_t i = 0; i < bins().size(); ++i) bin(i).scaleY(scalefactor); } /// Merge together the bin range with indices from @a from to @a to, inclusive void mergeBins(size_t from, size_t to) { _axis.mergeBins(from, to); } /// Merge every group of n bins, starting from the LHS void rebinBy(unsigned int n, size_t begin=0, size_t end=UINT_MAX) { _axis.rebinBy(n, begin, end); } /// Overloaded alias for rebinBy void rebin(unsigned int n, size_t begin=0, size_t end=UINT_MAX) { rebinBy(n, begin, end); } /// Rebin to the given list of bin edges void rebinTo(const std::vector<double>& newedges) { _axis.rebinTo(newedges); } /// Overloaded alias for rebinTo void rebin(const std::vector<double>& newedges) { rebinTo(newedges); } /// Bin addition operator void addBin(double xlow, double xhigh) { _axis.addBin(xlow, xhigh); } /// Bin addition operator void addBins(const std::vector<double> binedges) { _axis.addBins(binedges); } // /// Bin addition operator // void addBins(const std::vector<std::pair<double,double> > edges) { // _axis.addBins(edges); // } /// Add a new bin, perhaps already populated: CAREFUL! void addBin(const ProfileBin1D& b) { _axis.addBin(b); } /// @brief Bins addition operator /// /// Add multiple bins without resetting void addBins(const Bins& bins) { _axis.addBins(bins); } //@} /// @name Bin accessors //@{ /// Number of bins on this axis (not counting under/overflow) size_t numBins() const { return bins().size(); } /// Low edge of this histo's axis double xMin() const { return _axis.xMin(); } /// High edge of this histo's axis double xMax() const { return _axis.xMax(); } /// All bin edges on this histo's axis /// /// @note This only returns the finite edges, i.e. -inf and +inf are removed /// @todo Make the +-inf stripping controllable by a default-valued bool arg const std::vector<double> xEdges() const { return _axis.xEdges(); } /// Access the bin vector std::vector<YODA::ProfileBin1D>& bins() { return _axis.bins(); } /// Access the bin vector const std::vector<YODA::ProfileBin1D>& bins() const { return _axis.bins(); } /// Access a bin by index (non-const version) ProfileBin1D& bin(size_t index) { return _axis.bins()[index]; } /// Access a bin by index (const version) const ProfileBin1D& bin(size_t index) const { return _axis.bins()[index]; } /// Access a bin index by x-coordinate. int binIndexAt(double x) { return _axis.binIndexAt(x); } /// Access a bin by x-coordinate (const version) const ProfileBin1D& binAt(double x) const { return _axis.binAt(x); } /// Access summary distribution, including gaps and overflows (non-const version) Dbn2D& totalDbn() { return _axis.totalDbn(); } /// Access summary distribution, including gaps and overflows (const version) const Dbn2D& totalDbn() const { return _axis.totalDbn(); } /// Set summary distribution, mainly for persistency: CAREFUL! void setTotalDbn(const Dbn2D& dbn) { _axis.setTotalDbn(dbn); } /// Access underflow (non-const version) Dbn2D& underflow() { return _axis.underflow(); } /// Access underflow (const version) const Dbn2D& underflow() const { return _axis.underflow(); } /// Set underflow distribution, mainly for persistency: CAREFUL! void setUnderflow(const Dbn2D& dbn) { _axis.setUnderflow(dbn); } /// Access overflow (non-const version) Dbn2D& overflow() { return _axis.overflow(); } /// Access overflow (const version) const Dbn2D& overflow() const { return _axis.overflow(); } /// Set overflow distribution, mainly for persistency: CAREFUL! void setOverflow(const Dbn2D& dbn) { _axis.setOverflow(dbn); } //@} /// @name Whole histo data //@{ /// @todo Add integrals? Or are they too ambiguous to make a core function? /// Get the number of fills unsigned long numEntries(bool includeoverflows=true) const; /// Get the effective number of fills double effNumEntries(bool includeoverflows=true) const; /// Get sum of weights in histo. double sumW(bool includeoverflows=true) const; /// Get sum of squared weights in histo. double sumW2(bool includeoverflows=true) const; /// Get the mean x double xMean(bool includeoverflows=true) const; /// Get the variance in x double xVariance(bool includeoverflows=true) const; /// Get the standard deviation in x double xStdDev(bool includeoverflows=true) const { return std::sqrt(xVariance(includeoverflows)); } /// Get the standard error on <x> double xStdErr(bool includeoverflows=true) const; /// Get the RMS in x double xRMS(bool includeoverflows=true) const; //@} /// @name Adding and subtracting histograms //@{ /// Add another profile to this one Profile1D& operator += (const Profile1D& toAdd) { if (hasAnnotation("ScaledBy")) rmAnnotation("ScaledBy"); _axis += toAdd._axis; return *this; } /// Subtract another profile from this one Profile1D& operator -= (const Profile1D& toSubtract) { if (hasAnnotation("ScaledBy")) rmAnnotation("ScaledBy"); _axis -= toSubtract._axis; return *this; } inline bool operator == (const Profile1D& other){ return _axis == other._axis; } inline bool operator != (const Profile1D& other){ return ! operator == (other); } //@} protected: /// Access a bin by x-coordinate (non-const version) ProfileBin1D& binAt(double x) { return _axis.binAt(x); } private: /// @name Bin data //@{ /// The bins contained in this profile histogram Axis1D<ProfileBin1D, Dbn2D> _axis; //@} }; /// @name Combining profile histos: global operators //@{ /// Add two profile histograms inline Profile1D add(const Profile1D& first, const Profile1D& second) { Profile1D tmp = first; if (first.path() != second.path()) tmp.setPath(""); tmp += second; return tmp; } /// Add two profile histograms inline Profile1D operator + (const Profile1D& first, const Profile1D& second) { return add(first, second); } /// Subtract two profile histograms inline Profile1D subtract(const Profile1D& first, const Profile1D& second) { Profile1D tmp = first; if (first.path() != second.path()) tmp.setPath(""); tmp -= second; return tmp; } /// Subtract two profile histograms inline Profile1D operator - (const Profile1D& first, const Profile1D& second) { return subtract(first, second); } /// Divide two profile histograms Scatter2D divide(const Profile1D& numer, const Profile1D& denom); /// Divide two profile histograms inline Scatter2D operator / (const Profile1D& numer, const Profile1D& denom) { return divide(numer, denom); } //@} } #endif diff --git a/include/YODA/Profile2D.h b/include/YODA/Profile2D.h --- a/include/YODA/Profile2D.h +++ b/include/YODA/Profile2D.h @@ -1,433 +1,433 @@ // -*- C++ -*- // // This file is part of YODA -- Yet more Objects for Data Analysis // Copyright (C) 2008-2016 The YODA collaboration (see AUTHORS for details) // #ifndef YODA_Profile2D_h #define YODA_Profile2D_h #include "YODA/AnalysisObject.h" #include "YODA/ProfileBin2D.h" #include "YODA/Dbn3D.h" #include "YODA/Axis2D.h" #include "YODA/Scatter3D.h" #include "YODA/Exceptions.h" #include <vector> namespace YODA { // Forward declarations class Histo2D; class Scatter3D; /// Convenience typedef typedef Axis2D<ProfileBin2D, Dbn3D> Profile2DAxis; /// A two-dimensional profile histogram. class Profile2D : public AnalysisObject { public: /// Convenience typedefs typedef Profile2DAxis Axis; typedef Axis::Bins Bins; typedef ProfileBin2D Bin; typedef Axis::Outflows Outflows; /// @name Constructors //@{ /// Default constructor Profile2D(const std::string& path="", const std::string& title="") : AnalysisObject("Profile2D", path, title), _axis() { } /// Constructor giving range and number of bins Profile2D(size_t nbinsX, double lowerX, double upperX, size_t nbinsY, double lowerY, double upperY, const std::string& path="", const std::string& title="") : AnalysisObject("Profile2D", path, title), _axis(nbinsX, std::make_pair(lowerX, upperX), nbinsY, std::make_pair(lowerY, upperY)) { } /// Constructor giving explicit bin edges in the direction of X and Y Profile2D(const std::vector<double>& xedges, const std::vector<double>& yedges, const std::string& path="", const std::string& title="") : AnalysisObject("Profile2D", path, title), _axis(xedges, yedges) { } /// Constructor accepting an explicit collection of bins. Profile2D(const std::vector<Bin>& bins, const std::string& path="", const std::string& title="") : AnalysisObject("Profile2D", path, title), _axis(bins) { } /// A copy constructor with optional new path /// @todo Also allow title setting from the constructor? Profile2D(const Profile2D& p, const std::string& path=""); /// A constructor from a Scatter3D's binning, with optional new path /// @todo Also allow title setting from the constructor? Profile2D(const Scatter3D& s, const std::string& path=""); /// Constructor from a Histo2D's binning, with optional new path /// @todo Also allow title setting from the constructor? Profile2D(const Histo2D& h, const std::string& path=""); /// @brief State-setting constructor /// /// Mainly intended for internal persistency use. Profile2D(const std::vector<ProfileBin2D>& bins, const Dbn3D& totalDbn, const Outflows& outflows, const std::string& path="", const std::string& title="") : AnalysisObject("Profile2D", path, title), _axis(bins, totalDbn, outflows) { } /// Assignment operator Profile2D& operator = (const Profile2D& p2) { AnalysisObject::operator = (p2); //< AO treatment of paths etc. _axis = p2._axis; return *this; } /// Make a copy on the stack Profile2D clone() const { return Profile2D(*this); } /// Make a copy on the heap, via 'new' Profile2D* newclone() const { return new Profile2D(*this); } //@} /// Fill dimension of this data object size_t dim() const { return 2; } /// @name Modifiers //@{ /// Fill histo by value and weight - void fill(double x, double y, double z, double weight=1.0, double fraction=1.0); + virtual void fill(double x, double y, double z, double weight=1.0, double fraction=1.0); /// Fill histo x-y bin i with the given z value and weight - void fillBin(size_t i, double z, double weight=1.0, double fraction=1.0); + virtual void fillBin(size_t i, double z, double weight=1.0, double fraction=1.0); /// @brief Reset the histogram /// /// Keep the binning but reset the statistics void reset() { _axis.reset(); } /// Rescale as if all fill weights had been different by a @a scalefactor void scaleW(double scalefactor) { /// @todo Is this ScaledBy annotation needed? setAnnotation("ScaledBy", annotation<double>("ScaledBy", 1.0) * scalefactor); _axis.scaleW(scalefactor); } /// Rescale as if all z values had been different by factor @a scalefactor. void scaleZ(double scalefactor) { _axis.totalDbn().scaleZ(scalefactor); /// @todo Need to rescale overflows too, when they exist. // _axis.overflow().scaleZ(scalefactor); // _axis.underflow().scaleZ(scalefactor); for (size_t i = 0; i < bins().size(); ++i) bin(i).scaleZ(scalefactor); } /// @todo TODO // /// Merge together the bin range with indices from @a from to @a to, inclusive // void mergeBins(size_t from, size_t to) { // _axis.mergeBins(from, to); // } /// @todo TODO // /// Merge every group of n bins, starting from the LHS // void rebin(size_t n) { // throw "IMPLEMENT!"; // //_axis.rebin(n); // } // /// @brief Bin addition operator // /// // /// Add a bin to the axis, described by its x and y ranges. void addBin(Axis::EdgePair1D xrange, Axis::EdgePair1D yrange) { _axis.addBin(xrange, yrange); } // /// @brief Bin addition operator // /// // /// Add a bin to the axis, possibly pre-populated void addBin(const Bin& bin) { _axis.addBin(bin); } /// @brief Bins addition operator /// /// Add multiple bins from edge cuts without resetting void addBins(const Axis::Edges& xcuts, const Axis::Edges& ycuts) { _axis.addBins(xcuts, ycuts); } /// @brief Bins addition operator /// /// Add multiple bins without resetting void addBins(const Bins& bins) { _axis.addBins(bins); } /// @todo TODO // /// @brief Bin addition operator // /// // /// Add a set of bins delimiting coordinates of which are contained // /// in binLimits vector. // void addBin(const std::vector<Segment>& binLimits) { // _axis.addBin(binLimits); // } void eraseBin(size_t index) { _axis.eraseBin(index); } //@} /// @name Bin accessors //@{ /// Low x edge of this histo's axis double xMin() const { return _axis.xMin(); } /// High x edge of this histo's axis double xMax() const { return _axis.xMax(); } /// Low y edge of this histo's axis double yMin() const { return _axis.yMin(); } /// High y edge of this histo's axis double yMax() const { return _axis.yMax(); } /// Access the bin vector (non-const) std::vector<YODA::ProfileBin2D>& bins() { return _axis.bins(); } /// Access the bin vector (const) const std::vector<YODA::ProfileBin2D>& bins() const { return _axis.bins(); } /// Access a bin by index (non-const) ProfileBin2D& bin(size_t index) { return _axis.bins()[index]; } /// Access a bin by index (const) const ProfileBin2D& bin(size_t index) const { return _axis.bins()[index]; } /// Access a bin index by coordinate int binIndexAt(double x, double y) { return _axis.binIndexAt(x, y); } /// Access a bin by coordinate (const) const ProfileBin2D& binAt(double x, double y) const { return _axis.binAt(x, y); } /// Number of bins of this axis (not counting under/over flow) size_t numBins() const { return _axis.bins().size(); } /// Number of bins along the x axis size_t numBinsX() const { return _axis.numBinsX(); } /// Number of bins along the y axis size_t numBinsY() const { return _axis.numBinsY(); } /// Access summary distribution, including gaps and overflows (non-const version) Dbn3D& totalDbn() { return _axis.totalDbn(); } /// Access summary distribution, including gaps and overflows (const version) const Dbn3D& totalDbn() const { return _axis.totalDbn(); } /// Set summary distribution, including gaps and overflows void setTotalDbn(const Dbn3D& dbn) { _axis.setTotalDbn(dbn); } // /// @brief Access an outflow (non-const) // /// // /// Two indices are used, for x and y: -1 = underflow, 0 = in-range, and +1 = overflow. // /// (0,0) is not a valid overflow index pair, since it is in range for both x and y. // Dbn3D& outflow(int ix, int iy) { // return _axis.outflow(ix, iy); // } // /// @brief Access an outflow (const) // /// // /// Two indices are used, for x and y: -1 = underflow, 0 = in-range, and +1 = overflow. // /// (0,0) is not a valid overflow index pair, since it is in range for both x and y. // const Dbn3D& outflow(int ix, int iy) const { // return _axis.outflow(ix, iy); // } //@} /// @name Whole histo data //@{ /// Get the number of fills unsigned long numEntries(bool includeoverflows=true) const; /// Get the effective number of fills double effNumEntries(bool includeoverflows=true) const; /// Get sum of weights in histo double sumW(bool includeoverflows=true) const; /// Get the sum of squared weights in histo double sumW2(bool includeoverflows=true) const; /// Get the mean x double xMean(bool includeoverflows=true) const; /// Get the mean y double yMean(bool includeoverflows=true) const; /// Get the variance in x double xVariance(bool includeoverflows=true) const; /// Get the variance in y double yVariance(bool includeoverflows=true) const; /// Get the standard deviation in x double xStdDev(bool includeoverflows=true) const { return std::sqrt(xVariance(includeoverflows)); } /// Get the standard deviation in y double yStdDev(bool includeoverflows=true) const { return std::sqrt(yVariance(includeoverflows)); } /// Get the standard error on <x> double xStdErr(bool includeoverflows=true) const; /// Get the standard error on <y> double yStdErr(bool includeoverflows=true) const; /// Get the RMS in x double xRMS(bool includeoverflows=true) const; /// Get the RMS in y double yRMS(bool includeoverflows=true) const; //@} /// @name Adding and subtracting histograms //@{ /// Add another profile to this one Profile2D& operator += (const Profile2D& toAdd) { if (hasAnnotation("ScaledBy")) rmAnnotation("ScaledBy"); _axis += toAdd._axis; return *this; } /// Subtract another profile from this one Profile2D& operator -= (const Profile2D& toSubtract) { if (hasAnnotation("ScaledBy")) rmAnnotation("ScaledBy"); _axis -= toSubtract._axis; return *this; } inline bool operator == (const Profile2D& other){ return _axis == other._axis; } inline bool operator != (const Profile2D& other){ return ! operator == (other); } //@}- protected: /// Access a bin by coordinate (non-const) ProfileBin2D& binAt(double x, double y) { return _axis.binAt(x, y); } private: /// @name Bin data //@{ /// The bins contained in this profile histogram Axis2D<ProfileBin2D, Dbn3D> _axis; //@} }; /// @name Combining profile histos: global operators //@{ /// Add two profile histograms inline Profile2D add(const Profile2D& first, const Profile2D& second) { Profile2D tmp = first; if (first.path() != second.path()) tmp.setPath(""); tmp += second; return tmp; } /// Add two profile histograms inline Profile2D operator + (const Profile2D& first, const Profile2D& second) { return add(first,second); } /// Subtract two profile histograms inline Profile2D subtract(const Profile2D& first, const Profile2D& second) { Profile2D tmp = first; if (first.path() != second.path()) tmp.setPath(""); tmp -= second; return tmp; } /// Subtract two profile histograms inline Profile2D operator - (const Profile2D& first, const Profile2D& second) { return subtract(first,second); } /// Divide two profile histograms Scatter3D divide(const Profile2D& numer, const Profile2D& denom); /// Divide two profile histograms inline Scatter3D operator / (const Profile2D& numer, const Profile2D& denom) { return divide(numer, denom); } //@} } #endif