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