Back to home page

EIC code displayed by LXR

 
 

    


File indexing completed on 2026-08-06 09:38:19

0001 // -*- C++ -*-
0002 //
0003 // HistogramFactory.h is a part of ThePEG - Toolkit for HEP Event Generation
0004 // Copyright (C) 1999-2019 Leif Lonnblad
0005 //
0006 // ThePEG is licenced under version 3 of the GPL, see COPYING for details.
0007 // Please respect the MCnet academic guidelines, see GUIDELINES for details.
0008 //
0009 #ifndef LWH_HistogramFactory_H
0010 #define LWH_HistogramFactory_H
0011 //
0012 // This is the declaration of the HistogramFactory class.
0013 //
0014 
0015 #include "AIHistogramFactory.h"
0016 #include "Histogram1D.h"
0017 #include "Histogram2D.h"
0018 #include "Tree.h"
0019 #include <string>
0020 #include <stdexcept>
0021 
0022 namespace LWH {
0023 
0024 using namespace AIDA;
0025 
0026 /**
0027  * User level interface for factory classes of Histograms (binned,
0028  * unbinned, and profile). The created objects are assumed to be
0029  * managed by the tree which is associated to the factory. So far only
0030  * one-dimensional histograms are implemented in LWH.
0031  */
0032 class HistogramFactory: public IHistogramFactory {
0033 
0034 public:
0035 
0036   /**
0037    * Standard constructor.
0038    */
0039   HistogramFactory(Tree & t)
0040     : tree(&t) {}
0041 
0042   /**
0043    * Destructor.
0044    */
0045   virtual ~HistogramFactory() {}
0046 
0047   /**
0048    * Destroy an IBaseHistogram object.
0049    * @param hist The IBaseHistogram to be destroyed.
0050    * @return false If the histogram cannot be destroyed.
0051    */
0052   bool destroy(IBaseHistogram * hist) {
0053     IManagedObject * mo = dynamic_cast<IManagedObject *>(hist);
0054     if ( !mo ) return false;
0055     return tree->rm(tree->findPath(*mo));
0056   }
0057 
0058   /**
0059    * LWH cannot create a ICloud1D, an unbinned 1-dimensional histogram.
0060    */
0061   ICloud1D * createCloud1D(const std::string &, const std::string &,
0062                int = -1, const std::string & = "") {
0063     return error<ICloud1D>("ICloud1D");
0064   }
0065 
0066   /**
0067    * LWH cannot create a ICloud1D, an unbinned 1-dimensional histogram.
0068    */
0069   ICloud1D * createCloud1D(const std::string &) {
0070     return error<ICloud1D>("ICloud1D");
0071   }
0072 
0073   /**
0074    * LWH cannot create a copy of an ICloud1D.
0075    */
0076   ICloud1D * createCopy(const std::string &, const ICloud1D &) {
0077     return error<ICloud1D>("ICloud1D");
0078   }
0079 
0080   /**
0081    * LWH cannot create a ICloud2D, an unbinned 2-dimensional histogram.
0082    */
0083   ICloud2D * createCloud2D(const std::string &, const std::string &, int = -1,
0084                const std::string & = "") {
0085     return error<ICloud2D>("ICloud2D");
0086   }
0087 
0088 
0089   /**
0090    * LWH cannot create a ICloud2D, an unbinned 2-dimensional histogram.
0091    */
0092   ICloud2D * createCloud2D(const std::string &) {
0093     return error<ICloud2D>("ICloud2D");
0094   }
0095 
0096   /**
0097    * LWH cannot create a copy of an ICloud2D.
0098    */
0099   ICloud2D * createCopy(const std::string &, const ICloud2D &) {
0100     return error<ICloud2D>("ICloud2D");
0101   }
0102 
0103   /**
0104    * LWH cannot create a ICloud3D, an unbinned 3-dimensional histogram.
0105    */
0106   ICloud3D * createCloud3D(const std::string &, const std::string &, int = -1,
0107                const std::string & = "") {
0108     return error<ICloud3D>("ICloud3D");
0109   }
0110 
0111   /**
0112    * LWH cannot create a ICloud3D, an unbinned 3-dimensional histogram.
0113    */
0114   ICloud3D * createCloud3D(const std::string &) {
0115     return error<ICloud3D>("ICloud3D");
0116   }
0117 
0118   /**
0119    * LWH cannot create a copy of an ICloud3D.
0120    */
0121   ICloud3D * createCopy(const std::string &, const ICloud3D &) {
0122     return error<ICloud3D>("ICloud3D");
0123   }
0124 
0125   /**
0126    * Create a IHistogram1D.
0127    * @param path      The path of the created IHistogram. The path must be a
0128    *                  full path.  ("/folder1/folder2/dataName" is a valid path).
0129    *                  The characther `/` cannot be used in names; it is only
0130    *                  used to delimit directories within paths.
0131    * @param title     The title of the IHistogram1D.
0132    * @param nBins     The number of bins of the x axis.
0133    * @param lowerEdge The lower edge of the x axis.
0134    * @param upperEdge The upper edge of the x axis.
0135    * @return          The newly created IHistogram1D ot the null pointer
0136    *                  if something went wrong, such as a non existing
0137    *                  directrory in the path or that an object with the
0138    *                  given path already existed.
0139    * @throws          std::runtime_error if histogram could not be created.
0140    */
0141   IHistogram1D *
0142   createHistogram1D(const std::string & path, const std::string & title,
0143             int nBins, double lowerEdge, double upperEdge,
0144             const std::string & = "") {
0145     Histogram1D * hist = new Histogram1D(nBins, lowerEdge, upperEdge);
0146     hist->setTitle(title);
0147     if ( !tree->insert(path, hist) ) {
0148       delete hist;
0149       hist = 0;
0150       throw std::runtime_error("LWH could not create histogram '"
0151                    + title + "'." );
0152     }
0153     return hist;
0154   }
0155 
0156   /**
0157    * Create a IHistogram1D.
0158    * @param pathAndTitle The path of the created IHistogram. The path must be a
0159    *                     full path.  ("/folder1/folder2/dataName" is a valid
0160    *                     path). The characther `/` cannot be used in names; it
0161    *                     is only used to delimit directories within paths.
0162    * @param nBins        The number of bins of the x axis.
0163    * @param lowerEdge    The lower edge of the x axis.
0164    * @param upperEdge    The upper edge of the x axis.
0165    * @return             The newly created IHistogram1D.
0166    * @throws             std::runtime_error if histogram could not be created.
0167    */
0168   IHistogram1D *
0169   createHistogram1D(const std::string & pathAndTitle,
0170             int nBins, double lowerEdge, double upperEdge) {
0171     std::string title = pathAndTitle.substr(pathAndTitle.rfind('/') + 1);
0172     return createHistogram1D(pathAndTitle, title, nBins, lowerEdge, upperEdge);
0173   }
0174 
0175 
0176     /**
0177      * Create a IHistogram1D.
0178 
0179      * @param path      The path of the created IHistogram. The path can either
0180      *                  be a relative or full path.
0181      *                  ("/folder1/folder2/dataName" and "../folder/dataName"
0182      *                  are valid paths). All the directories in the path must
0183      *                  exist. The characther `/` cannot be used in names;
0184      *                  it is only used to delimit directories within paths.
0185      * @param title     The title of the IHistogram1D.
0186      * @param binEdges  The array of the bin edges for the x axis.
0187      */
0188   IHistogram1D *
0189   createHistogram1D(const std::string & path, const std::string & title,
0190             const std::vector<double> & binEdges,
0191             const std::string & = "") {
0192     Histogram1D * hist = new Histogram1D(binEdges);
0193     hist->setTitle(title);
0194     if ( !tree->insert(path, hist) ) {
0195       delete hist;
0196       hist = 0;
0197       throw std::runtime_error("LWH could not create histogram '"
0198                    + title + "'." );
0199     }
0200     return hist;
0201   }
0202 
0203   /**
0204    * Create a copy of an IHistogram1D.
0205    * @param path The path of the created IHistogram. The path must be a
0206    *             full path.  ("/folder1/folder2/dataName" is a valid
0207    *             path). The characther `/` cannot be used in names; it
0208    *             is only used to delimit directories within paths.
0209    * @param hist The IHistogram1D to be copied.
0210    * @return     The copy of the IHistogram1D.
0211    * @throws     std::runtime_error if histogram could not be created.
0212    */
0213   IHistogram1D *
0214   createCopy(const std::string & path, const IHistogram1D & hist) {
0215     Histogram1D * h = new Histogram1D(dynamic_cast<const Histogram1D &>(hist));
0216     h->setTitle(path.substr(path.rfind('/') + 1));
0217     if ( !tree->insert(path, h) ) {
0218       delete h;
0219       h = 0;
0220       throw std::runtime_error("LWH could not create a copy of histogram '"
0221                    + hist.title() + "'." );
0222     }
0223     return h;
0224   }
0225 
0226   /**
0227    * Create a IHistogram2D.
0228    */
0229   IHistogram2D *
0230   createHistogram2D(const std::string & path, const std::string & title,
0231             int nx, double xlo, double xup,
0232             int ny, double ylo, double yup,
0233             const std::string & = "") {
0234     Histogram2D * hist = new Histogram2D(nx, xlo, xup, ny, ylo, yup);
0235     hist->setTitle(title);
0236     if ( !tree->insert(path, hist) ) {
0237       delete hist;
0238       hist = 0;
0239       throw std::runtime_error("LWH could not create histogram '"
0240                                + title + "'." );
0241     }
0242     return hist;
0243   }
0244  
0245   /**
0246    * Create a IHistogram2D.
0247    */
0248   IHistogram2D * createHistogram2D(const std::string & pathAndTitle,
0249                                    int nx, double xlo, double xup,
0250                    int ny, double ylo, double yup) {
0251     std::string title  = pathAndTitle.substr(pathAndTitle.rfind('/') + 1);
0252     return createHistogram2D(pathAndTitle, title, nx, xlo, xup, ny, ylo, yup);
0253   }
0254 
0255   /**
0256    * Create a IHistogram2D.
0257    */
0258   IHistogram2D *
0259   createHistogram2D(const std::string & path, const std::string & title,
0260             const std::vector<double> & xedges,
0261             const std::vector<double> & yedges,
0262             const std::string & = "") {
0263     Histogram2D * hist = new Histogram2D(xedges, yedges);
0264     hist->setTitle(title);
0265     if ( !tree->insert(path, hist) ) {
0266       delete hist;
0267       hist = 0;
0268       throw std::runtime_error("LWH could not create histogram '"
0269                                + title + "'." );
0270     }
0271     return hist;
0272   }
0273 
0274   /**
0275    *Create a copy of an IHistogram2D.
0276    */
0277   IHistogram2D *
0278   createCopy(const std::string & path, const IHistogram2D & hist) {
0279     Histogram2D * h = new Histogram2D(dynamic_cast<const Histogram2D &>(hist));
0280     h->setTitle(path.substr(path.rfind('/') + 1));
0281     if ( !tree->insert(path, h) ) {
0282       delete h;
0283       h = 0;
0284       throw std::runtime_error("LWH could not create a copy of histogram '"
0285                                + hist.title() + "'." );
0286     }
0287     return h;
0288   }
0289 
0290   /**
0291    * LWH cannot create a IHistogram3D.
0292    */
0293   IHistogram3D * createHistogram3D(const std::string &, const std::string &,
0294                    int, double, double, int, double, double,
0295                    int, double, double,
0296                    const std::string & = "") {
0297     return error<IHistogram3D>("IHistogram3D");
0298   }
0299 
0300   /**
0301    * LWH cannot create a IHistogram3D.
0302    */
0303   IHistogram3D * createHistogram3D(const std::string &, int, double, double,
0304                    int, double, double, int, double, double) {
0305     return error<IHistogram3D>("IHistogram3D");
0306   }
0307 
0308   /**
0309    * LWH cannot create a IHistogram3D.
0310    */
0311   IHistogram3D * createHistogram3D(const std::string &, const std::string &,
0312                    const std::vector<double> &,
0313                    const std::vector<double> &,
0314                    const std::vector<double> &,
0315                    const std::string & = "") {
0316     return error<IHistogram3D>("IHistogram3D");
0317   }
0318 
0319   /**
0320    * LWH cannot create a copy of an IHistogram3D.
0321    */
0322   IHistogram3D * createCopy(const std::string &, const IHistogram3D &) {
0323     return error<IHistogram3D>("IHistogram3D");
0324   }
0325 
0326   /**
0327    * LWH cannot create a IProfile1D.
0328    */
0329   IProfile1D * createProfile1D(const std::string &, const std::string &,
0330                    int, double, double, const std::string & = "") {
0331     return error<IProfile1D>("IProfile1D");
0332   }
0333 
0334   /**
0335    * LWH cannot create a IProfile1D.
0336    */
0337   IProfile1D * createProfile1D(const std::string &, const std::string &,
0338                    int, double, double, double, double,
0339                    const std::string & = "") {
0340     return error<IProfile1D>("IProfile1D");
0341   }
0342 
0343   /**
0344    * LWH cannot create a IProfile1D.
0345    */
0346   IProfile1D * createProfile1D(const std::string &, const std::string &,
0347                    const std::vector<double> &,
0348                    const std::string & = "") {
0349     return error<IProfile1D>("IProfile1D");
0350   }
0351 
0352   /**
0353    * LWH cannot create a IProfile1D.
0354    */
0355   IProfile1D * createProfile1D(const std::string &, const std::string &,
0356                    const std::vector<double> &, double, double,
0357                    const std::string & = "") {
0358     return error<IProfile1D>("IProfile1D");
0359   }
0360 
0361   /**
0362    * LWH cannot create a IProfile1D.
0363    */
0364   IProfile1D * createProfile1D(const std::string &, int, double, double) {
0365     return error<IProfile1D>("IProfile1D");
0366   }
0367 
0368   /**
0369    * LWH cannot create a IProfile1D.
0370    */
0371   IProfile1D * createProfile1D(const std::string &,
0372                    int, double, double, double, double) {
0373     return error<IProfile1D>("IProfile1D");
0374   }
0375 
0376   /**
0377    * LWH cannot create a copy of an IProfile1D.
0378    */
0379   IProfile1D * createCopy(const std::string &, const IProfile1D &) {
0380     return error<IProfile1D>("IProfile1D");
0381   }
0382 
0383   /**
0384    * LWH cannot create a IProfile2D.
0385    */
0386   IProfile2D * createProfile2D(const std::string &, const std::string &,
0387                    int, double, double, int, double, double,
0388                    const std::string & = "") {
0389     return error<IProfile2D>("IProfile2D");
0390   }
0391 
0392   /**
0393    * LWH cannot create a IProfile2D.
0394    */
0395   IProfile2D * createProfile2D(const std::string &, const std::string &,
0396                    int, double, double, int,
0397                    double, double, double, double,
0398                    const std::string & = "") {
0399     return error<IProfile2D>("IProfile2D");
0400   }
0401 
0402   /**
0403    * LWH cannot create a IProfile2D.
0404    */
0405   IProfile2D * createProfile2D(const std::string &, const std::string &,
0406                    const std::vector<double> &,
0407                    const std::vector<double> &,
0408                    const std::string & = "") {
0409     return error<IProfile2D>("IProfile2D");
0410   }
0411 
0412   /**
0413    * LWH cannot create a IProfile2D.
0414    */
0415   IProfile2D * createProfile2D(const std::string &, const std::string &,
0416                    const std::vector<double> &,
0417                    const std::vector<double> &,
0418                    double, double, const std::string & = "") {
0419     return error<IProfile2D>("IProfile2D");
0420   }
0421 
0422   /**
0423    * LWH cannot create a IProfile2D.
0424    */
0425   IProfile2D * createProfile2D(const std::string &, int, double, double,
0426                    int, double, double) {
0427     return error<IProfile2D>("IProfile2D");
0428   }
0429 
0430   /**
0431    * LWH cannot create a IProfile2D.
0432    */
0433   IProfile2D * createProfile2D(const std::string &, int, double, double,
0434                    int, double, double, double, double) {
0435     return error<IProfile2D>("IProfile2D");
0436   }
0437 
0438   /**
0439    * LWH cannot create a copy of an IProfile2D.
0440    */
0441   IProfile2D * createCopy(const std::string &, const IProfile2D &) {
0442     return error<IProfile2D>("IProfile2D");
0443   }
0444 
0445   /**
0446    * Create a Histogram1D by adding two Histogram1D.
0447    * @param path  The path of the created IHistogram. The path must be a
0448    *              full path.  ("/folder1/folder2/dataName" is a valid
0449    *              path). The characther `/` cannot be used in names; it
0450    *              is only used to delimit directories within paths.
0451    * @param hist1 The first member of the addition.
0452    * @param hist2 The second member of the addition.
0453    * @return      The sum of the two IHistogram1D.
0454    * @throws      std::runtime_error if histogram could not be created.
0455    */
0456   Histogram1D * add(const std::string & path,
0457              const Histogram1D & hist1, const Histogram1D & hist2) {
0458     if ( !checkBins(hist1, hist2) ) return 0;
0459     Histogram1D * h = new Histogram1D(hist1);
0460     h->setTitle(path.substr(path.rfind('/') + 1));
0461     h->add(hist2);
0462     if ( !tree->insert(path, h) ) return 0;
0463     return h;
0464   }
0465     
0466   /**
0467    * Create an IHistogram1D by adding two IHistogram1D.
0468    * @param path  The path of the created IHistogram. The path must be a
0469    *              full path.  ("/folder1/folder2/dataName" is a valid
0470    *              path). The characther `/` cannot be used in names; it
0471    *              is only used to delimit directories within paths.
0472    * @param hist1 The first member of the addition.
0473    * @param hist2 The second member of the addition.
0474    * @return      The sum of the two IHistogram1D.
0475    * @throws      std::runtime_error if histogram could not be created.
0476    */
0477   IHistogram1D * add(const std::string & path,
0478              const IHistogram1D & hist1, const IHistogram1D & hist2) {
0479     return add(path, dynamic_cast<const Histogram1D &>(hist1),
0480            dynamic_cast<const Histogram1D &>(hist2));
0481   }
0482     
0483   /**
0484    * Create a Histogram1D by subtracting two Histogram1D.
0485    * @param path  The path of the created IHistogram. The path must be a
0486    *              full path.  ("/folder1/folder2/dataName" is a valid
0487    *              path). The characther `/` cannot be used in names; it
0488    *              is only used to delimit directories within paths.
0489    * @param h1    The first member of the subtraction.
0490    * @param h2    The second member of the subtraction.
0491    * @return      The difference of the two IHistogram1D.
0492    * @throws      std::runtime_error if histogram could not be created.
0493    */
0494   Histogram1D * subtract(const std::string & path,
0495             const Histogram1D & h1, const Histogram1D & h2) {
0496     if ( !checkBins(h1, h2) ) return 0;
0497     Histogram1D * h = new Histogram1D(h1);
0498     h->setTitle(path.substr(path.rfind('/') + 1));
0499     for ( int i = 0; i < h->ax->bins() + 2; ++i ) {
0500       h->sum[i] += h2.sum[i];
0501       h->sumw[i] -= h2.sumw[i];
0502       h->sumw2[i] += h2.sumw2[i];
0503     }
0504     if ( !tree->insert(path, h) ) return 0;
0505     return h;
0506   }
0507 
0508   /**
0509    * Create an IHistogram1D by subtracting two IHistogram1D.
0510    * @param path  The path of the created IHistogram. The path must be a
0511    *              full path.  ("/folder1/folder2/dataName" is a valid
0512    *              path). The characther `/` cannot be used in names; it
0513    *              is only used to delimit directories within paths.
0514    * @param hist1 The first member of the subtraction.
0515    * @param hist2 The second member of the subtraction.
0516    * @return      The difference of the two IHistogram1D.
0517    * @throws      std::runtime_error if histogram could not be created.
0518    */
0519   IHistogram1D * subtract(const std::string & path, const IHistogram1D & hist1,
0520               const IHistogram1D & hist2) {
0521     return subtract(path, dynamic_cast<const Histogram1D &>(hist1),
0522             dynamic_cast<const Histogram1D &>(hist2));
0523   }
0524 
0525   /**
0526    * Create a Histogram1D by multiplying two Histogram1D.
0527    * @param path  The path of the created IHistogram. The path must be a
0528    *              full path.  ("/folder1/folder2/dataName" is a valid
0529    *              path). The characther `/` cannot be used in names; it
0530    *              is only used to delimit directories within paths.
0531    * @param h1    The first member of the multiplication.
0532    * @param h2    The second member of the multiplication.
0533    * @return      The product of the two IHistogram1D.
0534    * @throws      std::runtime_error if histogram could not be created.
0535    */
0536   Histogram1D * multiply(const std::string & path,
0537             const Histogram1D & h1, const Histogram1D & h2) {
0538     if ( !checkBins(h1, h2) ) return 0;
0539     Histogram1D * h = new Histogram1D(h1);
0540     h->setTitle(path.substr(path.rfind('/') + 1));
0541     for ( int i = 0; i < h->ax->bins() + 2; ++i ) {
0542       h->sumw[i] *= h2.sumw[i];
0543       h->sumw2[i] += h1.sumw[i]*h1.sumw[i]*h2.sumw2[i] +
0544     h2.sumw[i]*h2.sumw[i]*h1.sumw2[i];
0545     }
0546     if ( !tree->insert(path, h) ) return 0;
0547     return h;
0548   }
0549 
0550   /**
0551    * Create an IHistogram1D by multiplying two IHistogram1D.
0552    * @param path  The path of the created IHistogram. The path must be a
0553    *              full path.  ("/folder1/folder2/dataName" is a valid
0554    *              path). The characther `/` cannot be used in names; it
0555    *              is only used to delimit directories within paths.
0556    * @param hist1 The first member of the multiplication.
0557    * @param hist2 The second member of the multiplication.
0558    * @return      The product of the two IHistogram1D.
0559    * @throws      std::runtime_error if histogram could not be created.
0560    */
0561   IHistogram1D * multiply(const std::string & path, const IHistogram1D & hist1,
0562               const IHistogram1D & hist2) {
0563     return multiply(path, dynamic_cast<const Histogram1D &>(hist1),
0564             dynamic_cast<const Histogram1D &>(hist2));
0565   }
0566 
0567   /**
0568    * Create n Histogram1D by dividing two Histogram1D.
0569    * @param path  The path of the created IHistogram. The path must be a
0570    *              full path.  ("/folder1/folder2/dataName" is a valid
0571    *              path). The characther `/` cannot be used in names; it
0572    *              is only used to delimit directories within paths.
0573    * @param h1    The first member of the division.
0574    * @param h2    The second member of the division.
0575    * @return      The ration of the two IHistogram1D.
0576    * @throws      std::runtime_error if histogram could not be created.
0577    */
0578   Histogram1D * divide(const std::string & path,
0579           const Histogram1D & h1, const Histogram1D & h2) {
0580     if ( !checkBins(h1, h2) ) return 0;
0581     Histogram1D * h = new Histogram1D(h1);
0582     h->setTitle(path.substr(path.rfind('/') + 1));
0583     for ( int i = 0; i < h->ax->bins() + 2; ++i ) {
0584       if ( h2.sum[i] == 0 || h2.sumw[i] == 0.0 ) {
0585     h->sum[i] = 0;
0586     h->sumw[i] = h->sumw2[i] = 0.0;
0587     continue;
0588       }
0589       h->sumw[i] /= h2.sumw[i];
0590       h->sumw2[i] = h1.sumw2[i]/(h2.sumw[i]*h2.sumw[i]) +
0591     h1.sumw[i]*h1.sumw[i]*h2.sumw2[i]/
0592     (h2.sumw[i]*h2.sumw[i]*h2.sumw[i]*h2.sumw[i]);
0593     }
0594     if ( !tree->insert(path, h) ) return 0;
0595     return h;
0596   }
0597 
0598   /**
0599    * Create an IHistogram1D by dividing two IHistogram1D.
0600    * @param path  The path of the created IHistogram. The path must be a
0601    *              full path.  ("/folder1/folder2/dataName" is a valid
0602    *              path). The characther `/` cannot be used in names; it
0603    *              is only used to delimit directories within paths.
0604    * @param hist1 The first member of the division.
0605    * @param hist2 The second member of the division.
0606    * @return      The ration of the two IHistogram1D.
0607    * @throws      std::runtime_error if histogram could not be created.
0608    */
0609   IHistogram1D * divide(const std::string & path, const IHistogram1D & hist1,
0610             const IHistogram1D & hist2) {
0611     return divide(path, dynamic_cast<const Histogram1D &>(hist1),
0612             dynamic_cast<const Histogram1D &>(hist2));
0613   }
0614 
0615   inline bool _neq(double a, double b, double eps = 1e-5) const {
0616     using std::abs;
0617     if ( a == 0 && b == 0 ) return false;
0618     if ( abs(a-b) < eps*(abs(a) + abs(b)) ) return false;
0619     return true;
0620   }
0621 
0622   /**
0623    * Check if two histograms have the same bins.
0624    */
0625   bool checkBins(const Histogram1D & h1, const Histogram1D & h2) const {
0626     if ( _neq(h1.ax->upperEdge(), h2.ax->upperEdge()) ||
0627      _neq(h1.ax->lowerEdge(), h2.ax->lowerEdge()) ||
0628      _neq(h1.ax->bins(), h2.ax->bins()) ) return false;
0629     if ( h1.fax && h2.fax ) return true;
0630     for ( int i = 0; i < h1.ax->bins(); ++i ) {
0631       if ( _neq(h1.ax->binUpperEdge(i), h2.ax->binUpperEdge(i)) ||
0632        _neq(h1.ax->binLowerEdge(i), h2.ax->binLowerEdge(i)) ) return false;
0633     }
0634     return true;
0635   }
0636 
0637   /**
0638    * Check if two histograms have the same bins.
0639    */
0640   bool checkBins(const Histogram2D & h1, const Histogram2D & h2) const {
0641     if (_neq( h1.xax->upperEdge(), h2.xax->upperEdge()) ||
0642         _neq( h1.xax->lowerEdge(), h2.xax->lowerEdge()) ||
0643         h1.xax->bins() != h2.xax->bins() ) return false;
0644     if (_neq( h1.yax->upperEdge(), h2.yax->upperEdge()) ||
0645         _neq( h1.yax->lowerEdge(), h2.yax->lowerEdge()) ||
0646         h1.yax->bins() != h2.yax->bins() ) return false;
0647     if ( h1.xfax && h2.xfax && h1.yfax && h2.yfax ) return true;
0648     for ( int i = 0; i < h1.xax->bins(); ++i ) {
0649       if ( _neq(h1.xax->binUpperEdge(i), h2.xax->binUpperEdge(i)) ||
0650            _neq(h1.xax->binLowerEdge(i), h2.xax->binLowerEdge(i)) )
0651     return false;
0652     }
0653     for ( int i = 0; i < h1.yax->bins(); ++i ) {
0654       if ( _neq(h1.yax->binUpperEdge(i), h2.yax->binUpperEdge(i)) ||
0655            _neq(h1.yax->binLowerEdge(i), h2.yax->binLowerEdge(i)) )
0656     return false;
0657     }
0658     return true;
0659   }
0660 
0661   /**
0662    * LWH cannot create an IHistogram2D by adding two IHistogram2D.
0663    */
0664   IHistogram2D * add(const std::string & path,
0665                      const IHistogram2D & hist1, const IHistogram2D & hist2) {
0666     return add(path, dynamic_cast<const Histogram2D &>(hist1),
0667                dynamic_cast<const Histogram2D &>(hist2));
0668   }
0669 
0670   /**
0671    * LWH cannot create an IHistogram2D by adding two IHistogram2D.
0672    */
0673   Histogram2D * add(const std::string & path,
0674             const Histogram2D & h1, const Histogram2D & h2) {
0675     if ( !checkBins(h1, h2) ) return 0;
0676     Histogram2D * h = new Histogram2D(h1);
0677     h->setTitle(path.substr(path.rfind('/') + 1));
0678     h->add(h2);
0679     if ( !tree->insert(path, h) ) {
0680       delete h;
0681       return 0;
0682     }
0683     return h;    
0684   }
0685 
0686   /**
0687    * LWH cannot create an IHistogram2D by subtracting two IHistogram2D.
0688    */
0689   Histogram2D * subtract(const std::string & path,
0690                           const Histogram2D & h1, const Histogram2D & h2) {
0691     if ( !checkBins(h1, h2) ) {
0692       //std::cout << "!!!!!!!" << std::endl;
0693       return 0;
0694     }
0695     Histogram2D * h = new Histogram2D(h1);
0696     h->setTitle(path.substr(path.rfind('/') + 1));
0697     for ( int ix = 0; ix < h->xax->bins() + 2; ++ix )
0698       for ( int iy = 0; iy < h->yax->bins() + 2; ++iy ) {
0699     h->sum[ix][iy] += h2.sum[ix][iy];
0700     h->sumw[ix][iy] -= h2.sumw[ix][iy];
0701     h->sumw2[ix][iy] += h2.sumw2[ix][iy];
0702     h->sumxw[ix][iy] -= h2.sumxw[ix][iy];
0703     h->sumx2w[ix][iy] -= h2.sumx2w[ix][iy];
0704     h->sumyw[ix][iy] -= h2.sumyw[ix][iy];
0705     h->sumy2w[ix][iy] -= h2.sumy2w[ix][iy];
0706     }
0707     if ( !tree->insert(path, h) ) {
0708       //std::cout << "&&&&&&&" << std::endl;
0709       delete h;
0710       return 0;
0711     }
0712     return h;
0713   }
0714 
0715   /**
0716    * LWH cannot create an IHistogram2D by subtracting two IHistogram2D.
0717    */
0718   IHistogram2D * subtract(const std::string & path,
0719                           const IHistogram2D & h1, const IHistogram2D & h2) {
0720     return subtract(path, dynamic_cast<const Histogram2D &>(h1),
0721                     dynamic_cast<const Histogram2D &>(h2));
0722   }
0723 
0724   /**
0725    * LWH cannot create an IHistogram2D by multiplying two IHistogram2D.
0726    */
0727   IHistogram2D * multiply(const std::string & path,
0728                           const IHistogram2D & h1, const IHistogram2D & h2) {
0729     return multiply(path, dynamic_cast<const Histogram2D &>(h1),
0730                     dynamic_cast<const Histogram2D &>(h2));
0731   }
0732 
0733   /**
0734    * LWH cannot create an IHistogram2D by multiplying two IHistogram2D.
0735    */
0736   Histogram2D * multiply(const std::string & path,
0737                           const Histogram2D & h1, const Histogram2D & h2) {
0738     if ( !checkBins(h1, h2) ) return 0;
0739     Histogram2D * h = new Histogram2D(h1);
0740     h->setTitle(path.substr(path.rfind('/') + 1));
0741     for ( int ix = 0; ix < h->xax->bins() + 2; ++ix )
0742       for ( int iy = 0; iy < h->yax->bins() + 2; ++iy ) {
0743       h->sum[ix][iy] *= h2.sum[ix][iy];
0744       h->sumw[ix][iy] *= h2.sumw[ix][iy];
0745       h->sumw2[ix][iy] += h1.sumw[ix][iy]*h1.sumw[ix][iy]*h2.sumw2[ix][iy] +
0746         h2.sumw[ix][iy]*h2.sumw[ix][iy]*h1.sumw2[ix][iy];
0747     }
0748     if ( !tree->insert(path, h) ) {
0749       delete h;
0750       return 0;
0751     }
0752     return h;
0753   }
0754 
0755   /**
0756    * LWH cannot create an IHistogram2D by dividing two IHistogram2D.
0757    */
0758   Histogram2D * divide(const std::string & path,
0759                         const Histogram2D & h1, const Histogram2D & h2) {
0760     if ( !checkBins(h1,h2) ) return 0;
0761     Histogram2D * h = new Histogram2D(h1);
0762     h->setTitle(path.substr(path.rfind('/') + 1));
0763     for ( int ix = 0; ix < h->xax->bins() + 2; ++ix )
0764       for ( int iy = 0; iy < h->yax->bins() + 2; ++iy ) {
0765       if ( h2.sum[ix][iy] == 0 || h2.sumw[ix][iy] == 0.0 ) {
0766     h->sum[ix][iy] = 0;
0767     h->sumw[ix][iy] = h->sumw2[ix][iy] = 0.0;
0768     continue;
0769       }
0770       h->sumw[ix][iy] /= h2.sumw[ix][iy];
0771       h->sumw2[ix][iy] = h1.sumw2[ix][iy]/(h2.sumw[ix][iy]*h2.sumw[ix][iy]) +
0772     h1.sumw[ix][iy]*h1.sumw[ix][iy]*h2.sumw2[ix][iy]/
0773     (h2.sumw[ix][iy]*h2.sumw[ix][iy]*h2.sumw[ix][iy]*h2.sumw[ix][iy]);
0774     }
0775     if ( !tree->insert(path, h) ) {
0776       delete h;
0777       return 0;
0778     }
0779     return h;
0780   }
0781 
0782 
0783   /**
0784    * LWH cannot create an IHistogram2D by dividing two IHistogram2D.
0785    */
0786   IHistogram2D * divide(const std::string & path,
0787                         const IHistogram2D & h1, const IHistogram2D & h2) {
0788     return divide(path, dynamic_cast<const Histogram2D &>(h1),
0789           dynamic_cast<const Histogram2D &>(h2));
0790   }
0791 
0792   /**
0793    * LWH cannot create an IHistogram3D by adding two IHistogram3D.
0794    */
0795   IHistogram3D * add(const std::string &,
0796              const IHistogram3D &, const IHistogram3D &) {
0797     return error<IHistogram3D>("3D histograms");
0798   }
0799 
0800   /**
0801    * LWH cannot create an IHistogram3D by subtracting two IHistogram3D.
0802    */
0803   IHistogram3D * subtract(const std::string &,
0804               const IHistogram3D &, const IHistogram3D &) {
0805     return error<IHistogram3D>("3D histograms");
0806   }
0807 
0808   /**
0809    *  LWH cannot create an IHistogram3D by multiplying two IHistogram3D.
0810    */
0811   IHistogram3D * multiply(const std::string &,
0812               const IHistogram3D &, const IHistogram3D &) {
0813     return error<IHistogram3D>("3D histograms");
0814   }
0815 
0816   /**
0817    * LWH cannot create an IHistogram3D by dividing two IHistogram3D.
0818    */
0819   IHistogram3D * divide(const std::string &,
0820             const IHistogram3D &, const IHistogram3D &) {
0821     return error<IHistogram3D>("3D histograms");
0822   }
0823 
0824   /**
0825    * LWH cannot create an IHistogram1D by projecting an IHistogram2D
0826    * along its x axis.
0827    */
0828   IHistogram1D * projectionX(const std::string & path, const IHistogram2D & h) {
0829     return projectionX(path, dynamic_cast<const Histogram2D &>(h));
0830   }
0831 
0832   /**
0833    * LWH cannot create an IHistogram1D by projecting an IHistogram2D
0834    * along its x axis.
0835    */
0836   Histogram1D * projectionX(const std::string & path, const Histogram2D & h) {
0837     return sliceX(path, h, 0, h.yax->bins() - 1);
0838   }
0839 
0840   /**
0841    * LWH cannot create an IHistogram1D by projecting an IHistogram2D
0842    * along its y axis.
0843    */
0844   IHistogram1D * projectionY(const std::string & path, const IHistogram2D & h) {
0845     return projectionY(path, dynamic_cast<const Histogram2D &>(h));
0846   }
0847 
0848   /**
0849    * LWH cannot create an IHistogram1D by projecting an IHistogram2D
0850    * along its y axis.
0851    */
0852   Histogram1D * projectionY(const std::string & path, const Histogram2D & h) {
0853     return sliceY(path, h, 0, h.xax->bins() - 1);
0854   }
0855 
0856   /**
0857    * LWH cannot create an IHistogram1D by slicing an IHistogram2D
0858    * parallel to the y axis at a given bin.
0859    */
0860   IHistogram1D *
0861   sliceX(const std::string & path, const IHistogram2D & h, int i) {
0862     return sliceX(path, dynamic_cast<const Histogram2D &>(h), i, i);
0863   }
0864 
0865   /**
0866    * LWH cannot create an IHistogram1D by slicing an IHistogram2D
0867    * parallel to the y axis at a given bin.
0868    */
0869   Histogram1D *
0870   sliceX(const std::string & path, const Histogram2D & h, int i) {
0871     return sliceX(path, h, i, i);
0872   }
0873 
0874   /**
0875    * LWH cannot create an IHistogram1D by slicing an IHistogram2D
0876    * parallel to the x axis at a given bin.
0877    */
0878   IHistogram1D *
0879   sliceY(const std::string & path, const IHistogram2D & h, int i) {
0880     return sliceY(path, dynamic_cast<const Histogram2D &>(h), i, i);
0881   }
0882 
0883   /**
0884    * LWH cannot create an IHistogram1D by slicing an IHistogram2D
0885    * parallel to the x axis at a given bin.
0886    */
0887   Histogram1D * sliceY(const std::string & path, const Histogram2D & h, int i) {
0888     return sliceY(path, h, i, i);
0889   }
0890 
0891   /**
0892    * LWH cannot create an IHistogram1D by slicing an IHistogram2D
0893    * parallel to the y axis between two bins (inclusive).
0894    */
0895   IHistogram1D *
0896   sliceX(const std::string & path, const IHistogram2D & h, int il, int iu) {
0897     return sliceX(path, dynamic_cast<const Histogram2D &>(h), il, iu);
0898   }
0899 
0900   /**
0901    * LWH cannot create an IHistogram1D by slicing an IHistogram2D
0902    * parallel to the y axis between two bins (inclusive).
0903    */
0904   Histogram1D *
0905   sliceX(const std::string & path, const Histogram2D & h2, int il, int iu) {
0906     Histogram1D * h1;
0907     if ( h2.xfax )
0908       h1 = new Histogram1D(h2.xfax->bins(), h2.xfax->lowerEdge(),
0909                h2.xfax->upperEdge());
0910     else {
0911       std::vector<double> edges(h2.xax->bins() + 1);
0912       edges.push_back(h2.xax->lowerEdge());
0913       for ( int i = 0; i < h2.xax->bins(); ++i )
0914     edges.push_back(h2.xax->binLowerEdge(i));
0915       h1 = new Histogram1D(edges);
0916     }
0917     for ( int ix = 0; ix < h2.xax->bins() + 2; ++ix )
0918       for ( int iy = il + 2; iy <= iu + 2; ++iy ) {
0919     h1->sum[ix] += h2.sum[ix][iy];
0920     h1->sumw[ix] += h2.sumw[ix][iy];
0921     h1->sumw2[ix] += h2.sumw2[ix][iy];
0922     h1->sumxw[ix] += h2.sumxw[ix][iy];
0923     h1->sumx2w[ix] += h2.sumx2w[ix][iy];
0924       }
0925     if ( !tree->insert(path, h1) ) {
0926       delete h1;
0927       return 0;
0928     }
0929     return h1;
0930   }
0931 
0932   /**
0933    * LWH cannot create an IHistogram1D by slicing an IHistogram2D
0934    * parallel to the x axis between two bins (inclusive).
0935    */
0936   IHistogram1D *
0937   sliceY(const std::string & path, const IHistogram2D & h, int il, int iu) {
0938     return sliceY(path, dynamic_cast<const Histogram2D &>(h), il, iu);
0939   }
0940 
0941   Histogram1D *
0942   sliceY(const std::string & path, const Histogram2D & h2, int il, int iu) {   
0943     Histogram1D * h1;
0944     if ( h2.yfax )
0945       h1 = new Histogram1D(h2.yfax->bins(), h2.yfax->lowerEdge(),
0946                h2.yfax->upperEdge());
0947     else {
0948       std::vector<double> edges(h2.yax->bins() + 1);
0949       edges.push_back(h2.yax->lowerEdge());
0950       for ( int i = 0; i < h2.yax->bins(); ++i )
0951     edges.push_back(h2.yax->binLowerEdge(i));
0952       h1 = new Histogram1D(edges);
0953     }
0954     for ( int iy = 0; iy < h2.yax->bins() + 2; ++iy )
0955       for ( int ix = il + 2; ix <= iu + 2; ++ix ) {
0956     h1->sum[iy] += h2.sum[ix][iy];
0957     h1->sumw[iy] += h2.sumw[ix][iy];
0958     h1->sumw2[iy] += h2.sumw2[ix][iy];
0959     h1->sumxw[iy] += h2.sumyw[ix][iy];
0960     h1->sumx2w[iy] += h2.sumy2w[ix][iy];
0961       }
0962     if ( !tree->insert(path, h1) ) {
0963       delete h1;
0964       return 0;
0965     }
0966     return h1;
0967   }
0968 
0969   /**
0970    * LWH cannot create an IHistogram2D by projecting an IHistogram3D
0971    * on the x-y plane.
0972    */
0973   IHistogram2D * projectionXY(const std::string &, const IHistogram3D &) {
0974     return error<IHistogram2D>("2D histograms");
0975   }
0976 
0977   /**
0978    * LWH cannot create an IHistogram2D by projecting an IHistogram3D
0979    * on the x-z plane.
0980    */
0981   IHistogram2D * projectionXZ(const std::string &, const IHistogram3D &) {
0982     return error<IHistogram2D>("2D histograms");
0983   }
0984 
0985   /**
0986    * LWH cannot create an IHistogram2D by projecting an IHistogram3D
0987    * on the y-z plane.
0988    */
0989   IHistogram2D * projectionYZ(const std::string &, const IHistogram3D &) {
0990     return error<IHistogram2D>("2D histograms");
0991   }
0992 
0993   /**
0994    * LWH cannot create an IHistogram2D by slicing an IHistogram3D
0995    * perpendicular to the Z axis, between "index1" and "index2"
0996    * (inclusive).
0997    */
0998   IHistogram2D * sliceXY(const std::string &, const IHistogram3D &, int, int) {
0999     return error<IHistogram2D>("2D histograms");
1000   }
1001 
1002   /**
1003    * LWH cannot create an IHistogram2D by slicing an IHistogram3D
1004    * perpendicular to the Y axis, between "index1" and "index2"
1005    * (inclusive).
1006    */
1007   IHistogram2D * sliceXZ(const std::string &, const IHistogram3D &, int, int) {
1008     return error<IHistogram2D>("2D histograms");
1009   }
1010 
1011   /**
1012    *  LWH cannot create an IHistogram2D by slicing an IHistogram3D
1013    * perpendicular to the X axis, between "index1" and "index2"
1014    * (inclusive).
1015    */
1016   IHistogram2D * sliceYZ(const std::string &, const IHistogram3D &, int, int) {
1017     return error<IHistogram2D>("2D histograms");
1018   }
1019 
1020 
1021 private:
1022 
1023   /** Throw a suitable error. */
1024   template <typename T>
1025   static T * error(std::string feature) {
1026     throw std::runtime_error("LWH cannot handle " + feature + ".");
1027   }
1028 
1029   /** The tree where the actual histograms are stored. */
1030   Tree * tree;
1031 
1032 };
1033 
1034 }
1035 
1036 #endif /* LWH_HistogramFactory_H */