Page Menu
Home
HEPForge
Search
Configure Global Search
Log In
Files
F9501607
No One
Temporary
Actions
View File
Edit File
Delete File
View Transforms
Subscribe
Mute Notifications
Award Token
Flag For Later
Size
62 KB
Subscribers
None
View Options
diff --git a/bin/rivet-nopy.cc b/bin/rivet-nopy.cc
--- a/bin/rivet-nopy.cc
+++ b/bin/rivet-nopy.cc
@@ -1,41 +1,42 @@
#include "Rivet/AnalysisHandler.hh"
#include "Rivet/AnalysisLoader.hh"
//#include "HepMC/IO_GenEvent.h"
#include "Rivet/Tools/RivetHepMC.hh"
+#include <fstream>
using namespace std;
int main(int argc, char** argv) {
if (argc < 2) {
cerr << "Usage: " << argv[0] << " <hepmcfile> <ana1> [<ana2> ...]" << '\n';
cout << "Available analyses:\n";
for (const string& a : Rivet::AnalysisLoader::analysisNames())
cout << " " << a << "\n";
cout << endl;
return 1;
}
Rivet::AnalysisHandler ah;
for (int i = 2; i < argc; ++i) {
ah.addAnalysis(argv[i]);
}
std::ifstream istr(argv[1], std::ios::in);
std::shared_ptr<Rivet::HepMC_IO_type> reader = Rivet::HepMCUtils::makeReader(istr);
std::shared_ptr<Rivet::RivetHepMC::GenEvent> evt = make_shared<Rivet::RivetHepMC::GenEvent>();
while(reader && Rivet::HepMCUtils::readEvent(reader, evt)){
ah.analyze(evt.get());
evt.reset(new Rivet::RivetHepMC::GenEvent());
}
istr.close();
- ah.setCrossSection(1.0, 0.0);
+ ah.setCrossSection(make_pair(1.0, 0.0));
ah.finalize();
ah.writeData("Rivet.yoda");
return 0;
}
diff --git a/include/Rivet/AnalysisHandler.hh b/include/Rivet/AnalysisHandler.hh
--- a/include/Rivet/AnalysisHandler.hh
+++ b/include/Rivet/AnalysisHandler.hh
@@ -1,366 +1,370 @@
// -*- C++ -*-
#ifndef RIVET_RivetHandler_HH
#define RIVET_RivetHandler_HH
#include "Rivet/Config/RivetCommon.hh"
#include "Rivet/Particle.hh"
#include "Rivet/AnalysisLoader.hh"
#include "Rivet/Tools/RivetYODA.hh"
namespace Rivet {
// Forward declaration and smart pointer for Analysis
class Analysis;
typedef std::shared_ptr<Analysis> AnaHandle;
/// A class which handles a number of analysis objects to be applied to
/// generated events. An {@link Analysis}' AnalysisHandler is also responsible
/// for handling the final writing-out of histograms.
class AnalysisHandler {
public:
/// @name Constructors and destructors. */
//@{
/// Preferred constructor, with optional run name.
AnalysisHandler(const string& runname="");
/// @brief Destructor
/// The destructor is not virtual, as this class should not be inherited from.
~AnalysisHandler();
//@}
private:
/// Get a logger object.
Log& getLog() const;
public:
/// @name Run properties and weights
//@{
/// Get the name of this run.
string runName() const;
/// Get the number of events seen. Should only really be used by external
/// steering code or analyses in the finalize phase.
size_t numEvents() const;
/// @brief Access the sum of the event weights seen
///
/// This is the weighted equivalent of the number of events. It should only
/// be used by external steering code or analyses in the finalize phase.
double sumW() const { return _eventCounter->sumW(); }
/// Access to the sum of squared-weights
double sumW2() const { return _eventCounter->sumW2(); }
/// Names of event weight categories
const vector<string>& weightNames() const { return _weightNames; }
/// Are any of the weights non-numeric?
size_t numWeights() const { return _weightNames.size(); }
/// Are any of the weights non-numeric?
bool haveNamedWeights() const;
/// Set the weight names from a GenEvent
void setWeightNames(const GenEvent& ge);
/// Get the index of the nominal weight-stream
size_t defaultWeightIndex() const { return _defaultWeightIdx; }
//@}
/// @name Cross-sections
//@{
/// Get the cross-section known to the handler.
Scatter1DPtr crossSection() const { return _xs; }
/// Set the cross-section for the process being generated.
- AnalysisHandler& setCrossSection(double xs, double xserr);
+ void setCrossSection(pair<double, double> xsec);
/// Get the nominal cross-section
double nominalCrossSection() const {
_xs.get()->setActiveWeightIdx(_defaultWeightIdx);
const YODA::Scatter1D::Points& ps = _xs->points();
if (ps.size() != 1) {
string errMsg = "cross section missing when requesting nominal cross section";
throw Error(errMsg);
}
double xs = ps[0].x();
_xs.get()->unsetActiveWeight();
return xs;
}
//@}
/// @name Beams
//@{
/// Set the beam particles for this run
AnalysisHandler& setRunBeams(const ParticlePair& beams) {
_beams = beams;
MSG_DEBUG("Setting run beams = " << beams << " @ " << sqrtS()/GeV << " GeV");
return *this;
}
/// Get the beam particles for this run, usually determined from the first event.
const ParticlePair& beams() const { return _beams; }
/// Get beam IDs for this run, usually determined from the first event.
/// @deprecated Use standalone beamIds(ah.beams()), to clean AH interface
PdgIdPair beamIds() const;
/// Get energy for this run, usually determined from the first event.
/// @deprecated Use standalone sqrtS(ah.beams()), to clean AH interface
double sqrtS() const;
/// Setter for _ignoreBeams
void setIgnoreBeams(bool ignore=true);
/// Setter for _skipWeights
void skipMultiWeights(bool ignore=false);
//@}
/// @name Handle analyses
//@{
/// Get a list of the currently registered analyses' names.
std::vector<std::string> analysisNames() const;
/// Get the collection of currently registered analyses.
const std::map<std::string, AnaHandle>& analysesMap() const {
return _analyses;
}
/// Get the collection of currently registered analyses.
std::vector<AnaHandle> analyses() const {
std::vector<AnaHandle> rtn;
rtn.reserve(_analyses.size());
for (const auto& apair : _analyses) rtn.push_back(apair.second);
return rtn;
}
/// Get a registered analysis by name.
AnaHandle analysis(const std::string& analysisname) {
if ( _analyses.find(analysisname) == _analyses.end() )
throw LookupError("No analysis named '" + analysisname + "' registered in AnalysisHandler");
try {
return _analyses[analysisname];
} catch (...) {
throw LookupError("No analysis named '" + analysisname + "' registered in AnalysisHandler");
}
}
/// Add an analysis to the run list by object
AnalysisHandler& addAnalysis(Analysis* analysis);
/// @brief Add an analysis to the run list using its name.
///
/// The actual Analysis to be used will be obtained via
/// AnalysisLoader::getAnalysis(string). If no matching analysis is found,
/// no analysis is added (i.e. the null pointer is checked and discarded.
AnalysisHandler& addAnalysis(const std::string& analysisname);
/// @brief Add an analysis with a map of analysis options.
AnalysisHandler& addAnalysis(const std::string& analysisname, std::map<string, string> pars);
/// @brief Add analyses to the run list using their names.
///
/// The actual {@link Analysis}' to be used will be obtained via
/// AnalysisHandler::addAnalysis(string), which in turn uses
/// AnalysisLoader::getAnalysis(string). If no matching analysis is found
/// for a given name, no analysis is added, but also no error is thrown.
AnalysisHandler& addAnalyses(const std::vector<std::string>& analysisnames);
/// Remove an analysis from the run list using its name.
AnalysisHandler& removeAnalysis(const std::string& analysisname);
/// Remove analyses from the run list using their names.
AnalysisHandler& removeAnalyses(const std::vector<std::string>& analysisnames);
///
//@}
/// @name Main init/execute/finalise
//@{
/// Initialize a run, with the run beams taken from the example event.
void init(const GenEvent& event);
/// @brief Analyze the given \a event by reference.
///
/// This function will call the AnalysisBase::analyze() function of all
/// included analysis objects.
void analyze(const GenEvent& event);
/// @brief Analyze the given \a event by pointer.
///
/// This function will call the AnalysisBase::analyze() function of all
/// included analysis objects, after checking the event pointer validity.
void analyze(const GenEvent* event);
-
+
/// Finalize a run. This function calls the AnalysisBase::finalize()
/// functions of all included analysis objects.
void finalize();
//@}
/// @name Histogram / data object access
//@{
+ /// After all subevents in an event group has been processed push
+ /// all histo fills to the relevant histograms.
+ void pushToPersistent();
+
/// Read analysis plots into the histo collection (via addData) from the named file.
void readData(const std::string& filename);
/// Get all multi-weight Rivet analysis object wrappers
vector<MultiweightAOPtr> getRivetAOs() const;
/// Get a pointer to a preloaded yoda object with the given path,
/// or null if path is not found.
const YODA::AnalysisObjectPtr getPreload(string path) const {
auto it = _preloads.find(path);
if ( it == _preloads.end() ) return nullptr;
return it->second;
}
/// Write all analyses' plots (via getData) to the named file.
void writeData(const std::string& filename) const;
/// Tell Rivet to dump intermediate result to a file named @a
/// dumpfile every @a period'th event. If @period is not positive,
/// no dumping will be done.
void dump(string dumpfile, int period) {
_dumpPeriod = period;
_dumpFile = dumpfile;
}
/// Take the vector of yoda files and merge them together using
/// the cross section and weight information provided in each
/// file. Each file in @a aofiles is assumed to have been produced
/// by Rivet. By default the files are assumed to contain
/// different processes (or the same processs but mutually
/// exclusive cuts), but if @a equiv if ture, the files are
/// assumed to contain output of completely equivalent (but
/// statistically independent) Rivet runs. The corresponding
/// analyses will be loaded and their analysis objects will be
/// filled with the merged result. finalize() will be run on each
/// relevant analysis. The resulting YODA file can then be rwitten
/// out by writeData(). If delopts is non-empty, it is assumed to
/// contain names different options to be merged into the same
/// analysis objects.
void mergeYodas(const vector<string> & aofiles,
const vector<string> & delopts = vector<string>(),
bool equiv = false);
/// Helper function to strip specific options from data object paths.
void stripOptions(YODA::AnalysisObjectPtr ao,
const vector<string> & delopts) const;
//@}
/// Indicate which Rivet stage we're in.
/// At the moment, only INIT is used to enable booking.
enum class Stage { OTHER, INIT, FINALIZE };
/// Which stage are we in?
Stage stage() const { return _stage; }
private:
/// Current handler stage
Stage _stage = Stage::OTHER;
/// The collection of Analysis objects to be used.
std::map<std::string, AnaHandle> _analyses;
/// A vector of pre-loaded object which do not have a valid
/// Analysis plugged in.
map<string,YODA::AnalysisObjectPtr> _preloads;
/// A vector containing copies of analysis objects after
/// finalize() has been run.
vector<YODA::AnalysisObjectPtr> _finalizedAOs;
/// @name Run properties
//@{
/// Weight names
std::vector<std::string> _weightNames;
std::vector<std::valarray<double> > _subEventWeights;
size_t _numWeightTypes; // always == WeightVector.size()
/// Run name
std::string _runname;
/// Event counter
mutable CounterPtr _eventCounter;
/// Cross-section known to AH
Scatter1DPtr _xs;
/// Beams used by this run.
ParticlePair _beams;
/// Flag to check if init has been called
bool _initialised;
/// Flag whether input event beams should be ignored in compatibility check
bool _ignoreBeams;
/// Flag to check if multiweights should be included
bool _skipWeights;
/// Current event number
int _eventNumber;
/// The index in the weight vector for the nominal weight stream
size_t _defaultWeightIdx;
/// Determines how often Rivet runs finalize() and writes the
/// result to a YODA file.
int _dumpPeriod;
/// The name of a YODA file to which Rivet periodically dumps
/// results.
string _dumpFile;
/// Flag to indicate periodic dumping is in progress
bool _dumping;
//@}
private:
/// The assignment operator is private and must never be called.
/// In fact, it should not even be implemented.
AnalysisHandler& operator=(const AnalysisHandler&);
/// The copy constructor is private and must never be called. In
/// fact, it should not even be implemented.
AnalysisHandler(const AnalysisHandler&);
};
}
#endif
diff --git a/include/Rivet/Tools/RivetHepMC.hh b/include/Rivet/Tools/RivetHepMC.hh
--- a/include/Rivet/Tools/RivetHepMC.hh
+++ b/include/Rivet/Tools/RivetHepMC.hh
@@ -1,105 +1,105 @@
// -*- C++ -*-
#ifndef RIVET_RivetHepMC_HH
#define RIVET_RivetHepMC_HH
#include <valarray>
#ifdef ENABLE_HEPMC_3
#include "HepMC3/HepMC3.h"
#include "HepMC3/Relatives.h"
#include "HepMC3/Reader.h"
namespace Rivet{
namespace RivetHepMC = HepMC3;
using RivetHepMC::ConstGenParticlePtr;
using RivetHepMC::ConstGenVertexPtr;
using RivetHepMC::Relatives;
using RivetHepMC::ConstGenHeavyIonPtr;
using HepMC_IO_type = RivetHepMC::Reader;
using PdfInfo = RivetHepMC::GenPdfInfo;
}
#else
#include "HepMC/GenEvent.h"
#include "HepMC/GenParticle.h"
#include "HepMC/HeavyIon.h"
#include "HepMC/GenVertex.h"
#include "HepMC/Version.h"
#include "HepMC/GenRanges.h"
#include "HepMC/IO_GenEvent.h"
namespace Rivet{
namespace RivetHepMC = HepMC;
// HepMC 2.07 provides its own #defines
typedef const HepMC::GenParticle* ConstGenParticlePtr;
typedef const HepMC::GenVertex* ConstGenVertexPtr;
typedef const HepMC::HeavyIon* ConstGenHeavyIonPtr;
/// @brief Replicated the HepMC3 Relatives syntax using HepMC2 IteratorRanges
/// This is necessary mainly because of capitalisation differences
class Relatives{
public:
constexpr Relatives(HepMC::IteratorRange relo): _internal(relo){}
constexpr HepMC::IteratorRange operator()() const {return _internal;}
operator HepMC::IteratorRange() const {return _internal;}
const static Relatives PARENTS;
const static Relatives CHILDREN;
const static Relatives ANCESTORS;
const static Relatives DESCENDANTS;
private:
const HepMC::IteratorRange _internal;
};
using HepMC_IO_type = HepMC::IO_GenEvent;
using PdfInfo = RivetHepMC::PdfInfo;
}
#endif
#include "Rivet/Tools/RivetSTL.hh"
#include "Rivet/Tools/Exceptions.hh"
namespace Rivet {
using RivetHepMC::GenEvent;
using ConstGenEventPtr = std::shared_ptr<const GenEvent>;
/// @todo Use mcutils?
namespace HepMCUtils{
ConstGenParticlePtr getParticlePtr(const RivetHepMC::GenParticle & gp);
std::vector<ConstGenParticlePtr> particles(ConstGenEventPtr ge);
std::vector<ConstGenParticlePtr> particles(const GenEvent *ge);
std::vector<ConstGenVertexPtr> vertices(ConstGenEventPtr ge);
std::vector<ConstGenVertexPtr> vertices(const GenEvent *ge);
std::vector<ConstGenParticlePtr> particles(ConstGenVertexPtr gv, const Relatives &relo);
std::vector<ConstGenParticlePtr> particles(ConstGenParticlePtr gp, const Relatives &relo);
int uniqueId(ConstGenParticlePtr gp);
int particles_size(ConstGenEventPtr ge);
int particles_size(const GenEvent *ge);
std::pair<ConstGenParticlePtr,ConstGenParticlePtr> beams(const GenEvent *ge);
std::shared_ptr<HepMC_IO_type> makeReader(std::istream &istr,
std::string * errm = 0);
bool readEvent(std::shared_ptr<HepMC_IO_type> io,
std::shared_ptr<GenEvent> evt);
void strip(GenEvent & ge,
const set<long> & stripid = {1, -1, 2, -2, 3,-3, 21});
vector<string> weightNames(const GenEvent & ge);
- double crossSection(const GenEvent & ge);
+ pair<double,double> crossSection(const GenEvent & ge);
std::valarray<double> weights(const GenEvent & ge);
}
}
#endif
diff --git a/src/Core/AnalysisHandler.cc b/src/Core/AnalysisHandler.cc
--- a/src/Core/AnalysisHandler.cc
+++ b/src/Core/AnalysisHandler.cc
@@ -1,696 +1,684 @@
// -*- C++ -*-
#include "Rivet/Config/RivetCommon.hh"
#include "Rivet/AnalysisHandler.hh"
#include "Rivet/Analysis.hh"
#include "Rivet/Tools/ParticleName.hh"
#include "Rivet/Tools/BeamConstraint.hh"
#include "Rivet/Tools/Logging.hh"
#include "Rivet/Projections/Beam.hh"
#include "YODA/IO.h"
#include <iostream>
using std::cout;
using std::cerr;
namespace Rivet {
AnalysisHandler::AnalysisHandler(const string& runname)
: _runname(runname),
_initialised(false), _ignoreBeams(false), _skipWeights(false),
_defaultWeightIdx(0), _dumpPeriod(0), _dumping(false)
{ }
AnalysisHandler::~AnalysisHandler()
{ }
Log& AnalysisHandler::getLog() const {
return Log::getLog("Rivet.Analysis.Handler");
}
/// http://stackoverflow.com/questions/4654636/how-to-determine-if-a-string-is-a-number-with-c
namespace {
bool is_number(const std::string& s) {
std::string::const_iterator it = s.begin();
while (it != s.end() && std::isdigit(*it)) ++it;
return !s.empty() && it == s.end();
}
}
/// Check if any of the weightnames is not a number
bool AnalysisHandler::haveNamedWeights() const {
bool dec=false;
for (unsigned int i=0;i<_weightNames.size();++i) {
string s = _weightNames[i];
if (!is_number(s)) {
dec=true;
break;
}
}
return dec;
}
void AnalysisHandler::init(const GenEvent& ge) {
if (_initialised)
throw UserError("AnalysisHandler::init has already been called: cannot re-initialize!");
/// @todo Should the Rivet analysis objects know about weight names?
setRunBeams(Rivet::beams(ge));
MSG_DEBUG("Initialising the analysis handler");
_eventNumber = ge.event_number();
setWeightNames(ge);
if (_skipWeights)
MSG_INFO("Only using nominal weight. Variation weights will be ignored.");
else if (haveNamedWeights())
MSG_INFO("Using named weights");
else
MSG_INFO("NOT using named weights. Using first weight as nominal weight");
_eventCounter = CounterPtr(weightNames(), Counter("_EVTCOUNT"));
// Set the cross section based on what is reported by this event.
- if (ge.cross_section()) {
- MSG_TRACE("Getting cross section.");
- double xs = ge.cross_section()->cross_section();
- double xserr = ge.cross_section()->cross_section_error();
- setCrossSection(xs, xserr);
- }
+ if ( ge.cross_section() ) setCrossSection(HepMCUtils::crossSection(ge));
// Check that analyses are beam-compatible, and remove those that aren't
const size_t num_anas_requested = analysisNames().size();
vector<string> anamestodelete;
for (const AnaHandle a : analyses()) {
if (!_ignoreBeams && !a->isCompatible(beams())) {
//MSG_DEBUG(a->name() << " requires beams " << a->requiredBeams() << " @ " << a->requiredEnergies() << " GeV");
anamestodelete.push_back(a->name());
}
}
for (const string& aname : anamestodelete) {
MSG_WARNING("Analysis '" << aname << "' is incompatible with the provided beams: removing");
removeAnalysis(aname);
}
if (num_anas_requested > 0 && analysisNames().empty()) {
cerr << "All analyses were incompatible with the first event's beams\n"
<< "Exiting, since this probably wasn't intentional!" << endl;
exit(1);
}
// Warn if any analysis' status is not unblemished
for (const AnaHandle a : analyses()) {
if ( a->info().preliminary() ) {
MSG_WARNING("Analysis '" << a->name() << "' is preliminary: be careful, it may change and/or be renamed!");
} else if ( a->info().obsolete() ) {
MSG_WARNING("Analysis '" << a->name() << "' is obsolete: please update!");
} else if (( a->info().unvalidated() ) ) {
MSG_WARNING("Analysis '" << a->name() << "' is unvalidated: be careful, it may be broken!");
}
}
// Initialize the remaining analyses
_stage = Stage::INIT;
for (AnaHandle a : analyses()) {
MSG_DEBUG("Initialising analysis: " << a->name());
try {
// Allow projection registration in the init phase onwards
a->_allowProjReg = true;
a->init();
//MSG_DEBUG("Checking consistency of analysis: " << a->name());
//a->checkConsistency();
} catch (const Error& err) {
cerr << "Error in " << a->name() << "::init method: " << err.what() << endl;
exit(1);
}
MSG_DEBUG("Done initialising analysis: " << a->name());
}
_stage = Stage::OTHER;
_initialised = true;
MSG_DEBUG("Analysis handler initialised");
}
void AnalysisHandler::setWeightNames(const GenEvent& ge) {
if (!_skipWeights) _weightNames = HepMCUtils::weightNames(ge);
if ( _weightNames.empty() ) _weightNames.push_back("");
for ( int i = 0, N = _weightNames.size(); i < N; ++i )
if ( _weightNames[i] == "" ) _defaultWeightIdx = i;
}
void AnalysisHandler::analyze(const GenEvent& ge) {
// Call init with event as template if not already initialised
if (!_initialised) init(ge);
assert(_initialised);
// Ensure that beam details match those from the first event (if we're checking beams)
if ( !_ignoreBeams ) {
const PdgIdPair beams = Rivet::beamIds(ge);
const double sqrts = Rivet::sqrtS(ge);
if (!compatible(beams, _beams) || !fuzzyEquals(sqrts, sqrtS())) {
cerr << "Event beams mismatch: "
<< PID::toBeamsString(beams) << " @ " << sqrts/GeV << " GeV" << " vs. first beams "
<< this->beams() << " @ " << this->sqrtS()/GeV << " GeV" << endl;
exit(1);
}
}
// Create the Rivet event wrapper
/// @todo Filter/normalize the event here
bool strip = ( getEnvParam("RIVET_STRIP_HEPMC", string("NOOOO") ) != "NOOOO" );
Event event(ge, strip);
// set the cross section based on what is reported by this event.
// if no cross section
- MSG_TRACE("getting cross section.");
- if (ge.cross_section()) {
- MSG_TRACE("getting cross section from GenEvent.");
- double xs = ge.cross_section()->cross_section();
- double xserr = ge.cross_section()->cross_section_error();
- setCrossSection(xs, xserr);
- }
+ if ( ge.cross_section() ) setCrossSection(HepMCUtils::crossSection(ge));
// Won't happen for first event because _eventNumber is set in init()
if (_eventNumber != ge.event_number()) {
- /// @todo Can we get away with not passing a matrix?
- MSG_TRACE("AnalysisHandler::analyze(): Pushing _eventCounter to persistent.");
- _eventCounter.get()->pushToPersistent(_subEventWeights);
- // if this is indeed a new event, push the temporary
- // histograms and reset
- for (const AnaHandle& a : analyses()) {
- for (auto ao : a->analysisObjects()) {
- MSG_TRACE("AnalysisHandler::analyze(): Pushing " << a->name() << "'s " << ao->name() << " to persistent.");
- ao.get()->pushToPersistent(_subEventWeights);
- }
- MSG_TRACE("AnalysisHandler::analyze(): finished pushing " << a->name() << "'s objects to persistent.");
- }
+ pushToPersistent();
- _eventNumber = ge.event_number();
+ _eventNumber = ge.event_number();
- MSG_DEBUG("nominal event # " << _eventCounter.get()->_persistent[0]->numEntries());
- MSG_DEBUG("nominal sum of weights: " << _eventCounter.get()->_persistent[0]->sumW());
- MSG_DEBUG("Event has " << _subEventWeights.size() << " sub events.");
- _subEventWeights.clear();
}
MSG_TRACE("starting new sub event");
_eventCounter.get()->newSubEvent();
for (const AnaHandle& a : analyses()) {
for (auto ao : a->analysisObjects()) {
ao.get()->newSubEvent();
}
}
_subEventWeights.push_back(event.weights());
MSG_DEBUG("Analyzing subevent #" << _subEventWeights.size() - 1 << ".");
_eventCounter->fill();
// Run the analyses
for (AnaHandle a : analyses()) {
MSG_TRACE("About to run analysis " << a->name());
try {
a->analyze(event);
} catch (const Error& err) {
cerr << "Error in " << a->name() << "::analyze method: " << err.what() << endl;
exit(1);
}
MSG_TRACE("Finished running analysis " << a->name());
}
if ( _dumpPeriod > 0 && numEvents() > 0 && numEvents()%_dumpPeriod == 0 ) {
MSG_INFO("Dumping intermediate results to " << _dumpFile << ".");
_dumping = numEvents()/_dumpPeriod;
finalize();
writeData(_dumpFile);
_dumping = 0;
}
}
void AnalysisHandler::analyze(const GenEvent* ge) {
if (ge == nullptr) {
MSG_ERROR("AnalysisHandler received null pointer to GenEvent");
//throw Error("AnalysisHandler received null pointer to GenEvent");
}
analyze(*ge);
}
+ void AnalysisHandler::pushToPersistent() {
+ if ( _subEventWeights.empty() ) return;
+ MSG_TRACE("AnalysisHandler::analyze(): Pushing _eventCounter to persistent.");
+ _eventCounter.get()->pushToPersistent(_subEventWeights);
+ for (const AnaHandle& a : analyses()) {
+ for (auto ao : a->analysisObjects()) {
+ MSG_TRACE("AnalysisHandler::analyze(): Pushing " << a->name()
+ << "'s " << ao->name() << " to persistent.");
+ ao.get()->pushToPersistent(_subEventWeights);
+ }
+ MSG_TRACE("AnalysisHandler::analyze(): finished pushing "
+ << a->name() << "'s objects to persistent.");
+ }
+ _subEventWeights.clear();
+ }
void AnalysisHandler::finalize() {
if (!_initialised) return;
MSG_INFO("Finalising analyses");
_stage = Stage::FINALIZE;
// First push all analyses' objects to persistent and final
MSG_TRACE("AnalysisHandler::finalize(): Pushing analysis objects to persistent.");
- _eventCounter.get()->pushToPersistent(_subEventWeights);
+ pushToPersistent();
+
+ // Copy all histos to finalize versions.
_eventCounter.get()->pushToFinal();
_xs.get()->pushToFinal();
- for (const AnaHandle& a : analyses()) {
- for (auto ao : a->analysisObjects()) {
- ao.get()->pushToPersistent(_subEventWeights);
+ for (const AnaHandle& a : analyses())
+ for (auto ao : a->analysisObjects())
ao.get()->pushToFinal();
- }
- }
for (AnaHandle a : analyses()) {
if ( _dumping && !a->info().reentrant() ) {
if ( _dumping == 1 )
MSG_INFO("Skipping finalize in periodic dump of " << a->name()
<< " as it is not declared reentrant.");
continue;
}
for (size_t iW = 0; iW < numWeights(); iW++) {
_eventCounter.get()->setActiveFinalWeightIdx(iW);
_xs.get()->setActiveFinalWeightIdx(iW);
for (auto ao : a->analysisObjects())
ao.get()->setActiveFinalWeightIdx(iW);
try {
MSG_TRACE("running " << a->name() << "::finalize() for weight " << iW << ".");
a->finalize();
} catch (const Error& err) {
cerr << "Error in " << a->name() << "::finalize method: " << err.what() << '\n';
exit(1);
}
}
}
// Print out number of events processed
const int nevts = numEvents();
MSG_INFO("Processed " << nevts << " event" << (nevts != 1 ? "s" : ""));
_stage = Stage::OTHER;
if ( _dumping ) return;
// Print out MCnet boilerplate
if (getLog().getLevel()<=20){
cout << endl;
cout << "The MCnet usage guidelines apply to Rivet: see http://www.montecarlonet.org/GUIDELINES" << endl;
cout << "Please acknowledge plots made with Rivet analyses, and cite arXiv:1003.0694 (http://arxiv.org/abs/1003.0694)" << endl;
}
}
AnalysisHandler& AnalysisHandler::addAnalysis(const string& analysisname, std::map<string, string> pars) {
// Make an option handle.
std::string parHandle = "";
for (map<string, string>::iterator par = pars.begin(); par != pars.end(); ++par) {
parHandle +=":";
parHandle += par->first + "=" + par->second;
}
return addAnalysis(analysisname + parHandle);
}
AnalysisHandler& AnalysisHandler::addAnalysis(const string& analysisname) {
// Check for a duplicate analysis
/// @todo Might we want to be able to run an analysis twice, with different params?
/// Requires avoiding histo tree clashes, i.e. storing the histos on the analysis objects.
string ananame = analysisname;
vector<string> anaopt = split(analysisname, ":");
if ( anaopt.size() > 1 ) ananame = anaopt[0];
AnaHandle analysis( AnalysisLoader::getAnalysis(ananame) );
if (analysis.get() != 0) { // < Check for null analysis.
MSG_DEBUG("Adding analysis '" << analysisname << "'");
map<string,string> opts;
for ( int i = 1, N = anaopt.size(); i < N; ++i ) {
vector<string> opt = split(anaopt[i], "=");
if ( opt.size() != 2 ) {
MSG_WARNING("Error in option specification. Skipping analysis " << analysisname);
return *this;
}
if ( !analysis->info().validOption(opt[0], opt[1]) ) {
MSG_WARNING("Cannot set option '" << opt[0] << "' to '" << opt[1]
<< "'. Skipping analysis " << analysisname);
return *this;
}
opts[opt[0]] = opt[1];
}
for ( auto opt: opts) {
analysis->_options[opt.first] = opt.second;
analysis->_optstring += ":" + opt.first + "=" + opt.second;
}
for (const AnaHandle& a : analyses()) {
if (a->name() == analysis->name() ) {
MSG_WARNING("Analysis '" << analysisname << "' already registered: skipping duplicate");
return *this;
}
}
analysis->_analysishandler = this;
_analyses[analysisname] = analysis;
} else {
MSG_WARNING("Analysis '" << analysisname << "' not found.");
}
// MSG_WARNING(_analyses.size());
// for (const AnaHandle& a : _analyses) MSG_WARNING(a->name());
return *this;
}
AnalysisHandler& AnalysisHandler::removeAnalysis(const string& analysisname) {
MSG_DEBUG("Removing analysis '" << analysisname << "'");
if (_analyses.find(analysisname) != _analyses.end()) _analyses.erase(analysisname);
// }
return *this;
}
// void AnalysisHandler::addData(const std::vector<YODA::AnalysisObjectPtr>& aos) {
// for (const YODA::AnalysisObjectPtr ao : aos) {
// string path = ao->path();
// if ( path.substr(0, 5) != "/RAW/" ) {
// _orphanedPreloads.push_back(ao);
// continue;
// }
// path = path.substr(4);
// ao->setPath(path);
// if (path.size() > 1) { // path > "/"
// try {
// const string ananame = ::split(path, "/")[0];
// AnaHandle a = analysis(ananame);
// /// @todo FIXXXXX
// //MultiweightAOPtr mao = ????; /// @todo generate right Multiweight object from ao
// //a->addAnalysisObject(mao); /// @todo Need to statistically merge...
// } catch (const Error& e) {
// MSG_TRACE("Adding analysis object " << path <<
// " to the list of orphans.");
// _orphanedPreloads.push_back(ao);
// }
// }
// }
// }
void AnalysisHandler::stripOptions(YODA::AnalysisObjectPtr ao,
const vector<string> & delopts) const {
string path = ao->path();
string ananame = split(path, "/")[0];
vector<string> anaopts = split(ananame, ":");
for ( int i = 1, N = anaopts.size(); i < N; ++i )
for ( auto opt : delopts )
if ( opt == "*" || anaopts[i].find(opt + "=") == 0 )
path.replace(path.find(":" + anaopts[i]), (":" + anaopts[i]).length(), "");
ao->setPath(path);
}
void AnalysisHandler::mergeYodas(const vector<string> & aofiles,
const vector<string> & delopts, bool equiv) {
// Convenient typedef;
typedef multimap<string, YODA::AnalysisObjectPtr> AOMap;
// Store all found weights here.
set<string> foundWeightNames;
// Stor all found analyses.
set<string> foundAnalyses;
// Store all analysis objects here.
vector<AOMap> allaos;
// Go through all files and collect information.
for ( auto file : aofiles ) {
allaos.push_back(AOMap());
AOMap & aomap = allaos.back();
vector<YODA::AnalysisObject*> aos_raw;
try {
YODA::read(file, aos_raw);
}
catch (...) { //< YODA::ReadError&
throw UserError("Unexpected error in reading file: " + file);
}
for (YODA::AnalysisObject* aor : aos_raw) {
YODA::AnalysisObjectPtr ao(aor);
AOPath path(ao->path());
if ( !path )
throw UserError("Invalid path name in file: " + file);
if ( !path.isRaw() ) continue;
foundWeightNames.insert(path.weight());
// Now check if any options should be removed.
for ( string delopt : delopts )
if ( path.hasOption(delopt) ) path.removeOption(delopt);
path.setPath();
if ( path.analysisWithOptions() != "" )
foundAnalyses.insert(path.analysisWithOptions());
aomap.insert(make_pair(path.path(), ao));
}
}
// Now make analysis handler aware of the weight names present.
_weightNames.clear();
_weightNames.push_back("");
_defaultWeightIdx = 0;
for ( string name : foundWeightNames ) _weightNames.push_back(name);
// Then we create and initialize all analyses
for ( string ananame : foundAnalyses ) addAnalysis(ananame);
for (AnaHandle a : analyses() ) {
MSG_TRACE("Initialising analysis: " << a->name());
if ( !a->info().reentrant() )
MSG_WARNING("Analysis " << a->name() << " has not been validated to have "
<< "a reentrant finalize method. The merged result is unpredictable.");
try {
// Allow projection registration in the init phase onwards
a->_allowProjReg = true;
a->init();
} catch (const Error& err) {
cerr << "Error in " << a->name() << "::init method: " << err.what() << endl;
exit(1);
}
MSG_TRACE("Done initialising analysis: " << a->name());
}
// Now get all booked analysis objects.
vector<MultiweightAOPtr> raos;
for (AnaHandle a : analyses()) {
for (const auto & ao : a->analysisObjects()) {
raos.push_back(ao);
}
}
// Collect global weights and xcoss sections and fix scaling for
// all files.
_eventCounter = CounterPtr(weightNames(), Counter("_EVTCOUNT"));
_xs = Scatter1DPtr(weightNames(), Scatter1D("_XSEC"));
for (size_t iW = 0; iW < numWeights(); iW++) {
_eventCounter.get()->setActiveWeightIdx(iW);
_xs.get()->setActiveWeightIdx(iW);
YODA::Counter & sumw = *_eventCounter;
YODA::Scatter1D & xsec = *_xs;
vector<YODA::Scatter1DPtr> xsecs;
vector<YODA::CounterPtr> sows;
for ( auto & aomap : allaos ) {
auto xit = aomap.find(xsec.path());
if ( xit == aomap.end() )
xsecs.push_back(dynamic_pointer_cast<YODA::Scatter1D>(xit->second));
else
xsecs.push_back(YODA::Scatter1DPtr());
xit = aomap.find(sumw.path());
if ( xit == aomap.end() )
sows.push_back(dynamic_pointer_cast<YODA::Counter>(xit->second));
else
sows.push_back(YODA::CounterPtr());
}
double xs = 0.0, xserr = 0.0;
for ( int i = 0, N = sows.size(); i < N; ++i ) {
if ( !sows[i] || !xsecs[i] ) continue;
double xseci = xsecs[i]->point(0).x();
double xsecerri = sqr(xsecs[i]->point(0).xErrAvg());
sumw += *sows[i];
double effnent = sows[i]->effNumEntries();
xs += (equiv? effnent: 1.0)*xseci;
xserr += (equiv? sqr(effnent): 1.0)*xsecerri;
}
vector<double> scales(sows.size(), 1.0);
if ( equiv ) {
xs /= sumw.effNumEntries();
xserr = sqrt(xserr)/sumw.effNumEntries();
} else {
xserr = sqrt(xserr);
for ( int i = 0, N = sows.size(); i < N; ++i )
scales[i] = (sumw.sumW()/sows[i]->sumW())*
(xsecs[i]->point(0).x()/xs);
}
xsec.point(0) = Point1D(xs, xserr);
// Go through alla analyses and add stuff to their analysis objects;
for (AnaHandle a : analyses()) {
for (const auto & ao : a->analysisObjects()) {
ao.get()->setActiveWeightIdx(iW);
YODA::AnalysisObjectPtr yao = ao.get()->activeYODAPtr();
for ( int i = 0, N = sows.size(); i < N; ++i ) {
if ( !sows[i] || !xsecs[i] ) continue;
auto range = allaos[i].equal_range(yao->path());
for ( auto aoit = range.first; aoit != range.second; ++aoit )
if ( !addaos(yao, aoit->second, scales[i]) )
MSG_WARNING("Cannot merge objects with path " << yao->path()
<<" of type " << yao->annotation("Type") );
}
ao.get()->unsetActiveWeight();
}
}
_eventCounter.get()->unsetActiveWeight();
_xs.get()->unsetActiveWeight();
}
// Finally we just have to finalize all analyses, leaving to the
// controlling program to write it out some yoda-file.
finalize();
}
void AnalysisHandler::readData(const string& filename) {
try {
/// @todo Use new YODA SFINAE to fill the smart ptr vector directly
vector<YODA::AnalysisObject*> aos_raw;
YODA::read(filename, aos_raw);
for (YODA::AnalysisObject* aor : aos_raw)
_preloads[aor->path()] = YODA::AnalysisObjectPtr(aor);
} catch (...) { //< YODA::ReadError&
throw UserError("Unexpected error in reading file: " + filename);
}
}
vector<MultiweightAOPtr> AnalysisHandler::getRivetAOs() const {
vector<MultiweightAOPtr> rtn;
for (AnaHandle a : analyses()) {
for (const auto & ao : a->analysisObjects()) {
rtn.push_back(ao);
}
}
rtn.push_back(_eventCounter);
rtn.push_back(_xs);
return rtn;
}
void AnalysisHandler::writeData(const string& filename) const {
// This is where we store the OAs to be written.
vector<YODA::AnalysisObjectPtr> output;
// First get all multiwight AOs
vector<MultiweightAOPtr> raos = getRivetAOs();
output.reserve(raos.size()*2*numWeights());
// Fix the oredering so that default weight is written out first.
vector<size_t> order;
if ( _defaultWeightIdx >= 0 && _defaultWeightIdx < numWeights() )
order.push_back(_defaultWeightIdx);
for ( size_t i = 0; i < numWeights(); ++i )
if ( i != _defaultWeightIdx ) order.push_back(i);
// Then we go through all finalized AOs one weight at a time
for (size_t iW : order ) {
for ( auto rao : raos ) {
rao.get()->setActiveFinalWeightIdx(iW);
if ( rao->path().find("/TMP/") != string::npos ) continue;
output.push_back(rao.get()->activeYODAPtr());
}
}
// Finally the RAW objects.
for (size_t iW : order ) {
for ( auto rao : raos ) {
rao.get()->setActiveWeightIdx(iW);
output.push_back(rao.get()->activeYODAPtr());
}
}
try {
YODA::write(filename, output.begin(), output.end());
} catch (...) { //< YODA::WriteError&
throw UserError("Unexpected error in writing file: " + filename);
}
}
string AnalysisHandler::runName() const { return _runname; }
size_t AnalysisHandler::numEvents() const { return _eventCounter->numEntries(); }
std::vector<std::string> AnalysisHandler::analysisNames() const {
std::vector<std::string> rtn;
for (AnaHandle a : analyses()) {
rtn.push_back(a->name());
}
return rtn;
}
AnalysisHandler& AnalysisHandler::addAnalyses(const std::vector<std::string>& analysisnames) {
for (const string& aname : analysisnames) {
//MSG_DEBUG("Adding analysis '" << aname << "'");
addAnalysis(aname);
}
return *this;
}
AnalysisHandler& AnalysisHandler::removeAnalyses(const std::vector<std::string>& analysisnames) {
for (const string& aname : analysisnames) {
removeAnalysis(aname);
}
return *this;
}
- AnalysisHandler& AnalysisHandler::setCrossSection(double xs, double xserr) {
+ void AnalysisHandler::setCrossSection(pair<double,double> xsec) {
_xs = Scatter1DPtr(weightNames(), Scatter1D("_XSEC"));
_eventCounter.get()->setActiveWeightIdx(_defaultWeightIdx);
double nomwgt = sumW();
// The cross section of each weight variation is the nominal cross section
// times the sumW(variation) / sumW(nominal).
// This way the cross section will work correctly
for (size_t iW = 0; iW < numWeights(); iW++) {
_eventCounter.get()->setActiveWeightIdx(iW);
double s = sumW() / nomwgt;
_xs.get()->setActiveWeightIdx(iW);
- _xs->addPoint(xs*s, xserr*s);
+ _xs->addPoint(xsec.first*s, xsec.second*s);
}
_eventCounter.get()->unsetActiveWeight();
_xs.get()->unsetActiveWeight();
- return *this;
+ return;
}
AnalysisHandler& AnalysisHandler::addAnalysis(Analysis* analysis) {
analysis->_analysishandler = this;
// _analyses.insert(AnaHandle(analysis));
_analyses[analysis->name()] = AnaHandle(analysis);
return *this;
}
PdgIdPair AnalysisHandler::beamIds() const {
return Rivet::beamIds(beams());
}
double AnalysisHandler::sqrtS() const {
return Rivet::sqrtS(beams());
}
void AnalysisHandler::setIgnoreBeams(bool ignore) {
_ignoreBeams=ignore;
}
void AnalysisHandler::skipMultiWeights(bool ignore) {
_skipWeights=ignore;
}
}
diff --git a/src/Core/Run.cc b/src/Core/Run.cc
--- a/src/Core/Run.cc
+++ b/src/Core/Run.cc
@@ -1,142 +1,143 @@
// -*- C++ -*-
#include "Rivet/Run.hh"
#include "Rivet/AnalysisHandler.hh"
#include "Rivet/Math/MathUtils.hh"
#include "Rivet/Tools/RivetPaths.hh"
#include "zstr/zstr.hpp"
#include <limits>
#include <iostream>
using std::cout;
using std::endl;
namespace Rivet {
Run::Run(AnalysisHandler& ah)
: _ah(ah), _fileweight(1.0), _xs(NAN)
{ }
Run::~Run() { }
Run& Run::setCrossSection(const double xs) {
_xs = xs;
return *this;
}
Run& Run::setListAnalyses(const bool dolist) {
_listAnalyses = dolist;
return *this;
}
// Fill event and check for a bad read state
bool Run::readEvent() {
/// @todo Clear rather than new the GenEvent object per-event?
_evt.reset(new GenEvent());
if(!HepMCUtils::readEvent(_hepmcReader, _evt)){
Log::getLog("Rivet.Run") << Log::DEBUG << "Read failed. End of file?" << endl;
return false;
}
// Rescale event weights by file-level weight, if scaling is non-trivial
if (!fuzzyEquals(_fileweight, 1.0)) {
for (size_t i = 0; i < (size_t) _evt->weights().size(); ++i) {
_evt->weights()[i] *= _fileweight;
}
}
return true;
}
bool Run::openFile(const std::string& evtfile, double weight) {
// Set current weight-scaling member
_fileweight = weight;
// In case makeReader fails.
std::string errormessage;
// Set up HepMC input reader objects
if (evtfile == "-") {
#ifdef HAVE_LIBZ
_istr = make_shared<zstr::istream>(std::cin);
_hepmcReader = HepMCUtils::makeReader(*_istr, &errormessage);
#else
_hepmcReader = HepMCUtils::makeReader(std::cin, &errormessage);
#endif
} else {
if ( !fileexists(evtfile) )
throw Error("Event file '" + evtfile + "' not found");
#ifdef HAVE_LIBZ
// NB. zstr auto-detects if file is deflated or plain-text
_istr = make_shared<zstr::ifstream>(evtfile.c_str());
#else
_istr = make_shared<std::ifstream>(evtfile.c_str());
#endif
_hepmcReader = HepMCUtils::makeReader(*_istr, &errormessage);
}
if (_hepmcReader == nullptr) {
Log::getLog("Rivet.Run")
<< Log::ERROR << "Read error on file '" << evtfile << "' "
<< errormessage << endl;
return false;
}
return true;
}
bool Run::init(const std::string& evtfile, double weight) {
if (!openFile(evtfile, weight)) return false;
// Read first event to define run conditions
bool ok = readEvent();
if (!ok) return false;
if(HepMCUtils::particles(_evt).size() == 0){
Log::getLog("Rivet.Run") << Log::ERROR << "Empty first event." << endl;
return false;
}
// Initialise AnalysisHandler with beam information from first event
_ah.init(*_evt);
// Set cross-section from command line
if (!std::isnan(_xs)) {
Log::getLog("Rivet.Run")
<< Log::DEBUG << "Setting user cross-section = " << _xs << " pb" << endl;
- _ah.setCrossSection(_xs, 0.0);
+
+ _ah.setCrossSection(make_pair(_xs, 0.0));
}
// List the chosen & compatible analyses if requested
if (_listAnalyses) {
for (const std::string& ana : _ah.analysisNames()) {
cout << ana << endl;
}
}
return true;
}
bool Run::processEvent() {
// Analyze event
_ah.analyze(*_evt);
return true;
}
bool Run::finalize() {
_evt.reset();
_ah.finalize();
return true;
}
}
diff --git a/src/Tools/RivetHepMC_2.cc b/src/Tools/RivetHepMC_2.cc
--- a/src/Tools/RivetHepMC_2.cc
+++ b/src/Tools/RivetHepMC_2.cc
@@ -1,200 +1,201 @@
// -*- C++ -*-
//#include <regex>
#include "Rivet/Tools/Utils.hh"
#include "Rivet/Tools/RivetHepMC.hh"
#include "Rivet/Tools/Logging.hh"
/*namespace {
inline std::vector<std::string> split(const std::string& input, const std::string& regex) {
// passing -1 as the submatch index parameter performs splitting
std::regex re(regex);
std::sregex_token_iterator
first{input.begin(), input.end(), re, -1},
last;
return {first, last};
}
}*/
namespace Rivet{
const Relatives Relatives::PARENTS = HepMC::parents;
const Relatives Relatives::CHILDREN = HepMC::children;
const Relatives Relatives::ANCESTORS = HepMC::ancestors;
const Relatives Relatives::DESCENDANTS = HepMC::descendants;
namespace HepMCUtils{
ConstGenParticlePtr getParticlePtr(const RivetHepMC::GenParticle & gp) {
return &gp;
}
std::vector<ConstGenParticlePtr> particles(ConstGenEventPtr ge){
std::vector<ConstGenParticlePtr> result;
for(GenEvent::particle_const_iterator pi = ge->particles_begin(); pi != ge->particles_end(); ++pi){
result.push_back(*pi);
}
return result;
}
std::vector<ConstGenParticlePtr> particles(const GenEvent *ge){
std::vector<ConstGenParticlePtr> result;
for(GenEvent::particle_const_iterator pi = ge->particles_begin(); pi != ge->particles_end(); ++pi){
result.push_back(*pi);
}
return result;
}
std::vector<ConstGenVertexPtr> vertices(ConstGenEventPtr ge){
std::vector<ConstGenVertexPtr> result;
for(GenEvent::vertex_const_iterator vi = ge->vertices_begin(); vi != ge->vertices_end(); ++vi){
result.push_back(*vi);
}
return result;
}
std::vector<ConstGenVertexPtr> vertices(const GenEvent *ge){
std::vector<ConstGenVertexPtr> result;
for(GenEvent::vertex_const_iterator vi = ge->vertices_begin(); vi != ge->vertices_end(); ++vi){
result.push_back(*vi);
}
return result;
}
std::vector<ConstGenParticlePtr> particles(ConstGenVertexPtr gv, const Relatives &relo){
std::vector<ConstGenParticlePtr> result;
/// @todo A particle_const_iterator on GenVertex would be nice...
// Before HepMC 2.7.0 there were no GV::particles_const_iterators and constness consistency was all screwed up :-/
#if HEPMC_VERSION_CODE >= 2007000
for (HepMC::GenVertex::particle_iterator pi = gv->particles_begin(relo); pi != gv->particles_end(relo); ++pi)
result.push_back(*pi);
#else
HepMC::GenVertex* gv2 = const_cast<HepMC::GenVertex*>(gv);
for (HepMC::GenVertex::particle_iterator pi = gv2->particles_begin(relo); pi != gv2->particles_end(relo); ++pi)
result.push_back(const_cast<ConstGenParticlePtr>(*pi));
#endif
return result;
}
std::vector<ConstGenParticlePtr> particles(ConstGenParticlePtr gp, const Relatives &relo){
ConstGenVertexPtr vtx;
switch(relo){
case HepMC::parents:
case HepMC::ancestors:
vtx = gp->production_vertex();
break;
case HepMC::children:
case HepMC::descendants:
vtx = gp->end_vertex();
break;
default:
throw std::runtime_error("Not implemented!");
break;
}
return particles(vtx, relo);
}
int uniqueId(ConstGenParticlePtr gp){
return gp->barcode();
}
int particles_size(ConstGenEventPtr ge){
return ge->particles_size();
}
int particles_size(const GenEvent *ge){
return ge->particles_size();
}
std::pair<ConstGenParticlePtr,ConstGenParticlePtr> beams(const GenEvent *ge){
return ge->beam_particles();
}
std::shared_ptr<HepMC::IO_GenEvent> makeReader(std::istream &istr,
std::string *) {
return make_shared<HepMC::IO_GenEvent>(istr);
}
bool readEvent(std::shared_ptr<HepMC::IO_GenEvent> io, std::shared_ptr<GenEvent> evt){
if(io->rdstate() != 0) return false;
if(!io->fill_next_event(evt.get())) return false;
return true;
}
// This functions could be filled with code doing the same stuff as
// in the HepMC3 version of This file.
void strip(GenEvent &, const set<long> &) {}
vector<string> weightNames(const GenEvent & ge) {
/// reroute the print output to a std::stringstream and process
/// The iteration is done over a map in hepmc2 so this is safe
vector<string> ret;
/// Obtaining weight names using regex probably neater, but regex
/// is not defined in GCC4.8, which is currently used by Lxplus.
/// Attempt an alternative solution based on stringstreams:
std::stringstream stream;
ge.weights().print(stream);
std::string pair; // placeholder for subtsring matches
while (std::getline(stream, pair, ' ')) {
if ( pair.size() < 2 ) continue;
pair.erase(pair.begin()); // removes the "(" on the LHS
pair.pop_back(); // removes the ")" on the RHS
if (pair.empty()) continue;
std::stringstream spair(pair);
vector<string> temp;
while (std::getline(spair, pair, ',')) {
temp.push_back(std::move(pair));
}
if (temp.size() == 2) {
// store the default weight based on weight names
if (temp[0] == "Weight" || temp[0] == "0" || temp[0] == "Default") {
ret.push_back("");
}
else ret.push_back(temp[0]);
}
}
/// Possible future solution based on regex
/*std::ostringstream stream;
ge.weights().print(stream); // Super lame, I know
string str = stream.str();
std::regex re("(([^()]+))"); // Regex for stuff enclosed by parentheses ()
for (std::sregex_iterator i = std::sregex_iterator(str.begin(), str.end(), re);
i != std::sregex_iterator(); ++i ) {
std::smatch m = *i;
vector<string> temp = ::split(m.str(), "[,]");
if (temp.size() ==2) {
// store the default weight based on weight names
if (temp[0] == "Weight" || temp[0] == "0" || temp[0] == "Default") {
ret.push_back("");
} else
ret.push_back(temp[0]);
}
}*/
return ret;
}
- double crossSection(const GenEvent & ge) {
- return ge.cross_section()->cross_section();
+ pair<double,double> crossSection(const GenEvent & ge) {
+ return make_pair(ge.cross_section()->cross_section(),
+ ge.cross_section()->cross_section_error());
}
std::valarray<double> weights(const GenEvent & ge) {
const size_t W = ge.weights().size();
std::valarray<double> wts(W);
for (unsigned int iw = 0; iw < W; ++iw)
wts[iw] = ge.weights()[iw];
return wts;
}
}
}
diff --git a/src/Tools/RivetHepMC_3.cc b/src/Tools/RivetHepMC_3.cc
--- a/src/Tools/RivetHepMC_3.cc
+++ b/src/Tools/RivetHepMC_3.cc
@@ -1,159 +1,179 @@
// -*- C++ -*-
#include "Rivet/Tools/RivetHepMC.hh"
#include "Rivet/Tools/ReaderCompressedAscii.hh"
#include "HepMC3/ReaderAscii.h"
#include "HepMC3/ReaderAsciiHepMC2.h"
+#include "HepMC3/GenCrossSection.h"
+#include <cassert>
namespace Rivet{
namespace HepMCUtils{
ConstGenParticlePtr getParticlePtr(const RivetHepMC::GenParticle & gp) {
return gp.shared_from_this();
}
std::vector<ConstGenParticlePtr> particles(ConstGenEventPtr ge){
return ge->particles();
}
std::vector<ConstGenParticlePtr> particles(const GenEvent *ge){
assert(ge);
return ge->particles();
}
std::vector<ConstGenVertexPtr> vertices(ConstGenEventPtr ge){
return ge->vertices();
}
std::vector<ConstGenVertexPtr> vertices(const GenEvent *ge){
assert(ge);
return ge->vertices();
}
std::vector<ConstGenParticlePtr> particles(ConstGenVertexPtr gv, const Relatives &relo){
return relo(gv);
}
std::vector<ConstGenParticlePtr> particles(ConstGenParticlePtr gp, const Relatives &relo){
return relo(gp);
}
int particles_size(ConstGenEventPtr ge){
return particles(ge).size();
}
int particles_size(const GenEvent *ge){
return particles(ge).size();
}
int uniqueId(ConstGenParticlePtr gp){
return gp->id();
}
std::pair<ConstGenParticlePtr,ConstGenParticlePtr> beams(const GenEvent *ge) {
std::vector<ConstGenParticlePtr> beamlist = ge->beams();
if ( beamlist.size() < 2 ) {
std::cerr << "CANNOT FIND ANY BEAMS!" << std::endl;
return std::pair<ConstGenParticlePtr,ConstGenParticlePtr>();
}
return std::make_pair(beamlist[0], beamlist[1]);
}
bool readEvent(std::shared_ptr<HepMC_IO_type> io, std::shared_ptr<GenEvent> evt){
return io->read_event(*evt) && !io->failed();
}
shared_ptr<HepMC_IO_type> makeReader(std::istream & istr,
std::string * errm) {
shared_ptr<HepMC_IO_type> ret;
// First scan forward and check if there is some hint as to what
// kind of file we are looking att.
int ntry = 10;
std::string header;
int filetype = -1;
while ( ntry ) {
std::getline(istr, header);
if ( header.empty() ) continue;
if ( header.substr(0, 34) == "HepMC::Asciiv3-START_EVENT_LISTING" ) {
filetype = 3;
break;
}
if ( header.substr(0, 44) == "HepMC::CompressedAsciiv3-START_EVENT_LISTING" ) {
filetype = 4;
break;
}
if ( header.substr(0, 38) == "HepMC::IO_GenEvent-START_EVENT_LISTING" ) {
filetype = 2;
break;
}
--ntry;
}
if ( filetype == 3 )
ret = make_shared<RivetHepMC::ReaderAscii>(istr);
else if ( filetype == 4 )
ret = make_shared<Rivet::ReaderCompressedAscii>(istr);
else
ret = make_shared<RivetHepMC::ReaderAsciiHepMC2>(istr);
if ( filetype == 0 && errm )
*errm += "Could not determine file type. Assuming HepMC2 file. ";
// Check that everything was ok.
if ( ret->failed() ) {
if ( errm ) *errm = "Problems reading from HepMC file.";
ret = shared_ptr<HepMC_IO_type>();
}
return ret;
}
void strip(GenEvent & ge, const set<long> & stripid) {
// std::cerr << "Stripping event " << ge.event_number() << std::endl;
vector<HepMC3::GenParticlePtr> allparticles = ge.particles();
for ( auto & p : allparticles ) {
if ( !p->production_vertex() || !p->end_vertex() ||
stripid.count(p->pid()) == 0 ||
p->production_vertex()->id() == 0 ) continue;
// std::cout << "Removing particle " << p->id()
// << " (" << p->pid() << ")" << std::endl;
HepMC3::GenVertexPtr vp = p->production_vertex();
HepMC3::GenVertexPtr ve = p->end_vertex();
if ( !vp || !ve ) continue;
if ( vp == ve ) continue;
// Check if the vertices would leave particles with the sam
// production as decay vertex - we don't want that.
if ( ( vp->particles_out().size() == 1 && vp->particles_out()[0] == p ) ||
( ve->particles_in().size() == 1 && ve->particles_in()[0] == p ) ) {
bool loop = false;
for ( auto pi : vp->particles_in() )
for ( auto po : ve->particles_out() )
if ( pi == po ) loop = true;
if ( loop ) continue;
}
if ( vp->particles_in().size() == 1 &&
( vp->particles_in()[0]->pid() > 21 &&
vp->particles_in()[0]->pid() < 30 ) )
continue;
vp->remove_particle_out(p);
ve->remove_particle_in(p);
if ( ve->particles_in().empty() ) {
auto prem = ve->particles_out();
for ( auto po : prem ) vp->add_particle_out(po);
ge.remove_vertex(ve);
}
else if ( vp->particles_out().empty() ) {
auto prem = vp->particles_in();
for ( auto pi : prem ) ve->add_particle_in(pi);
ge.remove_vertex(vp);
}
ge.remove_particle(p);
}
}
+ pair<double,double> crossSection(const GenEvent & ge) {
+ // Work-around since access functions are not const.
+ HepMC3::GenCrossSection xs = *ge.cross_section();
+ return make_pair(xs.xsec(), xs.xsec_err());
+ }
+
+ vector<string> weightNames(const GenEvent & ge) {
+ try {
+ return ge.weight_names("");
+ } catch (HepMC3::WeightError & w) {
+ return vector<string>();
+ }
+ }
+
+ std::valarray<double> weights(const GenEvent & ge) {
+ return std::valarray<double>(&ge.weights()[0], ge.weights().size());
+
+ }
}
}
diff --git a/test/testApi.cc b/test/testApi.cc
--- a/test/testApi.cc
+++ b/test/testApi.cc
@@ -1,34 +1,35 @@
#include "Rivet/AnalysisHandler.hh"
#include "HepMC/GenEvent.h"
#include "Rivet/Tools/RivetHepMC.hh"
+#include <fstream>
using namespace std;
int main(int argc, char* argv[]) {
assert(argc > 1);
Rivet::AnalysisHandler ah;
Rivet::Log::setLevel("Rivet", Rivet::Log::DEBUG);
// Specify the analyses to be used
ah.addAnalysis("EXAMPLE");
ah.addAnalyses({{ "MC_JETS", "EXAMPLE_CUTS", "EXAMPLE_SMEAR" }});
std::ifstream file("testApi.hepmc");
shared_ptr<Rivet::HepMC_IO_type> reader = Rivet::HepMCUtils::makeReader(file);
std::shared_ptr<Rivet::GenEvent> evt = make_shared<Rivet::GenEvent>();
double sum_of_weights = 0.0;
while ( Rivet::HepMCUtils::readEvent(reader, evt) ) {
// Analyse current event
ah.analyze(*evt);
sum_of_weights += evt->weights()[0];
}
file.close();
- ah.setCrossSection(1.0, 0.1);
+ ah.setCrossSection(make_pair(1.0, 0.1));
ah.finalize();
ah.writeData("out.yoda");
return 0;
}
diff --git a/test/testNaN.cc b/test/testNaN.cc
--- a/test/testNaN.cc
+++ b/test/testNaN.cc
@@ -1,74 +1,75 @@
#include "Rivet/AnalysisHandler.hh"
#include "Rivet/Analysis.hh"
#include "Rivet/Tools/RivetYODA.hh"
#include <limits>
#include <cmath>
#include <iostream>
+#include <fstream>
using namespace std;
class Test : public Rivet::Analysis {
public:
Test() : Analysis("Test") {}
void init() {
book(_h_test, "test", 50, 66.0, 116.0);
}
void analyze(const Rivet::Event & e) {
cout << "Normal fill" << endl;
_h_test->fill(90., 1.);
cout << "Underflow fill" << endl;
_h_test->fill(30.,1.);
cout << "Overflow fill" << endl;
_h_test->fill(130.,1.);
cout << "Inf fill" << endl;
try {
_h_test->fill(numeric_limits<double>::infinity(), 1.);
} catch (YODA::RangeError & e) {
cerr << e.what() << '\n';
if ( string(e.what()) != string("X is Inf") ) throw;
}
cout << "NaN fill" << endl;
try {
_h_test->fill(numeric_limits<double>::quiet_NaN(), 1.);
} catch (YODA::RangeError & e) {
cerr << e.what() << '\n';
if ( string(e.what()) != string("X is NaN") ) throw;
}
}
private:
Rivet::Histo1DPtr _h_test;
};
DECLARE_RIVET_PLUGIN(Test);
int main(int argc, char* argv[]) {
assert(argc > 1);
Rivet::AnalysisHandler rivet;
rivet.addAnalysis("Test");
std::ifstream file("testApi.hepmc");
shared_ptr<Rivet::HepMC_IO_type> reader = Rivet::HepMCUtils::makeReader(file);
std::shared_ptr<Rivet::GenEvent> evt = make_shared<Rivet::GenEvent>();
double sum_of_weights = 0.0;
while ( Rivet::HepMCUtils::readEvent(reader, evt) ) {
// Analyse current event
rivet.analyze(*evt);
sum_of_weights += evt->weights()[0];
}
file.close();
- rivet.setCrossSection(1.0, 0.1);
+ rivet.setCrossSection(make_pair(1.0, 0.1));
rivet.finalize();
rivet.writeData("NaN.aida");
return 0;
}
File Metadata
Details
Attached
Mime Type
text/x-diff
Expires
Sun, Feb 23, 2:47 PM (1 d, 7 h)
Storage Engine
blob
Storage Format
Raw Data
Storage Handle
4486706
Default Alt Text
(62 KB)
Attached To
rRIVETHG rivethg
Event Timeline
Log In to Comment