diff --git a/include/Rivet/Analysis.hh b/include/Rivet/Analysis.hh --- a/include/Rivet/Analysis.hh +++ b/include/Rivet/Analysis.hh @@ -1,1027 +1,1031 @@ // -*- C++ -*- #ifndef RIVET_Analysis_HH #define RIVET_Analysis_HH #include "Rivet/Config/RivetCommon.hh" #include "Rivet/AnalysisInfo.hh" #include "Rivet/Event.hh" #include "Rivet/Projection.hh" #include "Rivet/ProjectionApplier.hh" #include "Rivet/ProjectionHandler.hh" #include "Rivet/AnalysisLoader.hh" #include "Rivet/Tools/RivetYODA.hh" #include "Rivet/Tools/Logging.hh" #include "Rivet/Tools/ParticleUtils.hh" #include "Rivet/Tools/Cuts.hh" /// @def vetoEvent /// Preprocessor define for vetoing events, including the log message and return. #define vetoEvent \ do { MSG_DEBUG("Vetoing event on line " << __LINE__ << " of " << __FILE__); return; } while(0) namespace Rivet { // Forward declaration class AnalysisHandler; /// @brief This is the base class of all analysis classes in Rivet. /// /// There are /// three virtual functions which should be implemented in base classes: /// /// void init() is called by Rivet before a run is started. Here the /// analysis class should book necessary histograms. The needed /// projections should probably rather be constructed in the /// constructor. /// /// void analyze(const Event&) is called once for each event. Here the /// analysis class should apply the necessary Projections and fill the /// histograms. /// /// void finalize() is called after a run is finished. Here the analysis /// class should do whatever manipulations are necessary on the /// histograms. Writing the histograms to a file is, however, done by /// the Rivet class. class Analysis : public ProjectionApplier { /// The AnalysisHandler is a friend. friend class AnalysisHandler; public: /// @name Standard constructors and destructors. //@{ // /// The default constructor. // Analysis(); /// Constructor Analysis(const std::string& name); /// The destructor. virtual ~Analysis() {} //@} public: /// @name Main analysis methods //@{ /// Initialize this analysis object. A concrete class should here /// book all necessary histograms. An overridden function must make /// sure it first calls the base class function. virtual void init() { } /// Analyze one event. A concrete class should here apply the /// necessary projections on the \a event and fill the relevant /// histograms. An overridden function must make sure it first calls /// the base class function. virtual void analyze(const Event& event) = 0; /// Finalize this analysis object. A concrete class should here make /// all necessary operations on the histograms. Writing the /// histograms to a file is, however, done by the Rivet class. An /// overridden function must make sure it first calls the base class /// function. virtual void finalize() { } //@} public: /// @name Metadata /// Metadata is used for querying from the command line and also for /// building web pages and the analysis pages in the Rivet manual. //@{ /// Get the actual AnalysisInfo object in which all this metadata is stored. const AnalysisInfo& info() const { assert(_info && "No AnalysisInfo object :O"); return *_info; } /// @brief Get the name of the analysis. /// /// By default this is computed by combining the results of the experiment, /// year and Spires ID metadata methods and you should only override it if /// there's a good reason why those won't work. virtual std::string name() const { return (info().name().empty()) ? _defaultname : info().name(); } /// Get the Inspire ID code for this analysis. virtual std::string inspireId() const { return info().inspireId(); } /// Get the SPIRES ID code for this analysis (~deprecated). virtual std::string spiresId() const { return info().spiresId(); } /// @brief Names & emails of paper/analysis authors. /// /// Names and email of authors in 'NAME \<EMAIL\>' format. The first /// name in the list should be the primary contact person. virtual std::vector<std::string> authors() const { return info().authors(); } /// @brief Get a short description of the analysis. /// /// Short (one sentence) description used as an index entry. /// Use @a description() to provide full descriptive paragraphs /// of analysis details. virtual std::string summary() const { return info().summary(); } /// @brief Get a full description of the analysis. /// /// Full textual description of this analysis, what it is useful for, /// what experimental techniques are applied, etc. Should be treated /// as a chunk of restructuredText (http://docutils.sourceforge.net/rst.html), /// with equations to be rendered as LaTeX with amsmath operators. virtual std::string description() const { return info().description(); } /// @brief Information about the events needed as input for this analysis. /// /// Event types, energies, kinematic cuts, particles to be considered /// stable, etc. etc. Should be treated as a restructuredText bullet list /// (http://docutils.sourceforge.net/rst.html) virtual std::string runInfo() const { return info().runInfo(); } /// Experiment which performed and published this analysis. virtual std::string experiment() const { return info().experiment(); } /// Collider on which the experiment ran. virtual std::string collider() const { return info().collider(); } /// When the original experimental analysis was published. virtual std::string year() const { return info().year(); } /// Journal, and preprint references. virtual std::vector<std::string> references() const { return info().references(); } /// BibTeX citation key for this article. virtual std::string bibKey() const { return info().bibKey(); } /// BibTeX citation entry for this article. virtual std::string bibTeX() const { return info().bibTeX(); } /// Whether this analysis is trusted (in any way!) virtual std::string status() const { return (info().status().empty()) ? "UNVALIDATED" : info().status(); } /// Any work to be done on this analysis. virtual std::vector<std::string> todos() const { return info().todos(); } /// Return the allowed pairs of incoming beams required by this analysis. virtual const std::vector<PdgIdPair>& requiredBeams() const { return info().beams(); } /// Declare the allowed pairs of incoming beams required by this analysis. virtual Analysis& setRequiredBeams(const std::vector<PdgIdPair>& requiredBeams) { info().setBeams(requiredBeams); return *this; } /// Sets of valid beam energy pairs, in GeV virtual const std::vector<std::pair<double, double> >& requiredEnergies() const { return info().energies(); } /// Declare the list of valid beam energy pairs, in GeV virtual Analysis& setRequiredEnergies(const std::vector<std::pair<double, double> >& requiredEnergies) { info().setEnergies(requiredEnergies); return *this; } /// Return true if this analysis needs to know the process cross-section. /// @todo Remove this and require HepMC >= 2.06 bool needsCrossSection() const { return info().needsCrossSection(); } /// Declare whether this analysis needs to know the process cross-section from the generator. /// @todo Remove this and require HepMC >= 2.06 Analysis& setNeedsCrossSection(bool needed=true) { info().setNeedsCrossSection(needed); return *this; } //@} /// @name Internal metadata modifying methods //@{ /// Get the actual AnalysisInfo object in which all this metadata is stored (non-const). AnalysisInfo& info() { assert(_info && "No AnalysisInfo object :O"); return *_info; } //@} /// @name Run conditions //@{ /// Incoming beams for this run const ParticlePair& beams() const; /// Incoming beam IDs for this run const PdgIdPair beamIds() const; /// Centre of mass energy for this run double sqrtS() const; //@} /// @name Analysis / beam compatibility testing //@{ /// Check if analysis is compatible with the provided beam particle IDs and energies bool isCompatible(const ParticlePair& beams) const; /// Check if analysis is compatible with the provided beam particle IDs and energies bool isCompatible(PdgId beam1, PdgId beam2, double e1, double e2) const; /// Check if analysis is compatible with the provided beam particle IDs and energies bool isCompatible(const PdgIdPair& beams, const std::pair<double,double>& energies) const; //@} /// Set the cross section from the generator Analysis& setCrossSection(double xs); /// Access the controlling AnalysisHandler object. AnalysisHandler& handler() const { return *_analysishandler; } protected: /// Get a Log object based on the name() property of the calling analysis object. Log& getLog() const; /// Get the process cross-section in pb. Throws if this hasn't been set. double crossSection() const; /// Get the process cross-section per generated event in pb. Throws if this /// hasn't been set. vector<double> crossSectionPerEvent() const; /// Get the number of events seen (via the analysis handler). Use in the /// finalize phase only. size_t numEvents() const; /// Get the sum of event weights seen (via the analysis handler). Use in the /// finalize phase only. const vector<double>& sumOfWeights() const; protected: /// @name Histogram paths //@{ /// Get the canonical histogram "directory" path for this analysis. const std::string histoDir() const; /// Get the canonical histogram path for the named histogram in this analysis. const std::string histoPath(const std::string& hname) const; /// Get the canonical histogram path for the numbered histogram in this analysis. const std::string histoPath(unsigned int datasetId, unsigned int xAxisId, unsigned int yAxisId) const; /// Get the internal histogram name for given d, x and y (cf. HepData) const std::string makeAxisCode(unsigned int datasetId, unsigned int xAxisId, unsigned int yAxisId) const; //@} /// @name Histogram reference data //@{ /// Get reference data for a named histo /// @todo Move to the templated version when we have C++11 and can have a default fn template type const YODA::Scatter2D& refData(const string& hname) const; /// Get reference data for a numbered histo /// @todo Move to the templated version when we have C++11 and can have a default fn template type const YODA::Scatter2D& refData(unsigned int datasetId, unsigned int xAxisId, unsigned int yAxisId) const; /// Get reference data for a named histo /// @todo Would be nice to just use these and ditch the S2D no-template version, /// but we need C++11 for default args in function templates // template <typename T=Scatter2D> /// @todo SFINAE to ensure that the type inherits from YODA::AnalysisObject? template <typename T> const T& refData(const string& hname) const { _cacheRefData(); MSG_TRACE("Using histo bin edges for " << name() << ":" << hname); if (!_refdata[hname]) { MSG_ERROR("Can't find reference histogram " << hname); throw Exception("Reference data " + hname + " not found."); } return dynamic_cast<T&>(*_refdata[hname]); } /// Get reference data for a numbered histo /// @todo Would be nice to just use these and ditch the S2D no-template version, /// but we need C++11 for default args in function templates // template <typename T=Scatter2D> /// @todo SFINAE to ensure that the type inherits from YODA::AnalysisObject? template <typename T> const T& refData(unsigned int datasetId, unsigned int xAxisId, unsigned int yAxisId) const { const string hname = makeAxisCode(datasetId, xAxisId, yAxisId); return refData(hname); } //@} /// @name Counter booking //@{ /// Book a counter. CounterPtr bookCounter(const std::string& name, const std::string& title=""); // const std::string& valtitle="" /// Book a counter, using a path generated from the dataset and axis ID codes /// /// The paper, dataset and x/y-axis IDs will be used to build the histo name in the HepData standard way. CounterPtr bookCounter(unsigned int datasetId, unsigned int xAxisId, unsigned int yAxisId, const std::string& title=""); // const std::string& valtitle="" //@} /// @name 1D histogram booking //@{ /// Book a 1D histogram with @a nbins uniformly distributed across the range @a lower - @a upper . Histo1DPtr bookHisto1D(const std::string& name, size_t nbins, double lower, double upper, const std::string& title="", const std::string& xtitle="", const std::string& ytitle=""); /// Book a 1D histogram with non-uniform bins defined by the vector of bin edges @a binedges . Histo1DPtr bookHisto1D(const std::string& name, const std::vector<double>& binedges, const std::string& title="", const std::string& xtitle="", const std::string& ytitle=""); /// Book a 1D histogram with binning from a reference scatter. Histo1DPtr bookHisto1D(const std::string& name, const Scatter2D& refscatter, const std::string& title="", const std::string& xtitle="", const std::string& ytitle=""); /// Book a 1D histogram, using the binnings in the reference data histogram. Histo1DPtr bookHisto1D(const std::string& name, const std::string& title="", const std::string& xtitle="", const std::string& ytitle=""); /// Book a 1D histogram, using the binnings in the reference data histogram. /// /// The paper, dataset and x/y-axis IDs will be used to build the histo name in the HepData standard way. Histo1DPtr bookHisto1D(unsigned int datasetId, unsigned int xAxisId, unsigned int yAxisId, const std::string& title="", const std::string& xtitle="", const std::string& ytitle=""); //@} /// @name 2D histogram booking //@{ /// Book a 2D histogram with @a nxbins and @a nybins uniformly /// distributed across the ranges @a xlower - @a xupper and @a /// ylower - @a yupper respectively along the x- and y-axis. Histo2DPtr bookHisto2D(const std::string& name, size_t nxbins, double xlower, double xupper, size_t nybins, double ylower, double yupper, const std::string& title="", const std::string& xtitle="", const std::string& ytitle="", const std::string& ztitle=""); /// Book a 2D histogram with non-uniform bins defined by the /// vectorx of bin edges @a xbinedges and @a ybinedges. Histo2DPtr bookHisto2D(const std::string& name, const std::vector<double>& xbinedges, const std::vector<double>& ybinedges, const std::string& title="", const std::string& xtitle="", const std::string& ytitle="", const std::string& ztitle=""); // /// Book a 2D histogram with binning from a reference scatter. // Histo2DPtr bookHisto2D(const std::string& name, // const Scatter3D& refscatter, // const std::string& title="", // const std::string& xtitle="", // const std::string& ytitle="", // const std::string& ztitle=""); // /// Book a 2D histogram, using the binnings in the reference data histogram. // Histo2DPtr bookHisto2D(const std::string& name, // const std::string& title="", // const std::string& xtitle="", // const std::string& ytitle="", // const std::string& ztitle=""); // /// Book a 2D histogram, using the binnings in the reference data histogram. // /// // /// The paper, dataset and x/y-axis IDs will be used to build the histo name in the HepData standard way. // Histo2DPtr bookHisto2D(unsigned int datasetId, unsigned int xAxisId, unsigned int yAxisId, // const std::string& title="", // const std::string& xtitle="", // const std::string& ytitle="", // const std::string& ztitle=""); //@} /// @name 1D profile histogram booking //@{ /// Book a 1D profile histogram with @a nbins uniformly distributed across the range @a lower - @a upper . Profile1DPtr bookProfile1D(const std::string& name, size_t nbins, double lower, double upper, const std::string& title="", const std::string& xtitle="", const std::string& ytitle=""); /// Book a 1D profile histogram with non-uniform bins defined by the vector of bin edges @a binedges . Profile1DPtr bookProfile1D(const std::string& name, const std::vector<double>& binedges, const std::string& title="", const std::string& xtitle="", const std::string& ytitle=""); /// Book a 1D profile histogram with binning from a reference scatter. Profile1DPtr bookProfile1D(const std::string& name, const Scatter2D& refscatter, const std::string& title="", const std::string& xtitle="", const std::string& ytitle=""); /// Book a 1D profile histogram, using the binnings in the reference data histogram. Profile1DPtr bookProfile1D(const std::string& name, const std::string& title="", const std::string& xtitle="", const std::string& ytitle=""); /// Book a 1D profile histogram, using the binnings in the reference data histogram. /// /// The paper, dataset and x/y-axis IDs will be used to build the histo name in the HepData standard way. Profile1DPtr bookProfile1D(unsigned int datasetId, unsigned int xAxisId, unsigned int yAxisId, const std::string& title="", const std::string& xtitle="", const std::string& ytitle=""); //@} /// @name 2D profile histogram booking //@{ /// Book a 2D profile histogram with @a nxbins and @a nybins uniformly /// distributed across the ranges @a xlower - @a xupper and @a ylower - @a /// yupper respectively along the x- and y-axis. Profile2DPtr bookProfile2D(const std::string& name, size_t nxbins, double xlower, double xupper, size_t nybins, double ylower, double yupper, const std::string& title="", const std::string& xtitle="", const std::string& ytitle="", const std::string& ztitle=""); /// Book a 2D profile histogram with non-uniform bins defined by the vectorx /// of bin edges @a xbinedges and @a ybinedges. Profile2DPtr bookProfile2D(const std::string& name, const std::vector<double>& xbinedges, const std::vector<double>& ybinedges, const std::string& title="", const std::string& xtitle="", const std::string& ytitle="", const std::string& ztitle=""); /// Book a 2D profile histogram with binning from a reference scatter. // Profile2DPtr bookProfile2D(const std::string& name, // const Scatter3D& refscatter, // const std::string& title="", // const std::string& xtitle="", // const std::string& ytitle="", // const std::string& ztitle=""); // /// Book a 2D profile histogram, using the binnings in the reference data histogram. // Profile2DPtr bookProfile2D(const std::string& name, // const std::string& title="", // const std::string& xtitle="", // const std::string& ytitle="", // const std::string& ztitle=""); // /// Book a 2D profile histogram, using the binnings in the reference data histogram. // /// // /// The paper, dataset and x/y-axis IDs will be used to build the histo name in the HepData standard way. // Profile2DPtr bookProfile2D(unsigned int datasetId, unsigned int xAxisId, unsigned int yAxisId, // const std::string& title="", // const std::string& xtitle="", // const std::string& ytitle="", // const std::string& ztitle=""); //@} /// @name 2D scatter booking //@{ /// @brief Book a 2-dimensional data point set with the given name. /// /// @note Unlike histogram booking, scatter booking by default makes no /// attempt to use reference data to pre-fill the data object. If you want /// this, which is sometimes useful e.g. when the x-position is not really /// meaningful and can't be extracted from the data, then set the @a /// copy_pts parameter to true. This creates points to match the reference /// data's x values and errors, but with the y values and errors zeroed... /// assuming that there is a reference histo with the same name: if there /// isn't, an exception will be thrown. + + /* Scatter2DPtr bookScatter2D(const std::string& name, bool copy_pts=false, const std::string& title="", const std::string& xtitle="", const std::string& ytitle=""); /// @brief Book a 2-dimensional data point set, using the binnings in the reference data histogram. /// /// The paper, dataset and x/y-axis IDs will be used to build the histo name in the HepData standard way. /// /// @note Unlike histogram booking, scatter booking by default makes no /// attempt to use reference data to pre-fill the data object. If you want /// this, which is sometimes useful e.g. when the x-position is not really /// meaningful and can't be extracted from the data, then set the @a /// copy_pts parameter to true. This creates points to match the reference /// data's x values and errors, but with the y values and errors zeroed. Scatter2DPtr bookScatter2D(unsigned int datasetId, unsigned int xAxisId, unsigned int yAxisId, bool copy_pts=false, const std::string& title="", const std::string& xtitle="", const std::string& ytitle=""); /// @brief Book a 2-dimensional data point set with equally spaced x-points in a range. /// /// The y values and errors will be set to 0. Scatter2DPtr bookScatter2D(const std::string& name, size_t npts, double lower, double upper, const std::string& title="", const std::string& xtitle="", const std::string& ytitle=""); /// @brief Book a 2-dimensional data point set based on provided contiguous "bin edges". /// /// The y values and errors will be set to 0. Scatter2DPtr bookScatter2D(const std::string& hname, const std::vector<double>& binedges, const std::string& title, const std::string& xtitle, const std::string& ytitle); //@} + */ public: /// @name Analysis object manipulation /// @todo Should really be protected: only public to keep BinnedHistogram happy for now... //@{ /// Multiplicatively scale the given counter, @a cnt, by factor @s factor. void scale(CounterPtr cnt, double factor); /// Multiplicatively scale the given counters, @a cnts, by factor @s factor. /// @note Constness intentional, if weird, to allow passing rvalue refs of smart ptrs (argh) /// @todo Use SFINAE for a generic iterable of CounterPtrs void scale(const std::vector<CounterPtr>& cnts, double factor) { for (auto& c : cnts) scale(c, factor); } /// @todo YUCK! template <std::size_t array_size> void scale(const CounterPtr (&cnts)[array_size], double factor) { // for (size_t i = 0; i < std::extent<decltype(cnts)>::value; ++i) scale(cnts[i], factor); for (auto& c : cnts) scale(c, factor); } /// Normalize the given histogram, @a histo, to area = @a norm. void normalize(Histo1DPtr histo, double norm=1.0, bool includeoverflows=true); /// Normalize the given histograms, @a histos, to area = @a norm. /// @note Constness intentional, if weird, to allow passing rvalue refs of smart ptrs (argh) /// @todo Use SFINAE for a generic iterable of Histo1DPtrs void normalize(const std::vector<Histo1DPtr>& histos, double norm=1.0, bool includeoverflows=true) { for (auto& h : histos) normalize(h, norm, includeoverflows); } /// @todo YUCK! template <std::size_t array_size> void normalize(const Histo1DPtr (&histos)[array_size], double norm=1.0, bool includeoverflows=true) { for (auto& h : histos) normalize(h, norm, includeoverflows); } /// Multiplicatively scale the given histogram, @a histo, by factor @s factor. void scale(Histo1DPtr histo, double factor); /// Multiplicatively scale the given histograms, @a histos, by factor @s factor. /// @note Constness intentional, if weird, to allow passing rvalue refs of smart ptrs (argh) /// @todo Use SFINAE for a generic iterable of Histo1DPtrs void scale(const std::vector<Histo1DPtr>& histos, double factor) { for (auto& h : histos) scale(h, factor); } /// @todo YUCK! template <std::size_t array_size> void scale(const Histo1DPtr (&histos)[array_size], double factor) { for (auto& h : histos) scale(h, factor); } /// Normalize the given histogram, @a histo, to area = @a norm. void normalize(Histo2DPtr histo, double norm=1.0, bool includeoverflows=true); /// Normalize the given histograms, @a histos, to area = @a norm. /// @note Constness intentional, if weird, to allow passing rvalue refs of smart ptrs (argh) /// @todo Use SFINAE for a generic iterable of Histo2DPtrs void normalize(const std::vector<Histo2DPtr>& histos, double norm=1.0, bool includeoverflows=true) { for (auto& h : histos) normalize(h, norm, includeoverflows); } /// @todo YUCK! template <std::size_t array_size> void normalize(const Histo2DPtr (&histos)[array_size], double norm=1.0, bool includeoverflows=true) { for (auto& h : histos) normalize(h, norm, includeoverflows); } /// Multiplicatively scale the given histogram, @a histo, by factor @s factor. void scale(Histo2DPtr histo, double factor); /// Multiplicatively scale the given histograms, @a histos, by factor @s factor. /// @note Constness intentional, if weird, to allow passing rvalue refs of smart ptrs (argh) /// @todo Use SFINAE for a generic iterable of Histo2DPtrs void scale(const std::vector<Histo2DPtr>& histos, double factor) { for (auto& h : histos) scale(h, factor); } /// @todo YUCK! template <std::size_t array_size> void scale(const Histo2DPtr (&histos)[array_size], double factor) { for (auto& h : histos) scale(h, factor); } /// Helper for counter division. /// /// @note Assigns to the (already registered) output scatter, @a s. Preserves the path information of the target. void divide(CounterPtr c1, CounterPtr c2, Scatter1DPtr s) const; /// Helper for histogram division with raw YODA objects. /// /// @note Assigns to the (already registered) output scatter, @a s. Preserves the path information of the target. void divide(const YODA::Counter& c1, const YODA::Counter& c2, Scatter1DPtr s) const; /// Helper for histogram division. /// /// @note Assigns to the (already registered) output scatter, @a s. Preserves the path information of the target. void divide(Histo1DPtr h1, Histo1DPtr h2, Scatter2DPtr s) const; /// Helper for histogram division with raw YODA objects. /// /// @note Assigns to the (already registered) output scatter, @a s. Preserves the path information of the target. void divide(const YODA::Histo1D& h1, const YODA::Histo1D& h2, Scatter2DPtr s) const; /// Helper for profile histogram division. /// /// @note Assigns to the (already registered) output scatter, @a s. Preserves the path information of the target. void divide(Profile1DPtr p1, Profile1DPtr p2, Scatter2DPtr s) const; /// Helper for profile histogram division with raw YODA objects. /// /// @note Assigns to the (already registered) output scatter, @a s. Preserves the path information of the target. void divide(const YODA::Profile1D& p1, const YODA::Profile1D& p2, Scatter2DPtr s) const; /// Helper for 2D histogram division. /// /// @note Assigns to the (already registered) output scatter, @a s. Preserves the path information of the target. void divide(Histo2DPtr h1, Histo2DPtr h2, Scatter3DPtr s) const; /// Helper for 2D histogram division with raw YODA objects. /// /// @note Assigns to the (already registered) output scatter, @a s. Preserves the path information of the target. void divide(const YODA::Histo2D& h1, const YODA::Histo2D& h2, Scatter3DPtr s) const; /// Helper for 2D profile histogram division. /// /// @note Assigns to the (already registered) output scatter, @a s. Preserves the path information of the target. void divide(Profile2DPtr p1, Profile2DPtr p2, Scatter3DPtr s) const; /// Helper for 2D profile histogram division with raw YODA objects /// /// @note Assigns to the (already registered) output scatter, @a s. Preserves the path information of the target. void divide(const YODA::Profile2D& p1, const YODA::Profile2D& p2, Scatter3DPtr s) const; /// Helper for histogram efficiency calculation. /// /// @note Assigns to the (already registered) output scatter, @a s. Preserves the path information of the target. void efficiency(Histo1DPtr h1, Histo1DPtr h2, Scatter2DPtr s) const; /// Helper for histogram efficiency calculation. /// /// @note Assigns to the (already registered) output scatter, @a s. Preserves the path information of the target. void efficiency(const YODA::Histo1D& h1, const YODA::Histo1D& h2, Scatter2DPtr s) const; /// Helper for histogram asymmetry calculation. /// /// @note Assigns to the (already registered) output scatter, @a s. Preserves the path information of the target. void asymm(Histo1DPtr h1, Histo1DPtr h2, Scatter2DPtr s) const; /// Helper for histogram asymmetry calculation. /// /// @note Assigns to the (already registered) output scatter, @a s. Preserves the path information of the target. void asymm(const YODA::Histo1D& h1, const YODA::Histo1D& h2, Scatter2DPtr s) const; /// Helper for converting a differential histo to an integral one. /// /// @note Assigns to the (already registered) output scatter, @a s. Preserves the path information of the target. void integrate(Histo1DPtr h, Scatter2DPtr s) const; /// Helper for converting a differential histo to an integral one. /// /// @note Assigns to the (already registered) output scatter, @a s. Preserves the path information of the target. void integrate(const Histo1D& h, Scatter2DPtr s) const; //@} public: /// List of registered analysis data objects - const vector<AnalysisObjectPtr>& analysisObjects() const { + const vector<shared_ptr<MultiweightAOPtr> >& analysisObjects() const { return _analysisobjects; } protected: /// @name Data object registration, retrieval, and removal //@{ /// Register a data object in the histogram system - void addAnalysisObject(AnalysisObjectPtr ao); + void addAnalysisObject(shared_ptr<MultiweightAOPtr> ao); /// Get a data object from the histogram system /// @todo Use this default function template arg in C++11 // template <typename AO=AnalysisObjectPtr> template <typename AOPtr> const AOPtr& getAnalysisObject(const std::string& name) const { - foreach (const AnalysisObjectPtr& ao, analysisObjects()) { - if (ao->path() == histoPath(name)) return dynamic_cast<AOPtr&>(ao); + for (const shared_ptr<MultiweightAOPtr>& ao : analysisObjects()) { + if ((*ao)->path() == histoPath(name)) return dynamic_cast<const AOPtr&>(*ao); } throw Exception("Data object " + histoPath(name) + " not found"); } /// Get a data object from the histogram system (non-const) /// @todo Use this default function template arg in C++11 // template <typename AO=AnalysisObjectPtr> template <typename AOPtr> AOPtr& getAnalysisObject(const std::string& name) { - foreach (const AnalysisObjectPtr& ao, analysisObjects()) { - if (ao->path() == histoPath(name)) return dynamic_cast<AOPtr&>(ao); + for (shared_ptr<MultiweightAOPtr>& ao : _analysisobjects) { + if ((*ao)->path() == histoPath(name)) return dynamic_cast<AOPtr&>(*ao); } + throw Exception("Data object " + histoPath(name) + " not found"); } /// Unregister a data object from the histogram system (by name) void removeAnalysisObject(const std::string& path); /// Unregister a data object from the histogram system (by pointer) - void removeAnalysisObject(AnalysisObjectPtr ao); + void removeAnalysisObject(const MultiweightAOPtr& ao); /// Get a named Histo1D object from the histogram system const Histo1DPtr getHisto1D(const std::string& name) const { return getAnalysisObject<Histo1DPtr>(name); } /// Get a named Histo1D object from the histogram system (non-const) Histo1DPtr getHisto1D(const std::string& name) { return getAnalysisObject<Histo1DPtr>(name); } /// Get a Histo1D object from the histogram system by axis ID codes (non-const) const Histo1DPtr getHisto1D(unsigned int datasetId, unsigned int xAxisId, unsigned int yAxisId) const { return getAnalysisObject<Histo1DPtr>(makeAxisCode(datasetId, xAxisId, yAxisId)); } /// Get a Histo1D object from the histogram system by axis ID codes (non-const) Histo1DPtr getHisto1D(unsigned int datasetId, unsigned int xAxisId, unsigned int yAxisId) { return getAnalysisObject<Histo1DPtr>(makeAxisCode(datasetId, xAxisId, yAxisId)); } // /// Get a named Histo2D object from the histogram system // const Histo2DPtr getHisto2D(const std::string& name) const { // return getAnalysisObject<Histo2D>(name); // } // /// Get a named Histo2D object from the histogram system (non-const) // Histo2DPtr getHisto2D(const std::string& name) { // return getAnalysisObject<Histo2D>(name); // } // /// Get a Histo2D object from the histogram system by axis ID codes (non-const) // const Histo2DPtr getHisto2D(unsigned int datasetId, unsigned int xAxisId, unsigned int yAxisId) const { // return getAnalysisObject<Histo2D>(makeAxisCode(datasetId, xAxisId, yAxisId)); // } // /// Get a Histo2D object from the histogram system by axis ID codes (non-const) // Histo2DPtr getHisto2D(unsigned int datasetId, unsigned int xAxisId, unsigned int yAxisId) { // return getAnalysisObject<Histo2D>(makeAxisCode(datasetId, xAxisId, yAxisId)); // } /// Get a named Profile1D object from the histogram system const Profile1DPtr getProfile1D(const std::string& name) const { return getAnalysisObject<Profile1DPtr>(name); } /// Get a named Profile1D object from the histogram system (non-const) Profile1DPtr getProfile1D(const std::string& name) { return getAnalysisObject<Profile1DPtr>(name); } /// Get a Profile1D object from the histogram system by axis ID codes (non-const) const Profile1DPtr getProfile1D(unsigned int datasetId, unsigned int xAxisId, unsigned int yAxisId) const { return getAnalysisObject<Profile1DPtr>(makeAxisCode(datasetId, xAxisId, yAxisId)); } /// Get a Profile1D object from the histogram system by axis ID codes (non-const) Profile1DPtr getProfile1D(unsigned int datasetId, unsigned int xAxisId, unsigned int yAxisId) { return getAnalysisObject<Profile1DPtr>(makeAxisCode(datasetId, xAxisId, yAxisId)); } // /// Get a named Profile2D object from the histogram system // const Profile2DPtr getProfile2D(const std::string& name) const { // return getAnalysisObject<Profile2D>(name); // } // /// Get a named Profile2D object from the histogram system (non-const) // Profile2DPtr getProfile2D(const std::string& name) { // return getAnalysisObject<Profile2D>(name); // } // /// Get a Profile2D object from the histogram system by axis ID codes (non-const) // const Profile2DPtr getProfile2D(unsigned int datasetId, unsigned int xAxisId, unsigned int yAxisId) const { // return getAnalysisObject<Profile2D>(makeAxisCode(datasetId, xAxisId, yAxisId)); // } // /// Get a Profile2D object from the histogram system by axis ID codes (non-const) // Profile2DPtr getProfile2D(unsigned int datasetId, unsigned int xAxisId, unsigned int yAxisId) { // return getAnalysisObject<Profile2D>(makeAxisCode(datasetId, xAxisId, yAxisId)); // } /// Get a named Scatter2D object from the histogram system const Scatter2DPtr getScatter2D(const std::string& name) const { return getAnalysisObject<Scatter2DPtr>(name); } /// Get a named Scatter2D object from the histogram system (non-const) Scatter2DPtr getScatter2D(const std::string& name) { return getAnalysisObject<Scatter2DPtr>(name); } /// Get a Scatter2D object from the histogram system by axis ID codes (non-const) const Scatter2DPtr getScatter2D(unsigned int datasetId, unsigned int xAxisId, unsigned int yAxisId) const { return getAnalysisObject<Scatter2DPtr>(makeAxisCode(datasetId, xAxisId, yAxisId)); } /// Get a Scatter2D object from the histogram system by axis ID codes (non-const) Scatter2DPtr getScatter2D(unsigned int datasetId, unsigned int xAxisId, unsigned int yAxisId) { return getAnalysisObject<Scatter2DPtr>(makeAxisCode(datasetId, xAxisId, yAxisId)); } //@} private: /// Name passed to constructor (used to find .info analysis data file, and as a fallback) string _defaultname; /// Pointer to analysis metadata object unique_ptr<AnalysisInfo> _info; /// Storage of all plot objects /// @todo Make this a map for fast lookup by path? - vector<AnalysisObjectPtr> _analysisobjects; + vector<shared_ptr<MultiweightAOPtr> > _analysisobjects; /// @name Cross-section variables //@{ double _crossSection; bool _gotCrossSection; //@} /// The controlling AnalysisHandler object. AnalysisHandler* _analysishandler; /// Collection of cached refdata to speed up many autobookings: the /// reference data file should only be read once. mutable std::map<std::string, YODA::AnalysisObjectPtr> _refdata; private: /// @name Utility functions //@{ /// Get the reference data for this paper and cache it. void _cacheRefData() const; //@} /// The assignment operator is private and must never be called. /// In fact, it should not even be implemented. Analysis& operator=(const Analysis&); }; } // Include definition of analysis plugin system so that analyses automatically see it when including Analysis.hh #include "Rivet/AnalysisBuilder.hh" /// @def DECLARE_RIVET_PLUGIN /// Preprocessor define to prettify the global-object plugin hook mechanism. #define DECLARE_RIVET_PLUGIN(clsname) Rivet::AnalysisBuilder<clsname> plugin_ ## clsname /// @def DECLARE_ALIASED_RIVET_PLUGIN /// Preprocessor define to prettify the global-object plugin hook mechanism, with an extra alias name for this analysis. // #define DECLARE_ALIASED_RIVET_PLUGIN(clsname, alias) Rivet::AnalysisBuilder<clsname> plugin_ ## clsname ## ( ## #alias ## ) #define DECLARE_ALIASED_RIVET_PLUGIN(clsname, alias) DECLARE_RIVET_PLUGIN(clsname)( #alias ) /// @def DEFAULT_RIVET_ANA_CONSTRUCTOR /// Preprocessor define to prettify the manky constructor with name string argument #define DEFAULT_RIVET_ANALYSIS_CTOR(clsname) clsname() : Analysis(# clsname) {} // DEPRECATED ALIAS #define DEFAULT_RIVET_ANA_CONSTRUCTOR(clsname) DEFAULT_RIVET_ANALYSIS_CTOR(clsname) #endif diff --git a/include/Rivet/AnalysisHandler.hh b/include/Rivet/AnalysisHandler.hh --- a/include/Rivet/AnalysisHandler.hh +++ b/include/Rivet/AnalysisHandler.hh @@ -1,248 +1,259 @@ // -*- 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; // Needed to make smart pointers compare equivalent in the STL set struct CmpAnaHandle { bool operator() (const AnaHandle& a, const AnaHandle& b) { return a.get() < b.get(); } }; /// 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 //@{ /// 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; /// Get the sum of the event weights seen - the weighted equivalent of the /// number of events. Should only really be used by external steering code /// or analyses in the finalize phase. const vector<double>& sumOfWeights() const { return _sumOfWeights; } int numWeights() const { return _sumOfWeights.size(); } /// Set the active weight. void setActiveWeight(unsigned int iWeight); /// Is cross-section information required by at least one child analysis? bool needCrossSection() const; /// Set the cross-section for the process being generated. AnalysisHandler& setCrossSection(double xs); /// Get the cross-section known to the handler. double crossSection() const { return _xs; } /// Whether the handler knows about a cross-section. bool hasCrossSection() const; /// 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); //@} /// @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::set<AnaHandle, CmpAnaHandle>& analyses() const { return _analyses; } /// Get a registered analysis by name. const AnaHandle analysis(const std::string& analysisname) const; /// 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 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 //@{ /// Get all analyses' plots as a vector of analysis objects. std::vector<AnalysisObjectPtr> getData() const; + /// Get all analyses' plots as a vector of analysis objects. + void setWeightNames(const GenEvent& ge); + + /// Do we have named weights? + bool haveNamedWeights(); + + /// Write all analyses' plots to the named file. void writeData(const std::string& filename) const; //@} private: /// The collection of Analysis objects to be used. set<AnaHandle, CmpAnaHandle> _analyses; - /// @name Run properties //@{ + /// Weight names + std::vector<std::string> _weightNames; + std::vector<std::vector<double> > _subEventWeights; + size_t _numWeightTypes; // always == WeightVector.size() + /// Run name std::string _runname; /// Number of events seen. /// @todo Replace by a counter unsigned int _numEvents; /// Sum of event weights seen. /// @todo Replace by a counter vector<double> _sumOfWeights; /// Cross-section known to AH double _xs, _xserr; /// 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; /// Current event number int _eventNumber; //@} 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/Event.hh b/include/Rivet/Event.hh --- a/include/Rivet/Event.hh +++ b/include/Rivet/Event.hh @@ -1,174 +1,174 @@ // -*- C++ -*- #ifndef RIVET_Event_HH #define RIVET_Event_HH #include "Rivet/Config/RivetCommon.hh" #include "Rivet/Particle.hh" #include "Rivet/Projection.hh" namespace Rivet { /// Rivet wrapper for HepMC event and Projection references. /// /// Event is a concrete class representing an generated event in Rivet. It is /// constructed given a HepMC::GenEvent, a pointer to which is kept by the /// Event object throughout its lifetime. The user must therefore make sure /// that the corresponding HepMC::GenEvent will persist at least as long as /// the Event object. /// /// In addition to the HepMC::GenEvent object the Event also keeps track of /// all Projection objects which have been applied to the Event so far. class Event { public: /// @name Constructors and destructors. //@{ /// Constructor from a HepMC GenEvent pointer Event(const GenEvent* ge) : _genevent_original(ge), _genevent(*ge) { assert(ge); _init(*ge); } /// Constructor from a HepMC GenEvent reference /// @deprecated HepMC uses pointers, so we should talk to HepMC via pointers Event(const GenEvent& ge) : _genevent_original(&ge), _genevent(ge) { _init(ge); } /// Copy constructor Event(const Event& e) : _genevent_original(e._genevent_original), _genevent(e._genevent) { } //@} /// @name Major event properties //@{ /// Get the beam particles ParticlePair beams() const; /// Get the beam centre-of-mass energy double sqrtS() const; /// Get the beam centre-of-mass energy per nucleon double asqrtS() const; // /// Get the boost to the beam centre-of-mass // Vector3 beamCMSBoost() const; // /// Get the boost to the beam centre-of-mass // LorentzTransform beamCMSTransform(); /// The generated event obtained from an external event generator const GenEvent* genEvent() const { return &_genevent; } /// All the raw GenEvent particles, wrapped in Rivet::Particle objects const Particles& allParticles() const; /// @brief All the raw GenEvent particles, wrapped in Rivet::Particle objects, but with a Cut applied /// /// @note Due to the cut, this returns by value, i.e. involves an expensive copy inline Particles allParticles(const Cut& c) const { return filter_select(allParticles(), c); } /// @brief All the raw GenEvent particles, wrapped in Rivet::Particle objects, but with a selection function applied /// /// @note Due to the cut, this returns by value, i.e. involves an expensive copy template <typename FN> inline Particles allParticles(const FN& f) const { return filter_select(allParticles(), f); } /// @brief The generation weight associated with the event /// /// @todo This needs to be revisited when we finally add the mechanism to /// support NLO counter-events and weight vectors. - double weight() const; + std::vector<double> weights() const; //@} /// @name Projection running //@{ /// @brief Add a projection @a p to this Event. /// /// If an equivalent Projection has been applied before, the /// Projection::project(const Event&) of @a p is not called and a reference /// to the previous equivalent projection is returned. If no previous /// Projection was found, the Projection::project(const Event&) of @a p is /// called and a reference to @a p is returned. template <typename PROJ> const PROJ& applyProjection(PROJ& p) const { const Projection* cpp(&p); std::set<const Projection*>::const_iterator old = _projections.find(cpp); if (old != _projections.end()) { const Projection& pRef = **old; return pcast<PROJ>(pRef); } // Add the projection via the Projection base class (only // possible because Event is a friend of Projection) Projection* pp = const_cast<Projection*>(cpp); pp->project(*this); _projections.insert(pp); return p; } /// @brief Add a projection @a p to this Event by pointer. template <typename PROJ> const PROJ& applyProjection(PROJ* pp) const { if (!pp) throw Error("Event::applyProjection(PROJ*): Projection pointer is null."); return applyProjection(*pp); } //@} private: /// @brief Actual (shared) implementation of the constructors from GenEvents void _init(const GenEvent& ge); // /// @brief Convert the GenEvent to use conventional alignment // /// // /// For example, FHerwig only produces DIS events in the unconventional // /// hadron-lepton orientation and has to be corrected for DIS analysis // /// portability. // void _geNormAlignment(); /// @brief The generated event, as obtained from an external generator. /// /// This is the original GenEvent. In practise the version seen by users /// will often/always be a modified one. /// /// @todo Provide access to this via an Event::originalGenEvent() method? If requested... const GenEvent* _genevent_original; /// @brief The GenEvent used by Rivet analysis projections etc. /// /// This version may be rotated to a "normal" alignment, have /// generator-specific particles stripped out, etc. If an analysis is /// affected by these modifications, it is probably an unphysical analysis! /// /// Stored as a non-pointer since it may get overwritten, and memory for /// copying and cleanup is neater this way. /// @todo Change needed for HepMC3? mutable GenEvent _genevent; /// All the GenEvent particles, wrapped as Rivet::Particles /// @note To be populated lazily, hence mutability mutable Particles _particles; /// The set of Projection objects applied so far mutable std::set<ConstProjectionPtr> _projections; }; } #endif diff --git a/include/Rivet/Tools/RivetYODA.hh b/include/Rivet/Tools/RivetYODA.hh --- a/include/Rivet/Tools/RivetYODA.hh +++ b/include/Rivet/Tools/RivetYODA.hh @@ -1,303 +1,307 @@ #ifndef RIVET_RIVETYODA_HH #define RIVET_RIVETYODA_HH /// @author Andy Buckley /// @date 2009-01-30 /// @author David Grellscheid /// @date 2011-07-18 /// @author David Grellscheid /// @date 2016-09-27 #include "Rivet/Config/RivetCommon.hh" #include "YODA/AnalysisObject.h" #include "YODA/Counter.h" #include "YODA/Histo1D.h" #include "YODA/Histo2D.h" #include "YODA/Profile1D.h" #include "YODA/Profile2D.h" #include "YODA/Scatter1D.h" #include "YODA/Scatter2D.h" #include "YODA/Scatter3D.h" #include <map> namespace YODA { typedef std::shared_ptr<YODA::AnalysisObject> AnalysisObjectPtr; typedef std::shared_ptr<YODA::Histo1D> Histo1DPtr; typedef std::shared_ptr<YODA::Histo2D> Histo2DPtr; typedef std::shared_ptr<YODA::Profile1D> Profile1DPtr; typedef std::shared_ptr<YODA::Profile2D> Profile2DPtr; typedef std::shared_ptr<YODA::Scatter1D> Scatter1DPtr; typedef std::shared_ptr<YODA::Scatter2D> Scatter2DPtr; typedef std::shared_ptr<YODA::Scatter3D> Scatter3DPtr; typedef std::shared_ptr<YODA::Counter> CounterPtr; } namespace Rivet { class AnalysisObjectPtr { public: virtual ~AnalysisObjectPtr() {} virtual YODA::AnalysisObject* operator->() = 0; virtual YODA::AnalysisObject* operator->() const = 0; virtual const YODA::AnalysisObject & operator*() const = 0; + bool operator ==(const AnalysisObjectPtr& p) { return (this == &p); } + protected: /// @todo do we need this? // virtual void reset() = 0; }; /// @todo /// implement scatter1dptr and scatter2dptr here class Scatter1DPtr : public AnalysisObjectPtr { public: Scatter1DPtr() : _scatter(YODA::Scatter1DPtr()) { } - Scatter1DPtr(YODA::Scatter1DPtr& p) : + Scatter1DPtr(const YODA::Scatter1DPtr& p) : _scatter(p) { } bool operator!() const { return !_scatter; } operator bool() const { return bool(_scatter); } YODA::Scatter1D* operator->() { return _scatter.get(); } YODA::Scatter1D* operator->() const { return _scatter.get(); } YODA::Scatter1D & operator*() { return *_scatter; } const YODA::Scatter1D & operator*() const { return *_scatter; } protected: YODA::Scatter1DPtr _scatter; }; class Scatter2DPtr : public AnalysisObjectPtr { public: - Scatter2DPtr(YODA::Scatter2DPtr& p) : + Scatter2DPtr(const YODA::Scatter2DPtr& p) : _scatter(p) { } Scatter2DPtr() : _scatter(YODA::Scatter2DPtr()) { } bool operator!() { return !_scatter; } operator bool() { return bool(_scatter); } YODA::Scatter2D* operator->() { return _scatter.get(); } YODA::Scatter2D* operator->() const { return _scatter.get(); } YODA::Scatter2D & operator*() { return *_scatter; } const YODA::Scatter2D & operator*() const { return *_scatter; } protected: YODA::Scatter2DPtr _scatter; }; class Scatter3DPtr : public AnalysisObjectPtr { public: - Scatter3DPtr(YODA::Scatter3DPtr& p) : + Scatter3DPtr(const YODA::Scatter3DPtr& p) : _scatter(p) { } Scatter3DPtr() : _scatter(YODA::Scatter3DPtr()) { } bool operator!() { return !_scatter; } operator bool() { return bool(_scatter); } YODA::Scatter3D* operator->() { return _scatter.get(); } YODA::Scatter3D* operator->() const { return _scatter.get(); } YODA::Scatter3D & operator*() { return *_scatter; } const YODA::Scatter3D & operator*() const { return *_scatter; } protected: YODA::Scatter3DPtr _scatter; }; class MultiweightAOPtr : public AnalysisObjectPtr { - protected: + public: virtual void newSubEvent() = 0; /// @todo /// rename to setActive(Idx)? virtual void setActiveWeightIdx(unsigned int iWeight) = 0; virtual void pushToPersistent(const vector<vector<double> >& weight) = 0; }; #define RIVETAOPTR_COMMON(YODATYPE) \ class YODATYPE##Ptr : public MultiweightAOPtr { \ public: \ \ /* @todo \ * some things are not really well-defined here \ * for instance: fill() in the finalize() method and integral() in \ * the analyze() method. \ */ \ \ YODATYPE##Ptr(size_t len_of_weightvec, const YODA::YODATYPE& p) { \ for (size_t i = 0; i < len_of_weightvec; i++) \ _persistent.push_back(make_shared<YODA::YODATYPE>(p)); \ \ return; \ } \ \ YODA::YODATYPE##Ptr active() const { return _active; } \ \ /* @todo this probably need to loop over all? */ \ bool operator!() const {return !active();} \ operator bool() const {return bool(active());} \ \ YODA::YODATYPE* operator->() { \ return active().get(); \ } \ \ YODA::YODATYPE* operator->() const { \ return active().get(); \ } \ \ YODA::YODATYPE & operator*() { \ return *active(); \ } \ \ const YODA::YODATYPE & operator*() const { \ return *active(); \ } \ \ /* @todo \ * these need to be re-thought out. \ \ void reset() { active()->reset(); } \ */ \ \ /* @todo \ * these probably need to loop over all? \ * do we even want to provide equality? \ */ \ /* @todo \ * how about no. \ friend bool operator==(YODATYPE##Ptr a, YODATYPE##Ptr b){ \ if (a._persistent.size() != b._persistent.size()) \ return false; \ \ for (size_t i = 0; i < a._persistent.size(); i++) { \ if (a._persistent.at(i) != b._persistent.at(i)) { \ return false; \ } \ } \ \ return true; \ } \ \ friend bool operator!=(YODATYPE##Ptr a, YODATYPE##Ptr b){ \ return !(a == b); \ } \ \ \ friend bool operator<(YODATYPE##Ptr a, YODATYPE##Ptr b){ \ if (a._persistent.size() >= b._persistent.size()) \ return false; \ \ for (size_t i = 0; i < a._persistent.size(); i++) { \ if (*(a._persistent.at(i)) >= *(b._persistent.at(i))) { \ return false; \ } \ } \ \ return true; \ } \ */ \ \ + \ private: \ - \ void setActiveWeightIdx(unsigned int iWeight) { \ _active = _persistent.at(iWeight); \ return; \ } \ \ /* this is for dev only---we shouldn't need this in real runs. */ \ void unsetActiveWeight() { \ _active.reset(); \ return; \ } \ \ void newSubEvent() { \ YODA::YODATYPE##Ptr tmp = \ make_shared<YODA::YODATYPE>(_persistent[0]->clone()); \ tmp->reset(); \ _evgroup.push_back( tmp ); \ _active = _evgroup.back(); \ return; \ } \ \ const vector<YODA::YODATYPE##Ptr> & persistent() const { \ return _persistent; \ } \ \ /* to be implemented for each type */ \ void pushToPersistent(const vector<vector<double> >& weight); \ \ /* M of these, one for each weight */ \ vector<YODA::YODATYPE##Ptr> _persistent; \ \ /* N of these, one for each event in evgroup */ \ vector<YODA::YODATYPE##Ptr> _evgroup; \ \ YODA::YODATYPE##Ptr _active; \ + \ + friend class AnalysisHandler; \ }; RIVETAOPTR_COMMON(Histo1D) RIVETAOPTR_COMMON(Histo2D) RIVETAOPTR_COMMON(Profile1D) RIVETAOPTR_COMMON(Profile2D) RIVETAOPTR_COMMON(Counter) using YODA::Counter; using YODA::Histo1D; using YODA::HistoBin1D; using YODA::Histo2D; using YODA::HistoBin2D; using YODA::Profile1D; using YODA::ProfileBin1D; using YODA::Profile2D; using YODA::ProfileBin2D; using YODA::Scatter1D; using YODA::Point1D; using YODA::Scatter2D; using YODA::Point2D; using YODA::Scatter3D; using YODA::Point3D; /// Function to get a map of all the refdata in a paper with the /// given @a papername. map<string, YODA::AnalysisObjectPtr> getRefData(const string& papername); /// @todo Also provide a Scatter3D getRefData() version? /// Get the file system path to the reference file for this paper. string getDatafilePath(const string& papername); /// Return the integral over the histogram bins /// @deprecated Prefer to directly use the histo's integral() method. DEPRECATED("Prefer to directly use the histo's integral() method.") inline double integral(Histo1DPtr histo) { return histo->integral(); } } #endif diff --git a/src/Core/Analysis.cc b/src/Core/Analysis.cc --- a/src/Core/Analysis.cc +++ b/src/Core/Analysis.cc @@ -1,822 +1,780 @@ // -*- C++ -*- #include "Rivet/Config/RivetCommon.hh" #include "Rivet/Analysis.hh" #include "Rivet/AnalysisHandler.hh" #include "Rivet/AnalysisInfo.hh" #include "Rivet/Tools/BeamConstraint.hh" namespace Rivet { Analysis::Analysis(const string& name) : _crossSection(-1.0), _gotCrossSection(false), _analysishandler(NULL) { ProjectionApplier::_allowProjReg = false; _defaultname = name; unique_ptr<AnalysisInfo> ai = AnalysisInfo::make(name); assert(ai); _info = move(ai); assert(_info); } double Analysis::sqrtS() const { return handler().sqrtS(); } const ParticlePair& Analysis::beams() const { return handler().beams(); } const PdgIdPair Analysis::beamIds() const { return handler().beamIds(); } const string Analysis::histoDir() const { /// @todo Cache in a member variable string _histoDir; if (_histoDir.empty()) { _histoDir = "/" + name(); if (handler().runName().length() > 0) { _histoDir = "/" + handler().runName() + _histoDir; } replace_all(_histoDir, "//", "/"); //< iterates until none } return _histoDir; } const string Analysis::histoPath(const string& hname) const { const string path = histoDir() + "/" + hname; return path; } const string Analysis::histoPath(unsigned int datasetId, unsigned int xAxisId, unsigned int yAxisId) const { return histoDir() + "/" + makeAxisCode(datasetId, xAxisId, yAxisId); } const string Analysis::makeAxisCode(unsigned int datasetId, unsigned int xAxisId, unsigned int yAxisId) const { stringstream axisCode; axisCode << "d"; if (datasetId < 10) axisCode << 0; axisCode << datasetId; axisCode << "-x"; if (xAxisId < 10) axisCode << 0; axisCode << xAxisId; axisCode << "-y"; if (yAxisId < 10) axisCode << 0; axisCode << yAxisId; return axisCode.str(); } Log& Analysis::getLog() const { string logname = "Rivet.Analysis." + name(); return Log::getLog(logname); } size_t Analysis::numEvents() const { return handler().numEvents(); } const vector<double>& Analysis::sumOfWeights() const { return handler().sumOfWeights(); } /////////////////////////////////////////// bool Analysis::isCompatible(const ParticlePair& beams) const { return isCompatible(beams.first.pid(), beams.second.pid(), beams.first.energy(), beams.second.energy()); } bool Analysis::isCompatible(PdgId beam1, PdgId beam2, double e1, double e2) const { PdgIdPair beams(beam1, beam2); pair<double,double> energies(e1, e2); return isCompatible(beams, energies); } bool Analysis::isCompatible(const PdgIdPair& beams, const pair<double,double>& energies) const { // First check the beam IDs bool beamIdsOk = false; foreach (const PdgIdPair& bp, requiredBeams()) { if (compatible(beams, bp)) { beamIdsOk = true; break; } } if (!beamIdsOk) return false; // Next check that the energies are compatible (within 1% or 1 GeV, whichever is larger, for a bit of UI forgiveness) /// @todo Use some sort of standard ordering to improve comparisons, esp. when the two beams are different particles bool beamEnergiesOk = requiredEnergies().size() > 0 ? false : true; typedef pair<double,double> DoublePair; foreach (const DoublePair& ep, requiredEnergies()) { if ((fuzzyEquals(ep.first, energies.first, 0.01) && fuzzyEquals(ep.second, energies.second, 0.01)) || (fuzzyEquals(ep.first, energies.second, 0.01) && fuzzyEquals(ep.second, energies.first, 0.01)) || (abs(ep.first - energies.first) < 1*GeV && abs(ep.second - energies.second) < 1*GeV) || (abs(ep.first - energies.second) < 1*GeV && abs(ep.second - energies.first) < 1*GeV)) { beamEnergiesOk = true; break; } } return beamEnergiesOk; /// @todo Need to also check internal consistency of the analysis' /// beam requirements with those of the projections it uses. } /////////////////////////////////////////// Analysis& Analysis::setCrossSection(double xs) { _crossSection = xs; _gotCrossSection = true; return *this; } double Analysis::crossSection() const { if (!_gotCrossSection || std::isnan(_crossSection)) { string errMsg = "You did not set the cross section for the analysis " + name(); throw Error(errMsg); } return _crossSection; } vector<double> Analysis::crossSectionPerEvent() const { const vector<double>& sumW = sumOfWeights(); assert(sumW.size() != 0.0); // @todo // is this correct? vector<double> v(sumW); foreach (double& x, v) { x = _crossSection/x; } return v; } //////////////////////////////////////////////////////////// // Histogramming void Analysis::_cacheRefData() const { if (_refdata.empty()) { MSG_TRACE("Getting refdata cache for paper " << name()); _refdata = getRefData(name()); } } const Scatter2D& Analysis::refData(const string& hname) const { _cacheRefData(); MSG_TRACE("Using histo bin edges for " << name() << ":" << hname); if (!_refdata[hname]) { MSG_ERROR("Can't find reference histogram " << hname); throw Exception("Reference data " + hname + " not found."); } return dynamic_cast<Scatter2D&>(*_refdata[hname]); } const Scatter2D& Analysis::refData(unsigned int datasetId, unsigned int xAxisId, unsigned int yAxisId) const { const string hname = makeAxisCode(datasetId, xAxisId, yAxisId); return refData(hname); } CounterPtr Analysis::bookCounter(const string& cname, const string& title) { const string path = histoPath(cname); - CounterPtr ctr(handler().numWeights(), Counter(path, title)); + shared_ptr<CounterPtr> ctr = + make_shared<CounterPtr>(handler().numWeights(), Counter(path, title)); addAnalysisObject(ctr); MSG_TRACE("Made counter " << cname << " for " << name()); - return ctr; + return *ctr; } CounterPtr Analysis::bookCounter(unsigned int datasetId, unsigned int xAxisId, unsigned int yAxisId, const string& title) { // const string& xtitle, // const string& ytitle) { const string axisCode = makeAxisCode(datasetId, xAxisId, yAxisId); return bookCounter(axisCode, title); } Histo1DPtr Analysis::bookHisto1D(const string& hname, size_t nbins, double lower, double upper, const string& title, const string& xtitle, const string& ytitle) { const string path = histoPath(hname); - Histo1DPtr hist(handler().numWeights(), Histo1D(nbins, lower, upper, path, title)); - addAnalysisObject(hist); + shared_ptr<Histo1DPtr> hp = + make_shared<Histo1DPtr>(handler().numWeights(), Histo1D(nbins, lower, upper, path, title)); + addAnalysisObject(hp); + Histo1DPtr hist = *hp; MSG_TRACE("Made histogram " << hname << " for " << name()); hist->setAnnotation("XLabel", xtitle); hist->setAnnotation("YLabel", ytitle); return hist; } Histo1DPtr Analysis::bookHisto1D(const string& hname, const vector<double>& binedges, const string& title, const string& xtitle, const string& ytitle) { const string path = histoPath(hname); - Histo1DPtr hist(handler().numWeights(), Histo1D(binedges, path, title)); - addAnalysisObject(hist); + shared_ptr<Histo1DPtr> hp = + make_shared<Histo1DPtr>(handler().numWeights(), Histo1D(binedges, path, title)); + addAnalysisObject(hp); + + Histo1DPtr hist = *hp; MSG_TRACE("Made histogram " << hname << " for " << name()); hist->setAnnotation("XLabel", xtitle); hist->setAnnotation("YLabel", ytitle); return hist; } Histo1DPtr Analysis::bookHisto1D(const string& hname, const Scatter2D& refscatter, const string& title, const string& xtitle, const string& ytitle) { const string path = histoPath(hname); - Histo1DPtr hist(handler().numWeights(), Histo1D(refscatter, path)); - addAnalysisObject(hist); + shared_ptr<Histo1DPtr> hp = + make_shared<Histo1DPtr>(handler().numWeights(), Histo1D(refscatter, path)); + addAnalysisObject(hp); + + Histo1DPtr hist = *hp; MSG_TRACE("Made histogram " << hname << " for " << name()); hist->setTitle(title); hist->setAnnotation("XLabel", xtitle); hist->setAnnotation("YLabel", ytitle); return hist; } Histo1DPtr Analysis::bookHisto1D(const string& hname, const string& title, const string& xtitle, const string& ytitle) { const Scatter2D& refdata = refData(hname); return bookHisto1D(hname, refdata, title, xtitle, ytitle); } Histo1DPtr Analysis::bookHisto1D(unsigned int datasetId, unsigned int xAxisId, unsigned int yAxisId, const string& title, const string& xtitle, const string& ytitle) { const string axisCode = makeAxisCode(datasetId, xAxisId, yAxisId); return bookHisto1D(axisCode, title, xtitle, ytitle); } /// @todo Add booking methods which take a path, titles and *a reference Scatter from which to book* ///////////////// Histo2DPtr Analysis::bookHisto2D(const string& hname, size_t nxbins, double xlower, double xupper, size_t nybins, double ylower, double yupper, const string& title, const string& xtitle, const string& ytitle, const string& ztitle) { const string path = histoPath(hname); - Histo2DPtr hist(handler().numWeights(), Histo2D(nxbins, xlower, xupper, nybins, ylower, yupper, path, title)); - addAnalysisObject(hist); + shared_ptr<Histo2DPtr> hp = + make_shared<Histo2DPtr>(handler().numWeights(), Histo2D(nxbins, xlower, xupper, nybins, ylower, yupper, path, title)); + addAnalysisObject(hp); + + Histo2DPtr hist = *hp; MSG_TRACE("Made 2D histogram " << hname << " for " << name()); hist->setAnnotation("XLabel", xtitle); hist->setAnnotation("YLabel", ytitle); hist->setAnnotation("ZLabel", ztitle); return hist; } Histo2DPtr Analysis::bookHisto2D(const string& hname, const vector<double>& xbinedges, const vector<double>& ybinedges, const string& title, const string& xtitle, const string& ytitle, const string& ztitle) { const string path = histoPath(hname); - Histo2DPtr hist(handler().numWeights(), Histo2D(xbinedges, ybinedges, path, title)); - addAnalysisObject(hist); + shared_ptr<Histo2DPtr> hp = + make_shared<Histo2DPtr>(handler().numWeights(), Histo2D(xbinedges, ybinedges, path, title)); + addAnalysisObject(hp); + + Histo2DPtr hist = *hp; MSG_TRACE("Made 2D histogram " << hname << " for " << name()); hist->setAnnotation("XLabel", xtitle); hist->setAnnotation("YLabel", ytitle); hist->setAnnotation("ZLabel", ztitle); return hist; } - // Histo2DPtr Analysis::bookHisto2D(const string& hname, - // const Scatter3D& refscatter, - // const string& title="", - // const string& xtitle="", - // const string& ytitle="", - // const string& ztitle="") { - // const string path = histoPath(hname); - // Histo2DPtr hist( new Histo2D(refscatter, path) ); - // addAnalysisObject(hist); - // MSG_TRACE("Made 2D histogram " << hname << " for " << name()); - // hist->setTitle(title); - // hist->setAnnotation("XLabel", xtitle); - // hist->setAnnotation("YLabel", ytitle); - // hist->setAnnotation("ZLabel", ztitle); - // return hist; - // } - - - // Histo2DPtr Analysis::bookHisto2D(const string& hname, - // const string& title, - // const string& xtitle, - // const string& ytitle, - // const string& ztitle) { - // const Scatter3D& refdata = refData(hname); - // return bookHisto2D(hname, refdata, title, xtitle, ytitle, ztitle); - // } - - - // Histo2DPtr Analysis::bookHisto2D(unsigned int datasetId, unsigned int xAxisId, unsigned int yAxisId, - // const string& title, - // const string& xtitle, - // const string& ytitle, - // const string& ztitle) { - // const string axisCode = makeAxisCode(datasetId, xAxisId, yAxisId); - // return bookHisto2D(axisCode, title, xtitle, ytitle, ztitle); - // } - - - ///////////////// - - Profile1DPtr Analysis::bookProfile1D(const string& hname, size_t nbins, double lower, double upper, const string& title, const string& xtitle, const string& ytitle) { const string path = histoPath(hname); - Profile1DPtr prof(handler().numWeights(), Profile1D(nbins, lower, upper, path, title)); - addAnalysisObject(prof); + shared_ptr<Profile1DPtr> pp = + make_shared<Profile1DPtr>(handler().numWeights(), Profile1D(nbins, lower, upper, path, title)); + addAnalysisObject(pp); + + Profile1DPtr prof = *pp; MSG_TRACE("Made profile histogram " << hname << " for " << name()); prof->setAnnotation("XLabel", xtitle); prof->setAnnotation("YLabel", ytitle); return prof; } Profile1DPtr Analysis::bookProfile1D(const string& hname, const vector<double>& binedges, const string& title, const string& xtitle, const string& ytitle) { const string path = histoPath(hname); - Profile1DPtr prof(handler().numWeights(), Profile1D(binedges, path, title)); - addAnalysisObject(prof); + shared_ptr<Profile1DPtr> pp = + make_shared<Profile1DPtr>(handler().numWeights(), Profile1D(binedges, path, title)); + addAnalysisObject(pp); + + Profile1DPtr prof = *pp; MSG_TRACE("Made profile histogram " << hname << " for " << name()); prof->setAnnotation("XLabel", xtitle); prof->setAnnotation("YLabel", ytitle); return prof; } Profile1DPtr Analysis::bookProfile1D(const string& hname, const Scatter2D& refscatter, const string& title, const string& xtitle, const string& ytitle) { const string path = histoPath(hname); - Profile1DPtr prof(handler().numWeights(), Profile1D(refscatter, path)); - addAnalysisObject(prof); + shared_ptr<Profile1DPtr> pp = + make_shared<Profile1DPtr>(handler().numWeights(), Profile1D(refscatter, path)); + addAnalysisObject(pp); + + Profile1DPtr prof = *pp; MSG_TRACE("Made profile histogram " << hname << " for " << name()); prof->setTitle(title); prof->setAnnotation("XLabel", xtitle); prof->setAnnotation("YLabel", ytitle); return prof; } Profile1DPtr Analysis::bookProfile1D(const string& hname, const string& title, const string& xtitle, const string& ytitle) { const Scatter2D& refdata = refData(hname); return bookProfile1D(hname, refdata, title, xtitle, ytitle); } Profile1DPtr Analysis::bookProfile1D(unsigned int datasetId, unsigned int xAxisId, unsigned int yAxisId, const string& title, const string& xtitle, const string& ytitle) { const string axisCode = makeAxisCode(datasetId, xAxisId, yAxisId); return bookProfile1D(axisCode, title, xtitle, ytitle); } /////////////////// + /* Profile2DPtr Analysis::bookProfile2D(const string& hname, size_t nxbins, double xlower, double xupper, size_t nybins, double ylower, double yupper, const string& title, const string& xtitle, const string& ytitle, const string& ztitle) { const string path = histoPath(hname); - Profile2DPtr prof(handler().numWeights(), Profile2D(nxbins, xlower, xupper, nybins, ylower, yupper, path, title)); - addAnalysisObject(prof); + shared_ptr<Profile2DPtr> pp = + make_shared<Profile2DPtr>(handler().numWeights(), Profile2D(nxbins, xlower, xupper, nybins, ylower, yupper, path, title)); + addAnalysisObject(pp); + + Profile2DPtr prof = *pp; MSG_TRACE("Made 2D profile histogram " << hname << " for " << name()); prof->setAnnotation("XLabel", xtitle); prof->setAnnotation("YLabel", ytitle); prof->setAnnotation("ZLabel", ztitle); return prof; } Profile2DPtr Analysis::bookProfile2D(const string& hname, const vector<double>& xbinedges, const vector<double>& ybinedges, const string& title, const string& xtitle, const string& ytitle, const string& ztitle) { const string path = histoPath(hname); - Profile2DPtr prof(handler().numWeights(), Profile2D(xbinedges, ybinedges, path, title)); - addAnalysisObject(prof); + shared_ptr<Profile2DPtr> pp = + make_shared<Profile2DPtr>(handler().numWeights(), Profile2D(xbinedges, ybinedges, path, title)); + addAnalysisObject(pp); + + Profile2DPtr prof = *pp; MSG_TRACE("Made 2D profile histogram " << hname << " for " << name()); prof->setAnnotation("XLabel", xtitle); prof->setAnnotation("YLabel", ytitle); prof->setAnnotation("ZLabel", ztitle); return prof; } - // Profile2DPtr Analysis::bookProfile2D(const string& hname, - // const Scatter3D& refscatter, - // const string& title="", - // const string& xtitle="", - // const string& ytitle="", - // const string& ztitle="") { - // const string path = histoPath(hname); - // Profile2DPtr prof( new Profile2D(refscatter, path) ); - // addAnalysisObject(prof); - // MSG_TRACE("Made 2D profile histogram " << hname << " for " << name()); - // prof->setTitle(title); - // prof->setAnnotation("XLabel", xtitle); - // prof->setAnnotation("YLabel", ytitle); - // prof->setAnnotation("ZLabel", ztitle); - // return prof; - // } - - - // Profile2DPtr Analysis::bookProfile2D(const string& hname, - // const string& title, - // const string& xtitle, - // const string& ytitle, - // const string& ztitle) { - // const Scatter3D& refdata = refData(hname); - // return bookProfile2D(hname, refdata, title, xtitle, ytitle, ztitle); - // } - - - // Profile2DPtr Analysis::bookProfile2D(unsigned int datasetId, unsigned int xAxisId, unsigned int yAxisId, - // const string& title, - // const string& xtitle, - // const string& ytitle, - // const string& ztitle) { - // const string axisCode = makeAxisCode(datasetId, xAxisId, yAxisId); - // return bookProfile2D(axisCode, title, xtitle, ytitle, ztitle); - // } - - - ///////////////// - - Scatter2DPtr Analysis::bookScatter2D(unsigned int datasetId, unsigned int xAxisId, unsigned int yAxisId, bool copy_pts, const string& title, const string& xtitle, const string& ytitle) { const string axisCode = makeAxisCode(datasetId, xAxisId, yAxisId); return bookScatter2D(axisCode, copy_pts, title, xtitle, ytitle); } Scatter2DPtr Analysis::bookScatter2D(const string& hname, bool copy_pts, const string& title, const string& xtitle, const string& ytitle) { - Scatter2DPtr s; + shared_ptr<Scatter2DPtr> sp = make_shared<Scatter2DPtr>(make_shared<Scatter2D>()); const string path = histoPath(hname); if (copy_pts) { const Scatter2D& refdata = refData(hname); - s = make_shared<Scatter2D>(refdata, path); - foreach (Point2D& p, s->points()) p.setY(0, 0); + *sp = Scatter2DPtr(make_shared<Scatter2D>(refdata, path)); + foreach (Point2D& p, (*sp)->points()) p.setY(0, 0); } else { - s = make_shared<Scatter2D>(path); + *sp = Scatter2DPtr(make_shared<Scatter2D>(path)); } - addAnalysisObject(s); + addAnalysisObject(sp); + + Scatter2DPtr scat = *sp; MSG_TRACE("Made scatter " << hname << " for " << name()); - s->setTitle(title); - s->setAnnotation("XLabel", xtitle); - s->setAnnotation("YLabel", ytitle); - return s; + scat->setTitle(title); + scat->setAnnotation("XLabel", xtitle); + scat->setAnnotation("YLabel", ytitle); + return scat; } Scatter2DPtr Analysis::bookScatter2D(const string& hname, size_t npts, double lower, double upper, const string& title, const string& xtitle, const string& ytitle) { const string path = histoPath(hname); - Scatter2DPtr s = make_shared<Scatter2D>(path); + shared_ptr<Scatter2DPtr> sp = make_shared<Scatter2DPtr>(make_shared<Scatter2D>(path)); const double binwidth = (upper-lower)/npts; for (size_t pt = 0; pt < npts; ++pt) { const double bincentre = lower + (pt + 0.5) * binwidth; - s->addPoint(bincentre, 0, binwidth/2.0, 0); + (*sp)->addPoint(bincentre, 0, binwidth/2.0, 0); } - addAnalysisObject(s); + addAnalysisObject(sp); + + Scatter2DPtr scat = *sp; + MSG_TRACE("Made scatter " << hname << " for " << name()); - s->setTitle(title); - s->setAnnotation("XLabel", xtitle); - s->setAnnotation("YLabel", ytitle); - return s; + scat->setTitle(title); + scat->setAnnotation("XLabel", xtitle); + scat->setAnnotation("YLabel", ytitle); + return scat; } Scatter2DPtr Analysis::bookScatter2D(const string& hname, const vector<double>& binedges, const string& title, const string& xtitle, const string& ytitle) { const string path = histoPath(hname); - Scatter2DPtr s = make_shared<Scatter2D>(path); + shared_ptr<Scatter2DPtr> sp = + make_shared<Scatter2DPtr>(make_shared<Scatter2D>(path)); for (size_t pt = 0; pt < binedges.size()-1; ++pt) { const double bincentre = (binedges[pt] + binedges[pt+1]) / 2.0; const double binwidth = binedges[pt+1] - binedges[pt]; - s->addPoint(bincentre, 0, binwidth/2.0, 0); + (*sp)->addPoint(bincentre, 0, binwidth/2.0, 0); } - addAnalysisObject(s); + addAnalysisObject(sp); + + Scatter2DPtr scat = *sp; MSG_TRACE("Made scatter " << hname << " for " << name()); - s->setTitle(title); - s->setAnnotation("XLabel", xtitle); - s->setAnnotation("YLabel", ytitle); - return s; + scat->setTitle(title); + scat->setAnnotation("XLabel", xtitle); + scat->setAnnotation("YLabel", ytitle); + return scat; } + */ ///////////////////// void Analysis::divide(CounterPtr c1, CounterPtr c2, Scatter1DPtr s) const { const string path = s->path(); *s = *c1 / *c2; s->setPath(path); } void Analysis::divide(const Counter& c1, const Counter& c2, Scatter1DPtr s) const { const string path = s->path(); *s = c1 / c2; s->setPath(path); } void Analysis::divide(Histo1DPtr h1, Histo1DPtr h2, Scatter2DPtr s) const { const string path = s->path(); *s = *h1 / *h2; s->setPath(path); } void Analysis::divide(const Histo1D& h1, const Histo1D& h2, Scatter2DPtr s) const { const string path = s->path(); *s = h1 / h2; s->setPath(path); } void Analysis::divide(Profile1DPtr p1, Profile1DPtr p2, Scatter2DPtr s) const { const string path = s->path(); *s = *p1 / *p2; s->setPath(path); } void Analysis::divide(const Profile1D& p1, const Profile1D& p2, Scatter2DPtr s) const { const string path = s->path(); *s = p1 / p2; s->setPath(path); } void Analysis::divide(Histo2DPtr h1, Histo2DPtr h2, Scatter3DPtr s) const { const string path = s->path(); *s = *h1 / *h2; s->setPath(path); } void Analysis::divide(const Histo2D& h1, const Histo2D& h2, Scatter3DPtr s) const { const string path = s->path(); *s = h1 / h2; s->setPath(path); } void Analysis::divide(Profile2DPtr p1, Profile2DPtr p2, Scatter3DPtr s) const { const string path = s->path(); *s = *p1 / *p2; s->setPath(path); } void Analysis::divide(const Profile2D& p1, const Profile2D& p2, Scatter3DPtr s) const { const string path = s->path(); *s = p1 / p2; s->setPath(path); } /// @todo Counter and Histo2D efficiencies and asymms void Analysis::efficiency(Histo1DPtr h1, Histo1DPtr h2, Scatter2DPtr s) const { const string path = s->path(); *s = YODA::efficiency(*h1, *h2); s->setPath(path); } void Analysis::efficiency(const Histo1D& h1, const Histo1D& h2, Scatter2DPtr s) const { const string path = s->path(); *s = YODA::efficiency(h1, h2); s->setPath(path); } void Analysis::asymm(Histo1DPtr h1, Histo1DPtr h2, Scatter2DPtr s) const { const string path = s->path(); *s = YODA::asymm(*h1, *h2); s->setPath(path); } void Analysis::asymm(const Histo1D& h1, const Histo1D& h2, Scatter2DPtr s) const { const string path = s->path(); *s = YODA::asymm(h1, h2); s->setPath(path); } void Analysis::scale(CounterPtr cnt, double factor) { if (!cnt) { MSG_WARNING("Failed to scale counter=NULL in analysis " << name() << " (scale=" << factor << ")"); return; } if (std::isnan(factor) || std::isinf(factor)) { MSG_WARNING("Failed to scale counter=" << cnt->path() << " in analysis: " << name() << " (invalid scale factor = " << factor << ")"); factor = 0; } MSG_TRACE("Scaling counter " << cnt->path() << " by factor " << factor); try { cnt->scaleW(factor); } catch (YODA::Exception& we) { MSG_WARNING("Could not scale counter " << cnt->path()); return; } } void Analysis::normalize(Histo1DPtr histo, double norm, bool includeoverflows) { if (!histo) { MSG_WARNING("Failed to normalize histo=NULL in analysis " << name() << " (norm=" << norm << ")"); return; } MSG_TRACE("Normalizing histo " << histo->path() << " to " << norm); try { histo->normalize(norm, includeoverflows); } catch (YODA::Exception& we) { MSG_WARNING("Could not normalize histo " << histo->path()); return; } } void Analysis::scale(Histo1DPtr histo, double factor) { if (!histo) { MSG_WARNING("Failed to scale histo=NULL in analysis " << name() << " (scale=" << factor << ")"); return; } if (std::isnan(factor) || std::isinf(factor)) { MSG_WARNING("Failed to scale histo=" << histo->path() << " in analysis: " << name() << " (invalid scale factor = " << factor << ")"); factor = 0; } MSG_TRACE("Scaling histo " << histo->path() << " by factor " << factor); try { histo->scaleW(factor); } catch (YODA::Exception& we) { MSG_WARNING("Could not scale histo " << histo->path()); return; } } void Analysis::normalize(Histo2DPtr histo, double norm, bool includeoverflows) { if (!histo) { MSG_ERROR("Failed to normalize histo=NULL in analysis " << name() << " (norm=" << norm << ")"); return; } MSG_TRACE("Normalizing histo " << histo->path() << " to " << norm); try { histo->normalize(norm, includeoverflows); } catch (YODA::Exception& we) { MSG_WARNING("Could not normalize histo " << histo->path()); return; } } void Analysis::scale(Histo2DPtr histo, double factor) { if (!histo) { MSG_ERROR("Failed to scale histo=NULL in analysis " << name() << " (scale=" << factor << ")"); return; } if (std::isnan(factor) || std::isinf(factor)) { MSG_ERROR("Failed to scale histo=" << histo->path() << " in analysis: " << name() << " (invalid scale factor = " << factor << ")"); factor = 0; } MSG_TRACE("Scaling histo " << histo->path() << " by factor " << factor); try { histo->scaleW(factor); } catch (YODA::Exception& we) { MSG_WARNING("Could not scale histo " << histo->path()); return; } } void Analysis::integrate(Histo1DPtr h, Scatter2DPtr s) const { // preserve the path info const string path = s->path(); *s = toIntegralHisto(*h); s->setPath(path); } void Analysis::integrate(const Histo1D& h, Scatter2DPtr s) const { // preserve the path info const string path = s->path(); *s = toIntegralHisto(h); s->setPath(path); } /// @todo 2D versions of integrate... defined how, exactly?!? ////////////////////////////////// - void Analysis::addAnalysisObject(AnalysisObjectPtr ao) { + void Analysis::addAnalysisObject(shared_ptr<MultiweightAOPtr> ao) { _analysisobjects.push_back(ao); } void Analysis::removeAnalysisObject(const string& path) { - for (vector<AnalysisObjectPtr>::iterator it = _analysisobjects.begin(); it != _analysisobjects.end(); ++it) { - if ((*it)->path() == path) { + for (vector<shared_ptr<MultiweightAOPtr> >::iterator it = _analysisobjects.begin(); it != _analysisobjects.end(); ++it) { + if ((**it)->path() == path) { _analysisobjects.erase(it); break; } } } - void Analysis::removeAnalysisObject(AnalysisObjectPtr ao) { - for (vector<AnalysisObjectPtr>::iterator it = _analysisobjects.begin(); it != _analysisobjects.end(); ++it) { - if (*it == ao) { + void Analysis::removeAnalysisObject(const MultiweightAOPtr& ao) { + for (vector<shared_ptr<MultiweightAOPtr> >::iterator it = _analysisobjects.begin(); it != _analysisobjects.end(); ++it) { + if (**it == ao) { _analysisobjects.erase(it); break; } } } } diff --git a/src/Core/AnalysisHandler.cc b/src/Core/AnalysisHandler.cc --- a/src/Core/AnalysisHandler.cc +++ b/src/Core/AnalysisHandler.cc @@ -1,402 +1,422 @@ // -*- 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/WriterYODA.h" -#include "Rivet/Histo1D.hh" namespace Rivet { AnalysisHandler::AnalysisHandler(const string& runname) : _runname(runname), _numEvents(0), _sumOfWeights(0.0), _xs(NAN), _initialised(false), _ignoreBeams(false) {} AnalysisHandler::~AnalysisHandler() {} Log& AnalysisHandler::getLog() const { return Log::getLog("Rivet.Analysis.Handler"); } void AnalysisHandler::init(const GenEvent& ge) { if (_initialised) throw UserError("AnalysisHandler::init has already been called: cannot re-initialize!"); setRunBeams(Rivet::beams(ge)); MSG_DEBUG("Initialising the analysis handler"); _numEvents = 0; _eventNumber = ge.event_number(); setWeightNames(ge); if (haveNamedWeights()) { MSG_INFO("Using named weights"); } else { _weightNames.clear(); _weightNames.push_back("0"); MSG_INFO("NOT using named weights. Using first weight as nominal weight"); } _numWeightTypes = _weightNames.size(); _sumOfWeights = vector<double>(_numWeightTypes, 0.0); // 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 (toUpper(a->status()) == "PRELIMINARY") { MSG_WARNING("Analysis '" << a->name() << "' is preliminary: be careful, it may change and/or be renamed!"); } else if (toUpper(a->status()) == "OBSOLETE") { MSG_WARNING("Analysis '" << a->name() << "' is obsolete: please update!"); } else if (toUpper(a->status()).find("UNVALIDATED") != string::npos) { MSG_WARNING("Analysis '" << a->name() << "' is unvalidated: be careful, it may be broken!"); } } // Initialize the remaining analyses 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()); } _initialised = true; MSG_DEBUG("Analysis handler initialised"); } void AnalysisHandler::setWeightNames(const GenEvent& ge) { + return; + + /// @todo + /// this relies on boost and is removed for now + + /* /// reroute the print output to a stringstream and process /// The iteration is done over a map in hepmc2 so this is safe ostringstream stream; ge.weights().print(stream); // Super lame, I know string str = stream.str(); vector<string> temp; - boost::split(temp, str, boost::is_any_of("=")); + split(temp, str, is_any_of("=")); vector<string> tokens; - boost::split(tokens, temp[0], boost::is_any_of(" ")); + split(tokens, temp[0], is_any_of(" ")); /// Weights come in tuples: (StringName, doubleWeight) (AnotherName, anotherWeight) etc string wname; for (unsigned int i=0; i<tokens.size()-1;++i) { temp.clear(); - boost::split(temp, tokens[i], boost::is_any_of(",")); + split(temp, tokens[i], is_any_of(",")); if (temp.size()>0) { wname = temp[0]; - trim_left_if(wname,is_any_of("(")); + trim_left_if(wname, is_any_of("(")); _weightNames.push_back(wname); /// Turn into debug message MSG_INFO("Name of weight #" << i << ": " << wname); } } + */ } 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 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 Event event(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? + // if this is indeed a new event, push the temporary // histograms and reset - foreach (Rivet::Histo1DPtr& histo, _histograms) { - histo.rivetHisto1D()->pushToPersistent(_subEventWeights); + for (const AnaHandle& a : _analyses) { + for (const shared_ptr<MultiweightAOPtr>& aoptr : a->analysisObjects()) { + aoptr->pushToPersistent(_subEventWeights); + } } _eventNumber = ge.event_number(); // @todo // is this correct? // only incremented when event number changes. _numEvents++; MSG_DEBUG("Event #" << _numEvents << " nominal weight sum = " << _sumOfWeights[0]); MSG_DEBUG("Event has " << _subEventWeights.size() << " sub events."); _subEventWeights.clear(); } - foreach (Rivet::Histo1DPtr& histo, _histograms) { - histo.rivetHisto1D()->newEvent(); + for (const AnaHandle& a : _analyses) { + for (const shared_ptr<MultiweightAOPtr>& aoptr : a->analysisObjects()) { + aoptr->newSubEvent(); + } } _subEventWeights.push_back(event.weights()); MSG_DEBUG("Analyzing subevent #" << _subEventWeights.size() - 1 << "."); // @todo // is this the correct way to sum weights over sub events? for (unsigned int iWeight = 0; iWeight < _sumOfWeights.size(); iWeight++) { _sumOfWeights[iWeight] += _subEventWeights.back()[iWeight]; } // Cross-section #ifdef HEPMC_HAS_CROSS_SECTION if (ge.cross_section()) { _xs = ge.cross_section()->cross_section(); _xserr = ge.cross_section()->cross_section_error(); } #endif // 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()); } } void AnalysisHandler::analyze(const GenEvent* ge) { if (ge == NULL) { MSG_ERROR("AnalysisHandler received null pointer to GenEvent"); //throw Error("AnalysisHandler received null pointer to GenEvent"); } analyze(*ge); } void AnalysisHandler::finalize() { if (!_initialised) return; MSG_INFO("Finalising analyses"); for (AnaHandle a : _analyses) { a->setCrossSection(_xs); try { a->finalize(); } catch (const Error& err) { cerr << "Error in " << a->name() << "::finalize method: " << err.what() << endl; exit(1); } } // Print out number of events processed MSG_INFO("Processed " << _numEvents << " event" << (_numEvents == 1 ? "" : "s")); // // Delete analyses // MSG_DEBUG("Deleting analyses"); // _analyses.clear(); // Print out MCnet boilerplate 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) { // 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. for (const AnaHandle& a : _analyses) { if (a->name() == analysisname) { MSG_WARNING("Analysis '" << analysisname << "' already registered: skipping duplicate"); return *this; } } AnaHandle analysis( AnalysisLoader::getAnalysis(analysisname) ); if (analysis.get() != 0) { // < Check for null analysis. MSG_DEBUG("Adding analysis '" << analysisname << "'"); analysis->_analysishandler = this; _analyses.insert(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) { std::shared_ptr<Analysis> toremove; for (const AnaHandle a : _analyses) { if (a->name() == analysisname) { toremove = a; break; } } if (toremove.get() != 0) { MSG_DEBUG("Removing analysis '" << analysisname << "'"); _analyses.erase(toremove); } return *this; } - vector<AnalysisObjectPtr> AnalysisHandler::getData() const { - vector<AnalysisObjectPtr> rtn; + vector<shared_ptr<Rivet::AnalysisObjectPtr> > AnalysisHandler::getRivetAOs() const { + vector<shared_ptr<AnalysisObjectPtr> > rtn; + for (size_t i = 0; i < _numWeights; i++) { + // HERE WE ARE + } + } + + vector<YODA::AnalysisObjectPtr> AnalysisHandler::getData() const { + vector<YODA::AnalysisObjectPtr> rtn; rtn.push_back( make_shared<Counter>(YODA::Dbn0D(_numEvents, _sumOfWeights, _sumOfWeightsSq), "/_EVTCOUNT") ); YODA::Scatter1D::Points pts; pts.insert(YODA::Point1D(_xs, _xserr)); rtn.push_back( make_shared<Scatter1D>(pts, "/_XSEC") ); for (const AnaHandle a : analyses()) { vector<AnalysisObjectPtr> aos = a->analysisObjects(); // MSG_WARNING(a->name() << " " << aos.size()); for (const AnalysisObjectPtr ao : aos) { // Exclude paths starting with /TMP/ from final write-out /// @todo This needs to be much more nuanced for re-entrant histogramming if (ao->path().find("/TMP/") != string::npos) continue; rtn.push_back(ao); } } sort(rtn.begin(), rtn.end(), [](AnalysisObjectPtr a, AnalysisObjectPtr b) { return a->path() < b->path(); } ); return rtn; } void AnalysisHandler::writeData(const string& filename) const { const vector<AnalysisObjectPtr> aos = getData(); try { YODA::WriterYODA::write(filename, aos.begin(), aos.end()); - } catch (...) { /// @todo Move to specific YODA::WriteError type when YODA >= 1.5.0 is well-established + } catch ( YODA::WriteError ) { throw UserError("Unexpected error in writing file to: " + filename); } } string AnalysisHandler::runName() const { return _runname; } size_t AnalysisHandler::numEvents() const { return _numEvents; } double AnalysisHandler::sumOfWeights() const { return _sumOfWeights; } void AnalysisHandler::setSumOfWeights(const double& sum) { _sumOfWeights=sum; } std::vector<std::string> AnalysisHandler::analysisNames() const { std::vector<std::string> rtn; for (AnaHandle a : _analyses) { rtn.push_back(a->name()); } return rtn; } const AnaHandle AnalysisHandler::analysis(const std::string& analysisname) const { for (const AnaHandle a : analyses()) if (a->name() == analysisname) return a; throw Error("No analysis named '" + analysisname + "' registered in AnalysisHandler"); } 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; } bool AnalysisHandler::needCrossSection() const { bool rtn = false; for (const AnaHandle a : _analyses) { if (!rtn) rtn = a->needsCrossSection(); if (rtn) break; } return rtn; } AnalysisHandler& AnalysisHandler::setCrossSection(double xs) { _xs = xs; return *this; } bool AnalysisHandler::hasCrossSection() const { return (!std::isnan(crossSection())); } AnalysisHandler& AnalysisHandler::addAnalysis(Analysis* analysis) { analysis->_analysishandler = this; _analyses.insert(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; } } diff --git a/src/Core/Event.cc b/src/Core/Event.cc --- a/src/Core/Event.cc +++ b/src/Core/Event.cc @@ -1,114 +1,119 @@ // -*- C++ -*- #include "Rivet/Event.hh" #include "Rivet/Tools/BeamConstraint.hh" #include "Rivet/Projections/Beam.hh" #include "HepMC/GenEvent.h" namespace Rivet { ParticlePair Event::beams() const { return Rivet::beams(*this); } // PdgIdPair Event::beamIds() const { return pids(beams()); } double Event::sqrtS() const { return Rivet::sqrtS(beams()); } double Event::asqrtS() const { return Rivet::asqrtS(beams()); } // Vector3 Event::beamCMSBoost() const { return Rivet::beamCMSBoost(*this); } // LorentzTransform Event::beamCMSTransform() const { return Rivet::beamCMSTransform(*this); } void Event::_init(const GenEvent& ge) { // Use Rivet's preferred units if possible #ifdef HEPMC_HAS_UNITS _genevent.use_units(HepMC::Units::GEV, HepMC::Units::MM); #endif // Use the conventional alignment // _geNormAlignment(); /// @todo Filter the event to remove generator-specific particles: optional /// behaviour? Maybe disableable in an inconvenient way, e.g. with an env /// var, to communicate the appropriate distaste for this sort of truth /// analysis ;-) // Debug printout to check that copying/mangling has worked /// @todo Enable this when HepMC has been fixed to allow printing to a stream like the Rivet logger. //_genevent.print(); } // namespace { // unnamed namespace for hiding // // void _geRot180x(GenEvent& ge) { // /// @todo Use nicer iterators over HepMC particles // for (HepMC::GenEvent::particle_iterator ip = ge.particles_begin(); ip != ge.particles_end(); ++ip) { // const HepMC::FourVector& mom = (*ip)->momentum(); // (*ip)->set_momentum(HepMC::FourVector(mom.px(), -mom.py(), -mom.pz(), mom.e())); // } // /// @todo Use nicer iterators over HepMC vertices // for (HepMC::GenEvent::vertex_iterator iv = ge.vertices_begin(); iv != ge.vertices_end(); ++iv) { // const HepMC::FourVector& pos = (*iv)->position(); // (*iv)->set_position(HepMC::FourVector(pos.x(), -pos.y(), -pos.z(), pos.t())); // } // } // // } // void Event::_geNormAlignment() { // if (!_genevent.valid_beam_particles()) return; // typedef pair<HepMC::GenParticle*, HepMC::GenParticle*> GPPair; // GPPair bps = _genevent.beam_particles(); // // // Rotate e+- p and ppbar to put p along +z // /// @todo Is there an e+ e- convention for longitudinal boosting, e.g. at B-factories? Different from LEP? // // if (compatible(beamids, make_pdgid_pair(ELECTRON, PROTON)) || // // compatible(beamids, make_pdgid_pair(POSITRON, PROTON)) || // // compatible(beamids, make_pdgid_pair(ANTIPROTON, PROTON)) ) { // // Log::getLog("Rivet.Event") << Log::TRACE << "May need to rotate event..." << endl; // bool rot = false; // const HepMC::GenParticle* plusgp = 0; // if (bps.first->pdg_id() != PID::PROTON || bps.second->pdg_id() != PID::PROTON) { // if (bps.first->pdg_id() == PID::PROTON) { // plusgp = bps.first; // } else if (bps.second->pdg_id() == PID::PROTON) { // plusgp = bps.second; // } // if (plusgp && plusgp->momentum().pz() < 0) { // rot = true; // } // } // // // Do the rotation // if (rot) { // if (Log::getLog("Rivet.Event").isActive(Log::TRACE)) { // Log::getLog("Rivet.Event") << Log::TRACE << "Rotating event\n" // << "Before rotation: " // << bps.first->pdg_id() << "@pz=" << bps.first->momentum().pz()/GeV << ", " // << bps.second->pdg_id() << "@pz=" << bps.second->momentum().pz()/GeV << endl; // } // _geRot180x(_genevent); // } // } const Particles& Event::allParticles() const { if (_particles.empty()) { //< assume that empty means no attempt yet made for (const GenParticle* gp : particles(genEvent())) { _particles += Particle(gp); } } return _particles; } - double Event::weight() const { - return (!_genevent.weights().empty()) ? _genevent.weights()[0] : 1.0; + vector<double> Event::weights() const { + vector<double> v; + + for (unsigned int iw = 0; iw < _genevent.weights().size(); iw++) + v.push_back(_genevent.weights()[iw]); + + return v; } } diff --git a/src/Tools/RivetYODA.cc b/src/Tools/RivetYODA.cc --- a/src/Tools/RivetYODA.cc +++ b/src/Tools/RivetYODA.cc @@ -1,115 +1,115 @@ #include "Rivet/Config/RivetCommon.hh" #include "Rivet/Tools/RivetYODA.hh" #include "Rivet/Tools/RivetPaths.hh" #include "YODA/ReaderYODA.h" #include "YODA/ReaderAIDA.h" using namespace std; namespace Rivet { string getDatafilePath(const string& papername) { /// Try to find YODA otherwise fall back to try AIDA const string path1 = findAnalysisRefFile(papername + ".yoda"); if (!path1.empty()) return path1; const string path2 = findAnalysisRefFile(papername + ".aida"); if (!path2.empty()) return path2; throw Rivet::Error("Couldn't find ref data file '" + papername + ".yoda/aida" + " in $RIVET_REF_PATH, '" + getRivetDataPath() + "', or '.'"); } - map<string, AnalysisObjectPtr> getRefData(const string& papername) { + map<string, YODA::AnalysisObjectPtr> getRefData(const string& papername) { const string datafile = getDatafilePath(papername); // Make an appropriate data file reader and read the data objects /// @todo Remove AIDA support some day... YODA::Reader& reader = (datafile.find(".yoda") != string::npos) ? \ YODA::ReaderYODA::create() : YODA::ReaderAIDA::create(); vector<YODA::AnalysisObject *> aovec; reader.read(datafile, aovec); // Return value, to be populated - map<string, AnalysisObjectPtr> rtn; + map<string, YODA::AnalysisObjectPtr> rtn; foreach ( YODA::AnalysisObject* ao, aovec ) { - AnalysisObjectPtr refdata(ao); + YODA::AnalysisObjectPtr refdata(ao); if (!refdata) continue; const string plotpath = refdata->path(); // Split path at "/" and only return the last field, i.e. the histogram ID const size_t slashpos = plotpath.rfind("/"); const string plotname = (slashpos+1 < plotpath.size()) ? plotpath.substr(slashpos+1) : ""; rtn[plotname] = refdata; } return rtn; } void Histo1DPtr::pushToPersistent(const vector<vector<double> >& weight) { // loop over event weights for (size_t m = 0; m < _persistent.size(); ++m) { // this is the initial event---it always exists - YODA::Histo1DPtr sum = boost::make_shared<YODA::Histo1D>(_evgroup[0]->clone()); + YODA::Histo1DPtr sum = make_shared<YODA::Histo1D>(_evgroup[0]->clone()); sum->scaleW( weight[0][m] ); // loop over additional subevents (maybe there aren't any) // note loop starts at 1 for (size_t n = 1; n < _evgroup.size(); ++n) { - YODA::Histo1DPtr tmp = boost::make_shared<YODA::Histo1D>(_evgroup[n]->clone()); + YODA::Histo1DPtr tmp = make_shared<YODA::Histo1D>(_evgroup[n]->clone()); tmp->scaleW( weight[n][m] ); *sum += *tmp; } // sum typically only has one bin filled // do we really need to fill bin.size() times? bool filled_something = false; /// @todo /// this is not correct! /// we need to trick the histogram into thinking it was /// filled exactly onen time, even if subevents fall into /// different bins of the histogram /// how foreach(const YODA::HistoBin1D& b, sum->bins()) { if ( b.effNumEntries() != 0 && b.sumW() != 0 ) { // @todo number of fills will be wrong // needs to be xMid. xMean is not valid if bin contains neg.weights _persistent[m]->fill(b.xMid(), b.sumW()); filled_something = true; } } // @todo // overflow } _evgroup.clear(); _active.reset(); } void Histo2DPtr::pushToPersistent(const vector<vector<double> >& weight) { /// @todo return; } void Profile1DPtr::pushToPersistent(const vector<vector<double> >& weight) { /// @todo return; } void Profile2DPtr::pushToPersistent(const vector<vector<double> >& weight) { /// @todo return; } void Counter::pushToPersistent(const vector<vector<double> >& weight) { /// @todo return; } }