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 << "Analysis '" << analysisname << "' already registered: skipping duplicate" << endl;
00186         return *this;
00187       }
00188     }
00189     AnaHandle analysis( AnalysisLoader::getAnalysis(analysisname) );
00190     if (analysis.get() != 0) { // < Check for null analysis.
00191       getLog() << Log::DEBUG << "Adding analysis '" << analysisname << "'" << endl;
00192       analysis->_analysishandler = this;
00193       _analyses.insert(analysis);
00194     }
00195     return *this;
00196   }
00197 
00198 
00199   AnalysisHandler& AnalysisHandler::removeAnalysis(const string& analysisname) {
00200     shared_ptr<Analysis> toremove;
00201     foreach (const AnaHandle a, _analyses) {
00202       if (a->name() == analysisname) {
00203         toremove.reset( a.get() );
00204         break;
00205       }
00206     }
00207     if (toremove.get() != 0) {
00208       getLog() << Log::DEBUG << "Removing analysis '" << analysisname << "'" << endl;
00209       _analyses.erase(toremove);
00210     }
00211     return *this;
00212   }
00213 
00214 
00215   AnalysisHandler& AnalysisHandler::removeIncompatibleAnalyses(const PdgIdPair& beams) {
00216     vector<string> anamestodelete;
00217     foreach (const AnaHandle a, _analyses) {
00218       if (! a->isCompatible(beams)) {
00219         anamestodelete.push_back(a->name());
00220       }
00221     }
00222     foreach (const string& aname, anamestodelete) {
00223       getLog() << Log::WARN << "Removing incompatible analysis '"
00224                << aname << "'" << endl;
00225       removeAnalysis(aname);
00226     }
00227     return *this;
00228   }
00229 
00230 
00231   void AnalysisHandler::_setupFactories(const string& basefilename, HistoFormat storetype) {
00232     string filename(basefilename), storetypestr("");
00233     if (storetype == AIDAML) {
00234       if (!endsWith(filename, ".aida")) filename += ".aida";
00235       storetypestr = "xml";
00236     } else if (storetype == FLAT) {
00237       if (!endsWith(filename, ".data")) filename += ".data";
00238       storetypestr = "flat";
00239     } else if (storetype == ROOT) {
00240       if (!endsWith(filename, ".root")) filename += ".root";
00241       storetypestr = "root";
00242     }
00243     _theTreeFactory = _theAnalysisFactory->createTreeFactory();
00244     _theTree = _theTreeFactory->create(filename, storetypestr, false, true);
00245     _theHistogramFactory = _theAnalysisFactory->createHistogramFactory(tree());
00246     _theDataPointSetFactory = _theAnalysisFactory->createDataPointSetFactory(tree());
00247   }
00248 
00249 
00250   void AnalysisHandler::_setupFactories() {
00251     _theTreeFactory = _theAnalysisFactory->createTreeFactory();
00252     _theTree = _theTreeFactory->create();
00253     _theHistogramFactory = _theAnalysisFactory->createHistogramFactory(tree());
00254     _theDataPointSetFactory = _theAnalysisFactory->createDataPointSetFactory(tree());
00255   }
00256 
00257 
00258   void AnalysisHandler::commitData() {
00259     tree().commit();
00260   }
00261 
00262 
00263   void AnalysisHandler::writeData(const string& filename) {
00264     tree().commit(filename);
00265   }
00266 
00267 
00268   void AnalysisHandler::_normalizeTree(ITree& tree) {
00269     Log& log = getLog();
00270     const vector<string> paths = tree.listObjectNames("/", true); // args set recursive listing
00271     log << Log::TRACE << "Number of objects in AIDA tree = " << paths.size() << endl;
00272     const string tmpdir = "/RivetNormalizeTmp";
00273     tree.mkdir(tmpdir);
00274     foreach (const string& path, paths) {
00275 
00276       IManagedObject* hobj = tree.find(path);
00277       if (hobj) {
00278 
00279         // Weird seg fault on SLC4 when trying to dyn cast an IProfile ptr to a IHistogram
00280         // Fix by attempting to cast to IProfile first, only try IHistogram if it fails.
00281         IHistogram1D* histo = 0;
00282         IProfile1D* prof = dynamic_cast<IProfile1D*>(hobj);
00283         if (!prof) histo = dynamic_cast<IHistogram1D*>(hobj);
00284 
00285         // If it's a normal histo:
00286         if (histo) {
00287           log << Log::TRACE << "Converting histo " << path << " to DPS" << endl;
00288           tree.mv(path, tmpdir);
00289           const size_t lastslash = path.find_last_of("/");
00290           const string basename = path.substr(lastslash+1, path.length() - (lastslash+1));
00291           const string tmppath = tmpdir + "/" + basename;
00292           IHistogram1D* tmphisto = dynamic_cast<IHistogram1D*>(tree.find(tmppath));
00293           if (tmphisto) {
00294             //getLog() << Log::TRACE << "Temp histo " << tmppath << " exists" << endl;
00295             datapointsetFactory().create(path, *tmphisto);
00296           }
00297           tree.rm(tmppath);
00298         }
00299         // If it's a profile histo:
00300         else if (prof) {
00301           log << Log::TRACE << "Converting profile histo " << path << " to DPS" << endl;
00302           tree.mv(path, tmpdir);
00303           const size_t lastslash = path.find_last_of("/");
00304           const string basename = path.substr(lastslash+1, path.length() - (lastslash+1));
00305           const string tmppath = tmpdir + "/" + basename;
00306           IProfile1D* tmpprof = dynamic_cast<IProfile1D*>(tree.find(tmppath));
00307           if (tmpprof) {
00308             //getLog() << Log::TRACE << "Temp profile histo " << tmppath << " exists" << endl;
00309             datapointsetFactory().create(path, *tmpprof);
00310           }
00311           tree.rm(tmppath);
00312         }
00313 
00314       }
00315 
00316     }
00317     tree.rmdir(tmpdir);
00318   }
00319 
00320 
00321   string AnalysisHandler::runName() const { return _runname; }
00322   size_t AnalysisHandler::numEvents() const { return _numEvents; }
00323   double AnalysisHandler::sumOfWeights() const { return _sumOfWeights; }
00324 
00325 
00326   void AnalysisHandler::setSumOfWeights(const double& sum) {
00327     _sumOfWeights=sum;
00328   }
00329 
00330 
00331   std::vector<std::string> AnalysisHandler::analysisNames() const {
00332     std::vector<std::string> rtn;
00333     foreach (AnaHandle a, _analyses) {
00334       rtn.push_back(a->name());
00335     }
00336     return rtn;
00337   }
00338 
00339 
00340   AnalysisHandler& AnalysisHandler::addAnalyses(const std::vector<std::string>& analysisnames) {
00341     foreach (const string& aname, analysisnames) {
00342       //getLog() << Log::DEBUG << "Adding analysis '" << aname << "'" << endl;
00343       addAnalysis(aname);
00344     }
00345     return *this;
00346   }
00347 
00348 
00349   AnalysisHandler& AnalysisHandler::removeAnalyses(const std::vector<std::string>& analysisnames) {
00350     foreach (const string& aname, analysisnames) {
00351       removeAnalysis(aname);
00352     }
00353     return *this;
00354   }
00355 
00356 
00357 
00358   AIDA::IAnalysisFactory& AnalysisHandler::analysisFactory() {
00359     return *_theAnalysisFactory;
00360   }
00361 
00362 
00363   AIDA::ITree& AnalysisHandler::tree() {
00364     return *_theTree;
00365   }
00366 
00367 
00368   AIDA::IHistogramFactory& AnalysisHandler::histogramFactory() {
00369     return *_theHistogramFactory;
00370   }
00371 
00372 
00373   AIDA::IDataPointSetFactory& AnalysisHandler::datapointsetFactory() {
00374     return *_theDataPointSetFactory;
00375   }
00376 
00377 
00378   bool AnalysisHandler::needCrossSection() const {
00379     bool rtn = false;
00380     foreach (const AnaHandle a, _analyses) {
00381       if (!rtn) rtn = a->needsCrossSection();
00382       if (rtn) break;
00383     }
00384     return rtn;
00385   }
00386 
00387 
00388   AnalysisHandler& AnalysisHandler::setCrossSection(double xs) {
00389     _xs = xs;
00390     foreach (AnaHandle a, _analyses) {
00391       a->setCrossSection(xs);
00392     }
00393     return *this;
00394   }
00395 
00396 
00397   bool AnalysisHandler::hasCrossSection() const {
00398     return (crossSection() >= 0);
00399   }
00400 
00401 
00402   AnalysisHandler& AnalysisHandler::addAnalysis(Analysis* analysis) {
00403     analysis->_analysishandler = this;
00404     _analyses.insert(AnaHandle(analysis));
00405     return *this;
00406   }
00407 
00408 
00409   PdgIdPair AnalysisHandler::beamIds() const {
00410     return Rivet::beamIds(beams());
00411   }
00412 
00413 
00414   double AnalysisHandler::sqrtS() const {
00415     return Rivet::sqrtS(beams());
00416   }
00417 
00418 
00419 }