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