AnalysisHandler.cc

Go to the documentation of this file.
00001 // -*- C++ -*-
00002 #include "Rivet/Rivet.hh"
00003 #include "Rivet/Tools/Logging.hh"
00004 #include "Rivet/ParticleName.hh"
00005 #include "Rivet/AnalysisHandler.hh"
00006 #include "Rivet/RivetAIDA.hh"
00007 #include "Rivet/Analysis.hh"
00008 #include "Rivet/Event.hh"
00009 #include "Rivet/Projections/Beam.hh"
00010 #include "LWH/AIManagedObject.h"
00011 
00012 using namespace AIDA;
00013 
00014 namespace Rivet {
00015 
00016 
00017   AnalysisHandler::AnalysisHandler(const string& runname)
00018     : _runname(runname), _numEvents(0),
00019       _sumOfWeights(0.0), _xs(-1.0),
00020       _initialised(false)
00021   {
00022     _theAnalysisFactory.reset( createAnalysisFactory() );
00023     _setupFactories();
00024   }
00025 
00026 
00027   AnalysisHandler::AnalysisHandler(const string& basefilename,
00028                                    const string& runname, HistoFormat storetype)
00029     : _runname(runname), _numEvents(0),
00030       _sumOfWeights(0.0), _xs(-1.0),
00031       _initialised(false)
00032   {
00033     cerr << "AnalysisHandler(basefilename, runname, format) constructor is deprecated: "
00034          << "please migrate your code to use the one-arg constructor" << endl;
00035     _theAnalysisFactory.reset( createAnalysisFactory() );
00036     _setupFactories(basefilename, storetype);
00037   }
00038 
00039 
00040   // AnalysisHandler::AnalysisHandler(IAnalysisFactory& afac, string basefilename,
00041   //                                  string runname, HistoFormat storetype)
00042   //   : _runname(runname), _numEvents(0),
00043   //     _sumOfWeights(0.0), _xs(-1.0), _initialised(false),
00044   //     _theAnalysisFactory(&afac)
00045   // {
00046   //   _setupFactories(basefilename, storetype);
00047   //   initializeParticleNames();
00048   // }
00049 
00050 
00051   AnalysisHandler::~AnalysisHandler()
00052   {  }
00053 
00054 
00055   Log& AnalysisHandler::getLog() {
00056     return Log::getLog("Rivet.Analysis.Handler");
00057   }
00058 
00059 
00060   void AnalysisHandler::init(const GenEvent& ge) {
00061     assert(!_initialised);
00062     setRunBeams(Rivet::beams(ge));
00063     getLog() << Log::DEBUG << "Initialising the analysis handler" << endl;
00064     _numEvents = 0;
00065     _sumOfWeights = 0.0;
00066 
00067     // Check that analyses are beam-compatible
00068     const size_t num_anas_requested = analysisNames().size();
00069     removeIncompatibleAnalyses(beamIds());
00070     foreach (const AnaHandle a, analyses()) {
00071       if (toUpper(a->status()) != "VALIDATED") {
00072         getLog() << Log::WARN
00073                  << "Analysis '" << a->name() << "' is unvalidated: be careful!" << endl;
00074       }
00075     }
00076     if (num_anas_requested > 0 && analysisNames().size() == 0) {
00077       getLog() << Log::ERROR
00078                << "All analyses were incompatible with the first event's beams\n"
00079                << "Exiting, since this probably isn't intentional!" << endl;
00080       exit(1);
00081     }
00082 
00083     foreach (AnaHandle a, _analyses) {
00084       getLog() << Log::DEBUG << "Initialising analysis: " << a->name() << endl;
00085       try {
00086         // Allow projection registration in the init phase onwards
00087         a->_allowProjReg = true;
00088         a->init();
00089         //getLog() << Log::DEBUG << "Checking consistency of analysis: " << a->name() << endl;
00090         //a->checkConsistency();
00091       } catch (const Error& err) {
00092         getLog() << Log::ERROR << "Error in " << a->name() << "::init method: "
00093                  << err.what() << endl;
00094         exit(1);
00095       }
00096       getLog() << Log::DEBUG << "Done initialising analysis: " << a->name() << endl;
00097     }
00098     _initialised = true;
00099     getLog() << Log::DEBUG << "Analysis handler initialised" << endl;
00100   }
00101 
00102 
00103   void AnalysisHandler::analyze(const GenEvent& ge) {
00104     // Call init with event as template if not already initialised
00105     if (!_initialised) {
00106       init(ge);
00107     }
00108     // Proceed with event analysis
00109     assert(_initialised);
00110     // Ensure that beam details match those from first event
00111     const PdgIdPair beams = Rivet::beamIds(ge);
00112     const double sqrts = Rivet::sqrtS(ge);
00113     if (!compatible(beams, _beams) || !fuzzyEquals(sqrts, sqrtS())) {
00114       getLog() << Log::ERROR << "Event beams mismatch: "
00115                << toBeamsString(beams) << " @ " << sqrts/GeV << " GeV" << " vs. first beams "
00116                << this->beams() << " @ " << this->sqrtS()/GeV << " GeV" << endl;
00117       exit(1);
00118     }
00119 
00120 
00121     Event event(ge);
00122     _numEvents++;
00123     // Weights
00124     const double weight = event.weight();
00125     _sumOfWeights += weight;
00126     getLog() << Log::DEBUG << "Event #" << _numEvents << " weight = " << weight << endl;
00127     #ifdef HEPMC_HAS_CROSS_SECTION
00128     if (ge.cross_section()) {
00129       const double xs = ge.cross_section()->cross_section();
00130       setCrossSection(xs);
00131     }
00132     #endif
00133     foreach (AnaHandle a, _analyses) {
00134       //getLog() << Log::DEBUG << "About to run analysis " << a->name() << endl;
00135       try {
00136         a->analyze(event);
00137       } catch (const Error& err) {
00138         getLog() << Log::ERROR << "Error in " << a->name() << "::analyze method: "
00139                  << err.what() << endl;
00140         exit(1);
00141       }
00142       //getLog() << Log::DEBUG << "Finished running analysis " << a->name() << endl;
00143     }
00144   }
00145 
00146 
00147   void AnalysisHandler::finalize() {
00148     assert(_initialised);
00149     getLog() << Log::INFO << "Finalising analyses" << endl;
00150     foreach (AnaHandle a, _analyses) {
00151       try {
00152         a->finalize();
00153       } catch (const Error& err) {
00154         getLog() << Log::ERROR << "Error in " << a->name() << "::finalize method: "
00155                  << err.what() << endl;
00156         exit(1);
00157       }
00158     }
00159 
00160     // Print out number of events processed
00161     getLog() << Log::INFO << "Processed " << _numEvents << " event" << (_numEvents == 1 ? "" : "s") << endl;
00162 
00163     // Change AIDA histos into data point sets
00164     getLog() << Log::DEBUG << "Converting histograms to scatter plots" << endl;
00165     assert(_theTree != 0);
00166     _normalizeTree(tree());
00167 
00168     // Delete analyses
00169     getLog() << Log::DEBUG << "Deleting analyses" << endl;
00170     _analyses.clear();
00171 
00172     // Print out MCnet boilerplate
00173     cout << endl;
00174     cout << "The MCnet usage guidelines apply to Rivet: see http://www.montecarlonet.org/GUIDELINES" << endl;
00175     cout << "Please acknowledge plots made with Rivet analyses, and cite arXiv:1003.0694 (http://arxiv.org/abs/1003.0694)" << endl;
00176   }
00177 
00178 
00179   AnalysisHandler& AnalysisHandler::addAnalysis(const string& analysisname) {
00180     // Check for a duplicate analysis
00181     /// @todo Might we want to be able to run an analysis twice, with different params?
00182     ///       Requires avoiding histo tree clashes, i.e. storing the histos on the analysis objects.
00183     foreach (const AnaHandle& a, _analyses) {
00184       if (a->name() == analysisname) {
00185         getLog() << Log::WARNING 
00186          << "Analysis '" << analysisname 
00187          << "' already registered: skipping duplicate" << endl;
00188         return *this;
00189       }
00190     }
00191     AnaHandle analysis( AnalysisLoader::getAnalysis(analysisname) );
00192     if (analysis.get() != 0) { // < Check for null analysis.
00193       getLog() << Log::DEBUG << "Adding analysis '" << analysisname << "'" << endl;
00194       analysis->_analysishandler = this;
00195       _analyses.insert(analysis);
00196     }
00197     else {
00198       getLog() << Log::WARNING 
00199            << "Analysis '" << analysisname 
00200            << "' not found." << endl;
00201     }
00202     return *this;
00203   }
00204 
00205 
00206   AnalysisHandler& AnalysisHandler::removeAnalysis(const string& analysisname) {
00207     shared_ptr<Analysis> toremove;
00208     foreach (const AnaHandle a, _analyses) {
00209       if (a->name() == analysisname) {
00210         toremove.reset( a.get() );
00211         break;
00212       }
00213     }
00214     if (toremove.get() != 0) {
00215       getLog() << Log::DEBUG << "Removing analysis '" << analysisname << "'" << endl;
00216       _analyses.erase(toremove);
00217     }
00218     return *this;
00219   }
00220 
00221 
00222   AnalysisHandler& AnalysisHandler::removeIncompatibleAnalyses(const PdgIdPair& beams) {
00223     vector<string> anamestodelete;
00224     foreach (const AnaHandle a, _analyses) {
00225       if (! a->isCompatible(beams)) {
00226         anamestodelete.push_back(a->name());
00227       }
00228     }
00229     foreach (const string& aname, anamestodelete) {
00230       getLog() << Log::WARN << "Removing incompatible analysis '"
00231                << aname << "'" << endl;
00232       removeAnalysis(aname);
00233     }
00234     return *this;
00235   }
00236 
00237 
00238   void AnalysisHandler::_setupFactories(const string& basefilename, HistoFormat storetype) {
00239     string filename(basefilename), storetypestr("");
00240     if (storetype == AIDAML) {
00241       if (!endsWith(filename, ".aida")) filename += ".aida";
00242       storetypestr = "xml";
00243     } else if (storetype == FLAT) {
00244       if (!endsWith(filename, ".data")) filename += ".data";
00245       storetypestr = "flat";
00246     } else if (storetype == ROOT) {
00247       if (!endsWith(filename, ".root")) filename += ".root";
00248       storetypestr = "root";
00249     }
00250     _theTreeFactory = _theAnalysisFactory->createTreeFactory();
00251     _theTree = _theTreeFactory->create(filename, storetypestr, false, true);
00252     _theHistogramFactory = _theAnalysisFactory->createHistogramFactory(tree());
00253     _theDataPointSetFactory = _theAnalysisFactory->createDataPointSetFactory(tree());
00254   }
00255 
00256 
00257   void AnalysisHandler::_setupFactories() {
00258     _theTreeFactory = _theAnalysisFactory->createTreeFactory();
00259     _theTree = _theTreeFactory->create();
00260     _theHistogramFactory = _theAnalysisFactory->createHistogramFactory(tree());
00261     _theDataPointSetFactory = _theAnalysisFactory->createDataPointSetFactory(tree());
00262   }
00263 
00264 
00265   void AnalysisHandler::commitData() {
00266     tree().commit();
00267   }
00268 
00269 
00270   void AnalysisHandler::writeData(const string& filename) {
00271     tree().commit(filename);
00272   }
00273 
00274 
00275   void AnalysisHandler::_normalizeTree(ITree& tree) {
00276     Log& log = getLog();
00277     const vector<string> paths = tree.listObjectNames("/", true); // args set recursive listing
00278     log << Log::TRACE << "Number of objects in AIDA tree = " << paths.size() << endl;
00279     const string tmpdir = "/RivetNormalizeTmp";
00280     tree.mkdir(tmpdir);
00281     foreach (const string& path, paths) {
00282 
00283       IManagedObject* hobj = tree.find(path);
00284       if (hobj) {
00285 
00286         // Weird seg fault on SLC4 when trying to dyn cast an IProfile ptr to a IHistogram
00287         // Fix by attempting to cast to IProfile first, only try IHistogram if it fails.
00288         IHistogram1D* histo = 0;
00289         IProfile1D* prof = dynamic_cast<IProfile1D*>(hobj);
00290         if (!prof) histo = dynamic_cast<IHistogram1D*>(hobj);
00291 
00292         // If it's a normal histo:
00293         if (histo) {
00294           log << Log::TRACE << "Converting histo " << path << " to DPS" << endl;
00295           tree.mv(path, tmpdir);
00296           const size_t lastslash = path.find_last_of("/");
00297           const string basename = path.substr(lastslash+1, path.length() - (lastslash+1));
00298           const string tmppath = tmpdir + "/" + basename;
00299           IHistogram1D* tmphisto = dynamic_cast<IHistogram1D*>(tree.find(tmppath));
00300           if (tmphisto) {
00301             //getLog() << Log::TRACE << "Temp histo " << tmppath << " exists" << endl;
00302             datapointsetFactory().create(path, *tmphisto);
00303           }
00304           tree.rm(tmppath);
00305         }
00306         // If it's a profile histo:
00307         else if (prof) {
00308           log << Log::TRACE << "Converting profile histo " << path << " to DPS" << endl;
00309           tree.mv(path, tmpdir);
00310           const size_t lastslash = path.find_last_of("/");
00311           const string basename = path.substr(lastslash+1, path.length() - (lastslash+1));
00312           const string tmppath = tmpdir + "/" + basename;
00313           IProfile1D* tmpprof = dynamic_cast<IProfile1D*>(tree.find(tmppath));
00314           if (tmpprof) {
00315             //getLog() << Log::TRACE << "Temp profile histo " << tmppath << " exists" << endl;
00316             datapointsetFactory().create(path, *tmpprof);
00317           }
00318           tree.rm(tmppath);
00319         }
00320 
00321       }
00322 
00323     }
00324     tree.rmdir(tmpdir);
00325   }
00326 
00327 
00328   string AnalysisHandler::runName() const { return _runname; }
00329   size_t AnalysisHandler::numEvents() const { return _numEvents; }
00330   double AnalysisHandler::sumOfWeights() const { return _sumOfWeights; }
00331 
00332 
00333   void AnalysisHandler::setSumOfWeights(const double& sum) {
00334     _sumOfWeights=sum;
00335   }
00336 
00337 
00338   std::vector<std::string> AnalysisHandler::analysisNames() const {
00339     std::vector<std::string> rtn;
00340     foreach (AnaHandle a, _analyses) {
00341       rtn.push_back(a->name());
00342     }
00343     return rtn;
00344   }
00345 
00346 
00347   AnalysisHandler& AnalysisHandler::addAnalyses(const std::vector<std::string>& analysisnames) {
00348     foreach (const string& aname, analysisnames) {
00349       //getLog() << Log::DEBUG << "Adding analysis '" << aname << "'" << endl;
00350       addAnalysis(aname);
00351     }
00352     return *this;
00353   }
00354 
00355 
00356   AnalysisHandler& AnalysisHandler::removeAnalyses(const std::vector<std::string>& analysisnames) {
00357     foreach (const string& aname, analysisnames) {
00358       removeAnalysis(aname);
00359     }
00360     return *this;
00361   }
00362 
00363 
00364 
00365   AIDA::IAnalysisFactory& AnalysisHandler::analysisFactory() {
00366     return *_theAnalysisFactory;
00367   }
00368 
00369 
00370   AIDA::ITree& AnalysisHandler::tree() {
00371     return *_theTree;
00372   }
00373 
00374 
00375   AIDA::IHistogramFactory& AnalysisHandler::histogramFactory() {
00376     return *_theHistogramFactory;
00377   }
00378 
00379 
00380   AIDA::IDataPointSetFactory& AnalysisHandler::datapointsetFactory() {
00381     return *_theDataPointSetFactory;
00382   }
00383 
00384 
00385   bool AnalysisHandler::needCrossSection() const {
00386     bool rtn = false;
00387     foreach (const AnaHandle a, _analyses) {
00388       if (!rtn) rtn = a->needsCrossSection();
00389       if (rtn) break;
00390     }
00391     return rtn;
00392   }
00393 
00394 
00395   AnalysisHandler& AnalysisHandler::setCrossSection(double xs) {
00396     _xs = xs;
00397     foreach (AnaHandle a, _analyses) {
00398       a->setCrossSection(xs);
00399     }
00400     return *this;
00401   }
00402 
00403 
00404   bool AnalysisHandler::hasCrossSection() const {
00405     return (crossSection() >= 0);
00406   }
00407 
00408 
00409   AnalysisHandler& AnalysisHandler::addAnalysis(Analysis* analysis) {
00410     analysis->_analysishandler = this;
00411     _analyses.insert(AnaHandle(analysis));
00412     return *this;
00413   }
00414 
00415 
00416   PdgIdPair AnalysisHandler::beamIds() const {
00417     return Rivet::beamIds(beams());
00418   }
00419 
00420 
00421   double AnalysisHandler::sqrtS() const {
00422     return Rivet::sqrtS(beams());
00423   }
00424 
00425 
00426 }