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     // Proceed with event analysis
00100     assert(_initialised);
00101     // Ensure that beam details match those from 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 
00112     Event event(ge);
00113     _numEvents++;
00114     // Weights
00115     const double weight = event.weight();
00116     _sumOfWeights += weight;
00117     MSG_DEBUG("Event #" << _numEvents << " weight = " << weight);
00118     #ifdef HEPMC_HAS_CROSS_SECTION
00119     if (ge.cross_section()) {
00120       _xs = ge.cross_section()->cross_section();
00121     }
00122     #endif
00123     foreach (AnaHandle a, _analyses) {
00124       //MSG_DEBUG("About to run analysis " << a->name());
00125       try {
00126         a->analyze(event);
00127       } catch (const Error& err) {
00128         cerr     << "Error in " << a->name() << "::analyze method: "
00129                  << err.what() << endl;
00130         exit(1);
00131       }
00132       //MSG_DEBUG("Finished running analysis " << a->name());
00133     }
00134   }
00135 
00136 
00137   void AnalysisHandler::finalize() {
00138     if (!_initialised) return;
00139     MSG_INFO("Finalising analyses");
00140     foreach (AnaHandle a, _analyses) {
00141       a->setCrossSection(_xs);
00142       try {
00143         a->finalize();
00144       } catch (const Error& err) {
00145         cerr << "Error in " << a->name() << "::finalize method: "
00146              << err.what() << endl;
00147         exit(1);
00148       }
00149     }
00150 
00151     // Print out number of events processed
00152     MSG_INFO("Processed " << _numEvents << " event" << (_numEvents == 1 ? "" : "s"));
00153 
00154     // // Delete analyses
00155     // MSG_DEBUG("Deleting analyses");
00156     // _analyses.clear();
00157 
00158     // Print out MCnet boilerplate
00159     cout << endl;
00160     cout << "The MCnet usage guidelines apply to Rivet: see http://www.montecarlonet.org/GUIDELINES" << endl;
00161     cout << "Please acknowledge plots made with Rivet analyses, and cite arXiv:1003.0694 (http://arxiv.org/abs/1003.0694)" << endl;
00162   }
00163 
00164 
00165   AnalysisHandler& AnalysisHandler::addAnalysis(const string& analysisname) {
00166     // Check for a duplicate analysis
00167     /// @todo Might we want to be able to run an analysis twice, with different params?
00168     ///       Requires avoiding histo tree clashes, i.e. storing the histos on the analysis objects.
00169     foreach (const AnaHandle& a, _analyses) {
00170       if (a->name() == analysisname) {
00171         MSG_WARNING("Analysis '" << analysisname << "' already registered: skipping duplicate");
00172         return *this;
00173       }
00174     }
00175     AnaHandle analysis( AnalysisLoader::getAnalysis(analysisname) );
00176     if (analysis.get() != 0) { // < Check for null analysis.
00177       MSG_DEBUG("Adding analysis '" << analysisname << "'");
00178       analysis->_analysishandler = this;
00179       _analyses.insert(analysis);
00180     } else {
00181       MSG_WARNING("Analysis '" << analysisname << "' not found.");
00182     }
00183     // MSG_WARNING(_analyses.size());
00184     // foreach (const AnaHandle& a, _analyses) MSG_WARNING(a->name());
00185     return *this;
00186   }
00187 
00188 
00189   AnalysisHandler& AnalysisHandler::removeAnalysis(const string& analysisname) {
00190     shared_ptr<Analysis> toremove;
00191     foreach (const AnaHandle a, _analyses) {
00192       if (a->name() == analysisname) {
00193         toremove = a;
00194         break;
00195       }
00196     }
00197     if (toremove.get() != 0) {
00198       MSG_DEBUG("Removing analysis '" << analysisname << "'");
00199       _analyses.erase(toremove);
00200     }
00201     return *this;
00202   }
00203 
00204 
00205   vector<AnalysisObjectPtr> AnalysisHandler::getData() const {
00206     vector<AnalysisObjectPtr> rtn;
00207     foreach (const AnaHandle a, analyses()) {
00208       vector<AnalysisObjectPtr> aos = a->analysisObjects();
00209       // MSG_WARNING(a->name() << " " << aos.size());
00210       foreach (const AnalysisObjectPtr ao, aos) {
00211         // Exclude paths starting with /TMP/ from final write-out
00212         /// @todo This needs to be much more nuanced for re-entrant histogramming
00213         if (ao->path().find("/TMP/") != string::npos) continue;
00214         rtn.push_back(ao);
00215       }
00216     }
00217     sort(rtn.begin(), rtn.end(), cmpAOByPath);
00218     return rtn;
00219   }
00220 
00221 
00222   void AnalysisHandler::writeData(const string& filename) const {
00223     const vector<AnalysisObjectPtr> aos = getData();
00224     WriterYODA::write(filename, aos.begin(), aos.end());
00225   }
00226 
00227 
00228   string AnalysisHandler::runName() const { return _runname; }
00229   size_t AnalysisHandler::numEvents() const { return _numEvents; }
00230   double AnalysisHandler::sumOfWeights() const { return _sumOfWeights; }
00231 
00232 
00233   void AnalysisHandler::setSumOfWeights(const double& sum) {
00234     _sumOfWeights=sum;
00235   }
00236 
00237 
00238   std::vector<std::string> AnalysisHandler::analysisNames() const {
00239     std::vector<std::string> rtn;
00240     foreach (AnaHandle a, _analyses) {
00241       rtn.push_back(a->name());
00242     }
00243     return rtn;
00244   }
00245 
00246 
00247   AnalysisHandler& AnalysisHandler::addAnalyses(const std::vector<std::string>& analysisnames) {
00248     foreach (const string& aname, analysisnames) {
00249       //MSG_DEBUG("Adding analysis '" << aname << "'");
00250       addAnalysis(aname);
00251     }
00252     return *this;
00253   }
00254 
00255 
00256   AnalysisHandler& AnalysisHandler::removeAnalyses(const std::vector<std::string>& analysisnames) {
00257     foreach (const string& aname, analysisnames) {
00258       removeAnalysis(aname);
00259     }
00260     return *this;
00261   }
00262 
00263 
00264   bool AnalysisHandler::needCrossSection() const {
00265     bool rtn = false;
00266     foreach (const AnaHandle a, _analyses) {
00267       if (!rtn) rtn = a->needsCrossSection();
00268       if (rtn) break;
00269     }
00270     return rtn;
00271   }
00272 
00273 
00274   AnalysisHandler& AnalysisHandler::setCrossSection(double xs) {
00275     _xs = xs;
00276     return *this;
00277   }
00278 
00279 
00280   bool AnalysisHandler::hasCrossSection() const {
00281     return (!std::isnan(crossSection()));
00282   }
00283 
00284 
00285   AnalysisHandler& AnalysisHandler::addAnalysis(Analysis* analysis) {
00286     analysis->_analysishandler = this;
00287     _analyses.insert(AnaHandle(analysis));
00288     return *this;
00289   }
00290 
00291 
00292   PdgIdPair AnalysisHandler::beamIds() const {
00293     return Rivet::beamIds(beams());
00294   }
00295 
00296 
00297   double AnalysisHandler::sqrtS() const {
00298     return Rivet::sqrtS(beams());
00299   }
00300 
00301   void AnalysisHandler::setIgnoreBeams(bool ignore) {
00302     _ignoreBeams=ignore;
00303   }
00304 
00305 
00306 }