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