Analysis.cc

Go to the documentation of this file.
00001 // -*- C++ -*-
00002 #include "Rivet/Rivet.hh"
00003 #include "Rivet/RivetAIDA.hh"
00004 #include "Rivet/AnalysisHandler.hh"
00005 #include "Rivet/AnalysisInfo.hh"
00006 #include "Rivet/Analysis.hh"
00007 #include "Rivet/Tools/Logging.hh"
00008 #include "LWH/AIManagedObject.h"
00009 using namespace AIDA;
00010 
00011 namespace Rivet {
00012 
00013 
00014   namespace {
00015     string makeAxisCode(const size_t datasetId, const size_t xAxisId, const size_t yAxisId) {
00016       stringstream axisCode;
00017       axisCode << "d";
00018       if (datasetId < 10) axisCode << 0;
00019       axisCode << datasetId;
00020       axisCode << "-x";
00021       if (xAxisId < 10) axisCode << 0;
00022       axisCode << xAxisId;
00023       axisCode << "-y";
00024       if (yAxisId < 10) axisCode << 0;
00025       axisCode << yAxisId;
00026       return axisCode.str();
00027     }
00028   }
00029 
00030 
00031   ////////////////////////
00032 
00033 
00034   Analysis::Analysis(const string& name)
00035     : _crossSection(-1.0),
00036       _gotCrossSection(false),
00037       _needsCrossSection(false),
00038       _analysishandler(NULL),
00039       _madeHistoDir(false)
00040   {
00041     ProjectionApplier::_allowProjReg = false;
00042     _defaultname = name;
00043     AnalysisInfo* ai = AnalysisInfo::make(name);
00044     assert(ai != 0);
00045     _info.reset(ai);
00046     assert(_info.get() != 0);
00047     //setBeams(ANY, ANY);
00048   }
00049 
00050 
00051   Analysis::~Analysis()
00052   {  }
00053 
00054 
00055   IAnalysisFactory& Analysis::analysisFactory() {
00056     return handler().analysisFactory();
00057   }
00058 
00059 
00060   ITree& Analysis::tree() {
00061     return handler().tree();
00062   }
00063 
00064 
00065   IHistogramFactory& Analysis::histogramFactory() {
00066     return handler().histogramFactory();
00067   }
00068 
00069 
00070   IDataPointSetFactory& Analysis::datapointsetFactory() {
00071     return handler().datapointsetFactory();
00072   }
00073 
00074 
00075   double Analysis::sqrtS() const {
00076     return handler().sqrtS();
00077   }
00078 
00079   const ParticlePair& Analysis::beams() const {
00080     return handler().beams();
00081   }
00082 
00083   const PdgIdPair Analysis::beamIds() const {
00084     return handler().beamIds();
00085   }
00086 
00087 
00088   const string Analysis::histoDir() const {
00089     /// @todo This doesn't change: calc and cache at Analysis construction!
00090     string path = "/" + name();
00091     if (handler().runName().length() > 0) {
00092       path = "/" + handler().runName() + path;
00093     }
00094     while (find_first(path, "//")) {
00095       replace_all(path, "//", "/");
00096     }
00097     return path;
00098   }
00099 
00100 
00101   const string Analysis::histoPath(const string& hname) const {
00102     const string path = histoDir() + "/" + hname;
00103     return path;
00104   }
00105 
00106 
00107   Log& Analysis::getLog() const {
00108     string logname = "Rivet.Analysis." + name();
00109     return Log::getLog(logname);
00110   }
00111 
00112 
00113   size_t Analysis::numEvents() const {
00114     return handler().numEvents();
00115   }
00116 
00117 
00118   double Analysis::sumOfWeights() const {
00119     return handler().sumOfWeights();
00120   }
00121 
00122 
00123   ////////////////////////////////////////////////////////////
00124   // Metadata
00125 
00126   const AnalysisInfo& Analysis::info() const {
00127     assert(_info.get() != 0);
00128     return *_info;
00129   }
00130 
00131   string Analysis::name() const {
00132     if (_info && !_info->name().empty()) return _info->name();
00133     return _defaultname;
00134   }
00135 
00136   string Analysis::spiresId() const {
00137     if (!_info) return "NONE";
00138     return _info->spiresId();
00139   }
00140 
00141   vector<string> Analysis::authors() const {
00142     if (!_info) return std::vector<std::string>();
00143     return _info->authors();
00144   }
00145 
00146   string Analysis::summary() const {
00147     if (!_info) return "NONE";
00148     return _info->summary();
00149   }
00150 
00151   string Analysis::description() const {
00152     if (!_info) return "NONE";
00153     return _info->description();
00154   }
00155 
00156   string Analysis::runInfo() const {
00157     if (!_info) return "NONE";
00158     return _info->runInfo();
00159   }
00160 
00161   const std::vector<std::pair<double,double> >& Analysis::energies() const {
00162     return info().energies();
00163   }
00164 
00165   string Analysis::experiment() const {
00166     if (!_info) return "NONE";
00167     return _info->experiment();
00168   }
00169 
00170   string Analysis::collider() const {
00171     if (!_info) return "NONE";
00172     return _info->collider();
00173   }
00174 
00175   string Analysis::year() const {
00176     if (!_info) return "NONE";
00177     return _info->year();
00178   }
00179 
00180   vector<string> Analysis::references() const {
00181     if (!_info) return vector<string>();
00182     return _info->references();
00183   }
00184 
00185   string Analysis::bibKey() const {
00186     if (!_info) return "";
00187     return _info->bibKey();
00188   }
00189 
00190   string Analysis::bibTeX() const {
00191     if (!_info) return "";
00192     return _info->bibTeX();
00193   }
00194 
00195   string Analysis::status() const {
00196     if (!_info) return "UNVALIDATED";
00197     return _info->status();
00198   }
00199 
00200   vector<string> Analysis::todos() const {
00201     if (!_info) return vector<string>();
00202     return _info->todos();
00203   }
00204 
00205   const vector<PdgIdPair>& Analysis::requiredBeams() const {
00206     return info().beams();
00207   }
00208 
00209 
00210   /// @todo Deprecate?
00211   Analysis& Analysis::setBeams(PdgId beam1, PdgId beam2) {
00212     assert(_info.get() != 0);
00213     _info->_beams.clear();
00214     _info->_beams += make_pair(beam1, beam2);
00215     return *this;
00216   }
00217 
00218 
00219   /// @todo Deprecate?
00220   bool Analysis::isCompatible(PdgId beam1, PdgId beam2) const {
00221     PdgIdPair beams(beam1, beam2);
00222     return isCompatible(beams);
00223   }
00224 
00225 
00226   /// @todo Deprecate?
00227   bool Analysis::isCompatible(const PdgIdPair& beams) const {
00228     foreach (const PdgIdPair& bp, requiredBeams()) {
00229       if (compatible(beams, bp)) return true;
00230     }
00231     return false;
00232     /// @todo Need to also check internal consistency of the analysis'
00233     /// beam requirements with those of the projections it uses.
00234   }
00235 
00236 
00237   Analysis& Analysis::setCrossSection(double xs) {
00238     _crossSection = xs;
00239     _gotCrossSection = true;
00240     return *this;
00241   }
00242 
00243   /// @todo Deprecate, eventually
00244   bool Analysis::needsCrossSection() const {
00245     return _needsCrossSection;
00246   }
00247 
00248   /// @todo Deprecate, eventually
00249   Analysis& Analysis::setNeedsCrossSection(bool needed) {
00250     _needsCrossSection = needed;
00251     return *this;
00252   }
00253 
00254   double Analysis::crossSection() const {
00255     if (!_gotCrossSection || _crossSection < 0) {
00256       string errMsg = "You did not set the cross section for the analysis " + name();
00257       throw Error(errMsg);
00258     }
00259     return _crossSection;
00260   }
00261 
00262   double Analysis::crossSectionPerEvent() const {
00263     const double sumW = sumOfWeights();
00264     assert(sumW > 0);
00265     return _crossSection / sumW;
00266   }
00267 
00268 
00269   AnalysisHandler& Analysis::handler() const {
00270     return *_analysishandler;
00271   }
00272 
00273 
00274 
00275   ////////////////////////////////////////////////////////////
00276   // Histogramming
00277 
00278 
00279   void Analysis::_cacheBinEdges() const {
00280     _cacheXAxisData();
00281     if (_histBinEdges.empty()) {
00282       getLog() << Log::TRACE << "Getting histo bin edges from AIDA for paper " << name() << endl;
00283       _histBinEdges = getBinEdges(_dpsData);
00284     }
00285   }
00286 
00287 
00288   void Analysis::_cacheXAxisData() const {
00289     if (_dpsData.empty()) {
00290       getLog() << Log::TRACE << "Getting DPS x-axis data from AIDA for paper " << name() << endl;
00291       _dpsData = getDPSXValsErrs(name());
00292     }
00293   }
00294 
00295 
00296   const BinEdges& Analysis::binEdges(const string& hname) const {
00297     _cacheBinEdges();
00298     getLog() << Log::TRACE << "Using histo bin edges for " << name() << ":" << hname << endl;
00299     const BinEdges& edges = _histBinEdges.find(hname)->second;
00300     if (getLog().isActive(Log::TRACE)) {
00301       stringstream edges_ss;
00302       foreach (const double be, edges) {
00303         edges_ss << " " << be;
00304       }
00305       getLog() << Log::TRACE << "Edges:" << edges_ss.str() << endl;
00306     }
00307     return edges;
00308   }
00309 
00310 
00311   const BinEdges& Analysis::binEdges(size_t datasetId, size_t xAxisId, size_t yAxisId) const {
00312     const string hname = makeAxisCode(datasetId, xAxisId, yAxisId);
00313     return binEdges(hname);
00314   }
00315 
00316 
00317   BinEdges Analysis::logBinEdges(size_t nbins, double lower, double upper) {
00318     assert(lower>0.0);
00319     assert(upper>lower);
00320     double loglower=log10(lower);
00321     double logupper=log10(upper);
00322     vector<double> binedges;
00323     double stepwidth=(logupper-loglower)/double(nbins);
00324     for (size_t i=0; i<=nbins; ++i) {
00325       binedges.push_back(pow(10.0, loglower+double(i)*stepwidth));
00326     }
00327     return binedges;
00328   }
00329 
00330   IHistogram1D* Analysis::bookHistogram1D(size_t datasetId, size_t xAxisId,
00331                                           size_t yAxisId, const string& title,
00332                                           const string& xtitle, const string& ytitle)
00333   {
00334     const string axisCode = makeAxisCode(datasetId, xAxisId, yAxisId);
00335     return bookHistogram1D(axisCode, title, xtitle, ytitle);
00336   }
00337 
00338 
00339   IHistogram1D* Analysis::bookHistogram1D(const string& hname, const string& title,
00340                                           const string& xtitle, const string& ytitle)
00341   {
00342     // Get the bin edges (only read the AIDA file once)
00343     const BinEdges edges = binEdges(hname);
00344     _makeHistoDir();
00345     const string path = histoPath(hname);
00346     IHistogram1D* hist = histogramFactory().createHistogram1D(path, title, edges);
00347     getLog() << Log::TRACE << "Made histogram " << hname <<  " for " << name() << endl;
00348     hist->setXTitle(xtitle);
00349     hist->setYTitle(ytitle);
00350     return hist;
00351   }
00352 
00353 
00354   IHistogram1D* Analysis::bookHistogram1D(const string& hname,
00355                                           size_t nbins, double lower, double upper,
00356                                           const string& title,
00357                                           const string& xtitle, const string& ytitle) {
00358     _makeHistoDir();
00359     const string path = histoPath(hname);
00360     IHistogram1D* hist = histogramFactory().createHistogram1D(path, title, nbins, lower, upper);
00361     getLog() << Log::TRACE << "Made histogram " << hname <<  " for " << name() << endl;
00362     hist->setXTitle(xtitle);
00363     hist->setYTitle(ytitle);
00364     return hist;
00365   }
00366 
00367 
00368   IHistogram1D* Analysis::bookHistogram1D(const string& hname,
00369                                           const vector<double>& binedges,
00370                                           const string& title,
00371                                           const string& xtitle, const string& ytitle) {
00372     _makeHistoDir();
00373     const string path = histoPath(hname);
00374     IHistogram1D* hist = histogramFactory().createHistogram1D(path, title, binedges);
00375     getLog() << Log::TRACE << "Made histogram " << hname <<  " for " << name() << endl;
00376     hist->setXTitle(xtitle);
00377     hist->setYTitle(ytitle);
00378     return hist;
00379   }
00380 
00381   IHistogram2D*
00382   Analysis::bookHistogram2D(const string& hname,
00383                 size_t nxbins, double xlower, double xupper,
00384                 size_t nybins, double ylower, double yupper,
00385                 const string& title, const string& xtitle,
00386                 const string& ytitle, const string& ztitle) {
00387     _makeHistoDir();
00388     const string path = histoPath(hname);
00389     IHistogram2D* hist =
00390       histogramFactory().createHistogram2D(path, title, nxbins, xlower, xupper,
00391                        nybins, ylower, yupper);
00392     getLog() << Log::TRACE << "Made 2D histogram "
00393          << hname <<  " for " << name() << endl;
00394     hist->setXTitle(xtitle);
00395     hist->setYTitle(ytitle);
00396     hist->setZTitle(ztitle);
00397     return hist;
00398   }
00399 
00400 
00401   IHistogram2D*
00402   Analysis::bookHistogram2D(const string& hname,
00403                 const vector<double>& xbinedges,
00404                 const vector<double>& ybinedges,
00405                 const string& title, const string& xtitle,
00406                 const string& ytitle, const string& ztitle) {
00407     _makeHistoDir();
00408     const string path = histoPath(hname);
00409     IHistogram2D* hist =
00410       histogramFactory().createHistogram2D(path, title, xbinedges, ybinedges);
00411     getLog() << Log::TRACE << "Made 2D histogram " << hname <<  " for "
00412          << name() << endl;
00413     hist->setXTitle(xtitle);
00414     hist->setYTitle(ytitle);
00415     hist->setZTitle(ztitle);
00416     return hist;
00417   }
00418 
00419 
00420   /////////////////
00421 
00422 
00423   IProfile1D* Analysis::bookProfile1D(size_t datasetId, size_t xAxisId,
00424                                       size_t yAxisId, const string& title,
00425                                       const string& xtitle, const string& ytitle) {
00426     const string axisCode = makeAxisCode(datasetId, xAxisId, yAxisId);
00427     return bookProfile1D(axisCode, title, xtitle, ytitle);
00428   }
00429 
00430 
00431   IProfile1D* Analysis::bookProfile1D(const string& hname, const string& title,
00432                                       const string& xtitle, const string& ytitle)
00433   {
00434     // Get the bin edges (only read the AIDA file once)
00435     const BinEdges edges = binEdges(hname);
00436     _makeHistoDir();
00437     const string path = histoPath(hname);
00438     IProfile1D* prof = histogramFactory().createProfile1D(path, title, edges);
00439     getLog() << Log::TRACE << "Made profile histogram " << hname <<  " for " << name() << endl;
00440     prof->setXTitle(xtitle);
00441     prof->setYTitle(ytitle);
00442     return prof;
00443   }
00444 
00445 
00446   IProfile1D* Analysis::bookProfile1D(const string& hname,
00447                                       size_t nbins, double lower, double upper,
00448                                       const string& title,
00449                                       const string& xtitle, const string& ytitle) {
00450     _makeHistoDir();
00451     const string path = histoPath(hname);
00452     IProfile1D* prof = histogramFactory().createProfile1D(path, title, nbins, lower, upper);
00453     getLog() << Log::TRACE << "Made profile histogram " << hname <<  " for " << name() << endl;
00454     prof->setXTitle(xtitle);
00455     prof->setYTitle(ytitle);
00456     return prof;
00457   }
00458 
00459 
00460   IProfile1D* Analysis::bookProfile1D(const string& hname,
00461                                       const vector<double>& binedges,
00462                                       const string& title,
00463                                       const string& xtitle, const string& ytitle) {
00464     _makeHistoDir();
00465     const string path = histoPath(hname);
00466     IProfile1D* prof = histogramFactory().createProfile1D(path, title, binedges);
00467     getLog() << Log::TRACE << "Made profile histogram " << hname <<  " for " << name() << endl;
00468     prof->setXTitle(xtitle);
00469     prof->setYTitle(ytitle);
00470     return prof;
00471   }
00472 
00473 
00474   ///////////////////
00475 
00476 
00477 
00478   IDataPointSet* Analysis::bookDataPointSet(const string& hname, const string& title,
00479                                             const string& xtitle, const string& ytitle) {
00480     _makeHistoDir();
00481     const string path = histoPath(hname);
00482     IDataPointSet* dps = datapointsetFactory().create(path, title, 2);
00483     getLog() << Log::TRACE << "Made data point set " << hname <<  " for " << name() << endl;
00484     dps->setXTitle(xtitle);
00485     dps->setYTitle(ytitle);
00486     return dps;
00487   }
00488 
00489 
00490   IDataPointSet* Analysis::bookDataPointSet(const string& hname,
00491                                             size_t npts, double lower, double upper,
00492                                             const string& title,
00493                                             const string& xtitle, const string& ytitle) {
00494     IDataPointSet* dps = bookDataPointSet(hname, title, xtitle, ytitle);
00495     for (size_t pt = 0; pt < npts; ++pt) {
00496       const double binwidth = (upper-lower)/npts;
00497       const double bincentre = lower + (pt + 0.5) * binwidth;
00498       dps->addPoint();
00499       IMeasurement* meas = dps->point(pt)->coordinate(0);
00500       meas->setValue(bincentre);
00501       meas->setErrorPlus(binwidth/2.0);
00502       meas->setErrorMinus(binwidth/2.0);
00503     }
00504     return dps;
00505   }
00506 
00507 
00508   IDataPointSet* Analysis::bookDataPointSet(size_t datasetId, size_t xAxisId,
00509                                             size_t yAxisId, const string& title,
00510                                             const string& xtitle, const string& ytitle) {
00511     // Get the bin edges (only read the AIDA file once)
00512     _cacheXAxisData();
00513     // Build the axis code
00514     const string axisCode = makeAxisCode(datasetId, xAxisId, yAxisId);
00515     //const map<string, vector<DPSXPoint> > xpoints = getDPSXValsErrs(papername);
00516     getLog() << Log::TRACE << "Using DPS x-positions for " << name() << ":" << axisCode << endl;
00517     IDataPointSet* dps = bookDataPointSet(axisCode, title, xtitle, ytitle);
00518     const vector<DPSXPoint> xpts = _dpsData.find(axisCode)->second;
00519     for (size_t pt = 0; pt < xpts.size(); ++pt) {
00520       dps->addPoint();
00521       IMeasurement* meas = dps->point(pt)->coordinate(0);
00522       meas->setValue(xpts[pt].val);
00523       meas->setErrorPlus(xpts[pt].errplus);
00524       meas->setErrorMinus(xpts[pt].errminus);
00525     }
00526     getLog() << Log::TRACE << "Made DPS " << axisCode <<  " for " << name() << endl;
00527     return dps;
00528   }
00529 
00530 
00531   ////////////////////
00532 
00533 
00534   void Analysis::_makeHistoDir() {
00535     if (!_madeHistoDir) {
00536       if (! name().empty()) {
00537         // vector<string> dirs;
00538         // split(dirs, histoDir(), "/");
00539         // string pathpart;
00540         // foreach (const string& d, dirs) {
00541         //tree().mkdir();
00542         //}
00543         tree().mkdirs(histoDir());
00544       }
00545       _madeHistoDir = true;
00546     }
00547   }
00548 
00549 
00550   void Analysis::normalize(AIDA::IHistogram1D*& histo, double norm) {
00551     if (!histo) {
00552       getLog() << Log::ERROR << "Failed to normalise histo=NULL in analysis "
00553                << name() << " (norm=" << norm << ")" << endl;
00554       return;
00555     }
00556     const string hpath = tree().findPath(dynamic_cast<const AIDA::IManagedObject&>(*histo));
00557     getLog() << Log::TRACE << "Normalizing histo " << hpath << " to " << norm << endl;
00558 
00559     double oldintg = 0.0;
00560     int nBins = histo->axis().bins();
00561     for (int iBin = 0; iBin != nBins; ++iBin) {
00562       // Leaving out factor of binWidth because AIDA's "height" already includes a width factor.
00563       oldintg += histo->binHeight(iBin); // * histo->axis().binWidth(iBin);
00564     }
00565     if (oldintg == 0.0) {
00566       getLog() << Log::WARN << "Histo " << hpath << " has null integral during normalisation" << endl;
00567       return;
00568     }
00569 
00570     // Scale by the normalisation factor.
00571     scale(histo, norm/oldintg);
00572   }
00573 
00574 
00575   void Analysis::scale(AIDA::IHistogram1D*& histo, double scale) {
00576     if (!histo) {
00577       getLog() << Log::ERROR << "Failed to scale histo=NULL in analysis "
00578           << name() << " (scale=" << scale << ")" << endl;
00579       return;
00580     }
00581     const string hpath = tree().findPath(dynamic_cast<const AIDA::IManagedObject&>(*histo));
00582     getLog() << Log::TRACE << "Scaling histo " << hpath << endl;
00583 
00584     vector<double> x, y, ex, ey;
00585     for (size_t i = 0, N = histo->axis().bins(); i < N; ++i) {
00586       x.push_back(0.5 * (histo->axis().binLowerEdge(i) + histo->axis().binUpperEdge(i)));
00587       ex.push_back(histo->axis().binWidth(i)*0.5);
00588 
00589       // "Bin height" is a misnomer in the AIDA spec: width is neglected.
00590       // We'd like to do this: y.push_back(histo->binHeight(i) * scale);
00591       y.push_back(histo->binHeight(i)*scale/histo->axis().binWidth(i));
00592 
00593       // "Bin error" is a misnomer in the AIDA spec: width is neglected.
00594       // We'd like to do this: ey.push_back(histo->binError(i) * scale);
00595       ey.push_back(histo->binError(i)*scale/histo->axis().binWidth(i));
00596     }
00597 
00598     string title = histo->title();
00599     string xtitle = histo->xtitle();
00600     string ytitle = histo->ytitle();
00601 
00602     tree().mkdir("/tmpnormalize");
00603     tree().mv(hpath, "/tmpnormalize");
00604 
00605     AIDA::IDataPointSet* dps = datapointsetFactory().createXY(hpath, title, x, y, ex, ey);
00606     dps->setXTitle(xtitle);
00607     dps->setYTitle(ytitle);
00608 
00609     tree().rm(tree().findPath(dynamic_cast<AIDA::IManagedObject&>(*histo)));
00610     tree().rmdir("/tmpnormalize");
00611 
00612     // Set histo pointer to null - it can no longer be used.
00613     histo = 0;
00614   }
00615 
00616 
00617   void Analysis::normalize(AIDA::IHistogram2D*& histo, double norm) {
00618     if (!histo) {
00619       getLog() << Log::ERROR << "Failed to normalise histo=NULL in analysis "
00620                << name() << " (norm=" << norm << ")" << endl;
00621       return;
00622     }
00623     const string hpath = tree().findPath(dynamic_cast<const AIDA::IManagedObject&>(*histo));
00624     getLog() << Log::TRACE << "Normalizing histo " << hpath << " to " << norm << endl;
00625 
00626     double oldintg = 0.0;
00627     int nxBins = histo->xAxis().bins();
00628     int nyBins = histo->yAxis().bins();
00629     for (int ixBin = 0; ixBin != nxBins; ++ixBin)
00630       for (int iyBin = 0; iyBin != nyBins; ++iyBin) {
00631       // Leaving out factor of binWidth because AIDA's "height"
00632       // already includes a width factor.
00633     oldintg += histo->binHeight(ixBin, iyBin); // * histo->axis().binWidth(iBin);
00634     }
00635     if (oldintg == 0.0) {
00636       getLog() << Log::WARN << "Histo " << hpath
00637            << " has null integral during normalisation" << endl;
00638       return;
00639     }
00640 
00641     // Scale by the normalisation factor.
00642     scale(histo, norm/oldintg);
00643   }
00644 
00645 
00646   void Analysis::scale(AIDA::IHistogram2D*& histo, double scale) {
00647     if (!histo) {
00648       getLog() << Log::ERROR << "Failed to scale histo=NULL in analysis "
00649            << name() << " (scale=" << scale << ")" << endl;
00650       return;
00651     }
00652     const string hpath =
00653       tree().findPath(dynamic_cast<const AIDA::IManagedObject&>(*histo));
00654     getLog() << Log::TRACE << "Scaling histo " << hpath << endl;
00655 
00656     vector<double> x, y, z, ex, ey, ez;
00657     for (size_t ix = 0, Nx = histo->xAxis().bins(); ix < Nx; ++ix)
00658       for (size_t iy = 0, Ny = histo->yAxis().bins(); iy < Ny; ++iy) {
00659     x.push_back(0.5 * (histo->xAxis().binLowerEdge(ix) +
00660                histo->xAxis().binUpperEdge(ix)));
00661     ex.push_back(histo->xAxis().binWidth(ix)*0.5);
00662     y.push_back(0.5 * (histo->yAxis().binLowerEdge(iy) +
00663                histo->yAxis().binUpperEdge(iy)));
00664     ey.push_back(histo->yAxis().binWidth(iy)*0.5);
00665 
00666     // "Bin height" is a misnomer in the AIDA spec: width is neglected.
00667     // We'd like to do this: y.push_back(histo->binHeight(i) * scale);
00668     z.push_back(histo->binHeight(ix, iy)*scale/
00669             (histo->xAxis().binWidth(ix)*histo->yAxis().binWidth(iy)));
00670     // "Bin error" is a misnomer in the AIDA spec: width is neglected.
00671     // We'd like to do this: ey.push_back(histo->binError(i) * scale);
00672     ez.push_back(histo->binError(ix, iy)*scale/
00673              (histo->xAxis().binWidth(ix)*histo->yAxis().binWidth(iy)));
00674     }
00675 
00676     string title = histo->title();
00677     string xtitle = histo->xtitle();
00678     string ytitle = histo->ytitle();
00679     string ztitle = histo->ztitle();
00680 
00681     tree().mkdir("/tmpnormalize");
00682     tree().mv(hpath, "/tmpnormalize");
00683 
00684     AIDA::IDataPointSet* dps =
00685       datapointsetFactory().createXYZ(hpath, title, x, y, z, ex, ey, ez);
00686     dps->setXTitle(xtitle);
00687     dps->setYTitle(ytitle);
00688     dps->setZTitle(ztitle);
00689 
00690     tree().rm(tree().findPath(dynamic_cast<AIDA::IManagedObject&>(*histo)));
00691     tree().rmdir("/tmpnormalize");
00692 
00693     // Set histo pointer to null - it can no longer be used.
00694     histo = 0;
00695   }
00696 
00697 
00698 }