diff --git a/include/Rivet/Analysis.hh b/include/Rivet/Analysis.hh --- a/include/Rivet/Analysis.hh +++ b/include/Rivet/Analysis.hh @@ -1,1239 +1,1244 @@ // -*- 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/Cuts.hh" #include "Rivet/Tools/Logging.hh" #include "Rivet/Tools/ParticleUtils.hh" #include "Rivet/Tools/BinnedHistogram.hh" #include "Rivet/Tools/RivetMT2.hh" #include "Rivet/Tools/RivetYODA.hh" #include "Rivet/Tools/Percentile.hh" #include "Rivet/Projections/CentralityProjection.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. If options has been set for this instance, a /// corresponding string is appended at the end. virtual std::string name() const { return ( (info().name().empty()) ? _defaultname : info().name() ) + _optstring; } // get name of reference data file, which could be different from plugin name virtual std::string getRefDataName() const { return (info().getRefDataName().empty()) ? _defaultname : info().getRefDataName(); } // set name of reference data file, which could be different from plugin name virtual void setRefDataName(const std::string& ref_data="") { info().setRefDataName(!ref_data.empty() ? ref_data : 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 \' format. The first /// name in the list should be the primary contact person. virtual std::vector 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(); } /// The luminosity in inverse femtobarn virtual std::string luminosityfb() const { return info().luminosityfb(); } /// Journal, and preprint references. virtual std::vector 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 todos() const { return info().todos(); } /// Return the allowed pairs of incoming beams required by this analysis. virtual const std::vector& requiredBeams() const { return info().beams(); } /// Declare the allowed pairs of incoming beams required by this analysis. virtual Analysis& setRequiredBeams(const std::vector& requiredBeams) { info().setBeams(requiredBeams); return *this; } /// Sets of valid beam energy pairs, in GeV virtual const std::vector >& requiredEnergies() const { return info().energies(); } /// Get vector of analysis keywords virtual const std::vector & keywords() const { return info().keywords(); } /// Declare the list of valid beam energy pairs, in GeV virtual Analysis& setRequiredEnergies(const std::vector >& 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; /// Check if we are running rivet-merge. bool merging() const { return sqrtS() <= 0.0; } //@} /// @name Analysis / beam compatibility testing /// @todo Replace with beamsCompatible() with no args (calling beams() function internally) /// @todo Add beamsMatch() methods with same (shared-code?) tolerance as in beamsCompatible() //@{ /// 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& energies) const; //@} /// Set the cross section from the generator Analysis& setCrossSection(double xs); //, double xserr=0.0); /// 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. double crossSectionPerEvent() const; /// @brief Get the number of events seen (via the analysis handler). /// /// @note Use in the finalize phase only. size_t numEvents() const; /// @brief Get the sum of event weights seen (via the analysis handler). /// /// @note Use in the finalize phase only. double sumW() const; /// Alias double sumOfWeights() const { return sumW(); } /// @brief Get the sum of squared event weights seen (via the analysis handler). /// /// @note Use in the finalize phase only. double sumW2() 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 mkAxisCode(unsigned int datasetId, unsigned int xAxisId, unsigned int yAxisId) const; /// Alias /// @deprecated Prefer the "mk" form, consistent with other "making function" names const std::string makeAxisCode(unsigned int datasetId, unsigned int xAxisId, unsigned int yAxisId) const { return mkAxisCode(datasetId, xAxisId, yAxisId); } //@} /// @name Histogram reference data //@{ /// Get reference data for a named histo /// @todo SFINAE to ensure that the type inherits from YODA::AnalysisObject? template 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(*_refdata[hname]); } /// Get reference data for a numbered histo /// @todo SFINAE to ensure that the type inherits from YODA::AnalysisObject? template 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& binedges, 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::initializer_list& 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 /// vectors of bin edges @a xbinedges and @a ybinedges. Histo2DPtr bookHisto2D(const std::string& name, const std::vector& xbinedges, const std::vector& ybinedges, 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 /// vectors of bin edges @a xbinedges and @a ybinedges. Histo2DPtr bookHisto2D(const std::string& name, const std::initializer_list& xbinedges, const std::initializer_list& 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& binedges, 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::initializer_list& 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& xbinedges, const std::vector& ybinedges, 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::initializer_list& xbinedges, const std::initializer_list& 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& binedges, const std::string& title, const std::string& xtitle, const std::string& ytitle); /// Book a 2-dimensional data point set with x-points from an existing scatter and a new path. Scatter2DPtr bookScatter2D(const Scatter2DPtr scPtr, const std::string& path, const std::string& title = "", const std::string& xtitle = "", const std::string& ytitle = "" ); //@} public: /// @name accessing options for this Analysis instance. //@{ + /// Return the map of all options given to this analysis. + const std::map & options() { + return _options; + } + /// Get an option for this analysis instance as a string. std::string getOption(std::string optname) { if ( _options.find(optname) != _options.end() ) return _options.find(optname)->second; return ""; } /// Get an option for this analysis instance converted to a /// specific type (given by the specified @a def value). template T getOption(std::string optname, T def) { if (_options.find(optname) == _options.end()) return def; std::stringstream ss; ss << _options.find(optname)->second; T ret; ss >> ret; return ret; } //@} /// @brief Book a CentralityProjection /// /// Using a SingleValueProjection, @a proj, giving the value of an /// experimental observable to be used as a centrality estimator, /// book a CentralityProjection based on the experimentally /// measured pecentiles of this observable (as given by the /// reference data for the @a calHistName histogram in the @a /// calAnaName analysis. If a preloaded file with the output of a /// run using the @a calAnaName analysis contains a valid /// generated @a calHistName histogram, it will be used as an /// optional percentile binning. Also if this preloaded file /// contains a histogram with the name @a calHistName with an /// appended "_IMP" This histogram will be used to add an optional /// centrality percentile based on the generated impact /// parameter. If @increasing is true, a low (high) value of @proj /// is assumed to correspond to a more peripheral (central) event. const CentralityProjection& declareCentrality(const SingleValueProjection &proj, string calAnaName, string calHistName, const string projName, bool increasing = false); /// @brief Book a Pecentile wrapper around AnalysisObjects. /// /// Based on a previously registered CentralityProjection named @a /// projName book one AnalysisObject for each @a centralityBin and /// name them according to the corresponding code in the @a ref /// vector. template Percentile bookPercentile(string projName, vector > centralityBins, vector > ref) { typedef typename ReferenceTraits::RefT RefT; Percentile pctl(this, projName); const int nCent = centralityBins.size(); for (int iCent = 0; iCent < nCent; ++iCent) { const string axisCode = makeAxisCode(std::get<0>(ref[iCent]), std::get<1>(ref[iCent]), std::get<2>(ref[iCent])); const RefT & refscatter = refData(axisCode); shared_ptr ao = addOrGetCompatAO(make_shared(refscatter, histoPath(axisCode))); CounterPtr cnt = addOrGetCompatAO(make_shared(histoPath("TMP/COUNTER/" + axisCode))); pctl.add(ao, cnt, centralityBins[iCent]); } return pctl; } /// @brief Book Pecentile wrappers around AnalysisObjects. /// /// Based on a previously registered CentralityProjection named @a /// projName book one (or several) AnalysisObject(s) named /// according to @a ref where the x-axis will be filled according /// to the percentile output(s) of the @projName. template PercentileXaxis bookPercentileXaxis(string projName, tuple ref) { typedef typename ReferenceTraits::RefT RefT; PercentileXaxis pctl(this, projName); const string axisCode = makeAxisCode(std::get<0>(ref), std::get<1>(ref), std::get<2>(ref)); const RefT & refscatter = refData(axisCode); shared_ptr ao = addOrGetCompatAO(make_shared(refscatter, histoPath(axisCode))); pctl.add(proj, ao, make_shared()); return pctl; } /// @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& cnts, double factor) { for (auto& c : cnts) scale(c, factor); } /// @todo YUCK! template void scale(const CounterPtr (&cnts)[array_size], double factor) { // for (size_t i = 0; i < std::extent::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& histos, double norm=1.0, bool includeoverflows=true) { for (auto& h : histos) normalize(h, norm, includeoverflows); } /// @todo YUCK! template 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& histos, double factor) { for (auto& h : histos) scale(h, factor); } /// @todo YUCK! template 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& histos, double norm=1.0, bool includeoverflows=true) { for (auto& h : histos) normalize(h, norm, includeoverflows); } /// @todo YUCK! template 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& histos, double factor) { for (auto& h : histos) scale(h, factor); } /// @todo YUCK! template 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& analysisObjects() const { return _analysisobjects; } protected: /// @name Data object registration, retrieval, and removal //@{ /// Register a data object in the histogram system void addAnalysisObject(AnalysisObjectPtr ao); /// Register a data object in the system and return its pointer, /// or, if an object of the same path is already there, check if it /// is compatible (eg. same type and same binning) and return that /// object instead. Emits a warning if an incompatible object with /// the same name is found and replcaces that with the given data /// object. template std::shared_ptr addOrGetCompatAO(std::shared_ptr aonew) { foreach (const AnalysisObjectPtr& ao, analysisObjects()) { if ( ao->path() == aonew->path() ) { std::shared_ptr aoold = dynamic_pointer_cast(ao); if ( aoold && bookingCompatible(aonew, aoold) ) { MSG_TRACE("Bound pre-existing data object " << aonew->path() << " for " << name()); return aoold; } else { MSG_WARNING("Found incompatible pre-existing data object with same path " << aonew->path() << " for " << name()); } } } MSG_TRACE("Registered " << aonew->annotation("Type") << " " << aonew->path() << " for " << name()); addAnalysisObject(aonew); return aonew; } /// Get a data object from the histogram system template const std::shared_ptr getAnalysisObject(const std::string& name) const { foreach (const AnalysisObjectPtr& ao, analysisObjects()) { if (ao->path() == histoPath(name)) return dynamic_pointer_cast(ao); } throw LookupError("Data object " + histoPath(name) + " not found"); } /// Get a data object from the histogram system (non-const) template std::shared_ptr getAnalysisObject(const std::string& name) { foreach (const AnalysisObjectPtr& ao, analysisObjects()) { if (ao->path() == histoPath(name)) return dynamic_pointer_cast(ao); } throw LookupError("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); /// Get all data object from the AnalysisHandler. vector getAllData(bool includeorphans) const; /// Get a data object from another analysis (e.g. preloaded /// calibration histogram). /// Get a data object from the histogram system (non-const) template std::shared_ptr getAnalysisObject(const std::string & ananame, const std::string& name) { std::string path = "/" + ananame + "/" + name; for ( AnalysisObjectPtr ao : getAllData(true) ) { if ( ao->path() == path ) return dynamic_pointer_cast(ao); } return std::shared_ptr(); } /// Get a named Histo1D object from the histogram system const Histo1DPtr getHisto1D(const std::string& name) const { return getAnalysisObject(name); } /// Get a named Histo1D object from the histogram system (non-const) Histo1DPtr getHisto1D(const std::string& name) { return getAnalysisObject(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(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(makeAxisCode(datasetId, xAxisId, yAxisId)); } /// Get a named Histo2D object from the histogram system const Histo2DPtr getHisto2D(const std::string& name) const { return getAnalysisObject(name); } /// Get a named Histo2D object from the histogram system (non-const) Histo2DPtr getHisto2D(const std::string& name) { return getAnalysisObject(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(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(makeAxisCode(datasetId, xAxisId, yAxisId)); } /// Get a named Profile1D object from the histogram system const Profile1DPtr getProfile1D(const std::string& name) const { return getAnalysisObject(name); } /// Get a named Profile1D object from the histogram system (non-const) Profile1DPtr getProfile1D(const std::string& name) { return getAnalysisObject(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(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(makeAxisCode(datasetId, xAxisId, yAxisId)); } /// Get a named Profile2D object from the histogram system const Profile2DPtr getProfile2D(const std::string& name) const { return getAnalysisObject(name); } /// Get a named Profile2D object from the histogram system (non-const) Profile2DPtr getProfile2D(const std::string& name) { return getAnalysisObject(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(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(makeAxisCode(datasetId, xAxisId, yAxisId)); } /// Get a named Scatter2D object from the histogram system const Scatter2DPtr getScatter2D(const std::string& name) const { return getAnalysisObject(name); } /// Get a named Scatter2D object from the histogram system (non-const) Scatter2DPtr getScatter2D(const std::string& name) { return getAnalysisObject(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(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(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 _info; /// Storage of all plot objects /// @todo Make this a map for fast lookup by path? vector _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 _refdata; - /// Options the (this instance of) the analysis - map _options; + /// Options the (this instance of) the analysis + map _options; /// The string of options. string _optstring; 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 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 plugin_ ## clsname ## ( ## #alias ## ) #define DECLARE_ALIASED_RIVET_PLUGIN(clsname, alias) DECLARE_RIVET_PLUGIN(clsname)( #alias ) /// @def DEFAULT_RIVET_ANALYSIS_CONSTRUCTOR /// Preprocessor define to prettify the manky constructor with name string argument #define DEFAULT_RIVET_ANALYSIS_CONSTRUCTOR(clsname) clsname() : Analysis(# clsname) {} /// @def DEFAULT_RIVET_ANALYSIS_CTOR /// Slight abbreviation for DEFAULT_RIVET_ANALYSIS_CONSTRUCTOR #define DEFAULT_RIVET_ANALYSIS_CTOR(clsname) DEFAULT_RIVET_ANALYSIS_CONSTRUCTOR(clsname) #endif diff --git a/include/Rivet/Math/Vector3.hh b/include/Rivet/Math/Vector3.hh --- a/include/Rivet/Math/Vector3.hh +++ b/include/Rivet/Math/Vector3.hh @@ -1,381 +1,381 @@ #ifndef RIVET_MATH_VECTOR3 #define RIVET_MATH_VECTOR3 #include "Rivet/Math/MathHeader.hh" #include "Rivet/Math/MathUtils.hh" #include "Rivet/Math/VectorN.hh" namespace Rivet { class Vector3; typedef Vector3 ThreeVector; class Matrix3; Vector3 multiply(const double, const Vector3&); Vector3 multiply(const Vector3&, const double); Vector3 add(const Vector3&, const Vector3&); Vector3 operator*(const double, const Vector3&); Vector3 operator*(const Vector3&, const double); Vector3 operator/(const Vector3&, const double); Vector3 operator+(const Vector3&, const Vector3&); Vector3 operator-(const Vector3&, const Vector3&); /// @brief Three-dimensional specialisation of Vector. class Vector3 : public Vector<3> { friend class Matrix3; friend Vector3 multiply(const double, const Vector3&); friend Vector3 multiply(const Vector3&, const double); friend Vector3 add(const Vector3&, const Vector3&); friend Vector3 subtract(const Vector3&, const Vector3&); public: Vector3() : Vector<3>() { } template Vector3(const V3& other) { this->setX(other.x()); this->setY(other.y()); this->setZ(other.z()); } Vector3(const Vector<3>& other) { this->setX(other.get(0)); this->setY(other.get(1)); this->setZ(other.get(2)); } Vector3(double x, double y, double z) { this->setX(x); this->setY(y); this->setZ(z); } ~Vector3() { } public: static Vector3 mkX() { return Vector3(1,0,0); } static Vector3 mkY() { return Vector3(0,1,0); } static Vector3 mkZ() { return Vector3(0,0,1); } public: double x() const { return get(0); } double y() const { return get(1); } double z() const { return get(2); } Vector3& setX(double x) { set(0, x); return *this; } Vector3& setY(double y) { set(1, y); return *this; } Vector3& setZ(double z) { set(2, z); return *this; } /// Dot-product with another vector double dot(const Vector3& v) const { return _vec.dot(v._vec); } /// Cross-product with another vector Vector3 cross(const Vector3& v) const { Vector3 result; result._vec = _vec.cross(v._vec); return result; } /// Angle in radians to another vector double angle(const Vector3& v) const { const double localDotOther = unit().dot(v.unit()); if (localDotOther > 1.0) return 0.0; if (localDotOther < -1.0) return M_PI; return acos(localDotOther); } /// Unit-normalized version of this vector Vector3 unitVec() const { - /// @todo What to do in this situation? - if (isZero()) return *this; - else return *this * 1.0/this->mod(); + double md = mod(); + if ( md <= 0.0 ) return Vector3(); + else return *this * 1.0/md; } /// Synonym for unitVec Vector3 unit() const { return unitVec(); } /// Polar projection of this vector into the x-y plane Vector3 polarVec() const { Vector3 rtn = *this; rtn.setZ(0.); return rtn; } /// Synonym for polarVec Vector3 perpVec() const { return polarVec(); } /// Synonym for polarVec Vector3 rhoVec() const { return polarVec(); } /// Square of the polar radius ( double polarRadius2() const { return x()*x() + y()*y(); } /// Synonym for polarRadius2 double perp2() const { return polarRadius2(); } /// Synonym for polarRadius2 double rho2() const { return polarRadius2(); } /// Polar radius double polarRadius() const { return sqrt(polarRadius2()); } /// Synonym for polarRadius double perp() const { return polarRadius(); } /// Synonym for polarRadius double rho() const { return polarRadius(); } /// Angle subtended by the vector's projection in x-y and the x-axis. double azimuthalAngle(const PhiMapping mapping = ZERO_2PI) const { // If this is a null vector, return zero rather than let atan2 set an error state if (Rivet::isZero(mod2())) return 0.0; // Calculate the arctan and return in the requested range const double value = atan2( y(), x() ); return mapAngle(value, mapping); } /// Synonym for azimuthalAngle. double phi(const PhiMapping mapping = ZERO_2PI) const { return azimuthalAngle(mapping); } /// Angle subtended by the vector and the z-axis. double polarAngle() const { // Get number beween [0,PI] const double polarangle = atan2(polarRadius(), z()); return mapAngle0ToPi(polarangle); } /// Synonym for polarAngle double theta() const { return polarAngle(); } /// Purely geometric approximation to rapidity /// /// Also invariant under z-boosts, equal to y for massless particles. /// /// @note A cut-off is applied such that |eta| < log(2/DBL_EPSILON) double pseudorapidity() const { const double epsilon = DBL_EPSILON; double m = mod(); if ( m == 0.0 ) return 0.0; double pt = max(epsilon*m, perp()); double rap = std::log((m + fabs(z()))/pt); return z() > 0.0 ? rap: -rap; } /// Synonym for pseudorapidity double eta() const { return pseudorapidity(); } /// Convenience shortcut for fabs(eta()) double abseta() const { return fabs(eta()); } public: Vector3& operator*=(const double a) { _vec = multiply(a, *this)._vec; return *this; } Vector3& operator/=(const double a) { _vec = multiply(1.0/a, *this)._vec; return *this; } Vector3& operator+=(const Vector3& v) { _vec = add(*this, v)._vec; return *this; } Vector3& operator-=(const Vector3& v) { _vec = subtract(*this, v)._vec; return *this; } Vector3 operator-() const { Vector3 rtn; rtn._vec = -_vec; return rtn; } }; inline double dot(const Vector3& a, const Vector3& b) { return a.dot(b); } inline Vector3 cross(const Vector3& a, const Vector3& b) { return a.cross(b); } inline Vector3 multiply(const double a, const Vector3& v) { Vector3 result; result._vec = a * v._vec; return result; } inline Vector3 multiply(const Vector3& v, const double a) { return multiply(a, v); } inline Vector3 operator*(const double a, const Vector3& v) { return multiply(a, v); } inline Vector3 operator*(const Vector3& v, const double a) { return multiply(a, v); } inline Vector3 operator/(const Vector3& v, const double a) { return multiply(1.0/a, v); } inline Vector3 add(const Vector3& a, const Vector3& b) { Vector3 result; result._vec = a._vec + b._vec; return result; } inline Vector3 subtract(const Vector3& a, const Vector3& b) { Vector3 result; result._vec = a._vec - b._vec; return result; } inline Vector3 operator+(const Vector3& a, const Vector3& b) { return add(a, b); } inline Vector3 operator-(const Vector3& a, const Vector3& b) { return subtract(a, b); } // More physicsy coordinates etc. /// Angle (in radians) between two 3-vectors. inline double angle(const Vector3& a, const Vector3& b) { return a.angle(b); } ///////////////////////////////////////////////////// /// @name \f$ |\Delta eta| \f$ calculations from 3-vectors //@{ /// Calculate the difference in pseudorapidity between two spatial vectors. inline double deltaEta(const Vector3& a, const Vector3& b) { return deltaEta(a.pseudorapidity(), b.pseudorapidity()); } /// Calculate the difference in pseudorapidity between two spatial vectors. inline double deltaEta(const Vector3& v, double eta2) { return deltaEta(v.pseudorapidity(), eta2); } /// Calculate the difference in pseudorapidity between two spatial vectors. inline double deltaEta(double eta1, const Vector3& v) { return deltaEta(eta1, v.pseudorapidity()); } //@} /// @name \f$ \Delta phi \f$ calculations from 3-vectors //@{ /// Calculate the difference in azimuthal angle between two spatial vectors. inline double deltaPhi(const Vector3& a, const Vector3& b, bool sign=false) { return deltaPhi(a.azimuthalAngle(), b.azimuthalAngle(), sign); } /// Calculate the difference in azimuthal angle between two spatial vectors. inline double deltaPhi(const Vector3& v, double phi2, bool sign=false) { return deltaPhi(v.azimuthalAngle(), phi2, sign); } /// Calculate the difference in azimuthal angle between two spatial vectors. inline double deltaPhi(double phi1, const Vector3& v, bool sign=false) { return deltaPhi(phi1, v.azimuthalAngle(), sign); } //@} /// @name \f$ \Delta R \f$ calculations from 3-vectors //@{ /// Calculate the 2D rapidity-azimuthal ("eta-phi") distance between two spatial vectors. inline double deltaR2(const Vector3& a, const Vector3& b) { return deltaR2(a.pseudorapidity(), a.azimuthalAngle(), b.pseudorapidity(), b.azimuthalAngle()); } /// Calculate the 2D rapidity-azimuthal ("eta-phi") distance between two spatial vectors. inline double deltaR(const Vector3& a, const Vector3& b) { return sqrt(deltaR2(a,b)); } /// Calculate the 2D rapidity-azimuthal ("eta-phi") distance between two spatial vectors. inline double deltaR2(const Vector3& v, double eta2, double phi2) { return deltaR2(v.pseudorapidity(), v.azimuthalAngle(), eta2, phi2); } /// Calculate the 2D rapidity-azimuthal ("eta-phi") distance between two spatial vectors. inline double deltaR(const Vector3& v, double eta2, double phi2) { return sqrt(deltaR2(v, eta2, phi2)); } /// Calculate the 2D rapidity-azimuthal ("eta-phi") distance between two spatial vectors. inline double deltaR2(double eta1, double phi1, const Vector3& v) { return deltaR2(eta1, phi1, v.pseudorapidity(), v.azimuthalAngle()); } /// Calculate the 2D rapidity-azimuthal ("eta-phi") distance between two spatial vectors. inline double deltaR(double eta1, double phi1, const Vector3& v) { return sqrt(deltaR2(eta1, phi1, v)); } //@} /// @name Typedefs of vector types to short names /// @todo Switch canonical and alias names //@{ //typedef Vector3 V3; //< generic typedef Vector3 X3; //< spatial //@} } #endif diff --git a/include/Rivet/Projections/DISKinematics.hh b/include/Rivet/Projections/DISKinematics.hh --- a/include/Rivet/Projections/DISKinematics.hh +++ b/include/Rivet/Projections/DISKinematics.hh @@ -1,124 +1,126 @@ // -*- C++ -*- #ifndef RIVET_DISKinematics_HH #define RIVET_DISKinematics_HH #include "Rivet/Particle.hh" #include "Rivet/Event.hh" #include "Rivet/Projection.hh" #include "Rivet/Projections/DISLepton.hh" #include "Rivet/Projections/Beam.hh" namespace Rivet { /// @brief Get the DIS kinematic variables and relevant boosts for an event. class DISKinematics : public Projection { public: /// The default constructor. - DISKinematics() + DISKinematics(const DISLepton & lepton = DISLepton(), + const std::map & opts = + std::map()) : _theQ2(-1.0), _theW2(-1.0), _theX(-1.0), _theY(-1.0), _theS(-1.0) { setName("DISKinematics"); //addPdgIdPair(ANY, hadid); addProjection(Beam(), "Beam"); - addProjection(DISLepton(), "Lepton"); + addProjection(lepton, "Lepton"); } /// Clone on the heap. DEFAULT_RIVET_PROJ_CLONE(DISKinematics); protected: /// Perform the projection operation on the supplied event. virtual void project(const Event& e); /// Compare with other projections. virtual int compare(const Projection& p) const; public: /// The \f$Q^2\f$. double Q2() const { return _theQ2; } /// The \f$W^2\f$. double W2() const { return _theW2; } /// The Bjorken \f$x\f$. double x() const { return _theX; } /// The inelasticity \f$y\f$ double y() const { return _theY; } /// The centre of mass energy \f$s\f$ double s() const { return _theS; } /// The LorentzRotation needed to boost a particle to the hadronic CM frame. const LorentzTransform& boostHCM() const { return _hcm; } /// The LorentzRotation needed to boost a particle to the hadronic Breit frame. const LorentzTransform& boostBreit() const { return _breit; } /// The incoming hadron beam particle const Particle& beamHadron() const { return _inHadron; } /// The incoming lepton beam particle const Particle& beamLepton() const { return _inLepton; } /// The scattered DIS lepton const Particle& scatteredLepton() const { return _outLepton; } /// @brief 1/-1 multiplier indicating (respectively) whether the event has conventional orientation or not /// /// Conventional DIS orientation has the hadron travelling in the +z direction const int orientation() const { return sign(_inHadron.pz()); } private: /// The \f$Q^2\f$. double _theQ2; /// The \f$W^2\f$. double _theW2; /// The Bjorken \f$x\f$. double _theX; /// The Inelasticity \f$y\f$ double _theY; /// The centre of mass energy \f$s\f$ double _theS; /// Incoming and outgoing DIS particles Particle _inHadron, _inLepton, _outLepton; /// The LorentzRotation needed to boost a particle to the hadronic CM frame. LorentzTransform _hcm; /// The LorentzRotation needed to boost a particle to the hadronic Breit frame. LorentzTransform _breit; }; } #endif diff --git a/include/Rivet/Projections/DISLepton.hh b/include/Rivet/Projections/DISLepton.hh --- a/include/Rivet/Projections/DISLepton.hh +++ b/include/Rivet/Projections/DISLepton.hh @@ -1,69 +1,101 @@ // -*- C++ -*- #ifndef RIVET_DISLepton_HH #define RIVET_DISLepton_HH #include "Rivet/Projections/Beam.hh" #include "Rivet/Projections/PromptFinalState.hh" +#include "Rivet/Projections/HadronicFinalState.hh" +#include "Rivet/Projections/DressedLeptons.hh" #include "Rivet/Particle.hh" #include "Rivet/Event.hh" namespace Rivet { /// @brief Get the incoming and outgoing leptons in a DIS event. class DISLepton : public Projection { public: /// @name Constructors. //@{ - DISLepton(){ + /// Default constructor taking general options. + DISLepton(const std::map & opts = + std::map()): _isolDR(0.0) { setName("DISLepton"); addProjection(Beam(), "Beam"); - addProjection(PromptFinalState(), "FS"); + addProjection(HadronicFinalState(), "IFS"); + + auto isol = opts.find("IsolDR"); + if ( isol != opts.end() ) _isolDR = std::stod(isol->second); + + double dressdr = 0.0; + auto dress = opts.find("DressDR"); + if ( dress != opts.end() ) + dressdr = std::stod(dress->second); + + auto lmode = opts.find("LMODE"); + if ( lmode != opts.end() && lmode->second == "any" ) + addProjection(FinalState(), "LFS"); + else if ( lmode != opts.end() && lmode->second == "dressed" ) + addProjection(DressedLeptons(dressdr), "LFS"); + else + addProjection(PromptFinalState(), "LFS"); } + /// Constructor taking specific arguments + DISLepton(const FinalState & leptoncandidates, + const Beam & beamproj = Beam(), + const FinalState & isolationfs = FinalState(), + double isolationcut = 0.0): _isolDR(isolationcut) { + addProjection(leptoncandidates, "LFS"); + addProjection(isolationfs, "IFS"); + addProjection(beamproj, "Beam"); + } + + + /// Clone on the heap. DEFAULT_RIVET_PROJ_CLONE(DISLepton); //@} protected: /// Perform the projection operation on the supplied event. virtual void project(const Event& e); /// Compare with other projections. virtual int compare(const Projection& p) const; public: /// The incoming lepton const Particle& in() const { return _incoming; } /// The outgoing lepton const Particle& out() const { return _outgoing; } /// Sign of the incoming lepton pz component int pzSign() const { return sign(_incoming.pz()); } private: /// The incoming lepton Particle _incoming; /// The outgoing lepton Particle _outgoing; - // /// The charge sign of the DIS current - // double _charge; + /// If larger than zerp an isolation cut around the lepton is required. + double _isolDR; }; } #endif diff --git a/src/Projections/DISLepton.cc b/src/Projections/DISLepton.cc --- a/src/Projections/DISLepton.cc +++ b/src/Projections/DISLepton.cc @@ -1,74 +1,69 @@ // -*- C++ -*- #include "Rivet/Projections/DISLepton.hh" namespace Rivet { int DISLepton::compare(const Projection& p) const { const DISLepton& other = pcast(p); - return mkNamedPCmp(other, "Beam") || mkNamedPCmp(other, "FS"); + return mkNamedPCmp(other, "Beam") || mkNamedPCmp(other, "LFS") || + mkNamedPCmp(other, "IFS"); } void DISLepton::project(const Event& e) { // Find incoming lepton beam const ParticlePair& inc = applyProjection(e, "Beam").beams(); bool firstIsLepton = PID::isLepton(inc.first.pid()); bool secondIsLepton = PID::isLepton(inc.second.pid()); if (firstIsLepton && !secondIsLepton) { _incoming = inc.first; } else if (!firstIsLepton && secondIsLepton) { _incoming = inc.second; } else { throw Error("DISLepton could not find the correct beam"); } - // // Find outgoing scattered lepton via HepMC graph - // /// @todo Evidence that this doesn't work with Sherpa... FIX - // const GenParticle* current_l = _incoming.genParticle(); - // bool found_next_vertex = true; - // while (found_next_vertex) { - // found_next_vertex = false; - // if (!current_l->end_vertex()) break; - // // Get lists of outgoing particles consistent with a neutral (gamma/Z) or charged (W) DIS current - // /// @todo Avoid loops - // vector out_n, out_c; - // for (const GenParticle* pp : particles_out(current_l, HepMC::children)) { - // if (current_l->pdg_id() == pp->pdg_id()) out_n.push_back(pp); - // if (std::abs(std::abs(current_l->pdg_id()) - std::abs(pp->pdg_id())) == 1) out_c.push_back(pp); - // } - // if (out_n.empty() && out_c.empty()) { - // MSG_WARNING("No lepton in the new vertex"); - // break; - // } - // if (out_c.size() + out_n.size() > 1) { - // MSG_WARNING("More than one lepton in the new vertex"); - // break; - // } - // current_l = out_c.empty() ? out_n.front() : out_c.front(); - // found_next_vertex = true; - // } - // if (current_l != nullptr) { - // _outgoing = Particle(current_l); - // MSG_DEBUG("Found DIS lepton from event-record structure"); - // return; - // } + // If no graph-connected scattered lepton, use the hardest + // (preferably same-flavour) prompt FS lepton in the event. - // If no graph-connected scattered lepton, use the hardest (preferably same-flavour) prompt FS lepton in the event - /// @todo Specify the charged or neutral current being searched for in the DISLepton constructor/API, and remove the guesswork - const Particles fsleptons = applyProjection(e, "FS").particles(isLepton, cmpMomByE); - const Particles sfleptons = filter_select(fsleptons, Cuts::pid == _incoming.pid()); - MSG_DEBUG("SF leptons = " << sfleptons.size() << ", all leptons = " << fsleptons.size()); - if (!sfleptons.empty()) { + const Particles fsleptons = + applyProjection(e, "LFS").particles(isLepton, cmpMomByE); + Particles sfleptons = + filter_select(fsleptons, Cuts::pid == _incoming.pid()); + MSG_DEBUG("SF leptons = " << sfleptons.size() << ", all leptons = " + << fsleptons.size()); + if ( sfleptons.empty() ) sfleptons = fsleptons; + + if ( _isolDR > 0.0 ) { + const Particles & other = + applyProjection(e, "IFS").particles(); + while (!sfleptons.empty()) { + bool skip = false; + Particle testlepton = sfleptons.front(); + for ( auto p: other ) { + if ( skip ) break; + if ( deltaR(p, testlepton) < _isolDR ) skip = true; + for ( auto c : testlepton.constituents() ) { + if ( c.genParticle() == p.genParticle() ) { + skip = false; + break; + } + } + } + if ( !skip ) break; + sfleptons.erase(sfleptons.begin()); + } + } + + if ( !sfleptons.empty() ) { _outgoing = sfleptons.front(); - } else if (!fsleptons.empty()) { - _outgoing = fsleptons.front(); } else { throw Error("Could not find the scattered lepton"); } } }