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