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