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 } Generated on Tue Dec 13 2016 16:32:34 for The Rivet MC analysis system by ![]() |