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