|
[yoda-svn] r511 - in trunk: . include/YODA pyext/yoda pyext/yoda/include srcblackhole at projects.hepforge.org blackhole at projects.hepforge.orgMon Jul 23 14:41:42 BST 2012
Author: buckley Date: Mon Jul 23 14:41:42 2012 New Revision: 511 Log: Adding Cython mappings for Dbn3D and Profile2D, and other fixes/improvements. Added: trunk/pyext/yoda/include/20-Dbn3D.pyx Modified: trunk/ChangeLog trunk/include/YODA/Histo2D.h trunk/include/YODA/Makefile.am trunk/include/YODA/Profile2D.h trunk/include/YODA/ProfileBin2D.h trunk/pyext/yoda/Makefile.am trunk/pyext/yoda/include/20-Dbn2D.pyx trunk/pyext/yoda/include/30-ProfileBin2D.pyx trunk/pyext/yoda/include/40-Histo1D.pyx trunk/pyext/yoda/include/40-Histo2D.pyx trunk/pyext/yoda/include/40-Profile1D.pyx trunk/pyext/yoda/include/40-Profile2D.pyx trunk/pyext/yoda/shims.h trunk/src/Histo2D.cc trunk/src/Profile2D.cc Modified: trunk/ChangeLog ============================================================================== --- trunk/ChangeLog Mon Jul 23 10:50:37 2012 (r510) +++ trunk/ChangeLog Mon Jul 23 14:41:42 2012 (r511) @@ -1,3 +1,7 @@ +2012-07-23 Andy Buckley <andy.buckley at cern.ch> + + * Adding Cython mappings for Dbn3D and Profile2D, and other fixes/improvements. + 2012-07-22 Andy Buckley <andy.buckley at cern.ch> * Adding Cython mappings for Scatter3D and ProfileBin2D. Modified: trunk/include/YODA/Histo2D.h ============================================================================== --- trunk/include/YODA/Histo2D.h Mon Jul 23 10:50:37 2012 (r510) +++ trunk/include/YODA/Histo2D.h Mon Jul 23 14:41:42 2012 (r511) @@ -7,13 +7,10 @@ #define YODA_Histo2D_h #include "YODA/AnalysisObject.h" -#include "YODA/Profile1D.h" -#include "YODA/Histo1D.h" -#include "YODA/Scatter3D.h" #include "YODA/HistoBin2D.h" -#include "YODA/HistoBin1D.h" #include "YODA/Dbn2D.h" #include "YODA/Axis2D.h" +#include "YODA/Scatter3D.h" #include "YODA/Exceptions.h" #include <vector> @@ -22,15 +19,14 @@ // Forward declaration - class Scatter3D; + class Profile2D; /// Convenience typedef typedef Axis2D<HistoBin2D, Dbn2D> Histo2DAxis; - /// A one-dimensional histogram. + /// A two-dimensional histogram. class Histo2D : public AnalysisObject { - public: /// Convenience typedefs @@ -78,7 +74,13 @@ Histo2D(const Histo2D& h, const std::string& path=""); - /// @todo Add binning constructors from Scatter3D (and Profile2D?) + /// @todo Add binning constructors from Scatter3D and Profile2D? + + // /// A constructor from a Scatter3D's binning, with optional new path + // Histo2D(const Scatter3D& s, const std::string& path=""); + + // /// Constructor from a Profile2D's binning, with optional new path + // Histo2D(const Profile2D& h, const std::string& path=""); /// @brief State-setting constructor @@ -153,10 +155,6 @@ // _axis.mergeBins(from, to); // } - void eraseBin(size_t index) { - _axis.eraseBin(index); - } - /// Rebin the whole histo by a @a factorX in the X direction and /// @a factorY in the Y direction /// @todo TODO @@ -164,6 +162,10 @@ // _axis.rebin(factorX, factorY); // } + void eraseBin(size_t index) { + _axis.eraseBin(index); + } + //@} @@ -346,6 +348,12 @@ /// 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; + //@} Modified: trunk/include/YODA/Makefile.am ============================================================================== --- trunk/include/YODA/Makefile.am Mon Jul 23 10:50:37 2012 (r510) +++ trunk/include/YODA/Makefile.am Mon Jul 23 14:41:42 2012 (r511) @@ -2,13 +2,14 @@ Exceptions.h \ AnalysisObject.h \ Weights.h Bin.h \ - Dbn1D.h Dbn2D.h \ + Dbn1D.h Dbn2D.h Dbn3D.h \ Axis1D.h Bin1D.h \ Axis2D.h Bin2D.h \ Plot.h \ Histo1D.h HistoBin1D.h \ Histo2D.h HistoBin2D.h \ Profile1D.h ProfileBin1D.h \ + Profile2D.h ProfileBin2D.h \ Scatter2D.h Point2D.h \ Scatter3D.h Point3D.h \ Writer.h WriterAIDA.h WriterYODA.h \ Modified: trunk/include/YODA/Profile2D.h ============================================================================== --- trunk/include/YODA/Profile2D.h Mon Jul 23 10:50:37 2012 (r510) +++ trunk/include/YODA/Profile2D.h Mon Jul 23 14:41:42 2012 (r511) @@ -1,19 +1,23 @@ -#ifndef YODA_Profile1D_h -#define YODA_Profile1D_h +// -*- C++ -*- +// +// This file is part of YODA -- Yet more Objects for Data Analysis +// Copyright (C) 2008-2012 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/Scatter3D.h" #include "YODA/Dbn3D.h" #include "YODA/Axis2D.h" +#include "YODA/Scatter3D.h" #include "YODA/Exceptions.h" #include <vector> -#include <string> -#include <map> namespace YODA { + // Forward declarations class Histo2D; class Scatter3D; @@ -21,7 +25,8 @@ /// Convenience typedef typedef Axis2D<ProfileBin2D, Dbn3D> Profile2DAxis; - /// A one-dimensional profile histogram. + + /// A two-dimensional profile histogram. class Profile2D : public AnalysisObject { public: @@ -29,8 +34,7 @@ typedef Profile2DAxis Axis; typedef Axis::Bins Bins; typedef ProfileBin2D Bin; - typedef std::pair<double, double> Point; - typedef std::pair<Point, Point> Segment; + typedef Axis::Outflows Outflows; /// @name Constructors @@ -60,6 +64,14 @@ { } + /// 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 Profile2D(const Profile2D& p, const std::string& path=""); @@ -70,7 +82,14 @@ Profile2D(const Histo2D& h, const std::string& path=""); /// A state setting constructor - Profile2D(); + 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& p1) { @@ -141,15 +160,53 @@ // _axis.addBin(binLimits); // } + void eraseBin(size_t index) { + _axis.eraseBin(index); + } + //@} /// @name Bin accessors //@{ - /// Number of bins of this axis (not counting under/over flow) - size_t numBins() const { - return _axis.bins().size(); + /// Low x edge of this histo's axis + double lowEdgeX() const { + return _axis.lowEdgeX(); + } + /// Alias for lowEdgeX() + double xMin() const { + return lowEdgeX(); + } + + + /// Low y edge of this histo's axis + double lowEdgeY() const { + return _axis.lowEdgeY(); + } + /// Alias for lowEdgeY() + double yMin() const { + return lowEdgeY(); + } + + + /// High x edge of this histo's axis + double highEdgeX() const { + return _axis.highEdgeX(); + } + /// Alias for highEdgeX() + double xMax() const { + return highEdgeX(); + } + + + /// High y edge of this histo's axis + double highEdgeY() const { + return _axis.highEdgeY(); + } + /// Alias for highEdgeY() + double yMax() const { + return highEdgeY(); } @@ -165,22 +222,54 @@ /// 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 by x-coordinate (non-const) + /// Access a bin by coordinate (non-const) ProfileBin2D& binByCoord(double x, double y) { return _axis.binByCoord(x, y); } - /// Access a bin by x-coordinate (const) + /// Access a bin by coordinate (const) const ProfileBin2D& binByCoord(double x, double y) const { return _axis.binByCoord(x, y); } + /// Return bin index (non-const version) + int findBinIndex(double coordX, double coordY) { + return _axis.getBinIndex(coordX, coordY); + } + + /// Return bin index (const version) + const int findBinIndex(double coordX, double coordY) const { + return _axis.getBinIndex(coordX, coordY); + } + + + /// 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 + const size_t numBinsX() const { + return _axis.numBinsX(); + } + + /// Number of bins along the y axis + const size_t numBinsY() const{ + return _axis.numBinsY(); + } + + /// Access summary distribution, including gaps and overflows (non-const version) Dbn3D& totalDbn() { return _axis.totalDbn(); @@ -222,33 +311,41 @@ /// Get the sum of squared weights in histo double sumW2(bool includeoverflows=true) const; - /// @todo TODO - // /// Get the mean x - // double xMean(bool includeoverflows=true) const; + /// Get the mean x + double xMean(bool includeoverflows=true) const; - /// @todo TODO - // /// Get the mean y - // double yMean(bool includeoverflows=true) const; + /// Get the mean y + double yMean(bool includeoverflows=true) const; - /// @todo TODO - // /// Get the variance in x - // double xVariance(bool includeoverflows=true) const; + /// Get the variance in x + double xVariance(bool includeoverflows=true) const; - /// @todo TODO - // /// Get the variance in y - // double yVariance(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; /// @todo TODO - // /// Get the standard deviation in x - // double xStdDev(bool includeoverflows=true) const { - // return std::sqrt(xVariance(includeoverflows)); - // } + // /// Get the RMS in x + // double xRMS(bool includeoverflows=true) const; /// @todo TODO - // /// Get the standard deviation in y - // double yStdDev(bool includeoverflows=true) const { - // return std::sqrt(yVariance(includeoverflows)); - // } + // /// Get the RMS in y + // double yRMS(bool includeoverflows=true) const; //@} @@ -289,6 +386,7 @@ //@} }; + /// @name Combining profile histos: global operators //@{ Modified: trunk/include/YODA/ProfileBin2D.h ============================================================================== --- trunk/include/YODA/ProfileBin2D.h Mon Jul 23 10:50:37 2012 (r510) +++ trunk/include/YODA/ProfileBin2D.h Mon Jul 23 14:41:42 2012 (r511) @@ -1,3 +1,8 @@ +// -*- C++ -*- +// +// This file is part of YODA -- Yet more Objects for Data Analysis +// Copyright (C) 2008-2012 The YODA collaboration (see AUTHORS for details) +// #ifndef YODA_ProfileBin2D_h #define YODA_ProfileBin2D_h Modified: trunk/pyext/yoda/Makefile.am ============================================================================== --- trunk/pyext/yoda/Makefile.am Mon Jul 23 10:50:37 2012 (r510) +++ trunk/pyext/yoda/Makefile.am Mon Jul 23 14:41:42 2012 (r511) @@ -5,7 +5,7 @@ $(PYTHON) -m cython --cplus yoda.pyx yoda.pyx: include/00-imports.pyx include/10-AnalysisObject.pyx \ - include/20-Dbn1D.pyx include/20-Dbn2D.pyx \ + include/20-Dbn1D.pyx include/20-Dbn2D.pyx include/20-Dbn3D.pyx \ include/20-Point2D.pyx include/20-Point3D.pyx \ include/30-HistoBin1D.pyx include/30-ProfileBin1D.pyx \ include/30-HistoBin2D.pyx include/30-ProfileBin2D.pyx \ Modified: trunk/pyext/yoda/include/20-Dbn2D.pyx ============================================================================== --- trunk/pyext/yoda/include/20-Dbn2D.pyx Mon Jul 23 10:50:37 2012 (r510) +++ trunk/pyext/yoda/include/20-Dbn2D.pyx Mon Jul 23 14:41:42 2012 (r511) @@ -1,13 +1,14 @@ cdef extern from "YODA/Dbn2D.h" namespace "YODA": cdef cppclass cDbn2D "Dbn2D": cDbn2D() - cDbn2D(unsigned int numEntries, double sumW, double sumW2, double sumWX, double sumWX2, double sumWY, double sumWY2, double sumWXY) + cDbn2D(unsigned long numEntries, double sumW, double sumW2, + double sumWX, double sumWX2, double sumWY, double sumWY2, double sumWXY) void fill(double valX, double valY, double weight) void reset() void scaleW(double scalefactor) void scaleX(double factor) void scaleY(double factor) - void scaleXY(double factor) + void scaleXY(double xfactor, double yfactor) double xMean() double yMean() double xVariance() @@ -90,6 +91,8 @@ "Scale the y variable by the given factor" self.ptr().scaleY(factor) + # TODO: map scaleXY Pythonically, with list/tuple args? + @property def xMean(self): "Get the weighted mean x" Added: trunk/pyext/yoda/include/20-Dbn3D.pyx ============================================================================== --- /dev/null 00:00:00 1970 (empty, because file is newly added) +++ trunk/pyext/yoda/include/20-Dbn3D.pyx Mon Jul 23 14:41:42 2012 (r511) @@ -0,0 +1,265 @@ +cdef extern from "YODA/Dbn3D.h" namespace "YODA": + cdef cppclass cDbn3D "Dbn3D": + cDbn3D() + cDbn3D(unsigned long numEntries, double sumW, double sumW2, + double sumWX, double sumWX2, double sumWY, double sumWY2, double sumWZ, double sumWZ2, + double sumWXY, double sumWXZ, double sumWYZ, double sumWXYZ) + void fill(double valX, double valY, double valZ, double weight) + void reset() + void scaleW(double scalefactor) + void scaleX(double factor) + void scaleY(double factor) + void scaleZ(double factor) + void scaleXY(double xfactor, double yfactor) + void scaleXZ(double xfactor, double zfactor) + void scaleYZ(double yfactor, double zfactor) + void scaleXYZ(double xfactor, double yfactor, double zfactor) + double xMean() + double yMean() + double zMean() + double xVariance() + double yVariance() + double zVariance() + double xStdDev() + double yStdDev() + double zStdDev() + double xStdErr() + double yStdErr() + double zStdErr() + double xRMS() + double yRMS() + double zRMS() + unsigned long numEntries() + double effNumEntries() + double sumW() + double sumW2() + double sumWX() + double sumWX2() + double sumWY() + double sumWY2() + double sumWZ() + double sumWZ2() + double sumWXY() + double sumWXZ() + double sumWYZ() + double sumWXYZ() + # TODO: map operator+ and operator-, both internal and external + + +cdef class Dbn3D: + """ + A 2D distribution 'counter', used and exposed by 1D histograms and their bins. + + TODO: Allow no-arg construction? + TODO: map operator+ and operator-, both internal and external + """ + + cdef cDbn3D* thisptr + cdef bool _dealloc + + def __cinit__(self): + self._dealloc = False + + def __dealloc__(self): + if self._dealloc: + del self.thisptr + + + def __init__(self, *args, **kwargs): + cdef: + unsigned int numEntries + double sumW, sumW2, sumWX, sumWX2, sumWY, sumWY2, sumWZ, sumWZ2, sumWXY, sumWXZ, sumWYZ, sumWXYZ + assert len(args) == 13 + numEntries, sumW, sumW2, sumWX, sumWX2, sumWY, sumWY2, sumWZ, sumWZ2, sumWXY, sumWXZ, sumWYZ, sumWXYZ = args + self.setptr(new cDbn3D(numEntries, sumW, sumW2, sumWX, sumWX2, sumWY, sumWY2, sumWZ, sumWZ2, sumWXY, sumWXZ, sumWYZ, sumWXYZ), True) + + + cdef Dbn3D setptr(self, cDbn3D *ptr, bool dealloc): + if self._dealloc: + del self.thisptr + + self.thisptr = ptr + self._dealloc = dealloc + return self + + cdef cDbn3D* ptr(self): + return self.thisptr + + + def fill(self, double x, double y, double z, double weight=1.0): + "Fill the distribution with the given z and weight at given x and y." + self.ptr().fill(x, y, z, weight) + + def reset(self): + "Reset the distribution counters to the unfilled state." + self.ptr().reset() + + def scaleW(self, scalefactor): + "Scale the fill weights by the given factor" + self.ptr().scaleW(scalefactor) + + def scaleX(self, factor): + "Scale the x variable by the given factor" + self.ptr().scaleX(factor) + + def scaleY(self, factor): + "Scale the y variable by the given factor" + self.ptr().scaleY(factor) + + def scaleZ(self, factor): + "Scale the z variable by the given factor" + self.ptr().scaleZ(factor) + + # TODO: map scaleXY etc. -- Pythonically, with list/tuple args? + + @property + def xMean(self): + "Get the weighted mean x" + return self.ptr().xMean() + + @property + def yMean(self): + "Get the weighted mean y" + return self.ptr().yMean() + + @property + def zMean(self): + "Get the weighted mean z" + return self.ptr().zMean() + + @property + def xVariance(self): + "Get the weighted variance of x" + return self.ptr().xVariance() + + @property + def yVariance(self): + "Get the weighted variance of y" + return self.ptr().yVariance() + + @property + def zVariance(self): + "Get the weighted variance of z" + return self.ptr().zVariance() + + @property + def xStdDev(self): + "Get the weighted standard deviation of x" + return self.ptr().xStdDev() + + @property + def yStdDev(self): + "Get the weighted standard deviation of y" + return self.ptr().yStdDev() + + @property + def zStdDev(self): + "Get the weighted standard deviation of z" + return self.ptr().zStdDev() + + @property + def xStdErr(self): + "Get the weighted standard error on <x>" + return self.ptr().xStdDev() + + @property + def yStdErr(self): + "Get the weighted standard error on <y>" + return self.ptr().yStdDev() + + @property + def zStdErr(self): + "Get the weighted standard error on <z>" + return self.ptr().zStdDev() + + @property + def xRMS(self): + "Get the weighted RMS of x" + return self.ptr().xRMS() + + @property + def yRMS(self): + "Get the weighted RMS of y" + return self.ptr().yRMS() + + @property + def zRMS(self): + "Get the weighted RMS of z" + return self.ptr().zRMS() + + @property + def numEntries(self): + "Get the number of entries" + return self.ptr().numEntries() + + @property + def effNumEntries(self): + "Get the effective number of entries (for weighted events)" + return self.ptr().effNumEntries() + + @property + def sumW(self): + "Get the sum of weights" + return self.ptr().sumW() + + @property + def sumW2(self): + "Get the sum of squared-weights" + return self.ptr().sumW2() + + @property + def sumWX(self): + "Get the sum of weighted xs" + return self.ptr().sumWX() + + @property + def sumWX2(self): + "Get the sum of weighted squared-xs" + return self.ptr().sumWX2() + + @property + def sumWY(self): + "Get the sum of weighted ys" + return self.ptr().sumWY() + + @property + def sumWY2(self): + "Get the sum of weighted squared-ys" + return self.ptr().sumWY2() + + @property + def sumWZ(self): + "Get the sum of weighted zs" + return self.ptr().sumWZ() + + @property + def sumWZ2(self): + "Get the sum of weighted squared-zs" + return self.ptr().sumWZ2() + + @property + def sumWXY(self): + "Get the sum of weighted (x*y)s" + return self.ptr().sumWXY() + + @property + def sumWXZ(self): + "Get the sum of weighted (x*z)s" + return self.ptr().sumWXZ() + + @property + def sumWYZ(self): + "Get the sum of weighted (y*z)s" + return self.ptr().sumWYZ() + + @property + def sumWXYZ(self): + "Get the sum of weighted (x*y*z)s" + return self.ptr().sumWXYZ() + + +cdef Dbn3D Dbn3D_fromptr(cDbn3D *ptr, dealloc=False): + # Construct a Python Dbn3D from a pointer to a cDbn3D, + # without calling __init__ and excessive memory allocation + cdef Dbn3D dbn = Dbn3D.__new__(Dbn3D) + return dbn.setptr(ptr, dealloc) Modified: trunk/pyext/yoda/include/30-ProfileBin2D.pyx ============================================================================== --- trunk/pyext/yoda/include/30-ProfileBin2D.pyx Mon Jul 23 10:50:37 2012 (r510) +++ trunk/pyext/yoda/include/30-ProfileBin2D.pyx Mon Jul 23 14:41:42 2012 (r511) @@ -224,3 +224,9 @@ def __repr__(self): return 'ProfileBin2D(%r)' % self.volume + +cdef ProfileBin2D ProfileBin2D_fromptr(cProfileBin2D *ptr, dealloc=False): + # Construct a Python ProfileBin2D from a pointer to a cProfileBin2D, + # without calling __init__ and excessive memory allocation + cdef ProfileBin2D bin = ProfileBin2D.__new__(ProfileBin2D) + return bin.setptr(ptr, dealloc) Modified: trunk/pyext/yoda/include/40-Histo1D.pyx ============================================================================== --- trunk/pyext/yoda/include/40-Histo1D.pyx Mon Jul 23 10:50:37 2012 (r510) +++ trunk/pyext/yoda/include/40-Histo1D.pyx Mon Jul 23 14:41:42 2012 (r511) @@ -241,9 +241,9 @@ @property def totalDbn(self): """ - h.totalDbn -> Distribution1D + h.totalDbn -> Dbn1D - Return the Distribution1D object representing the total distribution. + Return the Dbn1D object representing the total distribution. """ return Dbn1D_fromptr(&self.ptr().totalDbn()) @@ -252,9 +252,9 @@ @property def underflow(self): """ - h.underflow -> Distribution1D + h.underflow -> Dbn1D - Return the Distribution1D object representing the underflow. + Return the Dbn1D object representing the underflow. """ return Dbn1D_fromptr(&self.ptr().underflow()) @@ -263,9 +263,9 @@ @property def overflow(self): """ - h.overflow -> Distribution1D + h.overflow -> Dbn1D - Return the Distribution1D object representing the overflow. + Return the Dbn1D object representing the overflow. """ return Dbn1D_fromptr(&self.ptr().overflow()) Modified: trunk/pyext/yoda/include/40-Histo2D.pyx ============================================================================== --- trunk/pyext/yoda/include/40-Histo2D.pyx Mon Jul 23 10:50:37 2012 (r510) +++ trunk/pyext/yoda/include/40-Histo2D.pyx Mon Jul 23 14:41:42 2012 (r511) @@ -32,11 +32,12 @@ cDbn2D& totalDbn() vector[cHistoBin2D]& bins() + int findBinIndex(double coordX, double coordY) cHistoBin2D& binByCoord(double x, double y) - cHistoBin2D& bin(size_t i) void eraseBin(size_t i) + # Statistical functions double integral(bool includeoverflows) double sumW(bool includeoverflows) Modified: trunk/pyext/yoda/include/40-Profile1D.pyx ============================================================================== --- trunk/pyext/yoda/include/40-Profile1D.pyx Mon Jul 23 10:50:37 2012 (r510) +++ trunk/pyext/yoda/include/40-Profile1D.pyx Mon Jul 23 14:41:42 2012 (r511) @@ -229,9 +229,9 @@ @property def totalDbn(self): """ - h.totalDbn -> Distribution1D + h.totalDbn -> Dbn2D - Return the Distribution1D object representing the total distribution. + Return the Dbn2D object representing the total distribution. """ return Dbn2D_fromptr(&self.ptr().totalDbn()) @@ -240,9 +240,9 @@ @property def underflow(self): """ - h.underflow -> Distribution1D + h.underflow -> Dbn2D - Return the Distribution1D object representing the underflow. + Return the Dbn2D object representing the underflow. """ return Dbn2D_fromptr(&self.ptr().underflow()) @@ -251,9 +251,9 @@ @property def overflow(self): """ - h.overflow -> Distribution1D + h.overflow -> Dbn2D - Return the Distribution1D object representing the overflow. + Return the Dbn2D object representing the overflow. """ return Dbn2D_fromptr(&self.ptr().overflow()) Modified: trunk/pyext/yoda/include/40-Profile2D.pyx ============================================================================== --- trunk/pyext/yoda/include/40-Profile2D.pyx Mon Jul 23 10:50:37 2012 (r510) +++ trunk/pyext/yoda/include/40-Profile2D.pyx Mon Jul 23 14:41:42 2012 (r511) @@ -1,691 +1,321 @@ -# cdef extern from "YODA/Histo2D.h" namespace "YODA": -# #cHisto2D operator + (cHisto2D &, cHisto2D &) -# #cHisto2D operator - (cHisto2D &, cHisto2D &) +cdef extern from "YODA/Profile2D.h" namespace "YODA": + #cProfile2D operator + (cProfile2D &, cProfile2D &) + #cProfile2D operator - (cProfile2D &, cProfile2D &) -# cdef cppclass cHisto2D "YODA::Histo2D"(cAnalysisObject): -# cHisto2D() -# cHisto2D(string& path, string& title) -# cHisto2D(size_t nbinsX, double lowerX, double upperX, -# size_t nbinsY, double lowerY, double upperY, -# string& path, string& title) -# cHisto2D(vector[cHistoBin2D]&, string& path, string& title) -# cHisto2D(vector[double]& xedges, vector[double]& yedges, string& path, string& title) -# cHisto2D(cHisto2D& h) + cdef cppclass cProfile2D "YODA::Profile2D"(cAnalysisObject): + cProfile2D() + cProfile2D(string& path, string& title) + cProfile2D(size_t nbinsX, double lowerX, double upperX, + size_t nbinsY, double lowerY, double upperY, + string& path, string& title) + cProfile2D(vector[cProfileBin2D]&, string& path, string& title) + cProfile2D(vector[double]& xedges, vector[double]& yedges, string& path, string& title) + cProfile2D(cProfile2D& h) -# void fill(double x, double y, double weight) -# void reset() -# void scaleW(double scalefactor) -# void scaleXY(double scaleX, double scaleY) -# # void mergeBins(size_t a, size_t b) -# # void rebin(int a, int b) + void fill(double x, double y, double z, double weight) + void reset() + void scaleW(double scalefactor) + void scaleXY(double scaleX, double scaleY) + # void mergeBins(size_t a, size_t b) + # void rebin(int a, int b) -# # Bin Accessors -# size_t numBins() -# size_t numBinsX() -# size_t numBinsY() + # Bin Accessors + size_t numBins() + size_t numBinsX() + size_t numBinsY() -# double lowEdgeX() -# double lowEdgeY() -# double highEdgeX() -# double highEdgeY() -# cDbn2D& outflow(int ix, int iy) -# cDbn2D& totalDbn() + double lowEdgeX() + double lowEdgeY() + double highEdgeX() + double highEdgeY() + cDbn3D& outflow(int ix, int iy) + cDbn3D& totalDbn() -# vector[cHistoBin2D]& bins() -# cHistoBin2D& binByCoord(double x, double y) + vector[cProfileBin2D]& bins() + int findBinIndex(double coordX, double coordY) + cProfileBin2D& binByCoord(double x, double y) + cProfileBin2D& bin(size_t i) + void eraseBin(size_t i) -# cHistoBin2D& bin(size_t i) -# void eraseBin(size_t i) + # Statistical functions + double sumW(bool includeoverflows) + double sumW2(bool includeoverflows) -# # Statistical functions -# double integral(bool includeoverflows) -# double sumW(bool includeoverflows) -# double sumW2(bool includeoverflows) + double xMean(bool includeoverflows) + double yMean(bool includeoverflows) -# double xMean(bool includeoverflows) -# double yMean(bool includeoverflows) + double xVariance(bool includeoverflows) + double yVariance(bool includeoverflows) -# double xVariance(bool includeoverflows) -# double yVariance(bool includeoverflows) + double xStdDev(bool includeoverflows) + double yStdDev(bool includeoverflows) -# double xStdDev(bool includeoverflows) -# double yStdDev(bool includeoverflows) + double xStdErr(bool includeoverflows) + double yStdErr(bool includeoverflows) -# double xStdErr(bool includeoverflows) -# double yStdErr(bool includeoverflows) +cdef class Profile2D(AnalysisObject): + """ + 2D profile histogram. Basic histogramming is currently supported, i.e. a + two-dimensional bin layout may be specified, filled, and queried. Outflow + distributions around the 8 sides and corners of the grid are supported, and + the bins need not be regularly sized or contiguous: bins which span rows + and/or columns, and gaps between bins are permitted. -# cdef class Histo2D(AnalysisObject): -# """ -# 2D histogram. Basic histogramming is currently supported, i.e. a two-dimensional bin layout -# may be specified, filled, and queried. Outflow distributions around the 8 sides and -# corners of the grid are supported, and the bins need not be regularly sized or contiguous: -# bins which span rows and/or columns, and gaps between bins are permitted. + TODO: Bin merging/rebinning is not currently supported (the algorithm has to + be a bit more complex than usual due to the increased number of ways for it + to not work if the bin shapes are irregular.) -# TODO: Bin merging/rebinning is not currently supported (the algorithm has to -# be a bit more complex than usual due to the increased number of ways for it -# to not work if the bin shapes are irregular.) + Rescaling of weights and/or the x and y axes is permitted in-place: the result + is a still-valid Profile2D. Binning-compatible 2D histograms may be + divided, resulting in a Scatter3D rather than a Profile2D, since further + fills would not be meaningful. -# Rescaling of weights and/or the x and y axes is permitted in-place: the result -# is a still-valid Histo2D. Binning-compatible 2D histograms may be -# divided, resulting in a Scatter3D rather than a Histo2D, since further -# fills would not be meaningful. + Several sets of arguments are permitted to the constructor: -# Several sets of arguments are permitted to the constructor: + * Profile2D() -- default constructor. Not usually useful in Python, due to availability of None. + * Profile2D(bins[, path, title]) -- constructor from a list of bins. + * Profile2D(nx, xlow, xhigh, ny, ylow, yhigh[, path, title]) -- construct a uniform bin grid in both x and y directions. + * Profile2D(xedges, yedges[, path, title]) -- make a regular bin grid with given bin edges in x and y. -# * Histo2D() -- default constructor. Not usually useful in Python, due to availability of None. -# * Histo2D(bins[, path, title]) -- constructor from a list of bins. -# * Histo2D(nx, xlow, xhigh, ny, ylow, yhigh[, path, title]) -- construct a uniform bin grid in both x and y directions. -# * Histo2D(xedges, yedges[, path, title]) -- make a regular bin grid with given bin edges in x and y. + The path and title arguments are optional, and may either be specified via the + positional parameters or via explicit keyword arguments, e.g. path='/foo/bar'. -# The path and title arguments are optional, and may either be specified via the -# positional parameters or via explicit keyword arguments, e.g. path='/foo/bar'. + TODO: Add constructors from Scatter and Histo2D + TODO: Support adding and erasing bins + TODO: Support add, mul, div operators + """ -# TODO: Add constructors from Scatter and Profile -# TODO: Support adding and erasing bins -# TODO: Support add, mul, div operators -# """ + def __cinit__(self): + self._dealloc = False -# def __cinit__(self): -# self._dealloc = False + def __init__(self, *args, **kwargs): + cdef: + size_t nbinsX, nbinsY + double lowX, highX, lowY, highY + ProfileBin2D item + vector[cProfileBin2D] bin_vector + vector[double] xedges + vector[double] yedges + char* path = '/' + char* title = '' -# def __init__(self, *args, **kwargs): -# cdef: -# size_t nbinsX, nbinsY -# double lowX, highX, lowY, highY -# HistoBin2D item -# vector[cHistoBin2D] bin_vector -# vector[double] xedges -# vector[double] yedges -# char* path = '/' -# char* title = '' + ## Permit path and title specification via kwargs + if "path" in kwargs: + path = kwargs["path"] + if "title" in kwargs: + title = kwargs["title"] -# ## Permit path and title specification via kwargs -# if "path" in kwargs: -# path = kwargs["path"] -# if "title" in kwargs: -# title = kwargs["title"] + # TODO: Map copy constructor -# # TODO: Map copy constructor + if len(args) == 0: + self.setptr(new cProfile2D(string(path), string(title)), True) + elif len(args) == 1: + # Profile2D(bins[, path, title]) + for b in args[0]: + item = b + bin_vector.push_back( item.ptr()[0] ) + self.setptr(new cProfile2D(bin_vector, string(path), string(title))) + elif len(args) == 2: + # Profile2D(xedges, yedges[, path, title]) + for x in args[0]: + xedges.push_back(x) + for y in args[1]: + yedges.push_back(y) + self.setptr(new cProfile2D(xedges, yedges, string(path), string(title))) + elif len(args) == 6: + # Profile2D(nx, xlow, xhigh, ny, ylow, yhigh[, path, title]) -- construct a uniform bin grid in both x and y directions. + nbinsX, lowX, highX, nbinsY, lowY, highY = args + self.setptr(new cProfile2D(nbinsX, lowX, highX, nbinsY, lowY, highY, + string(path), string(title)), True) -# if len(args) == 0: -# self.setptr(new cHisto2D(string(path), string(title)), True) -# elif len(args) == 1: -# # Histo2D(bins[, path, title]) -# for b in args[0]: -# item = b -# bin_vector.push_back( item.ptr()[0] ) -# self.setptr(new cHisto2D(bin_vector, string(path), string(title))) -# elif len(args) == 2: -# # Histo2D(xedges, yedges[, path, title]) -# for x in args[0]: -# xedges.push_back(x) -# for y in args[1]: -# yedges.push_back(y) -# self.setptr(new cHisto2D(xedges, yedges, string(path), string(title))) -# elif len(args) == 6: -# # Histo2D(nx, xlow, xhigh, ny, ylow, yhigh[, path, title]) -- construct a uniform bin grid in both x and y directions. -# nbinsX, lowX, highX, nbinsY, lowY, highY = args -# self.setptr(new cHisto2D(nbinsX, lowX, highX, nbinsY, lowY, highY, -# string(path), string(title)), True) + cdef cProfile2D* ptr(self): + return <cProfile2D *> self.thisptr -# cdef cHisto2D* ptr(self): -# return <cHisto2D *> self.thisptr + def fill(self, double x, double y, double z, double weight=1.0): + "Fill the bin at (x, y) with the given z value and weight" + self.ptr().fill(x, y, z, weight) -# def fill(self, double x, double y, double weight=1.0): -# "Fill the bin at (x, y) with the given weight" -# self.ptr().fill(x, y, weight) + def reset(self): + """Reset the histogram counters but leave the bin structure""" + self.ptr().reset() -# def reset(self): -# """Reset the histogram counters but leave the bin structure""" -# self.ptr().reset() + def scaleW(self, double factor): + """Scale the histogram and its statistics by the given factor""" + self.ptr().scaleW(factor) -# def scaleW(self, double factor): -# """Scale the histogram and its statistics by the given factor""" -# self.ptr().scaleW(factor) + # def mergeBins(self, size_t a, size_t b): + # self.ptr().mergeBins(a, b) -# # def mergeBins(self, size_t a, size_t b): -# # self.ptr().mergeBins(a, b) + # def rebin(self, int a, int b): + # self.ptr().rebin(a, b) -# # def rebin(self, int a, int b): -# # self.ptr().rebin(a, b) + @property + def bins(self): + "Access the bins" + cdef size_t i + return tuple(ProfileBin2D_fromptr(&self.ptr().bin(i)) for i in xrange(self.ptr().numBins())) -# @property -# def bins(self): -# "Access the bins" -# cdef size_t i -# return tuple(HistoBin2D_fromptr(&self.ptr().bin(i)) for i in xrange(self.ptr().numBins())) + @property + def lowEdgeX(self): + "The lower bound of the histogram bin range in x" + return self.ptr().lowEdgeX() -# @property -# def lowEdgeX(self): -# "The lower bound of the histogram bin range in x" -# return self.ptr().lowEdgeX() + @property + def lowEdgeY(self): + "The lower bound of the histogram bin range in y" + return self.ptr().lowEdgeY() -# @property -# def lowEdgeY(self): -# "The lower bound of the histogram bin range in y" -# return self.ptr().lowEdgeY() + @property + def highEdgeX(self): + "The upper bound of the histogram bin range in x" + return self.ptr().highEdgeX() -# @property -# def highEdgeX(self): -# "The upper bound of the histogram bin range in x" -# return self.ptr().highEdgeX() + @property + def highEdgeY(self): + "The upper bound of the histogram bin range in y" + return self.ptr().highEdgeY() -# @property -# def highEdgeY(self): -# "The upper bound of the histogram bin range in y" -# return self.ptr().highEdgeY() + @property + def totalDbn(self): + """ + h.totalDbn -> Dbn3D -# @property -# def totalDbn(self): -# """ -# h.totalDbn -> Dbn2D + Return the Dbn3D object representing the total distribution. -# Return the Dbn2D object representing the total distribution. + """ + return Dbn3D_fromptr(&self.ptr().totalDbn()) -# """ -# return Dbn2D_fromptr(&self.ptr().totalDbn()) + def outflow(self, ix, iy): + """ + h.outflow(ix, iy) -> Dbn3D -# def outflow(self, ix, iy): -# """ -# h.outflow(ix, iy) -> Dbn2D + Return the Dbn3D object representing the outflow in the (ix,iy) + direction, where ix, iy = {-1, 0, 1}. + """ + return Dbn3D_fromptr(&self.ptr().outflow(ix, iy)) -# Return the Dbn2D object representing the outflow in the (ix,iy) -# direction, where ix, iy = {-1, 0, 1}. -# """ -# return Dbn2D_fromptr(&self.ptr().outflow(ix, iy)) + def __delitem__(self, size_t ix): + self.ptr().eraseBin(ix) -# def __delitem__(self, size_t ix): -# self.ptr().eraseBin(ix) + def __getitem__(self, size_t ix): + return ProfileBin2D().set(self.ptr().bins()[ix]) -# def __getitem__(self, size_t ix): -# return HistoBin2D().set(self.ptr().bins()[ix]) + def sumW(self, bool overflows=True): + """ + h.sumW([bool overflows=True] -> float + Get the weight integral of the histo, with an optional bool argument to + decide whether the bin-range overflows are to be included. + """ + return self.ptr().sumW(overflows) -# def integral(self, bool overflows=True): -# """ -# h.integral([bool overflows=True] -> float -# Get the integral of the histo, with an optional bool argument to decide -# whether the bin-range overflows are to be included. Effectively a -# synonym for sumW. -# """ -# return self.ptr().integral(overflows) + def sumW2(self, bool overflows=True): + """ + h.sumW2([bool overflows=True] -> float + Get the weight**2 integral of the histo, with an optional bool argument + to decide whether the bin-range overflows are to be included. + """ + return self.ptr().sumW2(overflows) -# def sumW(self, bool overflows=True): -# """ -# h.sumW([bool overflows=True] -> float -# Get the weight integral of the histo, with an optional bool argument to -# decide whether the bin-range overflows are to be included. -# """ -# return self.ptr().sumW(overflows) + def mean(self, bool overflows=True): + """ + h.mean([bool overflows=True] -> (float, float) + Get the mean (x,y) point for this histo, with an optional bool argument + to decide whether the bin-range overflows are to be included. + """ + cdef cProfile2D *s = self.ptr() + return (s.xMean(overflows), s.yMean(overflows)) -# def sumW2(self, bool overflows=True): -# """ -# h.sumW2([bool overflows=True] -> float -# Get the weight**2 integral of the histo, with an optional bool argument -# to decide whether the bin-range overflows are to be included. -# """ -# return self.ptr().sumW2(overflows) + def variance(self, bool overflows=True): + """ + h.variance([bool overflows=True] -> (float, float) + Get the (x,y) variances for this histo, with an optional bool argument + to decide whether the bin-range overflows are to be included. + """ + cdef cProfile2D *s = self.ptr() + return (s.xVariance(overflows), s.yVariance(overflows)) -# def mean(self, bool overflows=True): -# """ -# h.mean([bool overflows=True] -> (float, float) -# Get the mean (x,y) point for this histo, with an optional bool argument -# to decide whether the bin-range overflows are to be included. -# """ -# cdef cHisto2D *s = self.ptr() -# return (s.xMean(overflows), s.yMean(overflows)) + def stdDev(self, bool overflows=True): + """ + h.stdDev([bool overflows=True] -> (float, float) + Get the (x,y) standard deviations for this histo, with an optional bool + argument to decide whether the bin-range overflows are to be included. + """ + cdef cProfile2D *s = self.ptr() + return (s.xStdDev(overflows), s.yStdDev(overflows)) -# def variance(self, bool overflows=True): -# """ -# h.variance([bool overflows=True] -> (float, float) -# Get the (x,y) variances for this histo, with an optional bool argument -# to decide whether the bin-range overflows are to be included. -# """ -# cdef cHisto2D *s = self.ptr() -# return (s.xVariance(overflows), s.yVariance(overflows)) + def stdErr(self, bool overflows=True): + """ + h.stdErr([bool overflows=True] -> (float, float) + Get the (x,y) standard errors on the mean for this histo, with an + optional bool argument to decide whether the bin-range overflows are to + be included. + """ + cdef cProfile2D *s = self.ptr() + return (s.xStdErr(overflows), s.yStdErr(overflows)) -# def stdDev(self, bool overflows=True): -# """ -# h.stdDev([bool overflows=True] -> (float, float) -# Get the (x,y) standard deviations for this histo, with an optional bool -# argument to decide whether the bin-range overflows are to be included. -# """ -# cdef cHisto2D *s = self.ptr() -# return (s.xStdDev(overflows), s.yStdDev(overflows)) + # def __add__(Profile2D a, Profile2D b): + # cdef cProfile2D *res + # res = new cProfile2D(a.ptr()[0] + b.ptr()[0]) + # return Profile2D().setptr(res) -# def stdErr(self, bool overflows=True): -# """ -# h.stdErr([bool overflows=True] -> (float, float) -# Get the (x,y) standard errors on the mean for this histo, with an -# optional bool argument to decide whether the bin-range overflows are to -# be included. -# """ -# cdef cHisto2D *s = self.ptr() -# return (s.xStdErr(overflows), s.yStdErr(overflows)) + # def __sub__(Profile2D a, Profile2D b): + # cdef cProfile2D *res + # res = new cProfile2D(a.ptr()[0] - b.ptr()[0]) + # return Profile2D().setptr(res) + # def __mul__(x, y): + # cdef cProfile2D *res + # tx, ty = type(x), type(y) + # if (tx is int or tx is float) and ty is Profile2D: + # histo = <Profile2D> y; factor = <Profile2D> x + # elif tx is Profile2D and (ty is int or ty is float): + # histo = <Profile2D> x; factor = <Profile2D> y + # else: + # raise RuntimeError('Cannot multiply %r by %r' % (tx, ty)) -# # def __add__(Histo2D a, Histo2D b): -# # cdef cHisto2D *res -# # res = new cHisto2D(a.ptr()[0] + b.ptr()[0]) -# # return Histo2D().setptr(res) + # res = new cProfile2D(histo.ptr()[0]) + # res.scaleW(factor) + # return Profile2D().setptr(res) -# # def __sub__(Histo2D a, Histo2D b): -# # cdef cHisto2D *res -# # res = new cHisto2D(a.ptr()[0] - b.ptr()[0]) -# # return Histo2D().setptr(res) + def __repr__(self): + return 'Profile2D%r' % self.bins -# # def __mul__(x, y): -# # cdef cHisto2D *res -# # tx, ty = type(x), type(y) -# # if (tx is int or tx is float) and ty is Histo2D: -# # histo = <Histo2D> y; factor = <Histo2D> x -# # elif tx is Histo2D and (ty is int or ty is float): -# # histo = <Histo2D> x; factor = <Histo2D> y -# # else: -# # raise RuntimeError('Cannot multiply %r by %r' % (tx, ty)) - -# # res = new cHisto2D(histo.ptr()[0]) -# # res.scaleW(factor) -# # return Histo2D().setptr(res) - - -# def __repr__(self): -# return 'Histo2D%r' % self.bins - - -# cdef Histo2D Histo2D_fromptr(cHisto2D *ptr, dealloc=False): -# # Construct a Python Histo2D from a pointer to a cHisto2D, -# # without calling __init__ and excessive memory allocation -# cdef Histo2D bin = Histo2D.__new__(Histo2D) -# return bin.setptr(ptr, dealloc) -# cdef extern from "YODA/Profile1D.h" namespace "YODA": - -# cdef cppclass cProfile1D "YODA::Profile1D"(cAnalysisObject): -# cProfile1D() -# cProfile1D(size_t nbins, double lower, double upper, string& path, string& title) -# cProfile1D(vector[double]& binedges, string& path, string& title) -# cProfile1D(cProfile1D& h, string& path) -# cProfile1D(cProfile1D& h) - -# void fill(double x, double y, double weight) -# void reset() -# void scaleW(double scalefactor) -# void mergeBins(size_t a, size_t b) -# void rebin(int n) - -# # Bin Accessors -# size_t numBins() -# double lowEdge() -# double highEdge() - -# vector[cProfileBin1D]& bins() -# cProfileBin1D& bin(size_t i) -# void eraseBin(size_t i) - -# cDbn2D& totalDbn() -# cDbn2D& underflow() -# cDbn2D& overflow() -# void addBin(double low, double high) -# void addBins(vector[double]& binedges) - -# # Statistical functions -# #double integral(bool includeoverflows) -# #double integral(size_t a, size_t b) -# double sumW(bool includeoverflows) -# double sumW2(bool includeoverflows) - -# cProfile1D add(cProfile1D &, cProfile1D &) -# cProfile1D subtract(cProfile1D &, cProfile1D &) -# cScatter2D divide(cProfile1D &, cProfile1D &) -# #cScatter2D mkScatter(cProfile1D &) - -# cdef extern from "YODA/Scatter2D.h" namespace "YODA": -# cScatter2D mkScatter(cProfile1D &) - - - -# cdef class Profile1D(AnalysisObject): -# """ -# 1D profile histogram. Complete histogramming is supported, including -# uniform/regular binning, variable width binning, unbinned gaps in the -# covered range, and under/overflows (including the gaps). Rebinning by -# integer factors, or by explicit merging of contiguous bins is also -# supported. - -# Rescaling of weights and/or the x axis is permitted in-place: the result -# is a still-valid Profile1D. Binning-compatible 2D profiles may be -# divided, resulting in a Scatter2D rather than a Profile1D, since further -# fills would not be meaningful. - -# Several sets of arguments are permitted to the constructor: - -# * Profile1D() -- default constructor. Not usually useful in Python, due to availability of None. -# * Profile1D(nbins, low, high[, path, title]) -- linear binning with n bins between low-high. -# * Profile1D(binedges[, path, title]) -- explicit bin edges (no bin gaps) - -# The path and title arguments are optional, and may either be specified via the -# positional parameters or via explicit keyword arguments, e.g. path='/foo/bar'. - -# TODO: Add constructors from Scatter and Histo -# TODO: Support addBin, addBins, eraseBin -# """ - -# def __init__(self, *args, **kwargs): -# self._dealloc = True -# cdef: -# size_t nbins -# double lower -# double upper -# vector[double] binedges -# char* path = '/' -# char* title = '' - -# ## Permit path and title specification via kwargs -# if "path" in kwargs: -# path = kwargs["path"] -# if "title" in kwargs: -# path = kwargs["title"] - -# ## Trigger different C++ constructors depending on Python args -# # TODO: Map copy constructors, esp. the path-resetting one -# if len(args) == 0: -# self.setptr(new cProfile1D()) -# else: -# if type(args[0]) is list: -# try: -# for i in args[0]: -# binedges.push_back(float(i)) -# except: -# raise Exception("Invalid binedges container supplied to Profile1D constructor") -# if len(args) >= 2: -# assert "path" not in kwargs -# path = args[1] -# if len(args) == 3: -# assert "title" not in kwargs -# path = args[2] -# if len(args) > 3: -# raise ValueError("Too many arguments supplied to Profile1D constructor with a binedge list first arg") -# self.setptr(new cProfile1D(binedges, string(path), string(title))) -# else: -# assert len(args) >= 3 -# nbins, lower, upper = args[0:3] -# if len(args) >= 4: -# assert "path" not in kwargs -# path = args[3] -# if len(args) == 5: -# assert "title" not in kwargs -# path = args[4] -# if len(args) > 5: -# raise ValueError("Too many arguments supplied to Profile1D constructor") -# self.setptr(new cProfile1D(nbins, lower, upper, string(path), string(title))) - - -# cdef cProfile1D* ptr(self): -# return <cProfile1D *> self.thisptr - - -# def asScatter(self): -# """ -# h.asScatter() -> Scatter2D - -# Return a 2D scatter data object from the profile's bins and heights. - -# """ -# cdef cScatter2D *s = new cScatter2D() -# s[0] = mkScatter(self.ptr()[0]) -# return Scatter2D_fromptr(s, True) - - -# def fill(self, double x, double y, double weight=1.0): -# """ -# h.fill(x, y[, weight=1.0]) -> self - -# Fill the given profile with value y at position x, and optional weighting. - -# """ -# self.ptr().fill(x, y, weight) -# return self - - -# def reset(self): -# """ -# h.reset() -> self - -# Reset the histogram but leave the bin structure - -# """ -# self.ptr().reset() -# return self - - -# def scaleW(self, double factor): -# """ -# s.scaleW(factor) -> self - -# Scale the histogram and its statistics by given factor - -# """ -# self.ptr().scaleW(factor) -# return self - - -# def mergeBins(self, size_t a, size_t b): -# """ -# s.mergeBins(from, to) -> self - -# Merge bins between indexes from `from` to `to` - -# """ -# self.ptr().mergeBins(a, b) - - -# def rebin(self, int n): -# """ -# s.rebin(n) -> self - -# Merge every nth bin in the current histogram. - -# """ -# self.ptr().rebin(n) - - -# @property -# def bins(self): -# """ -# h.bins -> tuple(ProfileBin1D) - -# Access the bin objects of this histogram. Bin objects are mutable and -# changes to the bin objects will be propagated back to the histogram -# unless the copy() method is called on a bin. - -# """ -# cdef size_t i -# # cdef ProfileBin1D bin -# return tuple(ProfileBin1D_fromptr(& self.ptr().bin(i)) for i in xrange(self.ptr().numBins())) - - -# @property -# def lowEdge(self): -# """ -# h.lowEdge -> float - -# The x-value of the lowest edge of the lowest bin of the histogram. - -# """ -# return self.ptr().lowEdge() - - -# @property -# def highEdge(self): -# """ -# h.highEdge -> float - -# The x-value of the highest edge of the highest bin of the histogram. - -# """ -# return self.ptr().highEdge() - - -# @property -# def totalDbn(self): -# """ -# h.totalDbn -> Distribution1D - -# Return the Distribution1D object representing the total distribution. - -# """ -# return Dbn2D_fromptr(&self.ptr().totalDbn()) - - -# @property -# def underflow(self): -# """ -# h.underflow -> Distribution1D - -# Return the Distribution1D object representing the underflow. - -# """ -# return Dbn2D_fromptr(&self.ptr().underflow()) - - -# @property -# def overflow(self): -# """ -# h.overflow -> Distribution1D - -# Return the Distribution1D object representing the overflow. - -# """ -# return Dbn2D_fromptr(&self.ptr().overflow()) - - -# # def __delitem__(self, size_t ix): -# # self.ptr().eraseBin(ix) - - -# def __getitem__(self, size_t ix): -# return ProfileBin1D_fromptr(& self.ptr().bin(ix)) - - -# def sumW(self, bool overflows=True): -# """ -# s.sumW([overflows]) -> float - -# Return the sum of weights of the histogram. If overflows is False, -# ignore over-and underflow bins. - -# """ - -# return self.ptr().sumW(overflows) - - -# def sumW2(self, bool overflows=True): -# """ -# s.sumW2([overflows]) -> float - -# Return the sum of weights squared. If overflows is False, ignore -# over-and underflow bins. - -# """ -# return self.ptr().sumW2(overflows) - - -# def __add__(Profile1D a, Profile1D b): -# cdef cProfile1D *res = new cProfile1D(add(a.ptr()[0], b.ptr()[0])) -# return Profile1D_fromptr(res, True) - - -# def __sub__(Profile1D a, Profile1D b): -# cdef cProfile1D *res = new cProfile1D(subtract(a.ptr()[0], b.ptr()[0])) -# return Profile1D_fromptr(res, True) - - -# def __mul__(x, y): -# """ -# Scalar multiplication. Equivalent to scaleW acting on a copy. - -# """ -# cdef cProfile1D *res -# tx, ty = type(x), type(y) -# if (tx is int or tx is float) and ty is Profile1D: -# histo = <Profile1D> y; factor = <Profile1D> x -# elif tx is Profile1D and (ty is int or ty is float): -# histo = <Profile1D> x; factor = <Profile1D> y -# else: -# raise RuntimeError('Cannot multiply %r by %r' % (tx, ty)) - -# res = new cProfile1D(histo.ptr()[0]) -# res.scaleW(factor) -# return Profile1D_fromptr(res, True) - - -# def _div_scalar(Profile1D x, double y): -# if y == 0: -# raise ArithmeticError('Profile1D: Divide by zero scalar') - -# cdef cProfile1D *res = new cProfile1D(x.ptr()[0]) - -# res.scaleW(1.0 / y) -# return Profile1D_fromptr(res, True) - - -# def _div_profile(Profile1D x, Profile1D y): -# cdef cScatter2D s = divide(x.ptr()[0], y.ptr()[0]) -# return Scatter2D_fromptr(&s) - - -# def __div__(x, y): -# """ -# Division by scalar (i.e. multiplication by reciprocal) or another -# 1D histogram. - -# """ -# tx = type(x); ty = type(y) -# if tx is Profile1D: -# if ty is int or ty is float: -# return x._div_scalar(y) -# elif ty is Profile1D: -# return x._div_profile(y) -# raise RuntimeError('Cannot multiply %r by %r' % (tx, ty)) - - -# def __repr__(self): -# return 'Profile1D%r' % self.bins - - -# cdef Profile1D Profile1D_fromptr(cProfile1D *ptr, bool dealloc=False): -# cdef Profile1D profile = Profile1D.__new__(Profile1D) -# return profile.setptr(ptr, dealloc) +cdef Profile2D Profile2D_fromptr(cProfile2D *ptr, dealloc=False): + # Construct a Python Profile2D from a pointer to a cProfile2D, + # without calling __init__ and excessive memory allocation + cdef Profile2D bin = Profile2D.__new__(Profile2D) + return bin.setptr(ptr, dealloc) Modified: trunk/pyext/yoda/shims.h ============================================================================== --- trunk/pyext/yoda/shims.h Mon Jul 23 10:50:37 2012 (r510) +++ trunk/pyext/yoda/shims.h Mon Jul 23 14:41:42 2012 (r511) @@ -11,9 +11,9 @@ #include "YODA/ProfileBin1D.h" // 2D -// #include "YODA/Histo2D.h" -// #include "YODA/Profile2D.h" -// #include "YODA/Scatter3D.h" +#include "YODA/Histo2D.h" +#include "YODA/Profile2D.h" +#include "YODA/Scatter3D.h" #include "YODA/HistoBin2D.h" #include "YODA/ProfileBin2D.h" @@ -77,3 +77,15 @@ Scatter2D Scatter2D_mkScatter(const Histo1D& h) { return YODA::mkScatter(h); } + +// Scatter2D Scatter2D_mkScatter(const Profile1D& p) { +// return YODA::mkScatter(p); +// } + +// Scatter3D Scatter3D_mkScatter(const Histo2D& h) { +// return YODA::mkScatter(h); +// } + +// Scatter3D Scatter3D_mkScatter(const Profile2D& p) { +// return YODA::mkScatter(p); +// } Modified: trunk/src/Histo2D.cc ============================================================================== --- trunk/src/Histo2D.cc Mon Jul 23 10:50:37 2012 (r510) +++ trunk/src/Histo2D.cc Mon Jul 23 14:41:42 2012 (r511) @@ -6,6 +6,7 @@ #include "YODA/Histo2D.h" #include "YODA/Scatter3D.h" #include <cmath> + using namespace std; namespace YODA { @@ -101,6 +102,18 @@ } + // double Profile2D::xRMS(bool includeoverflows) const { + // if (includeoverflows) return _axis.totalDbn().xRMS(); + // /// @todo Finish + // } + + + // double Profile2D::yRMS(bool includeoverflows) const { + // if (includeoverflows) return _axis.totalDbn().yRMS(); + // /// @todo Finish + // } + + ///////////////////////////////////// @@ -266,6 +279,7 @@ Scatter3D divide(const Histo2D& numer, const Histo2D& denom) { + /// @todo Don't abuse equality operator -- test *axis* compatibility if (numer != denom) throw GridError("The two histos are not equivalently binned!"); Scatter3D tmp; for (size_t i = 0; i < numer.numBins(); ++i) { Modified: trunk/src/Profile2D.cc ============================================================================== --- trunk/src/Profile2D.cc Mon Jul 23 10:50:37 2012 (r510) +++ trunk/src/Profile2D.cc Mon Jul 23 14:41:42 2012 (r511) @@ -1,3 +1,8 @@ +// -*- C++ -*- +// +// This file is part of YODA -- Yet more Objects for Data Analysis +// Copyright (C) 2008-2012 The YODA collaboration (see AUTHORS for details) +// #include "YODA/Profile2D.h" #include "YODA/Scatter3D.h" #include "YODA/Histo2D.h" @@ -28,9 +33,7 @@ double Profile2D::sumW(bool includeoverflows) const { if (includeoverflows) return _axis.totalDbn().sumW2(); double sumw = 0; - foreach (const ProfileBin2D& b, bins()) { - sumw += b.sumW(); - } + foreach (const ProfileBin2D& b, bins()) sumw += b.sumW(); return sumw; } @@ -38,13 +41,83 @@ double Profile2D::sumW2(bool includeoverflows) const { if (includeoverflows) return _axis.totalDbn().sumW2(); double sumw = 0; - foreach (const ProfileBin2D& b, bins()) { - sumw += b.sumW(); - } + foreach (const ProfileBin2D& b, bins()) sumw += b.sumW(); return sumw; } + double Profile2D::xMean(bool includeoverflows) const { + if (includeoverflows) return _axis.totalDbn().xMean(); + double sumwx = 0; + foreach (const ProfileBin2D& b, bins()) sumwx += b.sumWX(); + return sumwx/sumW(); + } + + + double Profile2D::yMean(bool includeoverflows) const { + if (includeoverflows) return _axis.totalDbn().yMean(); + double sumwy = 0; + foreach (const ProfileBin2D& b, bins()) sumwy += b.sumWY(); + return sumwy/sumW(); + } + + + double Profile2D::xVariance(bool includeoverflows) const { + if (includeoverflows) return _axis.totalDbn().xVariance(); + /// @todo Improve this, by adding the Dbn2Ds and returning the resulting xVariance + double sigma2 = 0; + const double xMean = this->xMean(); + for (size_t i = 0; i < bins().size(); ++i) { + const double diff = bin(i).focus().first - xMean; + sigma2 += diff * diff * bin(i).sumW(); + } + return sigma2/sumW(); + } + + + double Profile2D::yVariance(bool includeoverflows) const { + if (includeoverflows) return _axis.totalDbn().yVariance(); + /// @todo Improve this, by adding the Dbn2Ds and returning the resulting yVariance + double sigma2 = 0; + const double yMean = this->yMean(); + for (size_t i = 0; i < bins().size(); ++i) { + const double diff = bin(i).focus().first - yMean; + sigma2 += diff * diff * bin(i).sumW(); + } + return sigma2/sumW(); + } + + + double Profile2D::xStdErr(bool includeoverflows) const { + if (includeoverflows) return _axis.totalDbn().xStdErr(); + const double effNumEntries = sumW(false)*sumW(false)/sumW2(false); + return std::sqrt(xVariance(false) / effNumEntries); + } + + + double Profile2D::yStdErr(bool includeoverflows) const { + if (includeoverflows) return _axis.totalDbn().yStdErr(); + const double effNumEntries = sumW(false)*sumW(false)/sumW2(false); + return std::sqrt(yVariance(false) / effNumEntries); + } + + + // double Profile2D::xRMS(bool includeoverflows) const { + // if (includeoverflows) return _axis.totalDbn().xRMS(); + // /// @todo Finish + // } + + + // double Profile2D::yRMS(bool includeoverflows) const { + // if (includeoverflows) return _axis.totalDbn().yRMS(); + // /// @todo Finish + // } + + + + ///////////////////////////////////// + + /// A copy constructor with optional new path Profile2D::Profile2D(const Profile2D& p, const std::string& path) : AnalysisObject("Profile2D", p.path(), p, p.title()), _axis(p._axis) @@ -77,9 +150,10 @@ /// Divide two profile histograms Scatter3D divide(const Profile2D& numer, const Profile2D& denom) { - /// @todo TODO + /// @todo TODO -- implement! /// @todo Check that bins match + /// @todo Don't abuse equality operator -- test *axis* compatibility Scatter3D tmp; // for (size_t i = 0; i < numer.numBins(); ++i) {
More information about the yoda-svn mailing list |