rivet is hosted by Hepforge, IPPP Durham
AnalysisHandler.cc
Go to the documentation of this file.
00001 // -*- C++ -*-
00002 #include "Rivet/Config/RivetCommon.hh"
00003 #include "Rivet/AnalysisHandler.hh"
00004 #include "Rivet/Analysis.hh"
00005 #include "Rivet/Tools/ParticleName.hh"
00006 #include "Rivet/Tools/BeamConstraint.hh"
00007 #include "Rivet/Tools/Logging.hh"
00008 #include "Rivet/Projections/Beam.hh"
00009 #include "YODA/WriterYODA.h"
00010 
00011 namespace Rivet {
00012 
00013 
00014   AnalysisHandler::AnalysisHandler(const string& runname)
00015     : _runname(runname), _numEvents(0),
00016       _sumOfWeights(0.0), _xs(NAN),
00017       _initialised(false), _ignoreBeams(false)
00018   {}
00019 
00020 
00021   AnalysisHandler::~AnalysisHandler()
00022   {}
00023 
00024 
00025   Log& AnalysisHandler::getLog() const {
00026     return Log::getLog("Rivet.Analysis.Handler");
00027   }
00028 
00029 
00030   void AnalysisHandler::init(const GenEvent& ge) {
00031     if (_initialised)
00032       throw UserError("AnalysisHandler::init has already been called: cannot re-initialize!");
00033 
00034     setRunBeams(Rivet::beams(ge));
00035     MSG_DEBUG("Initialising the analysis handler");
00036     _numEvents = 0;
00037     _sumOfWeights = 0.0;
00038     _sumOfWeightsSq = 0.0;
00039 
00040     // Check that analyses are beam-compatible, and remove those that aren't
00041     const size_t num_anas_requested = analysisNames().size();
00042     vector<string> anamestodelete;
00043     for (const AnaHandle a : _analyses) {
00044       if (!_ignoreBeams && !a->isCompatible(beams())) {
00045         //MSG_DEBUG(a->name() << " requires beams " << a->requiredBeams() << " @ " << a->requiredEnergies() << " GeV");
00046         anamestodelete.push_back(a->name());
00047       }
00048     }
00049     for (const string& aname : anamestodelete) {
00050       MSG_WARNING("Analysis '" << aname << "' is incompatible with the provided beams: removing");
00051       removeAnalysis(aname);
00052     }
00053     if (num_anas_requested > 0 && analysisNames().empty()) {
00054       cerr << "All analyses were incompatible with the first event's beams\n"
00055            << "Exiting, since this probably wasn't intentional!" << endl;
00056       exit(1);
00057     }
00058 
00059     // Warn if any analysis' status is not unblemished
00060     for (const AnaHandle a : analyses()) {
00061       if (toUpper(a->status()) == "PRELIMINARY") {
00062         MSG_WARNING("Analysis '" << a->name() << "' is preliminary: be careful, it may change and/or be renamed!");
00063       } else if (toUpper(a->status()) == "OBSOLETE") {
00064         MSG_WARNING("Analysis '" << a->name() << "' is obsolete: please update!");
00065       } else if (toUpper(a->status()).find("UNVALIDATED") != string::npos) {
00066         MSG_WARNING("Analysis '" << a->name() << "' is unvalidated: be careful, it may be broken!");
00067       }
00068     }
00069 
00070     // Initialize the remaining analyses
00071     for (AnaHandle a : _analyses) {
00072       MSG_DEBUG("Initialising analysis: " << a->name());
00073       try {
00074         // Allow projection registration in the init phase onwards
00075         a->_allowProjReg = true;
00076         a->init();
00077         //MSG_DEBUG("Checking consistency of analysis: " << a->name());
00078         //a->checkConsistency();
00079       } catch (const Error& err) {
00080         cerr << "Error in " << a->name() << "::init method: " << err.what() << endl;
00081         exit(1);
00082       }
00083       MSG_DEBUG("Done initialising analysis: " << a->name());
00084     }
00085     _initialised = true;
00086     MSG_DEBUG("Analysis handler initialised");
00087   }
00088 
00089 
00090   void AnalysisHandler::analyze(const GenEvent& ge) {
00091     // Call init with event as template if not already initialised
00092     if (!_initialised) init(ge);
00093     assert(_initialised);
00094 
00095     // Ensure that beam details match those from the first event
00096     const PdgIdPair beams = Rivet::beamIds(ge);
00097     const double sqrts = Rivet::sqrtS(ge);
00098     if (!compatible(beams, _beams) || !fuzzyEquals(sqrts, sqrtS())) {
00099       cerr << "Event beams mismatch: "
00100            << PID::toBeamsString(beams) << " @ " << sqrts/GeV << " GeV" << " vs. first beams "
00101            << this->beams() << " @ " << this->sqrtS()/GeV << " GeV" << endl;
00102       exit(1);
00103     }
00104 
00105     // Create the Rivet event wrapper
00106     /// @todo Filter/normalize the event here
00107     Event event(ge);
00108 
00109     // Weights
00110     /// @todo Drop this / just report first weight when we support multiweight events
00111     _numEvents += 1;
00112     _sumOfWeights += event.weight();
00113     _sumOfWeightsSq += sqr(event.weight());
00114     MSG_DEBUG("Event #" << _numEvents << " weight = " << event.weight());
00115 
00116     // Cross-section
00117     #ifdef HEPMC_HAS_CROSS_SECTION
00118     if (ge.cross_section()) {
00119       _xs = ge.cross_section()->cross_section();
00120       _xserr = ge.cross_section()->cross_section_error();
00121     }
00122     #endif
00123 
00124     // Run the analyses
00125     for (AnaHandle a : _analyses) {
00126       MSG_TRACE("About to run analysis " << a->name());
00127       try {
00128         a->analyze(event);
00129       } catch (const Error& err) {
00130         cerr << "Error in " << a->name() << "::analyze method: " << err.what() << endl;
00131         exit(1);
00132       }
00133       MSG_TRACE("Finished running analysis " << a->name());
00134     }
00135   }
00136 
00137 
00138   void AnalysisHandler::analyze(const GenEvent* ge) {
00139     if (ge == NULL) {
00140       MSG_ERROR("AnalysisHandler received null pointer to GenEvent");
00141       //throw Error("AnalysisHandler received null pointer to GenEvent");
00142     }
00143     analyze(*ge);
00144   }
00145 
00146 
00147   void AnalysisHandler::finalize() {
00148     if (!_initialised) return;
00149     MSG_INFO("Finalising analyses");
00150     for (AnaHandle a : _analyses) {
00151       a->setCrossSection(_xs);
00152       try {
00153         a->finalize();
00154       } catch (const Error& err) {
00155         cerr << "Error in " << a->name() << "::finalize method: " << err.what() << endl;
00156         exit(1);
00157       }
00158     }
00159 
00160     // Print out number of events processed
00161     MSG_INFO("Processed " << _numEvents << " event" << (_numEvents == 1 ? "" : "s"));
00162 
00163     // // Delete analyses
00164     // MSG_DEBUG("Deleting analyses");
00165     // _analyses.clear();
00166 
00167     // Print out MCnet boilerplate
00168     cout << endl;
00169     cout << "The MCnet usage guidelines apply to Rivet: see http://www.montecarlonet.org/GUIDELINES" << endl;
00170     cout << "Please acknowledge plots made with Rivet analyses, and cite arXiv:1003.0694 (http://arxiv.org/abs/1003.0694)" << endl;
00171   }
00172 
00173 
00174   AnalysisHandler& AnalysisHandler::addAnalysis(const string& analysisname) {
00175     // Check for a duplicate analysis
00176     /// @todo Might we want to be able to run an analysis twice, with different params?
00177     ///       Requires avoiding histo tree clashes, i.e. storing the histos on the analysis objects.
00178     for (const AnaHandle& a : _analyses) {
00179       if (a->name() == analysisname) {
00180         MSG_WARNING("Analysis '" << analysisname << "' already registered: skipping duplicate");
00181         return *this;
00182       }
00183     }
00184     AnaHandle analysis( AnalysisLoader::getAnalysis(analysisname) );
00185     if (analysis.get() != 0) { // < Check for null analysis.
00186       MSG_DEBUG("Adding analysis '" << analysisname << "'");
00187       analysis->_analysishandler = this;
00188       _analyses.insert(analysis);
00189     } else {
00190       MSG_WARNING("Analysis '" << analysisname << "' not found.");
00191     }
00192     // MSG_WARNING(_analyses.size());
00193     // for (const AnaHandle& a : _analyses) MSG_WARNING(a->name());
00194     return *this;
00195   }
00196 
00197 
00198   AnalysisHandler& AnalysisHandler::removeAnalysis(const string& analysisname) {
00199     std::shared_ptr<Analysis> toremove;
00200     for (const AnaHandle a : _analyses) {
00201       if (a->name() == analysisname) {
00202         toremove = a;
00203         break;
00204       }
00205     }
00206     if (toremove.get() != 0) {
00207       MSG_DEBUG("Removing analysis '" << analysisname << "'");
00208       _analyses.erase(toremove);
00209     }
00210     return *this;
00211   }
00212 
00213 
00214   vector<AnalysisObjectPtr> AnalysisHandler::getData() const {
00215     vector<AnalysisObjectPtr> rtn;
00216     rtn.push_back( make_shared<Counter>(YODA::Dbn0D(_numEvents, _sumOfWeights, _sumOfWeightsSq), "/_EVTCOUNT") );
00217     YODA::Scatter1D::Points pts; pts.insert(YODA::Point1D(_xs, _xserr));
00218     rtn.push_back( make_shared<Scatter1D>(pts, "/_XSEC") );
00219     for (const AnaHandle a : analyses()) {
00220       vector<AnalysisObjectPtr> aos = a->analysisObjects();
00221       // MSG_WARNING(a->name() << " " << aos.size());
00222       for (const AnalysisObjectPtr ao : aos) {
00223         // Exclude paths starting with /TMP/ from final write-out
00224         /// @todo This needs to be much more nuanced for re-entrant histogramming
00225         if (ao->path().find("/TMP/") != string::npos) continue;
00226         rtn.push_back(ao);
00227       }
00228     }
00229     sort(rtn.begin(), rtn.end(),
00230          [](AnalysisObjectPtr a, AnalysisObjectPtr b) {
00231               return a->path() < b->path();
00232           }
00233         );
00234     return rtn;
00235   }
00236 
00237 
00238   void AnalysisHandler::writeData(const string& filename) const {
00239     const vector<AnalysisObjectPtr> aos = getData();
00240     try {
00241       YODA::WriterYODA::write(filename, aos.begin(), aos.end());
00242     } catch (...) { /// @todo Move to specific YODA::WriteError type when YODA >= 1.5.0 is well-established
00243       throw UserError("Unexpected error in writing file to: " + filename);
00244     }
00245   }
00246 
00247 
00248   string AnalysisHandler::runName() const { return _runname; }
00249   size_t AnalysisHandler::numEvents() const { return _numEvents; }
00250   double AnalysisHandler::sumOfWeights() const { return _sumOfWeights; }
00251 
00252 
00253   void AnalysisHandler::setSumOfWeights(const double& sum) {
00254     _sumOfWeights=sum;
00255   }
00256 
00257 
00258   std::vector<std::string> AnalysisHandler::analysisNames() const {
00259     std::vector<std::string> rtn;
00260     for (AnaHandle a : _analyses) {
00261       rtn.push_back(a->name());
00262     }
00263     return rtn;
00264   }
00265 
00266 
00267   const AnaHandle AnalysisHandler::analysis(const std::string& analysisname) const {
00268     for (const AnaHandle a : analyses())
00269       if (a->name() == analysisname) return a;
00270     throw Error("No analysis named '" + analysisname + "' registered in AnalysisHandler");
00271   }
00272 
00273 
00274   AnalysisHandler& AnalysisHandler::addAnalyses(const std::vector<std::string>& analysisnames) {
00275     for (const string& aname : analysisnames) {
00276       //MSG_DEBUG("Adding analysis '" << aname << "'");
00277       addAnalysis(aname);
00278     }
00279     return *this;
00280   }
00281 
00282 
00283   AnalysisHandler& AnalysisHandler::removeAnalyses(const std::vector<std::string>& analysisnames) {
00284     for (const string& aname : analysisnames) {
00285       removeAnalysis(aname);
00286     }
00287     return *this;
00288   }
00289 
00290 
00291   bool AnalysisHandler::needCrossSection() const {
00292     bool rtn = false;
00293     for (const AnaHandle a : _analyses) {
00294       if (!rtn) rtn = a->needsCrossSection();
00295       if (rtn) break;
00296     }
00297     return rtn;
00298   }
00299 
00300 
00301   AnalysisHandler& AnalysisHandler::setCrossSection(double xs) {
00302     _xs = xs;
00303     return *this;
00304   }
00305 
00306 
00307   bool AnalysisHandler::hasCrossSection() const {
00308     return (!std::isnan(crossSection()));
00309   }
00310 
00311 
00312   AnalysisHandler& AnalysisHandler::addAnalysis(Analysis* analysis) {
00313     analysis->_analysishandler = this;
00314     _analyses.insert(AnaHandle(analysis));
00315     return *this;
00316   }
00317 
00318 
00319   PdgIdPair AnalysisHandler::beamIds() const {
00320     return Rivet::beamIds(beams());
00321   }
00322 
00323 
00324   double AnalysisHandler::sqrtS() const {
00325     return Rivet::sqrtS(beams());
00326   }
00327 
00328   void AnalysisHandler::setIgnoreBeams(bool ignore) {
00329     _ignoreBeams=ignore;
00330   }
00331 
00332 
00333 }