|
[Rivet-svn] r2705 - in trunk: include include/LWH include/Rivet src/Coreblackhole at projects.hepforge.org blackhole at projects.hepforge.orgTue Oct 5 17:38:09 BST 2010
Author: lonnblad Date: Tue Oct 5 17:38:08 2010 New Revision: 2705 Log: Added 2D histograms to LWH. Added: trunk/include/LWH/AIHistogram2D.h trunk/include/LWH/Histogram2D.h Modified: trunk/include/LWH/AIBaseHistogram.h trunk/include/LWH/AIDataPointSet.h trunk/include/LWH/AIHistogramFactory.h trunk/include/LWH/DataPointSet.h trunk/include/LWH/DataPointSetFactory.h trunk/include/LWH/HistogramFactory.h trunk/include/Makefile.am trunk/include/Rivet/Analysis.hh trunk/include/Rivet/RivetAIDA.fhh trunk/include/Rivet/RivetAIDA.hh trunk/src/Core/Analysis.cc Modified: trunk/include/LWH/AIBaseHistogram.h ============================================================================== --- trunk/include/LWH/AIBaseHistogram.h Tue Sep 28 18:12:56 2010 (r2704) +++ trunk/include/LWH/AIBaseHistogram.h Tue Oct 5 17:38:08 2010 (r2705) @@ -87,11 +87,32 @@ return true; } + /** + * Get the z-axis title. + * @return The title. + * + */ + std::string ztitle() const { + return theZTitle; + } + + /** + * Set the z-axis title. + * @param title The new title. + * @return false If the title cannot be set. + * + */ + bool setZTitle(const std::string & ztitle) { + theZTitle = ztitle; + return true; + } + protected: std::string theTitle; std::string theXTitle; std::string theYTitle; + std::string theZTitle; }; Modified: trunk/include/LWH/AIDataPointSet.h ============================================================================== --- trunk/include/LWH/AIDataPointSet.h Tue Sep 28 18:12:56 2010 (r2704) +++ trunk/include/LWH/AIDataPointSet.h Tue Oct 5 17:38:08 2010 (r2705) @@ -113,11 +113,60 @@ return true; } + /** + * Get the z-axis title. + * @return The title. + * + */ + std::string ztitle() const { + return theZTitle; + } + + /** + * Set the z-axis title. + * @param title The new title. + * @return false If the title cannot be set. + * + */ + bool setZTitle(const std::string & ztitle) { + theZTitle = ztitle; + return true; + } + + /** + * Get the z-axis title. + * @return The title. + * + */ + std::string title(int i) const { + switch ( i ) { + case 0: return theXTitle; + case 1: return theYTitle; + case 2: return theZTitle; + default: return ""; + } + } + + /** + * Set the <i>-axis title. + * @param title The new title. + * @return false If the title cannot be set. + * + */ + bool setTitle(int i, const std::string & title) { + if ( i == 0 ) theXTitle = title; + else if ( i == 1 ) theYTitle = title; + else if ( i == 2 ) theZTitle = title; + else return false; + return true; + } + protected: std::string theTitle; std::string theXTitle; std::string theYTitle; + std::string theZTitle; }; Added: trunk/include/LWH/AIHistogram2D.h ============================================================================== --- /dev/null 00:00:00 1970 (empty, because file is newly added) +++ trunk/include/LWH/AIHistogram2D.h Tue Oct 5 17:38:08 2010 (r2705) @@ -0,0 +1,191 @@ +// -*- C++ -*- +#ifndef LWH_AIHistogram2D_H +#define LWH_AIHistogram2D_H + +#ifndef LWH_USING_AIDA + +/** @cond DONT_DOCUMENT_STRIPPED_DOWN_AIDA_INTERFACES */ + +#include "AIHistogram1D.h" + +namespace AIDA { + +class IAxis; + +class IHistogram2D : virtual public IHistogram { + +public: + + virtual ~IHistogram2D() { /* nop */; } + + /** + * Fill the IHistogram2D with a couple of values and the + * corresponding weight. + * @param x The x value to be filled in. + * @param y The y value to be filled in. + * @param weight The corresponding weight (by default 1). + * @return false If the weight is <0 or >1 (?). + * + */ + virtual bool fill(double x, double y, double weight = 1.) = 0; + + /** + * The weighted mean along the x axis of a given bin. + * @param indexX The x bin number (0...N-1) or OVERFLOW or UNDERFLOW. + * @param indexY The y bin number (0...N-1) or OVERFLOW or UNDERFLOW. + * @return The mean of the corresponding bin along the x axis. + * + */ + virtual double binMeanX(int indexX, int indexY) const = 0; + + /** + * The weighted mean along the y axis of a given bin. + * @param indexX The x bin number (0...N-1) or OVERFLOW or UNDERFLOW. + * @param indexY The y bin number (0...N-1) or OVERFLOW or UNDERFLOW. + * @return The mean of the corresponding bin along the y axis. + * + */ + virtual double binMeanY(int indexX, int indexY) const = 0; + + /** + * Number of entries in the corresponding bin (ie the number of times fill was called for this bin). + * @param indexX The x bin number (0...N-1) or OVERFLOW or UNDERFLOW. + * @param indexY The y bin number (0...N-1) or OVERFLOW or UNDERFLOW. + * @return The number of entries in the corresponding bin. + * + */ + virtual int binEntries(int indexX, int indexY) const = 0; + + /** + * Sum of all the entries of the bins along a given x bin. + * This is equivalent to <tt>projectionX().binEntries(index)</tt>. + * @param index The x bin number (0...N-1) or OVERFLOW or UNDERFLOW. + * @return The number of entries in the corresponding set of bins. + * + */ + virtual int binEntriesX(int index) const = 0; + + /** + * Sum of all the entries of the bins along a given y bin. + * This is equivalent to <tt>projectionY().binEntries(index)</tt>. + * @param index The y bin number (0...N-1) or OVERFLOW or UNDERFLOW. + * @return The number of entries in the corresponding set of bins. + * + */ + virtual int binEntriesY(int index) const = 0; + + /** + * Total height of a give bin (ie the sum of the weights in this bin). + * @param indexX The x bin number (0...N-1) or OVERFLOW or UNDERFLOW. + * @param indexY The y bin number (0...N-1) or OVERFLOW or UNDERFLOW. + * @return The height of the corresponding bin. + * + */ + virtual double binHeight(int indexX, int indexY) const = 0; + + /** + * Sum of all the heights of the bins along a given x bin. + * This is equivalent to <tt>projectionX().binHeight(index)</tt>. + * @param index The x bin number (0...N-1) or OVERFLOW or UNDERFLOW. + * @return The sum of the heights in the corresponding set of bins. + * + */ + virtual double binHeightX(int index) const = 0; + + /** + * Sum of all the heights of the bins along a given y bin. + * This is equivalent to <tt>projectionY().binHeight(index)</tt>. + * @param index The y bin number (0...N-1) or OVERFLOW or UNDERFLOW. + * @return The sum of the heights in the corresponding set of bins. + * + */ + virtual double binHeightY(int index) const = 0; + + /** + * The error of a given bin. + * @param indexX The x bin number (0...N-1) or OVERFLOW or UNDERFLOW. + * @param indexY The y bin number (0...N-1) or OVERFLOW or UNDERFLOW. + * @return The error on the corresponding bin. + * + */ + virtual double binError(int indexX, int indexY) const = 0; + + /** + * The mean of the IHistogram2D along the x axis. + * @return The mean of the IHistogram2D along the x axis. + * + */ + virtual double meanX() const = 0; + + /** + * The mean of the IHistogram2D along the y axis. + * @return The mean of the IHistogram2D along the y axis. + * + */ + virtual double meanY() const = 0; + + /** + * The RMS of the IHistogram2D along the x axis. + * @return The RMS if the IHistogram2D along the x axis. + * + */ + virtual double rmsX() const = 0; + + /** + * The RMS of the IHistogram2D along the y axis. + * @return The RMS if the IHistogram2D along the y axis. + * + */ + virtual double rmsY() const = 0; + + /** + * Get the x axis of the IHistogram2D. + * @return The x coordinate IAxis. + * + */ + virtual const IAxis & xAxis() const = 0; + + /** + * Get the y axis of the IHistogram2D. + * @return The y coordinate IAxis. + * + */ + virtual const IAxis & yAxis() const = 0; + + /** + * Get the bin number corresponding to a given coordinate along the x axis. + * This is a convenience method, equivalent to <tt>xAxis().coordToIndex(coord)</tt>. + * @see IAxis#coordToIndex(double) + * @param coord The coordinalte along the x axis. + * @return The corresponding bin number. + * + */ + virtual int coordToIndexX(double coord) const = 0; + + /** + * Get the bin number corresponding to a given coordinate along the y axis. + * This is a convenience method, equivalent to <tt>yAxis().coordToIndex(coord)</tt>. + * @see IAxis#coordToIndex(double) + * @param coord The coordinalte along the y axis. + * @return The corresponding bin number. + * + */ + virtual int coordToIndexY(double coord) const = 0; + + /** + * Add to this IHistogram2D the contents of another IHistogram2D. + * @param hist The IHistogram2D to be added to this IHistogram2D. + * @return false If the IHistogram2Ds binnings are incompatible. + * + */ + virtual bool add(const IHistogram2D & hist) = 0; +}; // class +} // namespace AIDA +/** @endcond */ + +#else +#include "AIDA/IHistogram2D.h" +#endif + +#endif /* LWH_AIHistogram2D_H */ + Modified: trunk/include/LWH/AIHistogramFactory.h ============================================================================== --- trunk/include/LWH/AIHistogramFactory.h Tue Sep 28 18:12:56 2010 (r2704) +++ trunk/include/LWH/AIHistogramFactory.h Tue Oct 5 17:38:08 2010 (r2705) @@ -67,7 +67,26 @@ // virtual IDataPointSet * divide(const std::string &, const IProfile1D &, // const IProfile1D &) = 0; - + virtual IHistogram2D * + createHistogram2D(const std::string & path, const std::string & title, + int nx, double xlo, double xup, + int ny, double ylo, double yup, + const std::string & = "") = 0; + + virtual IHistogram2D * + createHistogram2D(const std::string & pathAndTitle, + int nx, double xlo, double xup, + int ny, double ylo, double yup) = 0; + + virtual IHistogram2D * + createHistogram2D(const std::string & path, const std::string & title, + const std::vector<double> & xedges, + const std::vector<double> & yedges, + const std::string & = "") = 0; + + virtual IHistogram2D * + createCopy(const std::string & path, const IHistogram2D & hist) = 0; + }; } Modified: trunk/include/LWH/DataPointSet.h ============================================================================== --- trunk/include/LWH/DataPointSet.h Tue Sep 28 18:12:56 2010 (r2704) +++ trunk/include/LWH/DataPointSet.h Tue Oct 5 17:38:08 2010 (r2705) @@ -332,8 +332,9 @@ << "\"\n title=\"" << encodeForXML(title()) << "\" path=\"" << path << "\" dimension=\"" << dimension() << "\">\n"; - os << " <dimension dim=\"0\" title=\"" << encodeForXML(xtitle()) << "\" />\n"; - os << " <dimension dim=\"1\" title=\"" << encodeForXML(ytitle()) << "\" />\n"; + for ( int d = 0; d < dimension(); ++d ) + os << " <dimension dim=\"" << d << "\" title=\"" + << encodeForXML(title(d)) << "\" />\n"; for ( int i = 0, N = size(); i < N; ++i ) { os << " <dataPoint>\n"; for ( int j = 0, M = dimension(); j < M; ++j ) Modified: trunk/include/LWH/DataPointSetFactory.h ============================================================================== --- trunk/include/LWH/DataPointSetFactory.h Tue Sep 28 18:12:56 2010 (r2704) +++ trunk/include/LWH/DataPointSetFactory.h Tue Oct 5 17:38:08 2010 (r2705) @@ -8,6 +8,7 @@ #include "AIDataPointSetFactory.h" #include "DataPointSet.h" #include "Histogram1D.h" +#include "Histogram2D.h" #include "Profile1D.h" #include "Tree.h" #include <string> @@ -58,7 +59,7 @@ if ( !tree->insert(path, dset) ) { delete dset; dset = 0; - throw std::runtime_error("LWH could not create DataPointSet '" + throw std::runtime_error("LWH couldn't create DataPointSet '" + title + "'." ); } return dset; @@ -399,11 +400,11 @@ const std::vector<double> & exm, const std::vector<double> & eym, const std::vector<double> & ezm) { IDataPointSet * dset = create(path, title, 3); - for ( int i = 0, N = y.size(); i < N; ++i ) dset->addPoint(DataPoint(3)); + for ( int i = 0, N = z.size(); i < N; ++i ) dset->addPoint(DataPoint(3)); if ( !dset->setCoordinate(0, x, exp, exm) || !dset->setCoordinate(1, y, eyp, eym) || !dset->setCoordinate(2, z, ezp, ezm) ) - throw std::runtime_error("LWH could add points to DataPointSet '" + + throw std::runtime_error("LWH could not add points to DataPointSet '" + title + "'." ); return dset; } @@ -562,6 +563,56 @@ /** + * Create an IDataPointSet from an IHistogram2D. + * @param path The path of the IDataPointSet. The path can either + * be a relative or full path. + * ("/folder1/folder2/dataName" and "../folder/dataName" + * are valid paths). All the directories in the path + * must exist. The characther `/` cannot be used in + * names; it is only used to delimit directories within + * paths. + * @param hist The IHistogram2D from which the data is taken. + * @param options Options, currently not specified + * @return The newly created IDataPointSet. + */ + virtual IDataPointSet * + create(const std::string & path, const IHistogram2D & hist, + const std::string & = "") { + IDataPointSet * dset = create(path, hist.title(), 3); + //std::cout << hist.xtitle() << " & " << hist.ytitle() << std::endl; + + dset->setXTitle(hist.xtitle()); + dset->setYTitle(hist.ytitle()); + std::vector<double> x, y, z, ex, ey, ez; + for ( int ix = 2, Nx = hist.xAxis().bins() + 2; ix < Nx; ++ix ) + for ( int iy = 2, Ny = hist.yAxis().bins() + 2; iy < Ny; ++iy ) { + dset->addPoint(DataPoint(3)); + //x.push_back(hist.binMean(i - 2)); // < "Dynamic" version + // Shouldn't IAxis have a binCentre(size_t binId) method? (According to Java AIDA v3.3.0 API) + x.push_back((hist.xAxis().binLowerEdge(ix - 2) + + hist.xAxis().binUpperEdge(ix - 2))/2.0); + ex.push_back(hist.xAxis().binWidth(ix - 2)/2.0); + /// @todo This is not really the height or error: width needs to be included... + y.push_back((hist.yAxis().binLowerEdge(iy - 2) + + hist.yAxis().binUpperEdge(iy - 2))/2.0); + ey.push_back(hist.yAxis().binWidth(iy - 2)/2.0); + /// @todo This is not really the height or error: width needs to be included... + const double binwidth = hist.xAxis().binWidth(ix - 2)* + hist.yAxis().binWidth(iy - 2); + z.push_back(hist.binHeight(ix - 2, iy - 2)/binwidth); + //ey.push_back(hist.binError(i - 2)/2.0/binwidth); + ez.push_back(hist.binError(ix - 2, iy - 2)/binwidth); + } + if ( !dset->setCoordinate(0, x, ex, ex) || + !dset->setCoordinate(1, y, ey, ey) || + !dset->setCoordinate(2, z, ez, ez) ) + throw std::runtime_error("LWH could not add points to DataPointSet '" + + hist.title() + "'." ); + return dset; + } + + + /** * Create an IDataPointSet from an IProfile1D. * @param path The path of the IDataPointSet. The path can either * be a relative or full path. @@ -601,14 +652,6 @@ /** - * LWH cannot handle a IHistogram2D. - */ - virtual IDataPointSet * create(const std::string &, const IHistogram2D &, - const std::string & = "") { - return error<IDataPointSet>("IHistogram2D"); - } - - /** * LWH cannot handle a IHistogram3D. */ virtual IDataPointSet * create(const std::string &, const IHistogram3D &, Added: trunk/include/LWH/Histogram2D.h ============================================================================== --- /dev/null 00:00:00 1970 (empty, because file is newly added) +++ trunk/include/LWH/Histogram2D.h Tue Oct 5 17:38:08 2010 (r2705) @@ -0,0 +1,873 @@ +// -*- C++ -*- +#ifndef LWH_Histogram2D_H +#define LWH_Histogram2D_H +// +// This is the declaration of the Histogram1D class. +// + +#include "AIHistogram2D.h" +#include "ManagedObject.h" +#include "Axis.h" +#include "VariAxis.h" +#include <vector> +#include <stdexcept> + +#include <iostream> +#ifdef HAVE_ROOT + #include "TH2D.h" +#endif + + + +namespace LWH { + + using namespace AIDA; + + + /** + * User level interface to 1D Histogram. + */ + class Histogram2D: public IHistogram2D, public ManagedObject { + + public: + + /** HistFactory is a friend. */ + friend class HistogramFactory; + + public: + + /** + * Standard constructor. + */ + Histogram2D(int nx, double lox, double upx, + int ny, double loy, double upy) + : xfax(new Axis(nx, lox, upx)), xvax(0), yfax(new Axis(ny, loy, upy)), + sum(nx + 2, std::vector<int>(ny + 2)), + sumw(nx + 2, std::vector<double>(ny + 2)), + sumw2(nx + 2, std::vector<double>(ny + 2)), + sumxw(nx + 2, std::vector<double>(ny + 2)), + sumx2w(nx + 2, std::vector<double>(ny + 2)), + sumyw(nx + 2, std::vector<double>(ny + 2)), + sumy2w(nx + 2, std::vector<double>(ny + 2)) { + xax = xfax; + yax = yfax; + } + + /** + * Standard constructor for variable bin width. + */ + Histogram2D(const std::vector<double> & xedges, + const std::vector<double> & yedges) + : xfax(0), xvax(new VariAxis(xedges)), + yfax(0), yvax(new VariAxis(xedges)), + sum(xedges.size() + 1, std::vector<int>(yedges.size() + 1)), + sumw(xedges.size() + 1, std::vector<double>(yedges.size() + 1)), + sumw2(xedges.size() + 1, std::vector<double>(yedges.size() + 1)), + sumxw(xedges.size() + 1, std::vector<double>(yedges.size() + 1)), + sumx2w(xedges.size() + 1, std::vector<double>(yedges.size() + 1)), + sumyw(xedges.size() + 1, std::vector<double>(yedges.size() + 1)), + sumy2w(xedges.size() + 1, std::vector<double>(yedges.size() + 1)) { + xax = xvax; + yax = yvax; + } + + /** + * Copy constructor. + */ + Histogram2D(const Histogram2D & h) + : IBaseHistogram(h), IHistogram(h), IHistogram2D(h), ManagedObject(h), + xfax(0), xvax(0), yfax(0), yvax(0), + sum(h.sum), sumw(h.sumw), sumw2(h.sumw2), + sumxw(h.sumxw), sumx2w(h.sumx2w) , + sumyw(h.sumyw), sumy2w(h.sumy2w){ + const VariAxis * hxvax = dynamic_cast<const VariAxis *>(h.xax); + if ( hxvax ) xax = xvax = new VariAxis(*hxvax); + else xax = xfax = new Axis(dynamic_cast<const Axis &>(*h.xax)); + const VariAxis * hyvax = dynamic_cast<const VariAxis *>(h.yax); + if ( hyvax ) yax = yvax = new VariAxis(*hyvax); + else yax = yfax = new Axis(dynamic_cast<const Axis &>(*h.yax)); + } + + /// Destructor. + virtual ~Histogram2D() { + delete xax; + delete yax; + } + + /** + * Get the Histogram's title. + * @return The Histogram's title. + */ + // std::string title() const { + // return theTitle; + // } + + /** + * Get the Histogram's name. + * @return The Histogram's name + */ + std::string name() const { + return title(); + } + + /** + * Set the histogram title. + * @param title The title. + * @return false If title cannot be changed. + */ + // bool setTitle(const std::string & title) { + // theTitle = title; + // return true; + // } + + /** + * Not implemented in LWH. will throw an exception. + */ + IAnnotation & annotation() { + throw std::runtime_error("LWH cannot handle annotations"); + return *anno; + } + + /** + * Not implemented in LWH. will throw an exception. + */ + const IAnnotation & annotation() const { + throw std::runtime_error("LWH cannot handle annotations"); + return *anno; + } + + /** + * Get the Histogram's dimension. + * @return The Histogram's dimension. + */ + int dimension() const { + return 2; + } + + /** + * Reset the Histogram; as if just created. + * @return false If something goes wrong. + */ + bool reset() { + const int nx = xax->bins() + 2; + const int ny = yax->bins() + 2; + sum = std::vector< std::vector<int> >(nx, std::vector<int>(ny)); + sumw = std::vector< std::vector<double> >(nx, std::vector<double>(ny)); + sumw2 = sumw; + sumxw = sumw; + sumx2w = sumw; + sumyw = sumw; + sumy2w = sumw; + return true; + } + + /** + * Get the number of in-range entries in the Histogram. + * @return The number of in-range entries. + * + */ + int entries() const { + int si = 0; + for ( int ix = 2; ix < xax->bins() + 2; ++ix ) + for ( int iy = 2; iy < yax->bins() + 2; ++iy ) si += sum[ix][iy]; + return si; + } + + /** + * Sum of the entries in all the IHistogram's bins, + * i.e in-range bins, UNDERFLOW and OVERFLOW. + * This is equivalent to the number of times the + * method fill was invoked. + * @return The sum of all the entries. + */ + int allEntries() const { + return entries() + extraEntries(); + } + + /** + * Number of entries in the UNDERFLOW and OVERFLOW bins. + * @return The number of entries outside the range of the IHistogram. + */ + int extraEntries() const { + int esum = sum[0][0] + sum[1][0] + sum[0][1] + sum[1][1]; + for ( int ix = 2; ix < xax->bins() + 2; ++ix ) + esum += sum[ix][0] + sum[ix][1]; + for ( int iy = 2; iy < yax->bins() + 2; ++iy ) + esum += sum[0][iy] + sum[1][iy]; + return esum; + } + + /** + * Number of equivalent entries, + * i.e. <tt>SUM[ weight ] ^ 2 / SUM[ weight^2 ]</tt> + * @return The number of equivalent entries. + */ + double equivalentBinEntries() const { + double sw = 0.0; + double sw2 = 0.0; + for ( int ix = 2; ix < xax->bins() + 2; ++ix ) + for ( int iy = 2; iy < yax->bins() + 2; ++iy ) { + sw += sumw[ix][iy]; + sw2 += sumw2[ix][iy]; + } + return sw2/(sw*sw); + } + + /** + * Sum of in-range bin heights in the IHistogram, + * UNDERFLOW and OVERFLOW bins are excluded. + * @return The sum of the in-range bins heights. + * + */ + double sumBinHeights() const { + double sw = 0.0; + for ( int ix = 2; ix < xax->bins() + 2; ++ix ) + for ( int iy = 2; iy < yax->bins() + 2; ++iy ) sw += sumw[ix][iy]; + return sw; + } + + /** + * Sum of the heights of all the IHistogram's bins, + * i.e in-range bins, UNDERFLOW and OVERFLOW. + * @return The sum of all the bins heights. + */ + double sumAllBinHeights() const { + return sumBinHeights() + sumExtraBinHeights(); + } + + /** + * Sum of heights in the UNDERFLOW and OVERFLOW bins. + * @return The sum of the heights of the out-of-range bins. + */ + double sumExtraBinHeights() const { + int esum = sumw[0][0] + sumw[1][0] + sumw[0][1] + sumw[1][1]; + for ( int ix = 2; ix < xax->bins() + 2; ++ix ) + esum += sumw[ix][0] + sumw[ix][1]; + for ( int iy = 2; iy < yax->bins() + 2; ++iy ) + esum += sumw[0][iy] + sumw[1][iy]; + return esum; + } + + /** + * Minimum height of the in-range bins, + * i.e. not considering the UNDERFLOW and OVERFLOW bins. + * @return The minimum height among the in-range bins. + */ + double minBinHeight() const { + double minw = sumw[2][2]; + for ( int ix = 2; ix < xax->bins() + 2; ++ix ) + for ( int iy = 2; iy < yax->bins() + 2; ++iy ) + minw = std::min(minw, sumw[ix][iy]); + return minw; + } + + /** + * Maximum height of the in-range bins, + * i.e. not considering the UNDERFLOW and OVERFLOW bins. + * @return The maximum height among the in-range bins. + */ + double maxBinHeight() const{ + double maxw = sumw[2][2]; + for ( int ix = 2; ix < xax->bins() + 2; ++ix ) + for ( int iy = 2; iy < yax->bins() + 2; ++iy ) + maxw = std::max(maxw, sumw[ix][iy]); + return maxw; + } + + /** + * Fill the IHistogram1D with a value and the + * corresponding weight. + * @param x The value to be filled in. + * @param weight The corresponding weight (by default 1). + * @return false If the weight is <0 or >1 (?). + */ + bool fill(double x, double y, double weight = 1.) { + int ix = xax->coordToIndex(x) + 2; + int iy = yax->coordToIndex(y) + 2; + ++sum[ix][iy]; + sumw[ix][iy] += weight; + sumxw[ix][iy] += x*weight; + sumx2w[ix][iy] += x*x*weight; + sumyw[ix][iy] += y*weight; + sumy2w[ix][iy] += y*y*weight; + sumw2[ix][iy] += weight*weight; + return weight >= 0 && weight <= 1; + } + + /** + * The weighted mean along the x-axis of a bin. + * @param xindex The bin number (0...N-1) or OVERFLOW or UNDERFLOW. + * @param yindex The bin number (0...N-1) or OVERFLOW or UNDERFLOW. + * @return The mean of the corresponding bin. + */ + double binMeanX(int xindex, int yindex) const { + int ix = xindex + 2; + int iy = yindex + 2; + return sumw[ix][iy] != 0.0? sumxw[ix][iy]/sumw[ix][iy]: + ( xvax? xvax->binMidPoint(xindex): xfax->binMidPoint(xindex) ); + }; + + /** + * The weighted mean along the y-axis of a bin. + * @param xindex The bin number (0...N-1) or OVERFLOW or UNDERFLOW. + * @param yindex The bin number (0...N-1) or OVERFLOW or UNDERFLOW. + * @return The mean of the corresponding bin. + */ + double binMeanY(int xindex, int yindex) const { + int ix = xindex + 2; + int iy = yindex + 2; + return sumw[ix][iy] != 0.0? sumyw[ix][iy]/sumw[ix][iy]: + ( yvax? yvax->binMidPoint(yindex): xfax->binMidPoint(yindex) ); + }; + + /** + * The weighted x-RMS of a bin. + * @param xindex The bin number (0...N-1) or OVERFLOW or UNDERFLOW. + * @param yindex The bin number (0...N-1) or OVERFLOW or UNDERFLOW. + * @return The RMS of the corresponding bin. + */ + double binRmsX(int xindex, int yindex) const { + int ix = xindex + 2; + int iy = yindex + 2; + return sumw[ix][iy] == 0.0 || sum[ix][iy] < 2? xax->binWidth(xindex): + std::sqrt(std::max(sumw[ix][iy]*sumx2w[ix][iy] - + sumxw[ix][iy]*sumxw[ix][iy], 0.0))/sumw[ix][iy]; + }; + + /** + * The weighted y-RMS of a bin. + * @param xindex The bin number (0...N-1) or OVERFLOW or UNDERFLOW. + * @param yindex The bin number (0...N-1) or OVERFLOW or UNDERFLOW. + * @return The RMS of the corresponding bin. + */ + double binRmsY(int xindex, int yindex) const { + int ix = xindex + 2; + int iy = yindex + 2; + return sumw[ix][iy] == 0.0 || sum[ix][iy] < 2? yax->binWidth(yindex): + std::sqrt(std::max(sumw[ix][iy]*sumy2w[ix][iy] - + sumyw[ix][iy]*sumyw[ix][iy], 0.0))/sumw[ix][iy]; + }; + + /** + * Number of entries in the corresponding bin (ie the number of + * times fill was called for this bin). + * @param index The bin number (0...N-1) or OVERFLOW or UNDERFLOW. + * @return The number of entries in the corresponding bin. + */ + int binEntries(int xindex, int yindex) const { + return sum[xindex + 2][yindex + 2]; + } + + /** + * Sum of all the entries of the bins along a given x bin. + * This is equivalent to <tt>projectionX().binEntries(index)</tt>. + * @param index The x bin number (0...N-1) or OVERFLOW or UNDERFLOW. + * @return The number of entries in the corresponding set of bins. + * + */ + virtual int binEntriesX(int index) const { + int ret = 0; + for ( int iy = 2; iy < yax->bins() + 2; ++iy ) + ret += sum[index + 2][iy]; + return ret; + } + + /** + * Sum of all the entries of the bins along a given y bin. + * This is equivalent to <tt>projectionY().binEntries(index)</tt>. + * @param index The y bin number (0...N-1) or OVERFLOW or UNDERFLOW. + * @return The number of entries in the corresponding set of bins. + * + */ + virtual int binEntriesY(int index) const { + int ret = 0; + for ( int ix = 2; ix < xax->bins() + 2; ++ix ) + ret += sum[ix][index + 2]; + return ret; + } + + /** + * Total height of the corresponding bin (ie the sum of the weights + * in this bin). + * @param index The bin number (0...N-1) or OVERFLOW or UNDERFLOW. + * @return The height of the corresponding bin. + */ + double binHeight(int xindex, int yindex) const { + /// @todo While this is compatible with the reference AIDA + /// implementation, it is not the bin height! + return sumw[xindex + 2][yindex + 2]; + } + + /** + * Sum of all the heights of the bins along a given x bin. + * This is equivalent to <tt>projectionX().binHeight(index)</tt>. + * @param index The x bin number (0...N-1) or OVERFLOW or UNDERFLOW. + * @return The sum of the heights in the corresponding set of bins. + * + */ + virtual double binHeightX(int index) const { + double ret = 0; + for ( int iy = 2; iy < yax->bins() + 2; ++iy ) + ret += sumw[index + 2][iy]; + return ret; + } + + /** + * Sum of all the heights of the bins along a given y bin. + * This is equivalent to <tt>projectionY().binHeight(index)</tt>. + * @param index The y bin number (0...N-1) or OVERFLOW or UNDERFLOW. + * @return The sum of the heights in the corresponding set of bins. + * + */ + virtual double binHeightY(int index) const { + double ret = 0; + for ( int ix = 2; ix < xax->bins() + 2; ++ix ) + ret += sumw[ix][index + 2]; + return ret; + } + + /** + * The error of a given bin. + * @param index The bin number (0...N-1) or OVERFLOW or UNDERFLOW. + * @return The error on the corresponding bin. + * + */ + double binError(int xindex, int yindex) const { + return std::sqrt(sumw2[xindex + 2][yindex + 2]); + } + + /** + * The mean of the IHistogram2D along the x axis. + * @return The mean of the IHistogram2D along the x axis. + * + */ + double meanX() const { + double s = 0.0; + double sx = 0.0; + for ( int ix = 2; ix < xax->bins() + 2; ++ix ) + for ( int iy = 2; iy < yax->bins() + 2; ++iy ) { + s += sumw[ix][iy]; + sx += sumxw[ix][iy]; + } + return s != 0.0? sx/s: 0.0; + } + + /** + * The mean of the IHistogram2D along the y axis. + * @return The mean of the IHistogram2D along the y axis. + * + */ + double meanY() const { + double s = 0.0; + double sy = 0.0; + for ( int ix = 2; ix < xax->bins() + 2; ++ix ) + for ( int iy = 2; iy < yax->bins() + 2; ++iy ) { + s += sumw[ix][iy]; + sy += sumyw[ix][iy]; + } + return s != 0.0? sy/s: 0.0; + } + + /** + * The RMS of the IHistogram2D along the x axis. + * @return The RMS if the IHistogram2D along the x axis. + * + */ + double rmsX() const { + double s = 0.0; + double sx = 0.0; + double sx2 = 0.0; + for ( int ix = 2; ix < xax->bins() + 2; ++ix ) + for ( int iy = 2; iy < yax->bins() + 2; ++iy ) { + s += sumw[ix][iy]; + sx += sumxw[ix][iy]; + sx2 += sumx2w[ix][iy]; + } + return s != 0.0? std::sqrt(std::max(s*sx2 - sx*sx, 0.0))/s: + xax->upperEdge() - xax->lowerEdge(); + } + + /** + * The RMS of the IHistogram2D along the x axis. + * @return The RMS if the IHistogram2D along the x axis. + * + */ + double rmsY() const { + double s = 0.0; + double sy = 0.0; + double sy2 = 0.0; + for ( int ix = 2; ix < xax->bins() + 2; ++ix ) + for ( int iy = 2; iy < yax->bins() + 2; ++iy ) { + s += sumw[ix][iy]; + sy += sumyw[ix][iy]; + sy2 += sumy2w[ix][iy]; + } + return s != 0.0? std::sqrt(std::max(s*sy2 - sy*sy, 0.0))/s: + yax->upperEdge() - yax->lowerEdge(); + } + + /** The weights. */ + double getSumW(int xindex, int yindex) const { + return sumw[xindex + 2][yindex + 2]; + } + + /** The squared weights. */ + double getSumW2(int xindex, int yindex) const { + return sumw2[xindex + 2][yindex + 2]; + } + + /** The weighted x-values. */ + double getSumXW(int xindex, int yindex) const { + return sumxw[xindex + 2][yindex + 2]; + } + + /** The weighted x-square-values. */ + double getSumX2W(int xindex, int yindex) const { + return sumx2w[xindex + 2][yindex + 2]; + } + + /** The weighted x-values. */ + double getSumYW(int xindex, int yindex) const { + return sumyw[xindex + 2][yindex + 2]; + } + + /** The weighted x-square-values. */ + double getSumY2W(int xindex, int yindex) const { + return sumy2w[xindex + 2][yindex + 2]; + } + + /** + * Get the x axis of the IHistogram2D. + * @return The x coordinate IAxis. + */ + const IAxis & xAxis() const { + return *xax; + } + + /** + * Get the y axis of the IHistogram2D. + * @return The y coordinate IAxis. + */ + const IAxis & yAxis() const { + return *yax; + } + + /** + * Get the bin number corresponding to a given coordinate along the + * x axis. This is a convenience method, equivalent to + * <tt>axis().coordToIndex(coord)</tt>. + * @param coord The coordinalte along the x axis. + * @return The corresponding bin number. + */ + int coordToIndexX(double coord) const { + return xax->coordToIndex(coord); + } + + /** + * Get the bin number corresponding to a given coordinate along the + * y axis. This is a convenience method, equivalent to + * <tt>axis().coordToIndex(coord)</tt>. + * @param coord The coordinalte along the y axis. + * @return The corresponding bin number. + */ + int coordToIndexY(double coord) const { + return yax->coordToIndex(coord); + } + + /** + * Add to this Histogram2D the contents of another IHistogram2D. + * @param h The Histogram2D to be added to this IHistogram2D. + * @return false If the IHistogram1Ds binnings are incompatible. + */ + bool add(const Histogram2D & h) { + if ( xax->upperEdge() != h.xax->upperEdge() || + xax->lowerEdge() != h.xax->lowerEdge() || + xax->bins() != h.xax->bins() ) return false; + if ( yax->upperEdge() != h.yax->upperEdge() || + yax->lowerEdge() != h.yax->lowerEdge() || + yax->bins() != h.yax->bins() ) return false; + for ( int ix = 0; ix < xax->bins() + 2; ++ix ) + for ( int iy = 0; iy < yax->bins() + 2; ++iy ) { + sum[ix][iy] += h.sum[ix][iy]; + sumw[ix][iy] += h.sumw[ix][iy]; + sumxw[ix][iy] += h.sumxw[ix][iy]; + sumx2w[ix][iy] += h.sumx2w[ix][iy]; + sumyw[ix][iy] += h.sumyw[ix][iy]; + sumy2w[ix][iy] += h.sumy2w[ix][iy]; + sumw2[ix][iy] += h.sumw2[ix][iy]; + } + return true; + } + + /** + * Add to this IHistogram1D the contents of another IHistogram1D. + * @param hist The IHistogram1D to be added to this IHistogram1D. + * @return false If the IHistogram1Ds binnings are incompatible. + */ + bool add(const IHistogram2D & hist) { + return add(dynamic_cast<const Histogram2D &>(hist)); + } + + /** + * Scale the contents of this histogram with the given factor. + * @param s the scaling factor to use. + */ + bool scale(double s) { + for ( int ix = 0; ix < xax->bins() + 2; ++ix ) + for ( int iy = 0; iy < yax->bins() + 2; ++iy ) { + sumw[ix][iy] *= s; + sumxw[ix][iy] *= s; + sumx2w[ix][iy] *= s; + sumyw[ix][iy] *= s; + sumy2w[ix][iy] *= s; + sumw2[ix][iy] *= s*s; + } + return true; + } + + /** + * Scale the given histogram so that the integral over all bins + * (including overflow) gives \a intg. This function also corrects + * for the bin-widths, which means that it should only be run once + * for each histogram. Further rescaling must be done with the + * scale(double) function. + */ + void normalize(double intg) { + double oldintg = sumAllBinHeights(); + if ( oldintg == 0.0 ) return; + for ( int ix = 0; ix < xax->bins() + 2; ++ix ) + for ( int iy = 0; iy < yax->bins() + 2; ++iy ) { + double fac = intg/oldintg; + if ( ix >= 2 && iy >= 2 ) + fac /= (xax->binUpperEdge(ix - 2) - xax->binLowerEdge(ix - 2))* + (yax->binUpperEdge(iy - 2) - yax->binLowerEdge(iy - 2)); + sumw[ix][iy] *= fac; + sumxw[ix][iy] *= fac; + sumx2w[ix][iy] *= fac; + sumyw[ix][iy] *= fac; + sumy2w[ix][iy] *= fac; + sumw2[ix][iy] *= fac*fac; + } + } + + /** + * Return the integral over the histogram bins assuming it has been + * normalize()d. + */ + // double integral() const { + // double intg = sumw[0] + sumw[1]; + // for ( int i = 2; i < ax->bins() + 2; ++i ) + + // is this right? Leave out bin width factor? + + // intg += sumw[ix][iy]*(ax->binUpperEdge(i - 2) - ax->binLowerEdge(i - 2)); + // return intg; + // } + + /** + * Not implemented in LWH. + * @return null pointer always. + */ + void * cast(const std::string &) const { + return 0; + } + + /** + * Write out the histogram in the AIDA xml format. + */ + bool writeXML(std::ostream & os, std::string path, std::string name) { + //std::cout << "Writing out histogram " << name << " in AIDA file format!" << std::endl; + os << " <histogram2d name=\"" << encodeForXML(name) + << "\"\n title=\"" << encodeForXML(title()) + << "\" path=\"" << path + << "\">\n <axis max=\"" << xax->upperEdge() + << "\" numberOfBins=\"" << xax->bins() + << "\" min=\"" << xax->lowerEdge() + << "\" direction=\"x\""; + if ( xvax ) { + os << ">\n"; + for ( int i = 0, N = xax->bins() - 1; i < N; ++i ) + os << " <binBorder value=\"" << xax->binUpperEdge(i) << "\"/>\n"; + os << " </axis>\n"; + } else { + os << "/>\n"; + } + os << " <axis max=\"" << yax->upperEdge() + << "\" numberOfBins=\"" << yax->bins() + << "\" min=\"" << yax->lowerEdge() + << "\" direction=\"y\""; + if ( yvax ) { + os << ">\n"; + for ( int i = 0, N = yax->bins() - 1; i < N; ++i ) + os << " <binBorder value=\"" << yax->binUpperEdge(i) << "\"/>\n"; + os << " </axis>\n"; + } else { + os << "/>\n"; + } + os << " <statistics entries=\"" << entries() + << "\">\n <statistic mean=\"" << meanX() + << "\" direction=\"x\"\n rms=\"" << rmsX() + << "\"/>\n </statistics>\n <statistic mean=\"" << meanY() + << "\" direction=\"y\"\n rms=\"" << rmsY() + << "\"/>\n </statistics>\n <data2d>\n"; + for ( int ix = 0; ix < xax->bins() + 2; ++ix ) + for ( int iy = 0; iy < yax->bins() + 2; ++iy ) + if ( sum[ix][iy] ) { + os << " <bin2d binNumX=\""; + if ( ix == 0 ) os << "UNDERFLOW"; + else if ( ix == 1 ) os << "OVERFLOW"; + else os << ix - 2; + os << "\" binNumY=\""; + if ( iy == 0 ) os << "UNDERFLOW"; + else if ( iy == 1 ) os << "OVERFLOW"; + else os << iy - 2; + os << "\" entries=\"" << sum[ix][iy] + << "\" height=\"" << sumw[ix][iy] + << "\"\n error=\"" << std::sqrt(sumw2[ix][iy]) + << "\" error2=\"" << sumw2[ix][iy] + << "\"\n weightedMeanX=\"" << binMeanX(ix - 2, iy - 2) + << "\" weightedRmsX=\"" << binRmsX(ix - 2, iy - 2) + << "\"\n weightedMeanY=\"" << binMeanY(ix - 2, iy - 2) + << "\" weightedRmsY=\"" << binRmsY(ix - 2, iy - 2) + << "\"/>\n"; + } + os << " </data2d>\n </histogram2d>" << std::endl; + return true; + } + + + /** + * Write out the histogram in a flat text file suitable for + * eg. gnuplot to read. The coloums are layed out as 'x w w2 n'. + */ + bool writeFLAT(std::ostream & os, std::string path, std::string name) { + os << "#2D " << path << "/" << name << " " << xax->lowerEdge() + << " " << xax->bins() << " " << xax->upperEdge() << " " + << yax->lowerEdge() << " " << yax->bins() << " " << yax->upperEdge() + << " \"" << title() << "\"" << std::endl; + for ( int ix = 2; ix < xax->bins() + 2; ++ix ) { + for ( int iy = 2; iy < yax->bins() + 2; ++iy ) + os << 0.5*(xax->binLowerEdge(ix - 2)+xax->binUpperEdge(ix - 2)) << " " + << 0.5*(yax->binLowerEdge(iy - 2)+yax->binUpperEdge(iy - 2)) + << " " << sumw[ix][iy] << " " << sqrt(sumw2[ix][iy]) + << " " << sum[ix][iy] << std::endl; + os << std::endl; + } + os << std::endl; + return true; + } + + + + #ifdef HAVE_ROOT + /** + * Write out the histogram in Root file format. + */ + //bool writeROOT(std::ostream & os, std::string path, std::string name) { + bool writeROOT(TFile* file, std::string path, std::string name) { + + //std::cout << "Writing out histogram " << name.c_str() << " in ROOT file format" << std::endl; + + TH1D* hist1d; + int nbins; + if (!vax || vax->isFixedBinning() ) {//equidistant binning (easier case) + nbins = ax->bins(); + hist1d = new TH1D(name.c_str(), title().c_str(), nbins, ax->lowerEdge(), ax->upperEdge()); + } + else { + nbins = vax->bins(); + double* bins = new double[nbins+1]; + for (int i=0; i<nbins; ++i) { + bins[ix][iy] = vax->binEdges(i).first; + } + bins[nbins] = vax->binEdges(nbins-1).second; //take last bin right border + hist1d = new TH1D(name.c_str(), title().c_str(), nbins, bins); + delete bins; + } + + + double entries = 0; + for ( int i = 0; i < nbins + 2; ++i ) { + if ( sum[ix][iy] ) { + //i==0: underflow->RootBin(0), i==1: overflow->RootBin(NBins+1) + entries = entries + sum[ix][iy]; + int j=i; + if (i==0) j=0; //underflow + else if (i==1) j=nbins+1; //overflow + if (i>=2) j=i-1; //normal bin entries + hist1d->SetBinContent(j, sumw[ix][iy]); + hist1d->SetBinError(j, sqrt(sumw2[ix][iy])); + //hist1d->Fill(binMean(i), sumw[ix][iy]); + } + } + + hist1d->Sumw2(); + hist1d->SetEntries(entries); + + std::string DirName; //remove preceding slash from directory name, else ROOT error + for (unsigned int i=1; i<path.size(); ++i) DirName += path[i]; + if (!file->Get(DirName.c_str())) file->mkdir(DirName.c_str()); + file->cd(DirName.c_str()); + hist1d->Write(); + + delete hist1d; + + return true; + } + + #endif + + + + private: + + /** The title */ + // std::string theTitle; + + /** The axis. */ + IAxis * xax; + + /** Pointer (possibly null) to a axis with fixed bin width. */ + Axis * xfax; + + /** Pointer (possibly null) to a axis with fixed bin width. */ + VariAxis * xvax; + + /** The axis. */ + IAxis * yax; + + /** Pointer (possibly null) to a axis with fixed bin width. */ + Axis * yfax; + + /** Pointer (possibly null) to a axis with fixed bin width. */ + VariAxis * yvax; + + /** The counts. */ + std::vector< std::vector<int> > sum; + + /** The weights. */ + std::vector< std::vector<double> > sumw; + + /** The squared weights. */ + std::vector< std::vector<double> > sumw2; + + /** The weighted x-values. */ + std::vector< std::vector<double> > sumxw; + + /** The weighted x-square-values. */ + std::vector< std::vector<double> > sumx2w; + + /** The weighted y-values. */ + std::vector< std::vector<double> > sumyw; + + /** The weighted y-square-values. */ + std::vector< std::vector<double> > sumy2w; + + /** dummy pointer to non-existen annotation. */ + IAnnotation * anno; + + }; + +} + +#endif /* LWH_Histogram1D_H */ Modified: trunk/include/LWH/HistogramFactory.h ============================================================================== --- trunk/include/LWH/HistogramFactory.h Tue Sep 28 18:12:56 2010 (r2704) +++ trunk/include/LWH/HistogramFactory.h Tue Oct 5 17:38:08 2010 (r2705) @@ -7,6 +7,7 @@ #include "AIHistogramFactory.h" #include "Histogram1D.h" +#include "Histogram2D.h" #include "DataPointSet.h" #include "Profile1D.h" #include "Tree.h" @@ -220,35 +221,65 @@ /** * LWH cannot create a IHistogram2D. */ - IHistogram2D * createHistogram2D(const std::string &, const std::string &, - int, double, double, int, double, double, - const std::string & = "") { - return error<IHistogram2D>("IHistogram2D"); + IHistogram2D * + createHistogram2D(const std::string & path, const std::string & title, + int nx, double xlo, double xup, + int ny, double ylo, double yup, + const std::string & = "") { + Histogram2D * hist = new Histogram2D(nx, xlo, xup, ny, ylo, yup); + hist->setTitle(title); + if ( !tree->insert(path, hist) ) { + delete hist; + hist = 0; + throw std::runtime_error("LWH could not create histogram '" + + title + "'." ); + } + return hist; } /** * LWH cannot create a IHistogram2D. */ - IHistogram2D * createHistogram2D(const std::string &, - int, double, double, int, double, double) { - return error<IHistogram2D>("IHistogram2D"); + IHistogram2D * createHistogram2D(const std::string & pathAndTitle, + int nx, double xlo, double xup, + int ny, double ylo, double yup) { + std::string title = pathAndTitle.substr(pathAndTitle.rfind('/') + 1); + return createHistogram2D(pathAndTitle, title, nx, xlo, xup, ny, ylo, yup); } /** * LWH cannot create a IHistogram2D. */ - IHistogram2D * createHistogram2D(const std::string &, const std::string &, - const std::vector<double> &, - const std::vector<double> &, - const std::string & = "") { - return error<IHistogram2D>("IHistogram2D"); + IHistogram2D * + createHistogram2D(const std::string & path, const std::string & title, + const std::vector<double> & xedges, + const std::vector<double> & yedges, + const std::string & = "") { + Histogram2D * hist = new Histogram2D(xedges, yedges); + hist->setTitle(title); + if ( !tree->insert(path, hist) ) { + delete hist; + hist = 0; + throw std::runtime_error("LWH could not create histogram '" + + title + "'." ); + } + return hist; } /** * LWH cannot create a copy of an IHistogram2D. */ - IHistogram2D * createCopy(const std::string &, const IHistogram2D &) { - return error<IHistogram2D>("IHistogram2D"); + IHistogram2D * + createCopy(const std::string & path, const IHistogram2D & hist) { + Histogram2D * h = new Histogram2D(dynamic_cast<const Histogram2D &>(hist)); + h->setTitle(path.substr(path.rfind('/') + 1)); + if ( !tree->insert(path, h) ) { + delete h; + h = 0; + throw std::runtime_error("LWH could not create a copy of histogram '" + + hist.title() + "'." ); + } + return h; } /** @@ -584,7 +615,6 @@ Histogram1D * h = new Histogram1D(h1); h->setTitle(path.substr(path.rfind('/') + 1)); for ( int i = 0; i < h->ax->bins() + 2; ++i ) { - h->sum[i] *= h2.sum[i]; h->sumw[i] *= h2.sumw[i]; h->sumw2[i] += h1.sumw[i]*h1.sumw[i]*h2.sumw2[i] + h2.sumw[i]*h2.sumw[i]*h1.sumw2[i]; @@ -771,35 +801,178 @@ } /** + * Check if two histograms have the same bins. + */ + bool checkBins(const Histogram2D & h1, const Histogram2D & h2) const { + if (_neq( h1.xax->upperEdge(), h2.xax->upperEdge()) || + _neq( h1.xax->lowerEdge(), h2.xax->lowerEdge()) || + h1.xax->bins() != h2.xax->bins() ) return false; + if (_neq( h1.yax->upperEdge(), h2.yax->upperEdge()) || + _neq( h1.yax->lowerEdge(), h2.yax->lowerEdge()) || + h1.yax->bins() != h2.yax->bins() ) return false; + for ( int i = 0; i < h1.xax->bins(); ++i ) { + if ( _neq(h1.xax->binUpperEdge(i), h2.xax->binUpperEdge(i)) || + _neq(h1.xax->binLowerEdge(i), h2.xax->binLowerEdge(i)) ) + return false; + } + for ( int i = 0; i < h1.yax->bins(); ++i ) { + if ( _neq(h1.yax->binUpperEdge(i), h2.yax->binUpperEdge(i)) || + _neq(h1.yax->binLowerEdge(i), h2.yax->binLowerEdge(i)) ) + return false; + } + return true; + } + + /** * LWH cannot create an IHistogram2D by adding two IHistogram2D. */ - IHistogram2D * add(const std::string &, - const IHistogram2D &, const IHistogram2D &) { - return error<IHistogram2D>("2D histograms"); + IHistogram2D * add(const std::string & path, + const IHistogram2D & hist1, const IHistogram2D & hist2) { + return add(path, dynamic_cast<const Histogram2D &>(hist1), + dynamic_cast<const Histogram2D &>(hist2)); + } + + /** + * LWH cannot create an IHistogram2D by adding two IHistogram2D. + */ + Histogram2D * add(const std::string & path, + const Histogram2D & h1, const Histogram2D & h2) { + if ( !checkBins(h1, h2) ) return 0; + Histogram2D * h = new Histogram2D(h1); + h->setTitle(path.substr(path.rfind('/') + 1)); + h->add(h2); + if ( !tree->insert(path, h) ) { + delete h; + return 0; + } + return h; } /** * LWH cannot create an IHistogram2D by subtracting two IHistogram2D. */ - IHistogram2D * subtract(const std::string &, - const IHistogram2D &, const IHistogram2D &) { - return error<IHistogram2D>("2D histograms"); + Histogram2D * subtract(const std::string & path, + const Histogram2D & h1, const Histogram2D & h2) { + if ( !checkBins(h1, h2) ) { + //std::cout << "!!!!!!!" << std::endl; + return 0; + } + Histogram2D * h = new Histogram2D(h1); + h->setTitle(path.substr(path.rfind('/') + 1)); + for ( int ix = 0; ix < h->xax->bins() + 2; ++ix ) + for ( int iy = 0; iy < h->yax->bins() + 2; ++iy ) { + h->sum[ix][iy] += h2.sum[ix][iy]; + h->sumw[ix][iy] -= h2.sumw[ix][iy]; + h->sumw[ix][iy] -= h2.sumw[ix][iy]; + h->sumxw[ix][iy] -= h2.sumxw[ix][iy]; + h->sumx2w[ix][iy] -= h2.sumx2w[ix][iy]; + h->sumyw[ix][iy] -= h2.sumyw[ix][iy]; + h->sumy2w[ix][iy] -= h2.sumy2w[ix][iy]; + } + if ( !tree->insert(path, h) ) { + //std::cout << "&&&&&&&" << std::endl; + delete h; + return 0; + } + return h; + } + + /** + * LWH cannot create an IHistogram2D by subtracting two IHistogram2D. + */ + IHistogram2D * subtract(const std::string & path, + const IHistogram2D & h1, const IHistogram2D & h2) { + return subtract(path, dynamic_cast<const Histogram2D &>(h1), + dynamic_cast<const Histogram2D &>(h2)); } /** * LWH cannot create an IHistogram2D by multiplying two IHistogram2D. */ - IHistogram2D * multiply(const std::string &, - const IHistogram2D &, const IHistogram2D &) { - return error<IHistogram2D>("2D histograms"); + IHistogram2D * multiply(const std::string & path, + const IHistogram2D & h1, const IHistogram2D & h2) { + return multiply(path, dynamic_cast<const Histogram2D &>(h1), + dynamic_cast<const Histogram2D &>(h2)); + } + + /** + * LWH cannot create an IHistogram2D by multiplying two IHistogram2D. + */ + Histogram2D * multiply(const std::string & path, + const Histogram2D & h1, const Histogram2D & h2) { + if ( !checkBins(h1, h2) ) return 0; + Histogram2D * h = new Histogram2D(h1); + h->setTitle(path.substr(path.rfind('/') + 1)); + for ( int ix = 0; ix < h->xax->bins() + 2; ++ix ) + for ( int iy = 0; iy < h->yax->bins() + 2; ++iy ) { + h->sumw[ix][iy] *= h2.sumw[ix][iy]; + h->sumw2[ix][iy] += h1.sumw[ix][iy]*h1.sumw[ix][iy]*h2.sumw2[ix][iy] + + h2.sumw[ix][iy]*h2.sumw[ix][iy]*h1.sumw2[ix][iy]; + } + if ( !tree->insert(path, h) ) { + delete h; + return 0; + } + return h; } /** * LWH cannot create an IHistogram2D by dividing two IHistogram2D. */ - IHistogram2D * divide(const std::string &, - const IHistogram2D &, const IHistogram2D &) { - return error<IHistogram2D>("2D histograms"); + DataPointSet * divide(const std::string & path, + const Histogram2D & h1, const Histogram2D & h2) { + if ( !checkBins(h1,h2) ) return 0; + DataPointSet * h = new DataPointSet(3); + h->setTitle(path.substr(path.rfind('/') + 1)); + for (int ix = 0; ix < h1.xax->bins(); ++ix) { + const double xbinwidth = h1.xax->binWidth(ix); + const double xbincentre = + ( h1.xax->binLowerEdge(ix) + h1.xax->binUpperEdge(ix) ) / 2.0; + for (int iy = 0; iy < h1.yax->bins(); ++iy) { + const double ybinwidth = h1.yax->binWidth(iy); + const double ybincentre = + ( h1.yax->binLowerEdge(iy) + h1.yax->binUpperEdge(iy) ) / 2.0; + IDataPoint* point = h->addPoint(); + IMeasurement* x = point->coordinate(0); + x->setValue(xbincentre); + x->setErrorPlus(xbinwidth/2.0); + x->setErrorMinus(xbinwidth/2.0); + IMeasurement* y = point->coordinate(1); + y->setValue(ybincentre); + y->setErrorPlus(ybinwidth/2.0); + y->setErrorMinus(ybinwidth/2.0); + + double zval(0), zerr(0); + if ( h1.binHeight(ix, iy) == 0 || h2.binHeight(ix, iy) == 0 ) { + /// @todo Bad way of handling div by zero! + zval = 0.0; + zerr = 0.0; + } else { + zval = h1.binHeight(ix, iy) / h2.binHeight(ix, iy); + double z1relerr = h1.binError(ix, iy)/h1.binHeight(ix,iy); + double z2relerr = h2.binError(ix, iy)/h2.binHeight(ix,iy); + zerr = zval * sqrt(pow(z1relerr, 2) + pow(z2relerr, 2)); + } + IMeasurement* z = point->coordinate(2); + z->setValue(zval); + z->setErrorPlus(zerr); + z->setErrorMinus(zerr); + } + } + if ( !tree->insert(path, h) ) { + delete h; + return 0; + } + return h; + } + + /** + * LWH cannot create an IHistogram2D by dividing two IHistogram2D. + */ + IDataPointSet * divide(const std::string & path, + const IHistogram2D & h1, const IHistogram2D & h2) { + return divide(path, dynamic_cast<const Histogram1D &>(h1), + dynamic_cast<const Histogram1D &>(h2)); } /** @@ -838,48 +1011,145 @@ * LWH cannot create an IHistogram1D by projecting an IHistogram2D * along its x axis. */ - IHistogram1D * projectionX(const std::string &, const IHistogram2D &) { - return error<IHistogram1D>("2D histograms"); + IHistogram1D * projectionX(const std::string & path, const IHistogram2D & h) { + return projectionX(path, dynamic_cast<const Histogram2D &>(h)); + } + + /** + * LWH cannot create an IHistogram1D by projecting an IHistogram2D + * along its x axis. + */ + Histogram1D * projectionX(const std::string & path, const Histogram2D & h) { + return sliceX(path, h, h.xax->bins() - 1); + } + + /** + * LWH cannot create an IHistogram1D by projecting an IHistogram2D + * along its y axis. + */ + IHistogram1D * projectionY(const std::string & path, const IHistogram2D & h) { + return projectionY(path, dynamic_cast<const Histogram2D &>(h)); } /** * LWH cannot create an IHistogram1D by projecting an IHistogram2D * along its y axis. */ - IHistogram1D * projectionY(const std::string &, const IHistogram2D &) { - return error<IHistogram1D>("2D histograms"); + Histogram1D * projectionY(const std::string & path, const Histogram2D & h) { + return sliceY(path, h, h.yax->bins() - 1); } /** * LWH cannot create an IHistogram1D by slicing an IHistogram2D * parallel to the y axis at a given bin. */ - IHistogram1D * sliceX(const std::string &, const IHistogram2D &, int) { - return error<IHistogram1D>("2D histograms"); + IHistogram1D * + sliceX(const std::string & path, const IHistogram2D & h, int i) { + return sliceX(path, dynamic_cast<const Histogram2D &>(h), i, i); + } + + /** + * LWH cannot create an IHistogram1D by slicing an IHistogram2D + * parallel to the y axis at a given bin. + */ + Histogram1D * + sliceX(const std::string & path, const Histogram2D & h, int i) { + return sliceX(path, h, i, i); + } + + /** + * LWH cannot create an IHistogram1D by slicing an IHistogram2D + * parallel to the x axis at a given bin. + */ + IHistogram1D * + sliceY(const std::string & path, const IHistogram2D & h, int i) { + return sliceY(path, dynamic_cast<const Histogram2D &>(h), i, i); } /** * LWH cannot create an IHistogram1D by slicing an IHistogram2D * parallel to the x axis at a given bin. */ - IHistogram1D * sliceY(const std::string &, const IHistogram2D &, int) { - return error<IHistogram1D>("2D histograms"); + Histogram1D * sliceY(const std::string & path, const Histogram2D & h, int i) { + return sliceY(path, h, i, i); } /** * LWH cannot create an IHistogram1D by slicing an IHistogram2D * parallel to the y axis between two bins (inclusive). */ - IHistogram1D * sliceX(const std::string &, const IHistogram2D &, int, int) { - return error<IHistogram1D>("2D histograms"); + IHistogram1D * + sliceX(const std::string & path, const IHistogram2D & h, int il, int iu) { + return sliceX(path, dynamic_cast<const Histogram2D &>(h), il, iu); + } + + /** + * LWH cannot create an IHistogram1D by slicing an IHistogram2D + * parallel to the y axis between two bins (inclusive). + */ + Histogram1D * + sliceX(const std::string & path, const Histogram2D & h2, int il, int iu) { + Histogram1D * h1; + if ( h2.xfax ) + h1 = new Histogram1D(h2.xfax->bins(), h2.xfax->lowerEdge(), + h2.xfax->upperEdge()); + else { + std::vector<double> edges(h2.xax->bins() + 1); + edges.push_back(h2.xax->lowerEdge()); + for ( int i = 0; i < h2.xax->bins(); ++i ) + edges.push_back(h2.xax->binLowerEdge(i)); + h1 = new Histogram1D(edges); + } + for ( int ix = 0; ix < h2.xax->bins() + 2; ++ix ) + for ( int iy = il + 2; iy <= iu + 2; ++iy ) { + h1->sum[ix] += h2.sum[ix][iy]; + h1->sumw[ix] += h2.sumw[ix][iy]; + h1->sumw2[ix] += h2.sumw2[ix][iy]; + h1->sumxw[ix] += h2.sumxw[ix][iy]; + h1->sumx2w[ix] += h2.sumx2w[ix][iy]; + } + if ( !tree->insert(path, h1) ) { + delete h1; + return 0; + } + return h1; } /** * LWH cannot create an IHistogram1D by slicing an IHistogram2D * parallel to the x axis between two bins (inclusive). */ - IHistogram1D * sliceY(const std::string &, const IHistogram2D &, int, int) { - return error<IHistogram1D>("2D histograms"); + IHistogram1D * + sliceY(const std::string & path, const IHistogram2D & h, int il, int iu) { + return sliceY(path, dynamic_cast<const Histogram2D &>(h), il, iu); + } + + Histogram1D * + sliceY(const std::string & path, const Histogram2D & h2, int il, int iu) { + Histogram1D * h1; + if ( h2.yfax ) + h1 = new Histogram1D(h2.yfax->bins(), h2.yfax->lowerEdge(), + h2.yfax->upperEdge()); + else { + std::vector<double> edges(h2.yax->bins() + 1); + edges.push_back(h2.yax->lowerEdge()); + for ( int i = 0; i < h2.yax->bins(); ++i ) + edges.push_back(h2.yax->binLowerEdge(i)); + h1 = new Histogram1D(edges); + } + for ( int iy = 0; iy < h2.yax->bins() + 2; ++iy ) + for ( int ix = il + 2; ix <= iu + 2; ++ix ) { + h1->sum[iy] += h2.sum[ix][iy]; + h1->sumw[iy] += h2.sumw[ix][iy]; + h1->sumw2[iy] += h2.sumw2[ix][iy]; + h1->sumxw[iy] += h2.sumyw[ix][iy]; + h1->sumx2w[iy] += h2.sumy2w[ix][iy]; + } + if ( !tree->insert(path, h1) ) { + delete h1; + return 0; + } + return h1; } /** Modified: trunk/include/Makefile.am ============================================================================== --- trunk/include/Makefile.am Tue Sep 28 18:12:56 2010 (r2704) +++ trunk/include/Makefile.am Tue Oct 5 17:38:08 2010 (r2705) @@ -10,6 +10,7 @@ LWH/AIManagedObject.h \ LWH/AIBaseHistogram.h \ LWH/AIHistogram1D.h \ + LWH/AIHistogram2D.h \ LWH/AIProfile1D.h \ LWH/AIDataPointSet.h \ LWH/AIMeasurement.h \ @@ -22,6 +23,7 @@ LWH/DataPointSetFactory.h \ LWH/ManagedObject.h \ LWH/Histogram1D.h \ + LWH/Histogram2D.h \ LWH/Profile1D.h \ LWH/DataPointSet.h \ LWH/DataPoint.h \ Modified: trunk/include/Rivet/Analysis.hh ============================================================================== --- trunk/include/Rivet/Analysis.hh Tue Sep 28 18:12:56 2010 (r2704) +++ trunk/include/Rivet/Analysis.hh Tue Oct 5 17:38:08 2010 (r2705) @@ -218,6 +218,22 @@ /// @warning The old histogram will be deleted, and its pointer set to zero. void scale(AIDA::IHistogram1D*& histo, double scale); + /// Normalize the given histogram, @a histo. After this call the + /// histogram will have been transformed to a DataPointSet with the + /// same name and path. It has the same effect as + /// @c scale(histo, norm/sumOfWeights). + /// @param histo The histogram to be normalised. + /// @param norm The new area of the histogram. + /// @warning The old histogram will be deleted, and its pointer set to zero. + void normalize(AIDA::IHistogram2D*& histo, double norm=1.0); + + /// Multiplicatively scale the given histogram, @a histo. After this call the + /// histogram will have been transformed to a DataPointSet with the same name and path. + /// @param histo The histogram to be scaled. + /// @param scale The factor used to multiply the histogram bin heights. + /// @warning The old histogram will be deleted, and its pointer set to zero. + void scale(AIDA::IHistogram2D*& histo, double scale); + /// Set the cross section from the generator Analysis& setCrossSection(double xs); @@ -301,6 +317,33 @@ const std::vector<double>& binedges, const std::string& title="", const std::string& xtitle="", const std::string& ytitle=""); + /// Book a 2D histogram with @a nxbins and @a nybins uniformly + /// distributed across the ranges @a xlower - @a xupper and @a + /// ylower - @a yupper respectively along the x- and y-axis. + /// (NB. this returns a pointer rather than a reference since it + /// will have to be stored in the analysis class - there's no + /// point in forcing users to explicitly get the pointer from a + /// reference before they can use it!) + AIDA::IHistogram2D* + bookHistogram2D(const std::string& name, + size_t nxbins, double xlower, double xupper, + size_t nybins, double ylower, double yupper, + const std::string& title="", const std::string& xtitle="", + const std::string& ytitle="", const std::string& ztitle=""); + + /// Book a 2D histogram with non-uniform bins defined by the + /// vectorx of bin edges @a xbinedges and @a ybinedges. + /// (NB. this returns a pointer rather than a reference since it + /// will have to be stored in the analysis class - there's no + /// point in forcing users to explicitly get the pointer from a + /// reference before they can use it!) + AIDA::IHistogram2D* + bookHistogram2D(const std::string& name, + const std::vector<double>& xbinedges, + const std::vector<double>& ybinedges, + const std::string& title="", const std::string& xtitle="", + const std::string& ytitle="", const std::string& ztitle=""); + /// Book a 1D histogram based on the name in the corresponding AIDA /// file. The binnings will be obtained by reading the bundled AIDA data /// record file with the same filename as the analysis' name() property. Modified: trunk/include/Rivet/RivetAIDA.fhh ============================================================================== --- trunk/include/Rivet/RivetAIDA.fhh Tue Sep 28 18:12:56 2010 (r2704) +++ trunk/include/Rivet/RivetAIDA.fhh Tue Oct 5 17:38:08 2010 (r2705) @@ -9,6 +9,7 @@ class IAnalysisFactory; class IHistogramFactory; class IHistogram1D; + class IHistogram2D; class IProfile1D; class IDataPointSetFactory; class IDataPointSet; Modified: trunk/include/Rivet/RivetAIDA.hh ============================================================================== --- trunk/include/Rivet/RivetAIDA.hh Tue Sep 28 18:12:56 2010 (r2704) +++ trunk/include/Rivet/RivetAIDA.hh Tue Oct 5 17:38:08 2010 (r2705) @@ -10,6 +10,7 @@ #include "LWH/AIAnalysisFactory.h" #include "LWH/AIHistogramFactory.h" #include "LWH/AIHistogram1D.h" +#include "LWH/AIHistogram2D.h" #include "LWH/AIProfile1D.h" #include "LWH/AITreeFactory.h" #include "LWH/AIDataPointSetFactory.h" Modified: trunk/src/Core/Analysis.cc ============================================================================== --- trunk/src/Core/Analysis.cc Tue Sep 28 18:12:56 2010 (r2704) +++ trunk/src/Core/Analysis.cc Tue Oct 5 17:38:08 2010 (r2705) @@ -378,6 +378,44 @@ return hist; } + IHistogram2D* + Analysis::bookHistogram2D(const string& hname, + size_t nxbins, double xlower, double xupper, + size_t nybins, double ylower, double yupper, + const string& title, const string& xtitle, + const string& ytitle, const string& ztitle) { + _makeHistoDir(); + const string path = histoPath(hname); + IHistogram2D* hist = + histogramFactory().createHistogram2D(path, title, nxbins, xlower, xupper, + nybins, ylower, yupper); + getLog() << Log::TRACE << "Made 2D histogram " + << hname << " for " << name() << endl; + hist->setXTitle(xtitle); + hist->setYTitle(ytitle); + hist->setZTitle(ztitle); + return hist; + } + + + IHistogram2D* + Analysis::bookHistogram2D(const string& hname, + const vector<double>& xbinedges, + const vector<double>& ybinedges, + const string& title, const string& xtitle, + const string& ytitle, const string& ztitle) { + _makeHistoDir(); + const string path = histoPath(hname); + IHistogram2D* hist = + histogramFactory().createHistogram2D(path, title, xbinedges, ybinedges); + getLog() << Log::TRACE << "Made 2D histogram " << hname << " for " + << name() << endl; + hist->setXTitle(xtitle); + hist->setYTitle(ytitle); + hist->setZTitle(ztitle); + return hist; + } + ///////////////// @@ -576,4 +614,85 @@ } + void Analysis::normalize(AIDA::IHistogram2D*& histo, double norm) { + if (!histo) { + getLog() << Log::ERROR << "Failed to normalise histo=NULL in analysis " + << name() << " (norm=" << norm << ")" << endl; + return; + } + const string hpath = tree().findPath(dynamic_cast<const AIDA::IManagedObject&>(*histo)); + getLog() << Log::TRACE << "Normalizing histo " << hpath << " to " << norm << endl; + + double oldintg = 0.0; + int nxBins = histo->xAxis().bins(); + int nyBins = histo->yAxis().bins(); + for (int ixBin = 0; ixBin != nxBins; ++ixBin) + for (int iyBin = 0; iyBin != nyBins; ++iyBin) { + // Leaving out factor of binWidth because AIDA's "height" + // already includes a width factor. + oldintg += histo->binHeight(ixBin, iyBin); // * histo->axis().binWidth(iBin); + } + if (oldintg == 0.0) { + getLog() << Log::WARN << "Histo " << hpath + << " has null integral during normalisation" << endl; + return; + } + + // Scale by the normalisation factor. + scale(histo, norm/oldintg); + } + + + void Analysis::scale(AIDA::IHistogram2D*& histo, double scale) { + if (!histo) { + getLog() << Log::ERROR << "Failed to scale histo=NULL in analysis " + << name() << " (scale=" << scale << ")" << endl; + return; + } + const string hpath = + tree().findPath(dynamic_cast<const AIDA::IManagedObject&>(*histo)); + getLog() << Log::TRACE << "Scaling histo " << hpath << endl; + + vector<double> x, y, z, ex, ey, ez; + for (size_t ix = 0, Nx = histo->xAxis().bins(); ix < Nx; ++ix) + for (size_t iy = 0, Ny = histo->yAxis().bins(); iy < Ny; ++iy) { + x.push_back(0.5 * (histo->xAxis().binLowerEdge(ix) + + histo->xAxis().binUpperEdge(ix))); + ex.push_back(histo->xAxis().binWidth(ix)*0.5); + y.push_back(0.5 * (histo->yAxis().binLowerEdge(iy) + + histo->yAxis().binUpperEdge(iy))); + ey.push_back(histo->yAxis().binWidth(iy)*0.5); + + // "Bin height" is a misnomer in the AIDA spec: width is neglected. + // We'd like to do this: y.push_back(histo->binHeight(i) * scale); + z.push_back(histo->binHeight(ix, iy)*scale/ + (histo->xAxis().binWidth(ix)*histo->yAxis().binWidth(iy))); + // "Bin error" is a misnomer in the AIDA spec: width is neglected. + // We'd like to do this: ey.push_back(histo->binError(i) * scale); + ez.push_back(histo->binError(ix, iy)*scale/ + (histo->xAxis().binWidth(ix)*histo->yAxis().binWidth(iy))); + } + + string title = histo->title(); + string xtitle = histo->xtitle(); + string ytitle = histo->ytitle(); + string ztitle = histo->ztitle(); + + tree().mkdir("/tmpnormalize"); + tree().mv(hpath, "/tmpnormalize"); + + AIDA::IDataPointSet* dps = + datapointsetFactory().createXYZ(hpath, title, x, y, z, ex, ey, ez); + dps->setXTitle(xtitle); + dps->setYTitle(ytitle); + dps->setZTitle(ztitle); + + tree().rm(tree().findPath(dynamic_cast<AIDA::IManagedObject&>(*histo))); + tree().rmdir("/tmpnormalize"); + + // Set histo pointer to null - it can no longer be used. + histo = 0; + } + + }
More information about the Rivet-svn mailing list |