diff --git a/analyses/pluginRHIC/STAR_2008_S7869363.cc b/analyses/pluginRHIC/STAR_2008_S7869363.cc --- a/analyses/pluginRHIC/STAR_2008_S7869363.cc +++ b/analyses/pluginRHIC/STAR_2008_S7869363.cc @@ -1,173 +1,173 @@ // -*- C++ -*- #include "Rivet/Analysis.hh" #include "Rivet/Projections/ChargedFinalState.hh" #include "Rivet/Projections/LossyFinalState.hh" namespace Rivet { /// @todo Replace with SmearedParticles class STARRandomFilter { public: STARRandomFilter() { } // Return true to throw away a particle bool operator()(const Particle& p) { /// @todo Use a better RNG? size_t idx = int(floor(p.pT()/MeV/50)); if (idx > 11) idx = 11; return (rand()/static_cast(RAND_MAX) > _trkeff[idx]); } - int compare(const STARRandomFilter& other) const { - return true; + CmpState compare(const STARRandomFilter& other) const { + return CmpState::GT; // @todo really? } private: const static double _trkeff[12]; }; // Here we have the track reconstruction efficiencies for tracks with pT from 0 to 600 MeV // in steps of 50 MeV. The efficiency is assumed to be 0.88 for pT >= 600 MeV const double STARRandomFilter::_trkeff[12] = {0,0,0.38,0.72,0.78,0.81,0.82,0.84,0.85,0.86,0.87,0.88}; class STAR_2008_S7869363 : public Analysis { public: /// @name Constructors etc. //@{ /// Constructor STAR_2008_S7869363() : Analysis("STAR_2008_S7869363") { } //@} public: /// @name Analysis methods //@{ /// Book histograms and initialise projections before the run void init() { const ChargedFinalState cfs(-0.5, 0.5, 0.2*GeV); const LossyFinalState lfs(cfs, STARRandomFilter()); declare(lfs, "FS"); book(_h_dNch ,1, 1, 1); book(_h_dpT_Pi ,2, 1, 1); book(_h_dpT_Piplus ,2, 1, 2); book(_h_dpT_Kaon ,2, 1, 3); book(_h_dpT_Kaonplus ,2, 1, 4); book(_h_dpT_AntiProton ,2, 1, 5); book(_h_dpT_Proton ,2, 1, 6); // book(nCutsPassed, "nCutsPassed"); // book(nPi, "nPi"); // book(nPiPlus, "nPiPlus"); // book(nKaon, "nKaon"); // book(nKaonPlus, "nKaonPlus"); // book(nProton, "nProton"); // book(nAntiProton, "nAntiProton"); } /// Perform the per-event analysis void analyze(const Event& event) { const FinalState& charged = apply(event, "FS"); // Vertex reconstruction efficiencies as a function of charged multiplicity. // For events with more than 23 reconstructed tracks the efficiency is 100%. double vtxeffs[24] = { 0.000000,0.512667,0.739365,0.847131,0.906946,0.940922,0.959328,0.96997, 0.975838,0.984432,0.988311,0.990327,0.990758,0.995767,0.99412,0.992271, 0.996631,0.994802,0.99635,0.997384,0.998986,0.996441,0.994513,1.000000 }; double vtxeff = 1.0; if (charged.particles().size() < 24) { vtxeff = vtxeffs[charged.particles().size()]; } const double weight = vtxeff; for (const Particle& p : charged.particles()) { double pT = p.pT()/GeV; double y = p.rapidity(); if (fabs(y) < 0.1) { // nCutsPassed->fill(weight); const PdgId id = p.pid(); switch (id) { case -211: _h_dpT_Pi->fill(pT, weight/(TWOPI*pT*0.2)); // nPi->fill(weight); break; case 211: _h_dpT_Piplus->fill(pT, weight/(TWOPI*pT*0.2)); // nPiPlus->fill(weight); break; case -321: _h_dpT_Kaon->fill(pT, weight/(TWOPI*pT*0.2)); // nKaon->fill(weight); break; case 321: _h_dpT_Kaonplus->fill(pT, weight/(TWOPI*pT*0.2)); // nKaonPlus->fill(weight); break; case -2212: _h_dpT_AntiProton->fill(pT, weight/(TWOPI*pT*0.2)); // nAntiProton->fill(weight); break; case 2212: _h_dpT_Proton->fill(pT, weight/(TWOPI*pT*0.2)); // nProton->fill(weight); break; } } else { continue; } } _h_dNch->fill(charged.particles().size(), weight); } /// Normalise histograms etc., after the run void finalize() { //double nTot = nPi + nPiPlus + nKaon + nKaonPlus + nProton + nAntiProton; normalize(_h_dNch); /// @todo Norm to data! normalize(_h_dpT_Pi , 0.389825 ); normalize(_h_dpT_Piplus , 0.396025 ); normalize(_h_dpT_Kaon , 0.03897 ); normalize(_h_dpT_Kaonplus , 0.04046 ); normalize(_h_dpT_AntiProton, 0.0187255); normalize(_h_dpT_Proton , 0.016511 ); } private: Histo1DPtr _h_dNch; Histo1DPtr _h_dpT_Pi, _h_dpT_Piplus; Histo1DPtr _h_dpT_Kaon, _h_dpT_Kaonplus; Histo1DPtr _h_dpT_AntiProton, _h_dpT_Proton; Profile1DPtr _h_pT_vs_Nch; //CounterPtr nCutsPassed, nPi, nPiPlus, nKaon, nKaonPlus, nProton, nAntiProton; }; // The hook for the plugin system DECLARE_RIVET_PLUGIN(STAR_2008_S7869363); } diff --git a/include/Rivet/Jet.hh b/include/Rivet/Jet.hh --- a/include/Rivet/Jet.hh +++ b/include/Rivet/Jet.hh @@ -1,265 +1,234 @@ // -*- C++ -*- #ifndef RIVET_Jet_HH #define RIVET_Jet_HH #include "Rivet/Config/RivetCommon.hh" #include "Rivet/Jet.fhh" #include "Rivet/Particle.hh" #include "Rivet/Tools/Cuts.hh" #include "Rivet/Tools/Utils.hh" #include "Rivet/Tools/RivetFastJet.hh" #include "Rivet/Math/LorentzTrans.hh" #include namespace Rivet { /// @brief Representation of a clustered jet of particles. class Jet : public ParticleBase { public: /// @name Constructors //@{ /// Constructor from a FastJet PseudoJet, with optional full particle constituents information. Jet(const fastjet::PseudoJet& pj, const Particles& particles=Particles(), const Particles& tags=Particles()) { setState(pj, particles, tags); } /// Set the jet data, with optional full particle information. Jet(const FourMomentum& pjet, const Particles& particles=Particles(), const Particles& tags=Particles()) { setState(pjet, particles, tags); } /// Default constructor -- only for STL storability Jet() { clear(); } //@} /// @name Access jet constituents //@{ /// Number of particles in this jet. size_t size() const { return _particles.size(); } /// Get the particles in this jet. Particles& particles() { return _particles; } /// Get the particles in this jet (const version) const Particles& particles() const { return _particles; } /// Get the particles in this jet which pass a cut (const) const Particles particles(const Cut& c) const { return filter_select(_particles, c); } /// Get the particles in this jet which pass a filtering functor (const) const Particles particles(const ParticleSelector& s) const { return filter_select(_particles, s); } /// Get the particles in this jet (FastJet-like alias) Particles& constituents() { return particles(); } /// Get the particles in this jet (FastJet-like alias, const version) const Particles& constituents() const { return particles(); } /// Get the particles in this jet which pass a cut (FastJet-like alias, const) const Particles constituents(const Cut& c) const { return particles(c); } /// Get the particles in this jet which pass a filtering functor (FastJet-like alias, const) const Particles constituents(const ParticleSelector& s) const { return particles(s); } /// Check whether this jet contains a particular particle. bool containsParticle(const Particle& particle) const; /// Nicer alias for containsParticleId bool containsPID(const Particle& particle) const { return containsParticle(particle); } /// Check whether this jet contains a certain particle type. bool containsParticleId(PdgId pid) const; /// Nicer alias for containsParticleId bool containsPID(PdgId pid) const { return containsParticleId(pid); } /// Check whether this jet contains at least one of certain particle types. bool containsParticleId(const vector& pids) const; /// Nicer alias for containsParticleId bool containsPID(const vector& pids) const { return containsParticleId(pids); } //@} /// @name Tagging /// /// @note General sources of tag particles are planned. The default jet finding /// adds b-hadron, c-hadron, and tau tags by ghost association. //@{ /// @brief Particles which have been tag-matched to this jet Particles& tags() { return _tags; } /// @brief Particles which have been tag-matched to this jet (const version) const Particles& tags() const { return _tags; } /// @brief Particles which have been tag-matched to this jet _and_ pass a selector function /// /// @note Note the less efficient return by value, due to the filtering. Particles tags(const ParticleSelector& f) const { return filter_select(tags(), f); } /// @brief Particles which have been tag-matched to this jet _and_ pass a Cut /// /// @note Note the less efficient return by value, due to the cut-pass filtering. Particles tags(const Cut& c) const; /// @brief b particles which have been tag-matched to this jet (and pass an optional Cut) /// /// The default jet finding adds b-hadron tags by ghost association. Particles bTags(const Cut& c=Cuts::open()) const; /// @brief b particles which have been tag-matched to this jet _and_ pass a selector function Particles bTags(const ParticleSelector& f) const { return filter_select(bTags(), f); } /// Does this jet have at least one b-tag (that passes an optional Cut)? bool bTagged(const Cut& c=Cuts::open()) const { return !bTags(c).empty(); } /// Does this jet have at least one b-tag (that passes the supplied selector function)? bool bTagged(const ParticleSelector& f) const { return !bTags(f).empty(); } /// @brief c (and not b) particles which have been tag-matched to this jet (and pass an optional Cut) /// /// The default jet finding adds c-hadron tags by ghost association. Particles cTags(const Cut& c=Cuts::open()) const; /// @brief c (and not b) particles which have been tag-matched to this jet and pass a selector function Particles cTags(const ParticleSelector& f) const { return filter_select(cTags(), f); } /// Does this jet have at least one c-tag (that passes an optional Cut)? bool cTagged(const Cut& c=Cuts::open()) const { return !cTags(c).empty(); } /// Does this jet have at least one c-tag (that passes the supplied selector function)? bool cTagged(const ParticleSelector& f) const { return !cTags(f).empty(); } /// @brief Tau particles which have been tag-matched to this jet (and pass an optional Cut) /// /// The default jet finding adds tau tags by ghost association. Particles tauTags(const Cut& c=Cuts::open()) const; /// @brief Tau particles which have been tag-matched to this jet and pass a selector function Particles tauTags(const ParticleSelector& f) const { return filter_select(tauTags(), f); } /// Does this jet have at least one tau-tag (that passes an optional Cut)? bool tauTagged(const Cut& c=Cuts::open()) const { return !tauTags(c).empty(); } /// Does this jet have at least one tau-tag (that passes the supplied selector function)? bool tauTagged(const ParticleSelector& f) const { return !tauTags(f).empty(); } - - /// @brief Check whether this jet contains a bottom-flavoured hadron. - /// - /// @deprecated The bTags() or bTagged() function is probably what you want - /// for tagging. This one ignores the tags() list and draws conclusions - /// based directly on the jet constituents; the other gives a much better match - /// to typical experimental methods. - /// - /// @note The decision is made by first trying to find a bottom-flavoured particle - /// in the particles list. Most likely this will fail unless bottom hadrons - /// are set stable. If @a include_decay_products is true (the default), a - /// fallback is attempted, using the post-hadronization ancestor history of - /// all constituents. - DEPRECATED("Prefer the bTags() or bTagged() function") - bool containsBottom(bool include_decay_products=true) const; - - /// @brief Check whether this jet contains a charm-flavoured hadron. - /// - /// @deprecated The cTags() or cTagged() function is probably what you want - /// for tagging. This one ignores the tags() list and draws conclusions - /// based directly on the jet constituents; the other gives a much better match - /// to typical experimental methods. - /// - /// @note The decision is made by first trying to find a charm-flavoured particle - /// in the particles list. Most likely this will fail unless charmed hadrons - /// are set stable. If @a include_decay_products is true (the default), a - /// fallback is attempted, using the post-hadronization ancestor history of - /// all constituents. - DEPRECATED("Prefer the cTags() or cTagged() function") - bool containsCharm(bool include_decay_products=true) const; - //@} /// @name Effective jet 4-vector properties //@{ /// Get equivalent single momentum four-vector. const FourMomentum& momentum() const { return _momentum; } /// Apply an active Lorentz transform to this jet /// @note The Rivet jet momentum, constituent particles, and tag particles will be modified. /// @warning The FastJet cluster sequence and pseudojets will not be modified: don't use them after transformation! Jet& transformBy(const LorentzTransform& lt); /// Get the total energy of this jet. double totalEnergy() const { return momentum().E(); } /// Get the energy carried in this jet by neutral particles. double neutralEnergy() const; /// Get the energy carried in this jet by hadrons. double hadronicEnergy() const; //@} /// @name Interaction with FastJet //@{ /// Access the internal FastJet3 PseudoJet (as a const reference) const fastjet::PseudoJet& pseudojet() const { return _pseudojet; } /// Cast operator to FastJet3 PseudoJet (as a const reference) operator const fastjet::PseudoJet& () const { return pseudojet(); } //@} /// @name Set the jet constituents and properties //@{ /// @brief Set the jet data from a FastJet PseudoJet, with optional particle constituents and tags lists. /// /// @note The particles() list will be extracted from PseudoJet constituents /// by default, making use of an attached user info if one is found. Jet& setState(const fastjet::PseudoJet& pj, const Particles& particles=Particles(), const Particles& tags=Particles()); /// Set all the jet data, with optional full particle constituent and tag information. Jet& setState(const FourMomentum& mom, const Particles& particles, const Particles& tags=Particles()); /// @brief Set the particles collection with full particle information. /// /// If set, this overrides particle info extracted from the PseudoJet Jet& setParticles(const Particles& particles); Jet& setConstituents(const Particles& particles) { return setParticles(particles); } /// Reset this jet as empty. Jet& clear(); //@} private: /// FJ3 PseudoJet member to unify PseudoJet and Jet fastjet::PseudoJet _pseudojet; /// Full constituent particle information. (Filled from PseudoJet if possible.) /// @todo Make these mutable or similar? Add a flag to force a cache rebuild? Particles _particles; /// Particles used to tag this jet (can be anything, but c and b hadrons are the most common) Particles _tags; /// Effective jet 4-vector (just for caching) mutable FourMomentum _momentum; }; /// @name String representation and streaming support //@{ /// Allow a Jet to be passed to an ostream. std::ostream& operator << (std::ostream& os, const Jet& j); //@} } #include "Rivet/Tools/JetUtils.hh" #endif diff --git a/include/Rivet/Particle.hh b/include/Rivet/Particle.hh --- a/include/Rivet/Particle.hh +++ b/include/Rivet/Particle.hh @@ -1,709 +1,707 @@ // -*- C++ -*- #ifndef RIVET_Particle_HH #define RIVET_Particle_HH #include "Rivet/Particle.fhh" #include "Rivet/ParticleBase.hh" #include "Rivet/Config/RivetCommon.hh" #include "Rivet/Tools/Cuts.hh" #include "Rivet/Tools/Utils.hh" #include "Rivet/Math/LorentzTrans.hh" // NOTE: Rivet/Tools/ParticleUtils.hh included at the end #include "fastjet/PseudoJet.hh" namespace Rivet { /// Particle representation, either from a HepMC::GenEvent or reconstructed. class Particle : public ParticleBase { public: /// @name Constructors //@{ /// Default constructor. /// @note A particle without info is useless. This only exists to keep STL containers happy. Particle() : ParticleBase(), _original(nullptr), _id(PID::ANY) { } /// Constructor without GenParticle. Particle(PdgId pid, const FourMomentum& mom, const FourVector& pos=FourVector()) : ParticleBase(), _original(nullptr), _id(pid), _momentum(mom), _origin(pos) { } /// Constructor from a HepMC GenParticle pointer. Particle(const GenParticle* gp) : ParticleBase(), _original(gp), _id(gp->pdg_id()), _momentum(gp->momentum()) { const GenVertex* vprod = gp->production_vertex(); if (vprod != nullptr) { setOrigin(vprod->position().t(), vprod->position().x(), vprod->position().y(), vprod->position().z()); } } /// Constructor from a HepMC GenParticle. Particle(const GenParticle& gp) : ParticleBase(), _original(&gp), _id(gp.pdg_id()), _momentum(gp.momentum()) { const GenVertex* vprod = gp.production_vertex(); if (vprod != nullptr) { setOrigin(vprod->position().t(), vprod->position().x(), vprod->position().y(), vprod->position().z()); } } //@} /// @name Kinematic properties //@{ /// The momentum. const FourMomentum& momentum() const { return _momentum; } /// Set the momentum. Particle& setMomentum(const FourMomentum& momentum) { _momentum = momentum; return *this; } /// Set the momentum via components. Particle& setMomentum(double E, double px, double py, double pz) { _momentum = FourMomentum(E, px, py, pz); return *this; } /// Apply an active Lorentz transform to this particle Particle& transformBy(const LorentzTransform& lt); //@ /// @name Positional properties //@{ /// The origin position. const FourVector& origin() const { return _origin; } /// Set the origin position. Particle& setOrigin(const FourVector& position) { _origin = position; return *this; } /// Set the origin position via components. Particle& setOrigin(double t, double x, double y, double z) { _origin = FourMomentum(t, x, y, z); return *this; } //@} /// @name Other representations and implicit casts to momentum-like objects //@{ /// Converter to FastJet3 PseudoJet virtual fastjet::PseudoJet pseudojet() const { return fastjet::PseudoJet(mom().px(), mom().py(), mom().pz(), mom().E()); } /// Cast operator to FastJet3 PseudoJet operator PseudoJet () const { return pseudojet(); } /// Get a const pointer to the original GenParticle const GenParticle* genParticle() const { return _original; } /// Cast operator for conversion to GenParticle* operator const GenParticle* () const { return genParticle(); } //@} /// @name Particle ID code accessors //@{ /// This Particle's PDG ID code. PdgId pid() const { return _id; } /// Absolute value of the PDG ID code. PdgId abspid() const { return std::abs(_id); } /// This Particle's PDG ID code (alias). /// @deprecated Prefer the pid/abspid form PdgId pdgId() const { return _id; } //@} /// @name Charge //@{ /// The charge of this Particle. double charge() const { return PID::charge(pid()); } /// The absolute charge of this Particle. double abscharge() const { return PID::abscharge(pid()); } /// Three times the charge of this Particle (i.e. integer multiple of smallest quark charge). int charge3() const { return PID::charge3(pid()); } /// Alias for charge3 /// @deprecated Use charge3 int threeCharge() const { return PID::threeCharge(pid()); } /// Three times the absolute charge of this Particle (i.e. integer multiple of smallest quark charge). int abscharge3() const { return PID::abscharge3(pid()); } /// Is this Particle charged? bool isCharged() const { return charge3() != 0; } //@} /// @name Particle species //@{ /// Is this a hadron? bool isHadron() const { return PID::isHadron(pid()); } /// Is this a meson? bool isMeson() const { return PID::isMeson(pid()); } /// Is this a baryon? bool isBaryon() const { return PID::isBaryon(pid()); } /// Is this a lepton? bool isLepton() const { return PID::isLepton(pid()); } /// Is this a charged lepton? bool isChargedLepton() const { return PID::isChargedLepton(pid()); } /// Is this a neutrino? bool isNeutrino() const { return PID::isNeutrino(pid()); } /// Does this (hadron) contain a b quark? bool hasBottom() const { return PID::hasBottom(pid()); } /// Does this (hadron) contain a c quark? bool hasCharm() const { return PID::hasCharm(pid()); } // /// Does this (hadron) contain an s quark? // bool hasStrange() const { return PID::hasStrange(pid()); } /// Is this particle potentially visible in a detector? bool isVisible() const; //@} /// @name Constituents (for composite particles) //@{ /// Set direct constituents of this particle virtual void setConstituents(const Particles& cs, bool setmom=false); /// Add a single direct constituent to this particle virtual void addConstituent(const Particle& c, bool addmom=false); /// Add direct constituents to this particle virtual void addConstituents(const Particles& cs, bool addmom=false); /// Determine if this Particle is a composite of other Rivet Particles bool isComposite() const { return !constituents().empty(); } /// @brief Direct constituents of this particle, returned by reference /// /// The returned vector will be empty if this particle is non-composite, /// and its entries may themselves be composites. const Particles& constituents() const { return _constituents; } /// @brief Direct constituents of this particle, sorted by a functor /// @note Returns a copy, thanks to the sorting const Particles constituents(const ParticleSorter& sorter) const { return sortBy(constituents(), sorter); } /// @brief Direct constituents of this particle, filtered by a Cut /// @note Returns a copy, thanks to the filtering const Particles constituents(const Cut& c) const { return filter_select(constituents(), c); } /// @brief Direct constituents of this particle, sorted by a functor /// @note Returns a copy, thanks to the filtering and sorting const Particles constituents(const Cut& c, const ParticleSorter& sorter) const { return sortBy(constituents(c), sorter); } /// @brief Direct constituents of this particle, filtered by a selection functor /// @note Returns a copy, thanks to the filtering const Particles constituents(const ParticleSelector& selector) const { return filter_select(constituents(), selector); } /// @brief Direct constituents of this particle, filtered and sorted by functors /// @note Returns a copy, thanks to the filtering and sorting const Particles constituents(const ParticleSelector& selector, const ParticleSorter& sorter) const { return sortBy(constituents(selector), sorter); } /// @brief Fundamental constituents of this particle /// @note Returns {{*this}} if this particle is non-composite. Particles rawConstituents() const; /// @brief Fundamental constituents of this particle, sorted by a functor /// @note Returns a copy, thanks to the sorting const Particles rawConstituents(const ParticleSorter& sorter) const { return sortBy(rawConstituents(), sorter); } /// @brief Fundamental constituents of this particle, filtered by a Cut /// @note Returns a copy, thanks to the filtering const Particles rawConstituents(const Cut& c) const { return filter_select(rawConstituents(), c); } /// @brief Fundamental constituents of this particle, sorted by a functor /// @note Returns a copy, thanks to the filtering and sorting const Particles rawConstituents(const Cut& c, const ParticleSorter& sorter) const { return sortBy(rawConstituents(c), sorter); } /// @brief Fundamental constituents of this particle, filtered by a selection functor /// @note Returns a copy, thanks to the filtering const Particles rawConstituents(const ParticleSelector& selector) const { return filter_select(rawConstituents(), selector); } /// @brief Fundamental constituents of this particle, filtered and sorted by functors /// @note Returns a copy, thanks to the filtering and sorting const Particles rawConstituents(const ParticleSelector& selector, const ParticleSorter& sorter) const { return sortBy(rawConstituents(selector), sorter); } //@} /// @name Ancestry (for fundamental particles with a HepMC link) //@{ /// Get a list of the direct parents of the current particle (with optional selection Cut) /// /// @note This is valid in MC, but may not be answerable /// experimentally -- use this function with care when replicating /// experimental analyses! Particles parents(const Cut& c=Cuts::OPEN) const; /// Get a list of the direct parents of the current particle (with selector function) /// /// @note This is valid in MC, but may not be answerable /// experimentally -- use this function with care when replicating /// experimental analyses! Particles parents(const ParticleSelector& f) const { return filter_select(parents(), f); } /// Check whether any particle in the particle's parent list has the requested property /// /// @note This question is valid in MC, but may not be answerable /// experimentally -- use this function with care when replicating /// experimental analyses! bool hasParentWith(const ParticleSelector& f) const { return !parents(f).empty(); } /// Check whether any particle in the particle's parent list has the requested property /// /// @note This question is valid in MC, but may not be answerable /// experimentally -- use this function with care when replicating /// experimental analyses! bool hasParentWith(const Cut& c) const; /// Check whether any particle in the particle's parent list does not have the requested property /// /// @note This question is valid in MC, but may not be answerable /// experimentally -- use this function with care when replicating /// experimental analyses! bool hasParentWithout(const ParticleSelector& f) const { return hasParentWith([&](const Particle& p){ return !f(p); }); } /// Check whether any particle in the particle's parent list does not have the requested property /// /// @note This question is valid in MC, but may not be answerable /// experimentally -- use this function with care when replicating /// experimental analyses! bool hasParentWithout(const Cut& c) const; /// Check whether a given PID is found in the particle's parent list /// /// @note This question is valid in MC, but may not be answerable /// experimentally -- use this function with care when replicating /// experimental analyses! /// /// @deprecated Prefer e.g. hasParentWith(Cut::pid == 123) - //DEPRECATED("Prefer e.g. hasParentWith(Cut::pid == 123)"); bool hasParent(PdgId pid) const; /// Get a list of the ancestors of the current particle (with optional selection Cut) /// /// @note By default only physical ancestors, with status=2, are returned. /// /// @note This is valid in MC, but may not be answerable experimentally -- /// use this function with care when replicating experimental analyses! Particles ancestors(const Cut& c=Cuts::OPEN, bool only_physical=true) const; /// Get a list of the direct parents of the current particle (with selector function) /// /// @note By default only physical ancestors, with status=2, are returned. /// /// @note This is valid in MC, but may not be answerable experimentally -- /// use this function with care when replicating experimental analyses! Particles ancestors(const ParticleSelector& f, bool only_physical=true) const { return filter_select(ancestors(Cuts::OPEN, only_physical), f); } /// Check whether any particle in the particle's ancestor list has the requested property /// /// @note This question is valid in MC, but may not be answerable /// experimentally -- use this function with care when replicating /// experimental analyses! bool hasAncestorWith(const ParticleSelector& f, bool only_physical=true) const { return !ancestors(f, only_physical).empty(); } /// Check whether any particle in the particle's ancestor list has the requested property /// /// @note This question is valid in MC, but may not be answerable /// experimentally -- use this function with care when replicating /// experimental analyses! bool hasAncestorWith(const Cut& c, bool only_physical=true) const; /// Check whether any particle in the particle's ancestor list does not have the requested property /// /// @note This question is valid in MC, but may not be answerable /// experimentally -- use this function with care when replicating /// experimental analyses! bool hasAncestorWithout(const ParticleSelector& f, bool only_physical=true) const { return hasAncestorWith([&](const Particle& p){ return !f(p); }, only_physical); } /// Check whether any particle in the particle's ancestor list does not have the requested property /// /// @note This question is valid in MC, but may not be answerable /// experimentally -- use this function with care when replicating /// experimental analyses! bool hasAncestorWithout(const Cut& c, bool only_physical=true) const; /// Check whether a given PID is found in the particle's ancestor list /// /// @note This question is valid in MC, but may not be answerable /// experimentally -- use this function with care when replicating /// experimental analyses! /// /// @deprecated Prefer hasAncestorWith(Cuts::pid == pid) etc. - //DEPRECATED("Prefer e.g. hasAncestorWith(Cut::pid == 123)"); bool hasAncestor(PdgId pid, bool only_physical=true) const; /// @brief Determine whether the particle is from a b-hadron decay /// /// @note This question is valid in MC, but may not be perfectly answerable /// experimentally -- use this function with care when replicating /// experimental analyses! bool fromBottom() const; /// @brief Determine whether the particle is from a c-hadron decay /// /// @note If a hadron contains b and c quarks it is considered a bottom /// hadron and NOT a charm hadron. /// /// @note This question is valid in MC, but may not be perfectly answerable /// experimentally -- use this function with care when replicating /// experimental analyses! bool fromCharm() const; // /// @brief Determine whether the particle is from a s-hadron decay // /// // /// @note If a hadron contains b or c quarks as well as strange it is // /// considered a b or c hadron, but NOT a strange hadron. // /// // /// @note This question is valid in MC, but may not be perfectly answerable // /// experimentally -- use this function with care when replicating // /// experimental analyses! // bool fromStrange() const; /// @brief Determine whether the particle is from a hadron decay /// /// @note This question is valid in MC, but may not be perfectly answerable /// experimentally -- use this function with care when replicating /// experimental analyses! bool fromHadron() const; /// @brief Determine whether the particle is from a tau decay /// /// @note This question is valid in MC, but may not be perfectly answerable /// experimentally -- use this function with care when replicating /// experimental analyses! bool fromTau(bool prompt_taus_only=false) const; /// @brief Determine whether the particle is from a prompt tau decay /// /// @note This question is valid in MC, but may not be perfectly answerable /// experimentally -- use this function with care when replicating /// experimental analyses! bool fromPromptTau() const { return fromTau(true); } /// @brief Determine whether the particle is from a tau which decayed hadronically /// /// @note This question is valid in MC, but may not be perfectly answerable /// experimentally -- use this function with care when replicating /// experimental analyses! bool fromHadronicTau(bool prompt_taus_only=false) const; /// @brief Determine whether the particle is from a hadron or tau decay /// /// Specifically, walk up the ancestor chain until a status 2 hadron or /// tau is found, if at all. /// /// @note This question is valid in MC, but may not be perfectly answerable /// experimentally -- use this function with care when replicating /// experimental analyses! /// /// @deprecated Too vague: use fromHadron or fromHadronicTau bool fromDecay() const { return fromHadron() || fromPromptTau(); } /// @brief Shorthand definition of 'promptness' based on set definition flags /// /// A "direct" particle is one directly connected to the hard process. It is a /// preferred alias for "prompt", since it has no confusing implications about /// distinguishability by timing information. /// /// The boolean arguments allow a decay lepton to be considered direct if /// its parent was a "real" direct lepton. /// /// @note This one doesn't make any judgements about final-stateness bool isDirect(bool allow_from_direct_tau=false, bool allow_from_direct_mu=false) const; /// Alias for isDirect bool isPrompt(bool allow_from_prompt_tau=false, bool allow_from_prompt_mu=false) const { return isDirect(allow_from_prompt_tau, allow_from_prompt_mu); } //@} /// @name Decay info //@{ /// Whether this particle is stable according to the generator bool isStable() const; /// @todo isDecayed? How to restrict to physical particles? /// Get a list of the direct descendants from the current particle (with optional selection Cut) Particles children(const Cut& c=Cuts::OPEN) const; /// Get a list of the direct descendants from the current particle (with selector function) Particles children(const ParticleSelector& f) const { return filter_select(children(), f); } /// Check whether any direct child of this particle has the requested property /// /// @note This question is valid in MC, but may not be answerable /// experimentally -- use this function with care when replicating /// experimental analyses! bool hasChildWith(const ParticleSelector& f) const { return !children(f).empty(); } /// Check whether any direct child of this particle has the requested property /// /// @note This question is valid in MC, but may not be answerable /// experimentally -- use this function with care when replicating /// experimental analyses! bool hasChildWith(const Cut& c) const; /// Check whether any direct child of this particle does not have the requested property /// /// @note This question is valid in MC, but may not be answerable /// experimentally -- use this function with care when replicating /// experimental analyses! bool hasChildWithout(const ParticleSelector& f) const { return hasChildWith([&](const Particle& p){ return !f(p); }); } /// Check whether any direct child of this particle does not have the requested property /// /// @note This question is valid in MC, but may not be answerable /// experimentally -- use this function with care when replicating /// experimental analyses! bool hasChildWithout(const Cut& c) const; /// Get a list of all the descendants from the current particle (with optional selection Cut) Particles allDescendants(const Cut& c=Cuts::OPEN, bool remove_duplicates=true) const; /// Get a list of all the descendants from the current particle (with selector function) Particles allDescendants(const ParticleSelector& f, bool remove_duplicates=true) const { return filter_select(allDescendants(Cuts::OPEN, remove_duplicates), f); } /// Check whether any descendant of this particle has the requested property /// /// @note This question is valid in MC, but may not be answerable /// experimentally -- use this function with care when replicating /// experimental analyses! bool hasDescendantWith(const ParticleSelector& f, bool remove_duplicates=true) const { return !allDescendants(f, remove_duplicates).empty(); } /// Check whether any descendant of this particle has the requested property /// /// @note This question is valid in MC, but may not be answerable /// experimentally -- use this function with care when replicating /// experimental analyses! bool hasDescendantWith(const Cut& c, bool remove_duplicates=true) const; /// Check whether any descendant of this particle does not have the requested property /// /// @note This question is valid in MC, but may not be answerable /// experimentally -- use this function with care when replicating /// experimental analyses! bool hasDescendantWithout(const ParticleSelector& f, bool remove_duplicates=true) const { return hasDescendantWith([&](const Particle& p){ return !f(p); }, remove_duplicates); } /// Check whether any descendant of this particle does not have the requested property /// /// @note This question is valid in MC, but may not be answerable /// experimentally -- use this function with care when replicating /// experimental analyses! bool hasDescendantWithout(const Cut& c, bool remove_duplicates=true) const; /// Get a list of all the stable descendants from the current particle (with optional selection Cut) /// /// @todo Use recursion through replica-avoiding MCUtils functions to avoid bookkeeping duplicates /// @todo Insist that the current particle is post-hadronization, otherwise throw an exception? Particles stableDescendants(const Cut& c=Cuts::OPEN) const; /// Get a list of all the stable descendants from the current particle (with selector function) Particles stableDescendants(const ParticleSelector& f) const { return filter_select(stableDescendants(), f); } /// Check whether any stable descendant of this particle has the requested property /// /// @note This question is valid in MC, but may not be answerable /// experimentally -- use this function with care when replicating /// experimental analyses! bool hasStableDescendantWith(const ParticleSelector& f) const { return !stableDescendants(f).empty(); } /// Check whether any stable descendant of this particle has the requested property /// /// @note This question is valid in MC, but may not be answerable /// experimentally -- use this function with care when replicating /// experimental analyses! bool hasStableDescendantWith(const Cut& c) const; /// Check whether any stable descendant of this particle does not have the requested property /// /// @note This question is valid in MC, but may not be answerable /// experimentally -- use this function with care when replicating /// experimental analyses! bool hasStableDescendantWithout(const ParticleSelector& f) const { return hasStableDescendantWith([&](const Particle& p){ return !f(p); }); } /// Check whether any stable descendant of this particle does not have the requested property /// /// @note This question is valid in MC, but may not be answerable /// experimentally -- use this function with care when replicating /// experimental analyses! bool hasStableDescendantWithout(const Cut& c) const; /// Flight length (divide by mm or cm to get the appropriate units) double flightLength() const; //@} /// @name Duplicate testing //@{ /// @brief Determine whether a particle is the first in a decay chain to meet the function requirement inline bool isFirstWith(const ParticleSelector& f) const { if (!f(*this)) return false; //< This doesn't even meet f, let alone being the last to do so if (any(parents(), f)) return false; //< If a direct parent has this property, this isn't the first return true; } /// @brief Determine whether a particle is the first in a decay chain not to meet the function requirement inline bool isFirstWithout(const ParticleSelector& f) const { return isFirstWith([&](const Particle& p){ return !f(p); }); } /// @brief Determine whether a particle is the last in a decay chain to meet the function requirement inline bool isLastWith(const ParticleSelector& f) const { if (!f(*this)) return false; //< This doesn't even meet f, let alone being the last to do so if (any(children(), f)) return false; //< If a child has this property, this isn't the last return true; } /// @brief Determine whether a particle is the last in a decay chain not to meet the function requirement inline bool isLastWithout(const ParticleSelector& f) const { return isLastWith([&](const Particle& p){ return !f(p); }); } //@} protected: /// A pointer to the original GenParticle from which this Particle is projected (may be null) const GenParticle* _original; /// Constituent particles if this is a composite (may be empty) Particles _constituents; /// The PDG ID code for this Particle. PdgId _id; /// The momentum of this particle. FourMomentum _momentum; /// The creation position of this particle. FourVector _origin; }; /// @name String representation and streaming support //@{ /// Allow a Particle to be passed to an ostream. std::ostream& operator << (std::ostream& os, const Particle& p); /// Allow ParticlePair to be passed to an ostream. std::ostream& operator << (std::ostream& os, const ParticlePair& pp); //@} } #include "Rivet/Tools/ParticleUtils.hh" #endif diff --git a/include/Rivet/Projection.hh b/include/Rivet/Projection.hh --- a/include/Rivet/Projection.hh +++ b/include/Rivet/Projection.hh @@ -1,185 +1,185 @@ // -*- C++ -*- #ifndef RIVET_Projection_HH #define RIVET_Projection_HH #include "Rivet/Projection.fhh" #include "Rivet/ProjectionApplier.hh" #include "Rivet/ProjectionHandler.hh" #include "Rivet/Config/RivetCommon.hh" #include "Rivet/Tools/Cuts.hh" // NOTE: Cmp.hh, Event.hh and Particle.hh included at the bottom namespace Rivet { // Forward declaration class Event; /// @brief Base class for all Rivet projections. /// /// Projection is the base class of all Projections to be used by /// Rivet. A Projection object can be assigned to an Event object and /// will then define a processed part of the information available in /// the Event, which then can be used by other Projection objects /// and/or Analysis objects. /// /// The main virtual functions to be overridden by concrete sub-classes /// are project(const Event &) and compare(const Projection &). class Projection : public ProjectionApplier { public: /// Event is a friend. friend class Event; /// The Cmp specialization for Projection is a friend. friend class Cmp; /// @name Standard constructors and destructors. //@{ /// The default constructor. Projection(); /// Clone on the heap. virtual unique_ptr clone() const = 0; /// The destructor. virtual ~Projection(); //@} /// Get the name of the projection. virtual std::string name() const { return _name; } /// @name Projection operation and comparison //@{ /// Take the information available in the Event and make the /// calculations necessary to obtain the projection. Note that this /// function must never be called except inside the /// Event::applyProjection(Projection *) function. virtual void project(const Event& e) = 0; /// This function is used to define a unique ordering between /// different Projection objects of the same class. If this is /// considered to be equivalent to the Projector object, \a p, in the /// argument the function should return 0. If this object should be /// ordered before \a p a negative value should be returned, /// otherwise a positive value should be returned. This function must /// never be called explicitly, but should only be called from the /// operator<(const Projection &). When implementing the function in /// concrete sub-classes, it is then guaranteed that the Projection /// object \a p in the argument is of the same class as the sub-class /// and can be safely dynamically casted to that class. /// /// When implementing this function in a sub-class, the immediate /// base class version of the function should be called first. If the /// base class function returns a non-zero value, that value should /// be returned immediately. Only if zero is returned should this /// function check the member variables of the sub-class to determine /// whether this should be ordered before or after \a p, or if it is /// equivalent with \a p. - virtual int compare(const Projection& p) const = 0; + virtual CmpState compare(const Projection& p) const = 0; /// Determine whether this object should be ordered before the object /// \a p given as argument. If \a p is of a different class than /// this, the before() function of the corresponding type_info /// objects is used. Otherwise, if the objects are of the same class, /// the virtual compare(const Projection &) will be returned. bool before(const Projection& p) const; //@} /// @name Beam configuration /// @todo Does it really make sense to restrict Projections to particular beam configs? Do we use this in practice? //@{ /// Return the allowed beam pairs on which this projection can operate, not /// including recursion. Derived classes should ensure that all contained /// projections are registered in the @a _projections set for the beam /// constraint chaining to work. /// @todo Remove the beam constraints system from projections. virtual const std::set beamPairs() const; /// Add a colliding beam pair. /// @todo This deserves a better name! Projection& addPdgIdPair(PdgId beam1, PdgId beam2) { _beamPairs.insert(PdgIdPair(beam1, beam2)); return *this; } //@} protected: /// Get a Log object based on the getName() property of the calling projection object. Log& getLog() const { string logname = "Rivet.Projection." + name(); return Log::getLog(logname); } /// Used by derived classes to set their name. void setName(const std::string& name) { _name = name; } /// Shortcut to make a named Cmp comparison with the @c *this /// object automatically passed as one of the parent projections. Cmp mkNamedPCmp(const Projection& otherparent, const std::string& pname) const; /// Shortcut to make a named Cmp comparison with the @c *this /// object automatically passed as one of the parent projections. /// /// @note Alias for mkNamedPCmp Cmp mkPCmp(const Projection& otherparent, const std::string& pname) const; /// Block Projection copying virtual Projection& operator = (const Projection&); private: /// Name variable is used by the base class messages to identify /// which derived class is being handled. string _name; /// Beam-type constraint. /// @todo Remove? set _beamPairs; }; } /// Define "less" operator for Projection* containers in terms of the Projection::before virtual method. inline bool std::less::operator()(const Rivet::Projection* x, const Rivet::Projection* y) const { return x->before(*y); } #endif #include "Rivet/Event.hh" #include "Rivet/Particle.hh" #include "Rivet/Tools/Cmp.hh" /// @def DEFAULT_RIVET_PROJ_CLONE /// Preprocessor define to prettify the manky constructor with name string argument #define DEFAULT_RIVET_PROJ_CLONE(clsname) \ virtual unique_ptr clone() const { return unique_ptr(new clsname(*this)); } diff --git a/include/Rivet/Projections/Beam.hh b/include/Rivet/Projections/Beam.hh --- a/include/Rivet/Projections/Beam.hh +++ b/include/Rivet/Projections/Beam.hh @@ -1,206 +1,206 @@ // -*- C++ -*- #ifndef RIVET_Beam_HH #define RIVET_Beam_HH #include "Rivet/Projection.hh" #include "Rivet/Event.hh" #include "Rivet/Particle.hh" #include "Rivet/Math/LorentzTrans.hh" namespace Rivet { /// @name Standalone beam kinematics functions //@{ /// Get beam particles from an event ParticlePair beams(const Event& e); /// Get beam particle IDs from a pair of Particles /// @deprecated Use pids(beams) inline PdgIdPair beamIds(const ParticlePair& beams) { return pids(beams); } /// Get beam particle IDs from an event /// @deprecated Use pids(e.beams()) inline PdgIdPair beamIds(const Event& e) { return pids(beams(e)); } /// Get beam centre-of-mass energy from a pair of beam momenta double sqrtS(const FourMomentum& pa, const FourMomentum& pb); /// Get beam centre-of-mass energy from a pair of Particles inline double sqrtS(const ParticlePair& beams) { return sqrtS(beams.first.momentum(), beams.second.momentum()); } /// Get beam centre-of-mass energy from an Event inline double sqrtS(const Event& e) { return sqrtS(beams(e)); } /// Get per-nucleon beam centre-of-mass energy from a pair of beam momenta /// @note Uses a nominal nucleon mass of 0.939 GeV to convert masses to A double asqrtS(const FourMomentum& pa, const FourMomentum& pb); /// Get per-nucleon beam centre-of-mass energy from a pair of Particles /// @note Uses the sum of nuclear mass numbers A for each beam double asqrtS(const ParticlePair& beams); /// Get per-nucleon beam centre-of-mass energy from an Event /// @note Uses the sum of nuclear mass numbers A for each beam inline double asqrtS(const Event& e) { return asqrtS(beams(e)); } /// Get the Lorentz boost to the beam centre-of-mass system (CMS) from a pair of beam momenta inline FourMomentum cmsBoostVec(const FourMomentum& pa, const FourMomentum& pb) { return pa + pb; } /// Get the Lorentz boost to the beam centre-of-mass system (CMS) from a pair of Particles inline FourMomentum cmsBoostVec(const ParticlePair& beams) { return cmsBoostVec(beams.first, beams.second); } /// Get the Lorentz boost to the beam centre-of-mass system (CMS) from a pair of beam momenta FourMomentum acmsBoostVec(const FourMomentum& pa, const FourMomentum& pb); /// Get the Lorentz boost to the beam centre-of-mass system (CMS) from a pair of Particles FourMomentum acmsBoostVec(const ParticlePair& beams); /// Get the Lorentz boost to the beam centre-of-mass system (CMS) from a pair of beam momenta Vector3 cmsBetaVec(const FourMomentum& pa, const FourMomentum& pb); /// Get the Lorentz boost to the beam centre-of-mass system (CMS) from a pair of Particles inline Vector3 cmsBetaVec(const ParticlePair& beams) { return cmsBetaVec(beams.first, beams.second); } /// Get the Lorentz boost to the per-nucleon beam centre-of-mass system (ACMS) from a pair of beam momenta /// @note Uses a nominal nucleon mass of 0.939 GeV to convert masses to A Vector3 acmsBetaVec(const FourMomentum& pa, const FourMomentum& pb); /// Get the Lorentz boost to the per-nucleon beam centre-of-mass system (ACMS) from a pair of Particles /// @note Uses the sum of nuclear mass numbers A for each beam Vector3 acmsBetaVec(const ParticlePair& beams); /// Get the Lorentz boost to the beam centre-of-mass system (CMS) from a pair of beam momenta Vector3 cmsGammaVec(const FourMomentum& pa, const FourMomentum& pb); /// Get the Lorentz boost to the beam centre-of-mass system (CMS) from a pair of Particles inline Vector3 cmsGammaVec(const ParticlePair& beams) { return cmsGammaVec(beams.first, beams.second); } /// Get the Lorentz boost to the per-nucleon beam centre-of-mass system (ACMS) from a pair of beam momenta /// @note Uses a nominal nucleon mass of 0.939 GeV to convert masses to A Vector3 acmsGammaVec(const FourMomentum& pa, const FourMomentum& pb); /// Get the Lorentz boost to the per-nucleon beam centre-of-mass system (ACMS) from a pair of Particles /// @note Uses the sum of nuclear mass numbers A for each beam Vector3 acmsGammaVec(const ParticlePair& beams); /// Get the Lorentz transformation to the beam centre-of-mass system (CMS) from a pair of beam momenta LorentzTransform cmsTransform(const FourMomentum& pa, const FourMomentum& pb); /// Get the Lorentz transformation to the beam centre-of-mass system (CMS) from a pair of Particles inline LorentzTransform cmsTransform(const ParticlePair& beams) { return cmsTransform(beams.first, beams.second); } /// Get the Lorentz transformation to the per-nucleon beam centre-of-mass system (CMS) from a pair of beam momenta /// @note Uses a nominal nucleon mass of 0.939 GeV to convert masses to A LorentzTransform acmsTransform(const FourMomentum& pa, const FourMomentum& pb); /// Get the Lorentz transformation to the per-nucleon beam centre-of-mass system (CMS) from a pair of Particles /// @note Uses the sum of nuclear mass numbers A for each beam LorentzTransform acmsTransform(const ParticlePair& beams); //@} /// @brief Project out the incoming beams class Beam : public Projection { public: /// Default (and only) constructor Beam() { setName("Beam"); } /// Clone on the heap DEFAULT_RIVET_PROJ_CLONE(Beam); /// @name Beam particles and kinematics //@{ /// The pair of beam particles in the current collision const ParticlePair& beams() const { return _theBeams; } /// The pair of beam particle PDG codes in the current collision /// @deprecated Use pids(beams()) PdgIdPair beamIds() const { return pids(beams()); } /// Get centre of mass energy, \f$ \sqrt{s} \f$ double sqrtS() const { return Rivet::sqrtS(beams()); } /// Get the Lorentz boost to the beam centre-of-mass FourMomentum cmsBoostVec() const { return Rivet::cmsBoostVec(beams()); } /// Get the Lorentz transform to the beam centre-of-mass LorentzTransform cmsTransform() const { return Rivet::cmsTransform(beams()); } /// Get the beta factor vector for the Lorentz boost to the beam centre-of-mass Vector3 cmsBetaVec() const { return Rivet::cmsBetaVec(beams()); } /// Get the gamma factor vector for the Lorentz boost to the beam centre-of-mass Vector3 cmsGammaVec() const { return Rivet::cmsGammaVec(beams()); } //@} /// @name Per-nucleon beam kinematics //@{ /// Get per-nucleon centre of mass energy, \f$ \sqrt{s}/(A_1 + A_2) \f$ double asqrtS() const { return Rivet::asqrtS(beams()); } /// Get the Lorentz boost to the per-nucleon beam centre-of-mass Vector3 acmsBetaVec() const { return Rivet::acmsBetaVec(beams()); } /// Get the Lorentz boost to the per-nucleon beam centre-of-mass Vector3 acmsGammaVec() const { return Rivet::acmsGammaVec(beams()); } /// Get the Lorentz transform to the per-nucleon beam centre-of-mass LorentzTransform acmsTransform() const { return Rivet::acmsTransform(beams()); } //@} /// Get the beam interaction primary vertex (PV) position FourVector pv() const; /// Project on to the Event virtual void project(const Event& e); private: /// Compare with other projections -- it's always the same, since there are no params - virtual int compare(const Projection&) const { return EQUIVALENT; } + virtual CmpState compare(const Projection&) const { return CmpState::EQ; } /// The beam particles in the current collision ParticlePair _theBeams; }; } #endif diff --git a/include/Rivet/Projections/BeamThrust.hh b/include/Rivet/Projections/BeamThrust.hh --- a/include/Rivet/Projections/BeamThrust.hh +++ b/include/Rivet/Projections/BeamThrust.hh @@ -1,78 +1,78 @@ // -*- C++ -*- #ifndef RIVET_BeamThrust_HH #define RIVET_BeamThrust_HH #include "Rivet/Projection.hh" #include "Rivet/Projections/FinalState.hh" #include "Rivet/Event.hh" namespace Rivet { class BeamThrust : public Projection { public: /// Constructor. BeamThrust() {} BeamThrust(const FinalState& fsp) { setName("BeamThrust"); addProjection(fsp, "FS"); } /// Clone on the heap. DEFAULT_RIVET_PROJ_CLONE(BeamThrust); protected: /// Perform the projection on the Event void project(const Event& e) { const vector ps = applyProjection(e, "FS").particles(); calc(ps); } /// Compare projections - int compare(const Projection& p) const { + CmpState compare(const Projection& p) const { return mkNamedPCmp(p, "FS"); } public: double beamthrust() const { return _beamthrust; } public: /// @name Direct methods /// Ways to do the calculation directly, without engaging the caching system //@{ /// Manually calculate the beamthrust, without engaging the caching system void calc(const FinalState& fs); /// Manually calculate the beamthrust, without engaging the caching system void calc(const vector& fsparticles); /// Manually calculate the beamthrust, without engaging the caching system void calc(const vector& fsmomenta); //@} private: /// The beamthrust scalar. double _beamthrust; private: /// Explicitly calculate the beamthrust values. void _calcBeamThrust(const vector& fsmomenta); }; } #endif diff --git a/include/Rivet/Projections/CentralEtHCM.hh b/include/Rivet/Projections/CentralEtHCM.hh --- a/include/Rivet/Projections/CentralEtHCM.hh +++ b/include/Rivet/Projections/CentralEtHCM.hh @@ -1,58 +1,58 @@ // -*- C++ -*- #ifndef RIVET_CentralEtHCM_HH #define RIVET_CentralEtHCM_HH #include "Rivet/Particle.hh" #include "Rivet/Event.hh" #include "Rivet/Projections/DISFinalState.hh" namespace Rivet { /// @brief Summed \f$ E_\perp \f$ of central particles in HCM system. /// /// Sum up \f$ E_\perp \f$ of all particles in the hadronic final state in the /// central rapidity bin of the HCM system. class CentralEtHCM : public Projection { public: /// The default constructor. Must specify a FinalStateHCM projection /// object which is guaranteed to live throughout the run. CentralEtHCM(const DISFinalState& fs) { setName("CentralEtHCM"); addProjection(fs, "FS"); } /// Clone on the heap. DEFAULT_RIVET_PROJ_CLONE(CentralEtHCM); protected: /// Apply the projection on to the Event. void project(const Event& e); /// Compare with other projections - int compare(const Projection& p) const { + CmpState compare(const Projection& p) const { return mkNamedPCmp(p, "FS"); } public: /// The sum of the Et in the central rapidity bin. double sumEt() const { return _sumet; } private: /// The sum of the Et in the central rapidity bin. double _sumet; }; } #endif diff --git a/include/Rivet/Projections/ChargedFinalState.hh b/include/Rivet/Projections/ChargedFinalState.hh --- a/include/Rivet/Projections/ChargedFinalState.hh +++ b/include/Rivet/Projections/ChargedFinalState.hh @@ -1,44 +1,44 @@ // -*- C++ -*- #ifndef RIVET_ChargedFinalState_HH #define RIVET_ChargedFinalState_HH #include "Rivet/Projections/FinalState.hh" namespace Rivet { /// @brief Project only charged final state particles. class ChargedFinalState : public FinalState { public: /// @name Constructors //@{ /// Construction from another FinalState ChargedFinalState(const FinalState& fsp); /// Construction using Cuts object ChargedFinalState(const Cut& c=Cuts::open()); /// Single eta-range constructor. ChargedFinalState(double mineta, double maxeta, double minpt=0*GeV); /// Clone on the heap. DEFAULT_RIVET_PROJ_CLONE(ChargedFinalState); //@} /// Apply the projection on the supplied event. void project(const Event& e); /// Compare projections. - int compare(const Projection& p) const; + CmpState compare(const Projection& p) const; }; } #endif diff --git a/include/Rivet/Projections/ChargedLeptons.hh b/include/Rivet/Projections/ChargedLeptons.hh --- a/include/Rivet/Projections/ChargedLeptons.hh +++ b/include/Rivet/Projections/ChargedLeptons.hh @@ -1,55 +1,55 @@ // -*- C++ -*- #ifndef RIVET_ChargedLeptons_HH #define RIVET_ChargedLeptons_HH #include "Rivet/Projection.hh" #include "Rivet/Projections/ChargedFinalState.hh" #include "Rivet/Particle.hh" #include "Rivet/Event.hh" namespace Rivet { /// @brief Get charged final-state leptons /// /// @todo This is just electrons and muons, unless you set taus stable! class ChargedLeptons : public FinalState { public: /// Constructor ChargedLeptons(const FinalState& fsp=FinalState()) { setName("ChargedLeptons"); addProjection(ChargedFinalState(fsp), "ChFS"); } /// Constructor via Cut ChargedLeptons(const Cut& c) : ChargedLeptons(FinalState(c)) { } /// Clone on the heap. DEFAULT_RIVET_PROJ_CLONE(ChargedLeptons); protected: /// Apply the projection to the event. void project(const Event& evt); /// Compare projections. - int compare(const Projection& other) const; + CmpState compare(const Projection& other) const; public: /// Access the projected leptons. const Particles& chargedLeptons() const { return _theParticles; } }; } #endif diff --git a/include/Rivet/Projections/ConstLossyFinalState.hh b/include/Rivet/Projections/ConstLossyFinalState.hh --- a/include/Rivet/Projections/ConstLossyFinalState.hh +++ b/include/Rivet/Projections/ConstLossyFinalState.hh @@ -1,77 +1,77 @@ // -*- C++ -*- #ifndef RIVET_ConstLossyFinalState_HH #define RIVET_ConstLossyFinalState_HH #include "Rivet/Tools/Logging.hh" #include "Rivet/Config/RivetCommon.hh" #include "Rivet/Particle.hh" #include "Rivet/Event.hh" #include "Rivet/Projection.hh" #include "Rivet/Projections/FinalState.hh" #include "Rivet/Projections/LossyFinalState.hh" namespace Rivet { /// Functor used to implement constant random lossiness. class ConstRandomFilter { public: ConstRandomFilter(double lossFraction) : _lossFraction(lossFraction) { assert(_lossFraction >= 0); } // If operator() returns true, particle is deleted ("lost") bool operator()(const Particle&) { return rand01() < _lossFraction; } - int compare(const ConstRandomFilter& other) const { + CmpState compare(const ConstRandomFilter& other) const { return cmp(_lossFraction, other._lossFraction); } private: double _lossFraction; }; /// @brief Randomly lose a constant fraction of particles. class ConstLossyFinalState : public LossyFinalState { public: /// @name Constructors //@{ /// Constructor from a FinalState. ConstLossyFinalState(const FinalState& fsp, double lossfraction) : LossyFinalState(fsp, ConstRandomFilter(lossfraction)) { setName("ConstLossyFinalState"); } /// Stand-alone constructor. Initialises the base FinalState projection. ConstLossyFinalState(double lossfraction, double mineta = -MAXDOUBLE, double maxeta = MAXDOUBLE, double minpt = 0.0) : LossyFinalState(ConstRandomFilter(lossfraction), mineta, maxeta, minpt) { setName("ConstLossyFinalState"); } /// Clone on the heap. DEFAULT_RIVET_PROJ_CLONE(ConstLossyFinalState); //@} }; } #endif diff --git a/include/Rivet/Projections/DISFinalState.hh b/include/Rivet/Projections/DISFinalState.hh --- a/include/Rivet/Projections/DISFinalState.hh +++ b/include/Rivet/Projections/DISFinalState.hh @@ -1,92 +1,92 @@ // -*- C++ -*- #ifndef RIVET_DISFinalState_HH #define RIVET_DISFinalState_HH #include "Rivet/Projections/FinalState.hh" #include "Rivet/Projections/DISKinematics.hh" namespace Rivet { /// @brief Final state particles boosted to the hadronic center of mass system. /// /// NB. The DIS scattered lepton is not included in the final state particles. class DISFinalState: public FinalState { public: /// Type of DIS boost to apply enum class BoostFrame { HCM, BREIT, LAB }; /// @name Constructors //@{ /// Constructor with explicit FinalState /// @note The DISKinematics has no parameters, hence explicitly passing it as an arg shouldn't be necessary. DISFinalState(const FinalState& fs, BoostFrame boosttype, const DISKinematics& kinematicsp=DISKinematics()) : _boosttype(boosttype) { setName("DISFinalState"); declare(fs, "FS"); declare(kinematicsp, "Kinematics"); } /// Constructor with optional FinalState /// @note The DISKinematics has no parameters, hence explicitly passing it as an arg shouldn't be necessary. DISFinalState(BoostFrame boosttype, const FinalState& fs=FinalState(), const DISKinematics& kinematicsp=DISKinematics()) : DISFinalState(fs, boosttype, kinematicsp) { } /// Constructor with explicit cuts to define final-state particles /// @note The DISKinematics has no parameters, hence explicitly passing it as an arg shouldn't be necessary. DISFinalState(const Cut& c, BoostFrame boosttype, const DISKinematics& kinematicsp=DISKinematics()) : DISFinalState(FinalState(c), boosttype, kinematicsp) { } /// Constructor with explicit cuts to define final-state particles /// @note The DISKinematics has no parameters, hence explicitly passing it as an arg shouldn't be necessary. DISFinalState(BoostFrame boosttype, const Cut& c, const DISKinematics& kinematicsp=DISKinematics()) : DISFinalState(FinalState(c), boosttype, kinematicsp) { } // /// @brief Constructor with default FinalState // /// @note The DISKinematics has no parameters, hence explicitly passing it as an arg shouldn't be necessary. // DISFinalState(BoostFrame boosttype, const DISKinematics& kinematicsp=DISKinematics()) // : DISFinalState(FinalState(), boosttype, kinematicsp) // { } /// Backward compatible constructor with default FinalState /// @deprecated Prefer a version that doesn't need a DISKinematics argument DISFinalState(const DISKinematics& kinematicsp, BoostFrame boosttype) : DISFinalState(FinalState(), boosttype, kinematicsp) { } /// Clone on the heap. DEFAULT_RIVET_PROJ_CLONE(DISFinalState); //@} protected: /// Apply the projection on the supplied event. void project(const Event& e); /// Compare projections. - int compare(const Projection& p) const { + CmpState compare(const Projection& p) const { const DISFinalState& other = dynamic_cast(p); return mkNamedPCmp(p, "Kinematics") || mkNamedPCmp(p, "FS") || cmp(_boosttype, other._boosttype); } private: BoostFrame _boosttype; }; } #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,124 @@ // -*- 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() : _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"); } /// 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; + virtual CmpState 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,69 @@ // -*- C++ -*- #ifndef RIVET_DISLepton_HH #define RIVET_DISLepton_HH #include "Rivet/Projections/Beam.hh" #include "Rivet/Projections/PromptFinalState.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(){ setName("DISLepton"); addProjection(Beam(), "Beam"); addProjection(PromptFinalState(), "FS"); } /// 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; + virtual CmpState 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; }; } #endif diff --git a/include/Rivet/Projections/DressedLeptons.hh b/include/Rivet/Projections/DressedLeptons.hh --- a/include/Rivet/Projections/DressedLeptons.hh +++ b/include/Rivet/Projections/DressedLeptons.hh @@ -1,136 +1,127 @@ // -*- C++ -*- #ifndef RIVET_DressedLeptons_HH #define RIVET_DressedLeptons_HH #include "Rivet/Projection.hh" #include "Rivet/Projections/FinalState.hh" #include "Rivet/Projections/IdentifiedFinalState.hh" #include "Rivet/Config/RivetCommon.hh" namespace Rivet { /// A charged lepton meta-particle created by clustering photons close to the bare lepton /// @todo Remove completely -- it's unnecessary and too confusing (esp. between copying & aggregating) /// @deprecated Just use Particle.constituents() now. class DressedLepton : public Particle { public: /// Copy constructor (from Particle) DressedLepton(const Particle& dlepton); /// Components constructor /// @note This is not a copy constructor, hence the explicit second argument even if empty DressedLepton(const Particle& lepton, const Particles& photons, bool momsum=true); /// Add a photon to the dressed lepton /// @todo Deprecate and override add/setConstituents instead? void addPhoton(const Particle& p, bool momsum=true); /// Retrieve the bare lepton const Particle& bareLepton() const; /// Retrieve the bare lepton (alias) /// @deprecated Prefer the more physicsy bareLepton() const Particle& constituentLepton() const { return bareLepton(); } /// Retrieve the clustered photons const Particles photons() const { return slice(constituents(), 1); } /// Retrieve the clustered photons (alias) /// @deprecated Prefer the shorter photons() const Particles constituentPhotons() const { return photons(); } }; /// @brief Cluster photons from a given FS to all charged particles (typically leptons) /// /// This stores the original (bare) charged particles and photons as particles() /// while the newly created clustered lepton objects are accessible as /// dressedLeptons(). The clustering is done by a delta(R) cone around each bare /// lepton, with double counting being avoided by only adding a photon to the _closest_ /// bare lepton if it happens to be within the capture radius of more than one. class DressedLeptons : public FinalState { public: /// @brief Constructor with a single input FinalState (used for both photons and bare leptons) /// /// Provide a single final state projection used to select the photons and bare /// leptons, a photon-clustering delta(R) cone size around each bare lepton, and an optional /// cut on the _dressed_ leptons (i.e. the momenta after clustering). /// The final argument controls whether non-prompt photons are to be included. /// Set the clustering radius to 0 or negative to disable clustering. DressedLeptons(const FinalState& barefs, double dRmax, const Cut& cut=Cuts::open(), bool useDecayPhotons=false); /// @brief Constructor with distinct photon and lepton finders /// /// Provide final state projections used to select the photons and bare /// leptons (wish we had put the first two args the other way around...), /// a clustering delta(R) cone size around each bare lepton, and an optional /// cut on the _dressed_ leptons (i.e. the momenta after clustering.) /// The final argument controls whether non-prompt photons are to be included. /// Set the clustering radius to 0 or negative to disable clustering. /// /// @todo Convert second arg to a general ParticleFinder rather than an FS, to /// allow clustering on to unstables, e.g. taus via TauFinder. DressedLeptons(const FinalState& photons, const FinalState& bareleptons, double dRmax, const Cut& cut=Cuts::open(), bool useDecayPhotons=false); - // For compatibility only - /// @cond INTERNAL - DEPRECATED("Use the new form with no bool cluster argument") - DressedLeptons(const FinalState& photons, const FinalState& bareleptons, - double dRmax, const Cut& cut, bool, bool useDecayPhotons) - : DressedLeptons(photons, bareleptons, dRmax, cut, useDecayPhotons) - { } - /// @endcond - /// Clone this projection DEFAULT_RIVET_PROJ_CLONE(DressedLeptons); /// @brief Retrieve the dressed leptons /// @note Like particles() but with helper functions vector dressedLeptons() const { vector rtn; for (const Particle& p : particles(cmpMomByPt)) rtn += DressedLepton(p); //static_cast(p); return rtn; } /// @brief Retrieve the dressed leptons ordered by supplied sorting functor /// @note Like particles() but with helper functions vector dressedLeptons(const ParticleSorter& sorter) const { vector rtn; for (const Particle& p : particles(sorter)) rtn += DressedLepton(p); //static_cast(p); return rtn; } protected: /// Apply the projection on the supplied event. void project(const Event& e); /// Compare projections. - int compare(const Projection& p) const; + CmpState compare(const Projection& p) const; private: /// Maximum cone radius to find photons in double _dRmax; /// Whether to include photons from hadron (particularly pi0) and hadronic tau decays bool _fromDecay; }; } #endif diff --git a/include/Rivet/Projections/FParameter.hh b/include/Rivet/Projections/FParameter.hh --- a/include/Rivet/Projections/FParameter.hh +++ b/include/Rivet/Projections/FParameter.hh @@ -1,86 +1,86 @@ // -*- C++ -*- #ifndef RIVET_FParameter_HH #define RIVET_FParameter_HH #include "Rivet/Projection.hh" #include "Rivet/Projections/FinalState.hh" #include "Rivet/Event.hh" namespace Rivet { class FParameter : public Projection { public: /// @name Constructors etc. //@{ /// Constructor FParameter(const FinalState& fsp); /// Clone on the heap. DEFAULT_RIVET_PROJ_CLONE(FParameter); //@} protected: /// Perform the projection on the Event void project(const Event& e); /// Compare with other projections - //int compare(const Projection& p) const; + //CmpState compare(const Projection& p) const; // Taken from Thrust.hh - int compare(const Projection& p) const { + CmpState compare(const Projection& p) const { return mkNamedPCmp(p, "FS"); } public: /// Reset the projection void clear(); /// @name Access the event shapes by name /// @{ /// F-Parametr double F() const { return lambda1() >= lambda2() ? lambda2()/lambda1() : lambda1()/lambda2(); } /// @} /// @name Access the linearised transverse momentum tensor eigenvalues /// @{ double lambda1() const { return _lambdas[0]; } double lambda2() const { return _lambdas[1]; } /// @} /// @name Direct methods /// Ways to do the calculation directly, without engaging the caching system //@{ /// Manually calculate the sphericity, without engaging the caching system void calc(const FinalState& fs); /// Manually calculate the sphericity, without engaging the caching system void calc(const vector& fsparticles); /// Manually calculate the sphericity, without engaging the caching system void calc(const vector& fsmomenta); /// Manually calculate the sphericity, without engaging the caching system void calc(const vector& fsmomenta); //@} private: /// Eigenvalues. vector _lambdas; private: /// Actually do the calculation void _calcFParameter(const vector& fsmomenta); }; } #endif diff --git a/include/Rivet/Projections/FastJets.hh b/include/Rivet/Projections/FastJets.hh --- a/include/Rivet/Projections/FastJets.hh +++ b/include/Rivet/Projections/FastJets.hh @@ -1,291 +1,291 @@ // -*- C++ -*- #ifndef RIVET_FastJets_HH #define RIVET_FastJets_HH #include "Rivet/Jet.hh" #include "Rivet/Particle.hh" #include "Rivet/Projection.hh" #include "Rivet/Projections/JetAlg.hh" #include "Rivet/Projections/FinalState.hh" #include "Rivet/Tools/RivetFastJet.hh" #include "fastjet/SISConePlugin.hh" #include "fastjet/ATLASConePlugin.hh" #include "fastjet/CMSIterativeConePlugin.hh" #include "fastjet/CDFJetCluPlugin.hh" #include "fastjet/CDFMidPointPlugin.hh" #include "fastjet/D0RunIIConePlugin.hh" #include "fastjet/TrackJetPlugin.hh" #include "fastjet/JadePlugin.hh" //#include "fastjet/PxConePlugin.hh" namespace Rivet { /// Project out jets found using the FastJet package jet algorithms. class FastJets : public JetAlg { public: /// Wrapper enum for selected FastJet jet algorithms. /// @todo Move to JetAlg and alias here? enum Algo { KT, CAM, SISCONE, ANTIKT, // PXCONE, ATLASCONE, CMSCONE, CDFJETCLU, CDFMIDPOINT, D0ILCONE, JADE, DURHAM, TRACKJET, GENKTEE }; /// @name Constructors etc. //@{ /// Constructor from a FastJet JetDefinition /// /// @warning The AreaDefinition pointer must be heap-allocated: it will be stored/deleted via a shared_ptr. FastJets(const FinalState& fsp, const fastjet::JetDefinition& jdef, JetAlg::Muons usemuons=JetAlg::Muons::ALL, JetAlg::Invisibles useinvis=JetAlg::Invisibles::NONE, fastjet::AreaDefinition* adef=nullptr) : JetAlg(fsp, usemuons, useinvis), _jdef(jdef), _adef(adef) { _initBase(); } /// JetDefinition-based constructor with reordered args for easier specification of jet area definition /// /// @warning The AreaDefinition pointer must be heap-allocated: it will be stored/deleted via a shared_ptr. FastJets(const FinalState& fsp, const fastjet::JetDefinition& jdef, fastjet::AreaDefinition* adef, JetAlg::Muons usemuons=JetAlg::Muons::ALL, JetAlg::Invisibles useinvis=JetAlg::Invisibles::NONE) : FastJets(fsp, jdef, usemuons, useinvis, adef) { } /// Native argument constructor, using FastJet alg/scheme enums. /// /// @warning The AreaDefinition pointer must be heap-allocated: it will be stored/deleted via a shared_ptr. FastJets(const FinalState& fsp, fastjet::JetAlgorithm type, fastjet::RecombinationScheme recom, double rparameter, JetAlg::Muons usemuons=JetAlg::Muons::ALL, JetAlg::Invisibles useinvis=JetAlg::Invisibles::NONE, fastjet::AreaDefinition* adef=nullptr) : FastJets(fsp, fastjet::JetDefinition(type, rparameter, recom), usemuons, useinvis, adef) { } /// Native argument constructor with reordered args for easier specification of jet area definition /// /// @warning The AreaDefinition pointer must be heap-allocated: it will be stored/deleted via a shared_ptr. FastJets(const FinalState& fsp, fastjet::JetAlgorithm type, fastjet::RecombinationScheme recom, double rparameter, fastjet::AreaDefinition* adef, JetAlg::Muons usemuons=JetAlg::Muons::ALL, JetAlg::Invisibles useinvis=JetAlg::Invisibles::NONE) : FastJets(fsp, type, recom, rparameter, usemuons, useinvis, adef) { } /// @brief Explicitly pass in an externally-constructed plugin /// /// @warning Provided plugin and area definition pointers must be heap-allocated; Rivet will store/delete via a shared_ptr FastJets(const FinalState& fsp, fastjet::JetDefinition::Plugin* plugin, JetAlg::Muons usemuons=JetAlg::Muons::ALL, JetAlg::Invisibles useinvis=JetAlg::Invisibles::NONE, fastjet::AreaDefinition* adef=nullptr) : FastJets(fsp, fastjet::JetDefinition(plugin), usemuons, useinvis, adef) { _plugin.reset(plugin); } /// @brief Explicitly pass in an externally-constructed plugin, with reordered args for easier specification of jet area definition /// /// @warning Provided plugin and area definition pointers must be heap-allocated; Rivet will store/delete via a shared_ptr FastJets(const FinalState& fsp, fastjet::JetDefinition::Plugin* plugin, fastjet::AreaDefinition* adef, JetAlg::Muons usemuons=JetAlg::Muons::ALL, JetAlg::Invisibles useinvis=JetAlg::Invisibles::NONE) : FastJets(fsp, plugin, usemuons, useinvis, adef) { } /// @brief Convenience constructor using Rivet enums for most common jet algs (including some plugins). /// /// For the built-in algs, E-scheme recombination is used. For full control /// of FastJet built-in jet algs, use the constructors from native-args or a /// plugin pointer. /// /// @warning Provided area definition pointer must be heap-allocated; Rivet will store/delete via a shared_ptr FastJets(const FinalState& fsp, Algo alg, double rparameter, JetAlg::Muons usemuons=JetAlg::Muons::ALL, JetAlg::Invisibles useinvis=JetAlg::Invisibles::NONE, fastjet::AreaDefinition* adef=nullptr, double seed_threshold=1.0) : JetAlg(fsp, usemuons, useinvis) { _initBase(); _initJdef(alg, rparameter, seed_threshold); } // /// Same thing as above, but without an FS (for when we want to pass the particles directly to the calc method) // /// @todo Does this work properly, without internal HeavyQuarks etc.? // FastJets(Algo alg, double rparameter, double seed_threshold=1.0) { _initJdef(alg, rparameter, seed_threshold); } // /// Same thing as above, but without an FS (for when we want to pass the particles directly to the calc method) // /// @todo Does this work properly, without internal HeavyQuarks etc.? // FastJets(fastjet::JetAlgorithm type, fastjet::RecombinationScheme recom, double rparameter) { _initJdef(type, recom, rparameter); } // /// Same thing as above, but without an FS (for when we want to pass the particles directly to the calc method) // /// @todo Does this work properly, without internal HeavyQuarks etc.? // FastJets(fastjet::JetDefinition::Plugin* plugin) : _jdef(plugin), _plugin(plugin) { // // _plugin.reset(plugin); // // _jdef = fastjet::JetDefinition(plugin); // } /// Clone on the heap. DEFAULT_RIVET_PROJ_CLONE(FastJets); //@} /// @name Static helper functions for FastJet interaction, with tagging //@{ /// Make PseudoJets for input to a ClusterSequence, with user_index codes for constituent- and tag-particle linking static PseudoJets mkClusterInputs(const Particles& fsparticles, const Particles& tagparticles=Particles()); /// Make a Rivet Jet from a PseudoJet holding a user_index code for lookup of Rivet fsparticle or tagparticle links static Jet mkJet(const PseudoJet& pj, const Particles& fsparticles, const Particles& tagparticles=Particles()); /// Convert a whole list of PseudoJets to a list of Jets, with mkJet-style unpacking static Jets mkJets(const PseudoJets& pjs, const Particles& fsparticles, const Particles& tagparticles=Particles()); //@} /// Reset the projection. Jet def, etc. are unchanged. void reset(); /// @brief Use provided jet area definition /// /// @warning The provided pointer must be heap-allocated: it will be stored/deleted via a shared_ptr. /// @note Provide an adef null pointer to re-disable jet area calculation void useJetArea(fastjet::AreaDefinition* adef) { _adef.reset(adef); } /// @name Access to the jets //@{ /// Get the jets (unordered) with pT > ptmin. Jets _jets() const; /// Get the pseudo jets (unordered). PseudoJets pseudoJets(double ptmin=0.0) const; /// Alias PseudoJets pseudojets(double ptmin=0.0) const { return pseudoJets(ptmin); } /// Get the pseudo jets, ordered by \f$ p_T \f$. PseudoJets pseudoJetsByPt(double ptmin=0.0) const { return sorted_by_pt(pseudoJets(ptmin)); } /// Alias PseudoJets pseudojetsByPt(double ptmin=0.0) const { return pseudoJetsByPt(ptmin); } /// Get the pseudo jets, ordered by \f$ E \f$. PseudoJets pseudoJetsByE(double ptmin=0.0) const { return sorted_by_E(pseudoJets(ptmin)); } /// Alias PseudoJets pseudojetsByE(double ptmin=0.0) const { return pseudoJetsByE(ptmin); } /// Get the pseudo jets, ordered by rapidity. PseudoJets pseudoJetsByRapidity(double ptmin=0.0) const { return sorted_by_rapidity(pseudoJets(ptmin)); } /// Alias PseudoJets pseudojetsByRapidity(double ptmin=0.0) const { return pseudoJetsByRapidity(ptmin); } /// Trim (filter) a jet, keeping tag and constituent info in the resulting jet Jet trimJet(const Jet& input, const fastjet::Filter& trimmer) const; //@} /// @name Access to the FastJet clustering objects such as jet def, area def, and cluster //@{ /// Return the cluster sequence. /// @todo Care needed re. const shared_ptr vs. shared_ptr const shared_ptr clusterSeq() const { return _cseq; } /// Return the area-enabled cluster sequence (if an area defn exists, otherwise returns a null ptr). /// @todo Care needed re. const shared_ptr vs. shared_ptr const shared_ptr clusterSeqArea() const { return areaDef() ? dynamic_pointer_cast(_cseq) : nullptr; } /// Return the jet definition. const fastjet::JetDefinition& jetDef() const { return _jdef; } /// @brief Return the area definition. /// /// @warning May be null! /// @todo Care needed re. const shared_ptr vs. shared_ptr const shared_ptr areaDef() const { return _adef; } //@} private: /// Shared utility functions to implement constructor behaviour void _initBase(); void _initJdef(Algo alg, double rparameter, double seed_threshold); protected: /// Perform the projection on the Event. void project(const Event& e); /// Compare projections. - int compare(const Projection& p) const; + CmpState compare(const Projection& p) const; public: /// Do the calculation locally (no caching). void calc(const Particles& fsparticles, const Particles& tagparticles=Particles()); private: /// Jet definition fastjet::JetDefinition _jdef; /// Pointer to user-handled area definition std::shared_ptr _adef; /// Cluster sequence std::shared_ptr _cseq; /// FastJet external plugin std::shared_ptr _plugin; /// Map of vectors of y scales. This is mutable so we can use caching/lazy evaluation. mutable std::map > _yscales; /// Particles used for constituent and tag lookup Particles _fsparticles, _tagparticles; }; } #endif diff --git a/include/Rivet/Projections/FinalState.hh b/include/Rivet/Projections/FinalState.hh --- a/include/Rivet/Projections/FinalState.hh +++ b/include/Rivet/Projections/FinalState.hh @@ -1,56 +1,56 @@ // -*- C++ -*- #ifndef RIVET_FinalState_HH #define RIVET_FinalState_HH #include "Rivet/Projections/ParticleFinder.hh" namespace Rivet { /// @brief Project out all final-state particles in an event. /// Probably the most important projection in Rivet! class FinalState : public ParticleFinder { public: /// @name Standard constructors etc. //@{ /// Construction using Cuts object FinalState(const Cut& c=Cuts::open()); /// Construction using another FinalState and a Cuts object FinalState(const FinalState& fsp, const Cut& c); /// Old constructor with numeric cut arguments, retained for compatibility /// @deprecated Use the versions with Cut arguments FinalState(double mineta, double maxeta, double minpt=0.0*GeV); /// Clone on the heap. DEFAULT_RIVET_PROJ_CLONE(FinalState); //@} /// Apply the projection to the event. virtual void project(const Event& e); /// Compare projections. - virtual int compare(const Projection& p) const; + virtual CmpState compare(const Projection& p) const; /// Decide if a particle is to be accepted or not. /// @todo Rename to _accept or acceptFinal? virtual bool accept(const Particle& p) const; private: // Hide lossy copy constructors for all classes derived from FinalState template FinalState(const T& rhs); template FinalState const& operator=(T const& rhs); }; } #endif diff --git a/include/Rivet/Projections/FoxWolframMoments.hh b/include/Rivet/Projections/FoxWolframMoments.hh --- a/include/Rivet/Projections/FoxWolframMoments.hh +++ b/include/Rivet/Projections/FoxWolframMoments.hh @@ -1,72 +1,72 @@ // -*- C++ -*- #ifndef RIVET_FoxWolframMoments_HH #define RIVET_FoxWolframMoments_HH #include "Rivet/Config/RivetCommon.hh" #include "Rivet/Projection.hh" #include "Rivet/Projections/FinalState.hh" #include "Rivet/Projections/VetoedFinalState.hh" #include "Rivet/Projections/VisibleFinalState.hh" #include "Rivet/Particle.hh" #include "Rivet/Event.hh" #include #define MAXMOMENT 5 namespace Rivet { /// @brief Calculate Fox-Wolfram moments class FoxWolframMoments : public Projection { public: /// Constructor. FoxWolframMoments(const FinalState& fsp) { setName("FoxWolframMoments"); addProjection(fsp, "FS"); /// @todo Let the user supply any projection they like? VisibleFinalState vfs(fsp); addProjection(vfs, "VFS"); // Initialize moments vector for (int i = 0; i < MAXMOMENT ; ++i) { _fwmoments.push_back(0.0); } } /// Clone on the heap. DEFAULT_RIVET_PROJ_CLONE(FoxWolframMoments); /// The projected Fox-Wolfram Moment of order l double getFoxWolframMoment(unsigned int l) const { if (l < MAXMOMENT) { return _fwmoments[l]; } /// @todo What?!? return -666.0; } protected: /// Apply the projection to the event. void project(const Event& e); /// Compare projections. - int compare(const Projection& p) const; + CmpState compare(const Projection& p) const; private: vector _fwmoments; }; } #endif diff --git a/include/Rivet/Projections/HadronicFinalState.hh b/include/Rivet/Projections/HadronicFinalState.hh --- a/include/Rivet/Projections/HadronicFinalState.hh +++ b/include/Rivet/Projections/HadronicFinalState.hh @@ -1,51 +1,51 @@ // -*- C++ -*- #ifndef RIVET_HadronicFinalState_HH #define RIVET_HadronicFinalState_HH #include "Rivet/Tools/Logging.hh" #include "Rivet/Config/RivetCommon.hh" #include "Rivet/Particle.hh" #include "Rivet/Event.hh" #include "Rivet/Projection.hh" #include "Rivet/Projections/FinalState.hh" namespace Rivet { /// @brief Project only hadronic final state particles. class HadronicFinalState : public FinalState { public: /// Constructor: the supplied FinalState projection is assumed to live through the run. HadronicFinalState(const FinalState& fsp) { setName("HadronicFinalState"); addProjection(fsp, "FS"); } HadronicFinalState(double mineta = -MAXDOUBLE, double maxeta = MAXDOUBLE, double minpt = 0.0*GeV) { setName("HadronicFinalState"); addProjection(FinalState(mineta, maxeta, minpt), "FS"); } /// Clone on the heap. DEFAULT_RIVET_PROJ_CLONE(HadronicFinalState); protected: /// Apply the projection on the supplied event. void project(const Event& e); /// Compare projections. - int compare(const Projection& p) const; + CmpState compare(const Projection& p) const; }; } #endif diff --git a/include/Rivet/Projections/HeavyHadrons.hh b/include/Rivet/Projections/HeavyHadrons.hh --- a/include/Rivet/Projections/HeavyHadrons.hh +++ b/include/Rivet/Projections/HeavyHadrons.hh @@ -1,112 +1,112 @@ // -*- C++ -*- #ifndef RIVET_HeavyHadrons_HH #define RIVET_HeavyHadrons_HH #include "Rivet/Projections/FinalState.hh" #include "Rivet/Projections/UnstableFinalState.hh" #include "Rivet/Particle.hh" #include "Rivet/Event.hh" namespace Rivet { /// @brief Project out the last pre-decay b and c hadrons. /// /// This currently defines a c-hadron as one which contains a @a c quark and /// @a{not} a @a b quark. /// /// @todo This assumes that the heavy hadrons are unstable... should we also look for stable ones in case the decays are disabled? class HeavyHadrons : public FinalState { public: /// @name Constructors and destructors. //@{ /// Constructor with specification of the minimum and maximum pseudorapidity /// \f$ \eta \f$ and the min \f$ p_T \f$ (in GeV). HeavyHadrons(const Cut& c=Cuts::open()) { setName("HeavyHadrons"); addProjection(UnstableFinalState(c), "UFS"); } /// Clone on the heap. DEFAULT_RIVET_PROJ_CLONE(HeavyHadrons); //@} /// @name b hadron accessors //@{ /// Get all weakly decaying b hadrons (return by reference) const Particles& bHadrons() const { return _theBs; } /// Get weakly decaying b hadrons with a Cut applied (return by value) Particles bHadrons(const Cut& c) const { return filter_select(bHadrons(), c); } /// Get weakly decaying b hadrons with a pTmin cut (return by value) /// @deprecated Prefer bHadrons(Cuts::pT > x) Particles bHadrons(double ptmin) const { return bHadrons(Cuts::pT > ptmin); } /// Get weakly decaying b hadrons with a general filter function applied (return by value) Particles bHadrons(const ParticleSelector& s) const { return filter_select(bHadrons(), s); } //@} /// @name b hadron accessors //@{ /// Get all weakly decaying c hadrons (return by reference) const Particles& cHadrons() const { return _theCs; } /// Get weakly decaying c hadrons with a Cut applied (return by value) Particles cHadrons(const Cut& c) const { return filter_select(cHadrons(), c); } /// Get weakly decaying c hadrons with a pTmin cut (return by value) /// @deprecated Prefer cHadrons(Cuts::pT > x) Particles cHadrons(double ptmin) const { return cHadrons(Cuts::pT > ptmin); } /// Get weakly decaying c hadrons with a general filter function applied (return by value) Particles cHadrons(const ParticleSelector& s) const { return filter_select(cHadrons(), s); } //@} protected: /// Apply the projection to the event. virtual void project(const Event& e); /// Compare projections (only difference is in UFS definition) - virtual int compare(const Projection& p) const { + virtual CmpState compare(const Projection& p) const { return mkNamedPCmp(p, "UFS"); } /// b and c hadron containers Particles _theBs, _theCs; }; } #endif diff --git a/include/Rivet/Projections/Hemispheres.hh b/include/Rivet/Projections/Hemispheres.hh --- a/include/Rivet/Projections/Hemispheres.hh +++ b/include/Rivet/Projections/Hemispheres.hh @@ -1,175 +1,175 @@ // -*- C++ -*- #ifndef RIVET_Hemispheres_HH #define RIVET_Hemispheres_HH #include "Rivet/Projections/FinalState.hh" #include "Rivet/Projections/AxesDefinition.hh" namespace Rivet { /// @brief Calculate the hemisphere masses and broadenings. /// /// Calculate the hemisphere masses and broadenings, with event hemispheres /// defined by the plane normal to the thrust vector, \f$ \vec{n}_\mathrm{T} \f$. /// /// The "high" hemisphere mass, /// \f$ M^2_\mathrm{high} / E^2_\mathrm{vis} \f$, is defined as /// \f[ /// \frac{M^2_\mathrm{high}}{E^2_\mathrm{vis}} = /// \frac{1}{E^2_\mathrm{vis}} \max /// \left( /// \left| \sum_{\vec{p}_k \cdot \vec{n}_\mathrm{T} > 0} p_k \right|^2 , /// \left| \sum_{\vec{p}_k \cdot \vec{n}_\mathrm{T} < 0} p_k \right|^2 /// \right) /// \f] /// and the corresponding "low" hemisphere mass, /// \f$ M^2_\mathrm{low} / E^2_\mathrm{vis} \f$, /// is the sum of momentum vectors in the opposite hemisphere, i.e. /// \f$ \max \rightarrow \min \f$ in the formula above. /// /// Finally, we define a hemisphere mass difference: /// \f[ /// \frac{M^2_\mathrm{diff} }{ E^2_\mathrm{vis}} = /// \frac{ M^2_\mathrm{high} - M^2_\mathrm{low} }{ E^2_\mathrm{vis}} . /// \f] /// /// Similarly to the masses, we also define hemisphere broadenings, using the /// momenta transverse to the thrust axis: /// \f[ /// B_\pm = /// \frac{ /// \sum{\pm \vec{p}_i \cdot \vec{n}_\mathrm{T} > 0} /// |\vec{p}_i \times \vec{n}_\mathrm{T} | /// }{ /// 2 \sum_i | \vec{p}_i | /// } /// \f] /// and then a set of the broadening maximum, minimum, sum and difference as follows: /// \f[ B_\mathrm{max} = \max(B_+, B_-) \f] /// \f[ B_\mathrm{min} = \min(B_+, B_-) \f] /// \f[ B_\mathrm{sum} = B_+ + B_- \f] /// \f[ B_\mathrm{diff} = |B_+ - B_-| \f] /// /// Internally, this projection uses a Thrust or Sphericity projection to /// determine the hemisphere orientation. class Hemispheres : public Projection { public: /// Constructor. Hemispheres(const AxesDefinition& ax) { setName("Hemispheres"); addProjection(ax, "Axes"); clear(); } /// Clone on the heap. DEFAULT_RIVET_PROJ_CLONE(Hemispheres); /// Reset the projection void clear() { _E2vis = -1; _M2high = -1; _M2low = -1; _Bmax = -1; _Bmin = -1; _highMassEqMaxBroad = true; } /// Use the projection manually (i.e. outside the projection mechanism) with raw 4-momentum inputs. void calc(const Vector3& n, const std::vector& p4s); /// Use the projection manually (i.e. outside the projection mechanism) with particle inputs. void calc(const Vector3& n, const Particles& particles); /// Use the projection manually (i.e. outside the projection mechanism) with jet inputs. void calc(const Vector3& n, const Jets& jets); protected: /// Perform the projection on the Event. void project(const Event& e); /// Compare with other projections. - int compare(const Projection& p) const { + CmpState compare(const Projection& p) const { return mkNamedPCmp(p, "Axes"); } public: /// @name Hemisphere masses (scaled by \f$ 1 / E^2_\mathrm{vis} \f$). //@{ double E2vis() const { return _E2vis; } double Evis() const { return sqrt(_E2vis); } double M2high() const { return _M2high; } double Mhigh() const { return sqrt(M2high()); } double M2low() const { return _M2low; } double Mlow() const { return sqrt(M2low()); } double M2diff() const { return _M2high -_M2low; } double Mdiff() const { return sqrt(M2diff()); } double M2sum() const { return _M2high +_M2low; } double Msum() const { return sqrt(M2sum()); } double scaledM2high() const { if (isZero(_M2high)) return 0.0; if (!isZero(_E2vis)) return _M2high/_E2vis; else return std::numeric_limits::max(); } double scaledMhigh() const { return sqrt(scaledM2high()); } double scaledM2low() const { if (isZero(_M2low)) return 0.0; if (!isZero(_E2vis)) return _M2low/_E2vis; else return std::numeric_limits::max(); } double scaledMlow() const { return sqrt(scaledM2low()); } double scaledM2diff() const { if (M2diff() == 0.0) return 0.0; if (_E2vis != 0.0) return M2diff()/_E2vis; else return std::numeric_limits::max(); } double scaledMdiff() const { return sqrt(scaledM2diff()); } //@} /// @name Hemisphere broadenings. //@{ double Bmax() const { return _Bmax; } double Bmin() const { return _Bmin; } double Bsum() const { return _Bmax + _Bmin; } double Bdiff() const { return fabs(_Bmax - _Bmin); } // <- fabs(), just in case... //@} /// Is the hemisphere with the max mass the same as the one with the max broadening? bool massMatchesBroadening() { return _highMassEqMaxBroad; } private: /// Visible energy-squared, \f$ E^2_\mathrm{vis} \f$. double _E2vis; /// Hemisphere mass variables. double _M2high, _M2low; /// Hemisphere broadening variables. double _Bmax, _Bmin; /// Is the hemisphere with the max mass the same as the one with the max broadening? bool _highMassEqMaxBroad; }; } #endif diff --git a/include/Rivet/Projections/IdentifiedFinalState.hh b/include/Rivet/Projections/IdentifiedFinalState.hh --- a/include/Rivet/Projections/IdentifiedFinalState.hh +++ b/include/Rivet/Projections/IdentifiedFinalState.hh @@ -1,136 +1,125 @@ // -*- C++ -*- #ifndef RIVET_IdentifiedFinalState_HH #define RIVET_IdentifiedFinalState_HH #include "Rivet/Projections/FinalState.hh" namespace Rivet { /// @brief Produce a final state which only contains specified particle IDs. class IdentifiedFinalState : public FinalState { public: /// @name Constructors //@{ /// Constructor with a FinalState and optional list of PDG ID codes. IdentifiedFinalState(const FinalState& fsp, const vector& pids=vector()); - /// Constructor with a list of PDG ID codes and a FinalState - /// @deprecated Use the version with FinalState as 1st arg - DEPRECATED("Use the version with FinalState as 1st arg") - IdentifiedFinalState(const vector& pids, const FinalState& fsp); - /// Constructor with a FinalState and a single PDG ID code. IdentifiedFinalState(const FinalState& fsp, PdgId pid); - /// Constructor with a single PDG ID code and a FinalState. - /// @deprecated Use the version with FinalState as 1st arg - DEPRECATED("Use the version with FinalState as 1st arg") - IdentifiedFinalState(PdgId pid, const FinalState& fsp); - - /// Construction using optional Cuts object and optional list of PDG ID codes IdentifiedFinalState(const Cut& c=Cuts::open(), const vector& pids=vector()); /// Construction using list of PDG ID codes and an optional Cuts object IdentifiedFinalState(const vector& pids, const Cut& c=Cuts::open()); /// Construction using Cuts object and a single PDG ID code IdentifiedFinalState(const Cut& c, PdgId pid); /// Construction using a single PDG ID code and an optional Cuts object IdentifiedFinalState(PdgId pid, const Cut& c=Cuts::open()); /// Clone on the heap. DEFAULT_RIVET_PROJ_CLONE(IdentifiedFinalState); //@} /// Get the list of particle IDs to accept. const set& acceptedIds() const { return _pids; } /// Add an accepted particle ID. IdentifiedFinalState& acceptId(PdgId pid) { _pids.insert(pid); return *this; } /// Add a set of accepted particle IDs. IdentifiedFinalState& acceptIds(const vector& pids) { for (const PdgId pid : pids) { _pids.insert(pid); } return *this; } /// Add an accepted particle ID and its antiparticle. IdentifiedFinalState& acceptIdPair(PdgId pid) { _pids.insert(pid); _pids.insert(-pid); return *this; } /// Add a set of accepted particle IDs and their antiparticles. IdentifiedFinalState& acceptIdPairs(const vector& pids) { for (const PdgId pid : pids) { _pids.insert(pid); _pids.insert(-pid); } return *this; } /// Accept all neutrinos (convenience method). IdentifiedFinalState& acceptNeutrinos() { acceptIdPair(PID::NU_E); acceptIdPair(PID::NU_MU); acceptIdPair(PID::NU_TAU); return *this; } /// Accept all charged leptons (convenience method). IdentifiedFinalState& acceptChLeptons() { acceptIdPair(PID::ELECTRON); acceptIdPair(PID::MUON); acceptIdPair(PID::TAU); return *this; } /// Reset the list of particle IDs to accept. void reset() { _pids.clear(); } // The remaining particles virtual const Particles& remainingParticles() const { return _remainingParticles; } /// Apply the projection on the supplied event. void project(const Event& e); /// Compare projections. - int compare(const Projection& p) const; + CmpState compare(const Projection& p) const; private: /// The final-state particles. set _pids; // A vector of all other particles in the final state Particles _remainingParticles; }; } #endif diff --git a/include/Rivet/Projections/InitialQuarks.hh b/include/Rivet/Projections/InitialQuarks.hh --- a/include/Rivet/Projections/InitialQuarks.hh +++ b/include/Rivet/Projections/InitialQuarks.hh @@ -1,59 +1,59 @@ // -*- C++ -*- #ifndef RIVET_InitialQuarks_HH #define RIVET_InitialQuarks_HH #include "Rivet/Projection.hh" #include "Rivet/Particle.hh" #include "Rivet/Event.hh" namespace Rivet { /// @brief Project out quarks from the hard process in \f$ e^+ e^- \to Z^0 \f$ events /// /// @deprecated We're not sure exactly when we'lll get rid of this, but it's going to happen... /// /// @warning This is a very dangerous and specific projection! class InitialQuarks : public Projection { public: /// @name Standard constructors and destructors. //@{ /// The default constructor. May specify the minimum and maximum /// pseudorapidity \f$ \eta \f$ and the min \f$ p_T \f$ (in GeV). InitialQuarks() { setName("InitialQuarks"); } /// Clone on the heap. DEFAULT_RIVET_PROJ_CLONE(InitialQuarks); //@} /// Access the projected final-state particles. virtual const Particles& particles() const { return _theParticles; } /// Is this final state empty? virtual bool empty() const { return _theParticles.empty(); } protected: /// Apply the projection to the event. virtual void project(const Event& e); /// Compare projections. - virtual int compare(const Projection& p) const; + virtual CmpState compare(const Projection& p) const; protected: /// The final-state particles. Particles _theParticles; }; } #endif diff --git a/include/Rivet/Projections/InvMassFinalState.hh b/include/Rivet/Projections/InvMassFinalState.hh --- a/include/Rivet/Projections/InvMassFinalState.hh +++ b/include/Rivet/Projections/InvMassFinalState.hh @@ -1,91 +1,91 @@ // -*- C++ -*- #ifndef RIVET_InvMassFinalState_HH #define RIVET_InvMassFinalState_HH #include "Rivet/Projections/FinalState.hh" namespace Rivet { /// @brief Identify particles which can be paired to fit within a given invariant mass window class InvMassFinalState : public FinalState { public: /// Constructor for a single inv-mass pair. InvMassFinalState(const FinalState& fsp, const std::pair& idpair, // pair of decay products double minmass, // min inv mass double maxmass, // max inv mass double masstarget=-1.0); /// Constructor for multiple inv-mass pairs. InvMassFinalState(const FinalState& fsp, const std::vector >& idpairs, // vector of pairs of decay products double minmass, // min inv mass double maxmass, // max inv mass double masstarget=-1.0); /// Same thing as above, but we want to pass the particles directly to the calc method InvMassFinalState(const std::pair& idpair, // pair of decay products double minmass, // min inv mass double maxmass, // max inv mass double masstarget=-1.0); InvMassFinalState(const std::vector >& idpairs, // vector of pairs of decay products double minmass, // min inv mass double maxmass, // max inv mass double masstarget=-1.0); /// Clone on the heap. DEFAULT_RIVET_PROJ_CLONE(InvMassFinalState); /// Constituent pairs. const std::vector >& particlePairs() const; /// Choose whether to use the full inv mass or just the transverse mass. void useTransverseMass(bool usetrans=true) { _useTransverseMass = usetrans; } /// Operate on a given particle vector directly instead of through project (no caching) void calc(const Particles& inparticles); /// Apply the projection on the supplied event. void project(const Event& e); /// Compare projections. - int compare(const Projection& p) const; + CmpState compare(const Projection& p) const; private: /// IDs of the decay products. vector _decayids; /// Constituent pairs. vector > _particlePairs; /// Min inv mass. double _minmass; /// Max inv mass. double _maxmass; /// Target mass if only one pair should be returned. double _masstarget; /// Flag to decide whether to use the full inv mass or just the transverse mass. bool _useTransverseMass; }; } #endif diff --git a/include/Rivet/Projections/JetAlg.hh b/include/Rivet/Projections/JetAlg.hh --- a/include/Rivet/Projections/JetAlg.hh +++ b/include/Rivet/Projections/JetAlg.hh @@ -1,218 +1,218 @@ // -*- C++ -*- #ifndef RIVET_JetAlg_HH #define RIVET_JetAlg_HH #include "Rivet/Projection.hh" #include "Rivet/Projections/FinalState.hh" #include "Rivet/Projections/VisibleFinalState.hh" #include "Rivet/Particle.hh" #include "Rivet/Jet.hh" namespace Rivet { /// Abstract base class for projections which can return a set of {@link Jet}s. class JetAlg : public Projection { public: /// Enum for the treatment of muons: whether to include all, some, or none in jet-finding enum class Muons { NONE, DECAY, ALL }; /// Enum for the treatment of invisible particles: whether to include all, some, or none in jet-finding enum class Invisibles { NONE, DECAY, ALL }; /// Constructor JetAlg(const FinalState& fs, Muons usemuons = Muons::ALL, Invisibles useinvis = Invisibles::NONE); /// Default constructor JetAlg() = default; /// Clone on the heap. virtual unique_ptr clone() const = 0; /// Destructor virtual ~JetAlg() = default; /// @name Control the treatment of muons and invisible particles /// /// Since MC-based jet calibration (and/or particle flow) can add back in /// particles that weren't seen in calorimeters/trackers. //@{ /// @brief Include (some) muons in jet construction. /// /// The default behaviour is that jets are only constructed from visible /// particles. Some jet studies, including those from ATLAS, use a definition /// in which neutrinos from hadron decays are included via MC-based calibrations. /// Setting this flag to true avoids the automatic restriction to a VisibleFinalState. void useMuons(Muons usemuons = Muons::ALL) { _useMuons = usemuons; } /// @brief Include (some) invisible particles in jet construction. /// /// The default behaviour is that jets are only constructed from visible /// particles. Some jet studies, including those from ATLAS, use a definition /// in which neutrinos from hadron decays are included via MC-based calibrations. /// Setting this flag to true avoids the automatic restriction to a VisibleFinalState. void useInvisibles(Invisibles useinvis = Invisibles::DECAY) { _useInvisibles = useinvis; } /// @brief obsolete chooser DEPRECATED("make an explicit choice from Invisibles::{NONE,DECAY,ALL}. This boolean call does not allow for ALL") void useInvisibles(bool useinvis) { _useInvisibles = useinvis ? Invisibles::DECAY : Invisibles::NONE; } //@} /// @name Access to jet objects //@{ /// Get jets in no guaranteed order, with an optional Cut /// @note Returns a copy rather than a reference, due to cuts virtual Jets jets(const Cut& c=Cuts::open()) const { return filter_select(_jets(), c); } /// Get jets in no guaranteed order, with a selection functor /// @note Returns a copy rather than a reference, due to cuts virtual Jets jets(const JetSelector& selector) const { return filter_select(_jets(), selector); } /// Get the jets with a Cut applied, and ordered by supplied sorting functor /// @note Returns a copy rather than a reference, due to cuts and sorting Jets jets(const Cut& c, const JetSorter& sorter) const { /// @todo Will the vector be efficiently std::move'd by value through this function chain? return sortBy(jets(c), sorter); } /// Get the jets, ordered by supplied sorting functor, with an optional Cut /// @note Returns a copy rather than a reference, due to cuts and sorting Jets jets(const JetSorter& sorter, const Cut& c=Cuts::open()) const { /// @todo Will the vector be efficiently std::move'd by value through this function chain? return jets(c, sorter); } /// Get the jets, ordered by supplied sorting function object, with optional cuts on \f$ p_\perp \f$ and rapidity. /// @note Returns a copy rather than a reference, due to cuts and sorting Jets jets(const JetSelector& selector, const JetSorter& sorter) const { /// @todo Will the vector be efficiently std::move'd by value through this function chain? return sortBy(jets(selector), sorter); } /// Get the jets, ordered by supplied sorting functor and with a selection functor applied /// @note Returns a copy rather than a reference, due to cuts and sorting Jets jets(const JetSorter& sorter, const JetSelector selector) const { /// @todo Will the vector be efficiently std::move'd by value through this function chain? return jets(selector, sorter); } /// Get the jets, ordered by \f$ p_T \f$, with optional cuts. /// /// @note Returns a copy rather than a reference, due to cuts and sorting /// /// This is a very common use-case, so is available as syntatic sugar for jets(c, cmpMomByPt). /// @todo The other sorted accessors should be removed in a cleanup. Jets jetsByPt(const Cut& c=Cuts::open()) const { return jets(c, cmpMomByPt); } /// Get the jets, ordered by \f$ p_T \f$, with cuts via a selection functor. /// /// @note Returns a copy rather than a reference, due to cuts and sorting /// /// This is a very common use-case, so is available as syntatic sugar for jets(c, cmpMomByPt). /// @todo The other sorted accessors should be removed in a cleanup. Jets jetsByPt(const JetSelector& selector) const { return jets(selector, cmpMomByPt); } /// Get the jets, ordered by \f$ p_T \f$, with a cut on \f$ p_\perp \f$. /// /// @deprecated Use the version with a Cut argument /// @note Returns a copy rather than a reference, due to cuts and sorting /// /// This is a very common use-case, so is available as syntatic sugar for jets(Cuts::pT >= ptmin, cmpMomByPt). /// @todo The other sorted accessors should be removed in a cleanup. Jets jetsByPt(double ptmin) const { return jets(Cuts::pT >= ptmin, cmpMomByPt); } //@} protected: /// @brief Internal pure virtual method for getting jets in no guaranteed order. virtual Jets _jets() const = 0; public: /// Count the jets size_t size() const { return jets().size(); } /// Count the jets after a Cut is applied. size_t size(const Cut& c) const { return jets(c).size(); } /// Count the jets after a selection functor is applied. size_t size(const JetSelector& s) const { return jets(s).size(); } /// Is this jet finder empty? bool empty() const { return size() == 0; } /// Is this jet finder empty after a Cut is applied? bool empty(const Cut& c) const { return size(c) == 0; } /// Is this jet finder empty after a selection functor is applied? bool empty(const JetSelector& s) const { return size(s) == 0; } /// Clear the projection. virtual void reset() = 0; typedef Jet entity_type; typedef Jets collection_type; /// Template-usable interface common to FinalState. collection_type entities() const { return jets(); } // /// Do the calculation locally (no caching). // virtual void calc(const Particles& constituents, const Particles& tagparticles=Particles()) = 0; protected: /// Perform the projection on the Event. virtual void project(const Event& e) = 0; /// Compare projections. - virtual int compare(const Projection& p) const = 0; + virtual CmpState compare(const Projection& p) const = 0; protected: /// Flag to determine whether or not to exclude (some) muons from the would-be constituents. Muons _useMuons; /// Flag to determine whether or not to exclude (some) invisible particles from the would-be constituents. Invisibles _useInvisibles; }; /// Compatibility typedef, for equivalence with ParticleFinder /// @todo Should we make this the canonical name? Would "require" a header filename change -> breakage or ugly. using JetFinder = JetAlg; } #endif diff --git a/include/Rivet/Projections/JetShape.hh b/include/Rivet/Projections/JetShape.hh --- a/include/Rivet/Projections/JetShape.hh +++ b/include/Rivet/Projections/JetShape.hh @@ -1,199 +1,199 @@ // -*- C++ -*- #ifndef RIVET_JetShape_HH #define RIVET_JetShape_HH #include "Rivet/Config/RivetCommon.hh" #include "Rivet/Projection.hh" #include "Rivet/Projections/JetAlg.hh" #include "Rivet/Particle.hh" #include "Rivet/Event.hh" #include "Rivet/Tools/Utils.hh" namespace Rivet { ///* /// @brief Calculate the jet shape. /// /// Calculate the differential and integral jet shapes in \f$P_{\perp}\f$ for a given /// set of jets. This particular jet shape projection calculates jet shapes relative /// to jet centroids, using only the particles associated to each jet, for the hardest /// \f$ n \f$ jets. /// /// The rapidity scheme (\f$ \eta \f$ or \f$ y \f$) has to be specified when /// invoking the constructor. /// /// The differential jet shape around a given jet axis at distance interval /// \f$ r \pm \delta{r}/2 \f$ is defined as /// \f[ /// \rho(r) = /// \frac{1}{\delta r} \frac{1}{N_\mathrm{jets}} /// \sum_\mathrm{jets} \frac{P_\perp(r - \delta r/2, r+\delta r/2)}{p_\perp(0, R)} /// \f] /// with \f$ 0 \le r \le R \f$ and \f$ P_\perp(r_1, r_2) = \sum_{\in [r_1, r_2)} p_\perp \f$. /// /// The integral jet shape around a given jet axes until distance \f$ r \f$ is defined as /// \f[ /// \Psi(r) = /// \frac{1}{N_\mathrm{jets}} /// \sum_\mathrm{jets} \frac{P_\perp(0, r)}{p_\perp(0, R)} /// \f] /// with \f$ 0 \le r \le R \f$ and \f$ P_\perp(r_1, r_2) = \sum_{\in [r_1, r_2)} p_\perp \f$. /// /// The constructor expects also the binning in radius \f$ r \f$ to be supplied. /// class JetShape : public Projection { public: /// @name Constructors etc. //@{ /// Constructor from histo range and number of bins. JetShape(const JetAlg& jetalg, double rmin, double rmax, size_t nbins, double ptmin=0, double ptmax=MAXDOUBLE, double absrapmin=-MAXDOUBLE, double absrapmax=-MAXDOUBLE, RapScheme rapscheme=RAPIDITY); /// Constructor from vector of bin edges. JetShape(const JetAlg& jetalg, vector binedges, double ptmin=0, double ptmax=MAXDOUBLE, double absrapmin=-MAXDOUBLE, double absrapmax=-MAXDOUBLE, RapScheme rapscheme=RAPIDITY); /// Clone on the heap. DEFAULT_RIVET_PROJ_CLONE(JetShape); //@} /// Reset projection between events. void clear(); /// Do the calculation directly on a supplied collection of Jet objects. void calc(const Jets& jets); public: /// Number of equidistant radius bins. size_t numBins() const { return _binedges.size() - 1; } /// Number of jets which passed cuts. size_t numJets() const { return _diffjetshapes.size(); } /// \f$ r_\text{min} \f$ value. double rMin() const { return _binedges.front(); } /// \f$ r_\text{max} \f$ value. double rMax() const { return _binedges.back(); } /// \f$ p_\perp^\text{min} \f$ value. double ptMin() const { return _ptcuts.first; } /// \f$ p_\perp^\text{max} \f$ value. double ptMax() const { return _ptcuts.second; } /// Central \f$ r \f$ value for bin @a rbin. double rBinMin(size_t rbin) const { assert(inRange(rbin, 0u, numBins())); return _binedges[rbin]; } /// Central \f$ r \f$ value for bin @a rbin. double rBinMax(size_t rbin) const { assert(inRange(rbin, 0u, numBins())); return _binedges[rbin+1]; } /// Central \f$ r \f$ value for bin @a rbin. double rBinMid(size_t rbin) const { assert(inRange(rbin, 0u, numBins())); //cout << _binedges << '\n'; return (_binedges[rbin] + _binedges[rbin+1])/2.0; } /// Return value of differential jet shape profile histo bin. double diffJetShape(size_t ijet, size_t rbin) const { assert(inRange(ijet, 0u, numJets())); assert(inRange(rbin, 0u, numBins())); return _diffjetshapes[ijet][rbin]; } /// Return value of integrated jet shape profile histo bin. double intJetShape(size_t ijet, size_t rbin) const { assert(inRange(ijet, 0u, numJets())); assert(inRange(rbin, 0u, numBins())); double rtn = 0; for (size_t i = 0; i <= rbin; ++i) { rtn += _diffjetshapes[ijet][i]; } return rtn; } /// @todo Provide int and diff jet shapes with some sort of area normalisation? // /// Return value of \f$ \Psi \f$ (integrated jet shape) at given radius for a \f$ p_T \f$ bin. // /// @todo Remove this external indexing thing // double psi(size_t pTbin) const { // return _PsiSlot[pTbin]; // } protected: /// Apply the projection to the event. void project(const Event& e); /// Compare projections. - int compare(const Projection& p) const; + CmpState compare(const Projection& p) const; private: /// @name Jet shape parameters //@{ /// Vector of radius bin edges vector _binedges; /// Lower and upper cuts on contributing jet \f$ p_\perp \f$. pair _ptcuts; /// Lower and upper cuts on contributing jet (pseudo)rapidity. pair _rapcuts; /// Rapidity scheme RapScheme _rapscheme; //@} /// @name The projected jet shapes //@{ /// Jet shape histo -- first index is jet number, second is r bin vector< vector > _diffjetshapes; //@} }; } #endif diff --git a/include/Rivet/Projections/LeadingParticlesFinalState.hh b/include/Rivet/Projections/LeadingParticlesFinalState.hh --- a/include/Rivet/Projections/LeadingParticlesFinalState.hh +++ b/include/Rivet/Projections/LeadingParticlesFinalState.hh @@ -1,75 +1,75 @@ // -*- C++ -*- #ifndef RIVET_LeadingParticlesFinalState_HH #define RIVET_LeadingParticlesFinalState_HH #include "Rivet/Event.hh" #include "Rivet/Projection.hh" #include "Rivet/Projections/FinalState.hh" namespace Rivet { /// @brief Get the highest-pT occurrences of FS particles with the specified PDG IDs. class LeadingParticlesFinalState : public FinalState { public: /// Constructor: the supplied FinalState projection is assumed to live through the run. LeadingParticlesFinalState(const FinalState& fsp) : FinalState(), _leading_only(false) { setName("LeadingParticlesFinalState"); addProjection(fsp, "FS"); } /// Clone on the heap. DEFAULT_RIVET_PROJ_CLONE(LeadingParticlesFinalState); /// Add a particle ID to the list of leading particles selected LeadingParticlesFinalState& addParticleId(long id) { _ids.insert(id); return *this; } /// Add a particle ID to the list of leading particles selected LeadingParticlesFinalState& addParticleIdPair(long id) { _ids.insert(id); _ids.insert(-id); return *this; } /// Toggle whether to keep track only of the leading particle of any ID, /// or the leading particle of all IDs separately /// Default is the latter (=false) void setLeadingOnly(const bool& leadingonly) { _leading_only = leadingonly; } // /// Check if a particle of a particular ID was found in the current event // bool hasParticleId(const PdgId pid) const; // /// Get a particle of a particular ID (check it exists first) // bool get(const PdgId pid) const; /// Apply the projection on the supplied event. void project(const Event& e); /// Compare projections. - int compare(const Projection& p) const; + CmpState compare(const Projection& p) const; private: /// Check if the particle's ID is in the list bool inList(const Particle& particle) const; /// IDs of the leading particles to be selected std::set_ids; bool _leading_only; }; } #endif diff --git a/include/Rivet/Projections/LossyFinalState.hh b/include/Rivet/Projections/LossyFinalState.hh --- a/include/Rivet/Projections/LossyFinalState.hh +++ b/include/Rivet/Projections/LossyFinalState.hh @@ -1,81 +1,81 @@ // -*- C++ -*- #ifndef RIVET_LossyFinalState_HH #define RIVET_LossyFinalState_HH #include "Rivet/Tools/Logging.hh" #include "Rivet/Config/RivetCommon.hh" #include "Rivet/Particle.hh" #include "Rivet/Event.hh" #include "Rivet/Projection.hh" #include "Rivet/Projections/FinalState.hh" namespace Rivet { /// @brief Templated FS projection which can lose some of the supplied particles. template class LossyFinalState : public FinalState { public: /// @name Constructors //@{ /// Constructor from FinalState. LossyFinalState(const FinalState& fsp, FILTER filter) : _filter(filter) { setName("LossyFinalState"); addProjection(fsp, "FS"); } /// Stand-alone constructor. Initialises the base FinalState projection. LossyFinalState(FILTER filter, double mineta = -MAXDOUBLE, double maxeta = MAXDOUBLE, double minpt = 0.0) : _filter(filter) { setName("LossyFinalState"); addProjection(FinalState(mineta, maxeta, minpt), "FS"); } /// Virtual destructor, to allow subclassing virtual ~LossyFinalState() { } /// Clone on the heap. DEFAULT_RIVET_PROJ_CLONE(LossyFinalState); //@} /// Apply the projection on the supplied event. void project(const Event& e) { const FinalState& fs = applyProjection(e, "FS"); getLog() << Log::DEBUG << "Pre-loss number of FS particles = " << fs.particles().size() << '\n'; _theParticles.clear(); std::remove_copy_if(fs.particles().begin(), fs.particles().end(), std::back_inserter(_theParticles), _filter); getLog() << Log::DEBUG << "Filtered number of FS particles = " << _theParticles.size() << '\n'; } /// Compare projections. - int compare(const Projection& p) const { + CmpState compare(const Projection& p) const { const LossyFinalState& other = pcast< LossyFinalState >(p); - const int fscmp = mkNamedPCmp(other, "FS"); - if (fscmp) return fscmp; + const CmpState fscmp = mkNamedPCmp(other, "FS"); + if (fscmp != CmpState::EQ) return fscmp; return _filter.compare(other._filter); } protected: /// Filtering object: must support operator(const Particle&) and compare(const Filter&) FILTER _filter; }; } #endif diff --git a/include/Rivet/Projections/MergedFinalState.hh b/include/Rivet/Projections/MergedFinalState.hh --- a/include/Rivet/Projections/MergedFinalState.hh +++ b/include/Rivet/Projections/MergedFinalState.hh @@ -1,46 +1,46 @@ // -*- C++ -*- #ifndef RIVET_MergedFinalState_HH #define RIVET_MergedFinalState_HH #include "Rivet/Tools/Logging.hh" #include "Rivet/Config/RivetCommon.hh" #include "Rivet/Particle.hh" #include "Rivet/Event.hh" #include "Rivet/Projection.hh" #include "Rivet/Projections/FinalState.hh" namespace Rivet { /// @brief Get final state particles merged from two FinalState projections. class MergedFinalState : public FinalState { public: /// @name Constructors //@{ MergedFinalState(const FinalState& fspa, const FinalState& fspb) { setName("MergedFinalState"); addProjection(fspa, "FSA"); addProjection(fspb, "FSB"); } /// Clone on the heap. DEFAULT_RIVET_PROJ_CLONE(MergedFinalState); //@} protected: /// Apply the projection on the supplied event. void project(const Event& e); /// Compare projections. - int compare(const Projection& p) const; + CmpState compare(const Projection& p) const; }; } #endif diff --git a/include/Rivet/Projections/MissingMomentum.hh b/include/Rivet/Projections/MissingMomentum.hh --- a/include/Rivet/Projections/MissingMomentum.hh +++ b/include/Rivet/Projections/MissingMomentum.hh @@ -1,154 +1,154 @@ // -*- C++ -*- #ifndef RIVET_MissingMomentum_HH #define RIVET_MissingMomentum_HH #include "Rivet/Config/RivetCommon.hh" #include "Rivet/Projection.hh" #include "Rivet/Projections/VisibleFinalState.hh" #include "Rivet/Particle.hh" #include "Rivet/Event.hh" namespace Rivet { /// @brief Calculate missing \f$ E \f$, \f$ E_\perp \f$ etc. /// /// Project out the total visible energy vector, allowing missing /// \f$ E \f$, \f$ E_\perp \f$ etc. to be calculated. Final state /// visibility restrictions are automatic. class MissingMomentum : public Projection { public: /// Default constructor with optional cut. MissingMomentum(const Cut& c=Cuts::open()) { setName("MissingMomentum"); FinalState fs(c); addProjection(fs, "FS"); addProjection(VisibleFinalState(fs), "VisibleFS"); } /// Constructor. MissingMomentum(const FinalState& fs) { setName("MissingMomentum"); addProjection(fs, "FS"); addProjection(VisibleFinalState(fs), "VisibleFS"); } /// Clone on the heap. DEFAULT_RIVET_PROJ_CLONE(MissingMomentum); /// @name Visible/missing four-momentum functions //@{ /// The vector-summed visible four-momentum in the event. /// /// @note Reverse this vector with .reverse() to get the missing momentum vector. /// /// @note The optional @a mass argument is used to set a mass on the 4-vector. By /// default it is zero (since missing momentum is really a 3-momentum quantity: /// adding the E components of visible momenta just gives a huge mass) const FourMomentum visibleMomentum(double mass=0*GeV) const; /// Alias for visibleMomentum const FourMomentum visibleMom(double mass=0*GeV) const { return visibleMomentum(mass); } /// The missing four-momentum in the event, required to balance the final state. /// /// @note The optional @a mass argument is used to set a mass on the 4-vector. By /// default it is zero (since missing momentum is really a 3-momentum quantity: /// adding the E components of visible momenta just gives a huge mass) const FourMomentum missingMomentum(double mass=0*GeV) const { return visibleMomentum(mass).reverse(); } /// Alias for missingMomentum const FourMomentum missingMom(double mass=0*GeV) const { return missingMomentum(mass); } //@} /// @name Transverse momentum functions /// @note This may be what you want, even if the paper calls it "missing Et"! /// @todo Move into a common base class for MissingMomentum and SmearedMET -- MomentumBalance, METFinder? //@{ /// The vector-summed visible transverse momentum in the event, as a 3-vector with z=0 /// @note Reverse this vector with operator- to get the missing pT vector. const Vector3& vectorPt() const { return _vpt; } /// Convenience vector MPT function const Vector3 vectorMissingPt() const { return -vectorPt(); } // Alias const Vector3 vectorMPT() const { return vectorMissingPt(); } /// The vector-summed missing transverse momentum in the event. double missingPt() const { return vectorPt().mod(); } // /// Alias for missingPt // double mpt() const { return missingPt(); } /// The scalar-summed visible transverse momentum in the event. double scalarPt() const { return _spt; } // /// Alias for scalarPt // double spt() const { return scalarPt(); } //@} /// @name Transverse energy functions /// @warning Despite the common names "MET" and "SET", what's often meant is the pT functions above! /// @todo Move into a common base class for MissingMomentum and SmearedMET -- MomentumBalance, METFinder? //@{ /// The vector-summed visible transverse energy in the event, as a 3-vector with z=0 /// @note Reverse this vector with operator- to get the missing ET vector. const Vector3& vectorEt() const { return _vet; } /// Convenience vector MET function const Vector3 vectorMissingEt() const { return -vectorEt(); } // Alias const Vector3 vectorMET() const { return vectorMissingEt(); } /// The vector-summed missing transverse energy in the event. double missingEt() const { return vectorEt().mod(); } /// Alias for missingEt double met() const { return missingEt(); } /// The scalar-summed visible transverse energy in the event. double scalarEt() const { return _set; } /// Alias for scalarEt double set() const { return scalarEt(); } //@} public: /// Clear the projection results. void clear(); protected: /// Apply the projection to the event. void project(const Event& e); /// Compare projections. - int compare(const Projection& p) const; + CmpState compare(const Projection& p) const; private: /// The total visible momentum FourMomentum _momentum; /// Scalar transverse energy double _set, _spt; /// Vector transverse energy Vector3 _vet, _vpt; }; } #endif diff --git a/include/Rivet/Projections/NeutralFinalState.hh b/include/Rivet/Projections/NeutralFinalState.hh --- a/include/Rivet/Projections/NeutralFinalState.hh +++ b/include/Rivet/Projections/NeutralFinalState.hh @@ -1,65 +1,65 @@ // -*- C++ -*- #ifndef RIVET_NeutralFinalState_HH #define RIVET_NeutralFinalState_HH #include "Rivet/Projections/FinalState.hh" namespace Rivet { /// @brief Project only neutral final state particles. class NeutralFinalState : public FinalState { public: /// @name Constructors //@{ /// Construction from another FinalState NeutralFinalState(const FinalState& fsp, double etmin=0*GeV) : _Etmin(etmin) { setName("NeutralFinalState"); addProjection(fsp, "FS"); } /// Construction using Cuts object NeutralFinalState(const Cut& c=Cuts::open()) : _Etmin(0.0*GeV) { setName("NeutralFinalState"); addProjection(FinalState(c), "FS"); } /// Construction from explicit eta range and min ET cut values NeutralFinalState(double mineta, double maxeta, double etmin=0*GeV) : _Etmin(etmin) { setName("NeutralFinalState"); addProjection(FinalState(mineta, maxeta, 0.0*GeV), "FS"); } /// Clone on the heap. DEFAULT_RIVET_PROJ_CLONE(NeutralFinalState); //@} /// Apply the projection on the supplied event. void project(const Event& e); /// Compare projections. - int compare(const Projection& p) const; + CmpState compare(const Projection& p) const; protected: /// The minimum allowed transverse energy. /// @todo Remove in favour of a Cut double _Etmin; }; } #endif diff --git a/include/Rivet/Projections/NonHadronicFinalState.hh b/include/Rivet/Projections/NonHadronicFinalState.hh --- a/include/Rivet/Projections/NonHadronicFinalState.hh +++ b/include/Rivet/Projections/NonHadronicFinalState.hh @@ -1,50 +1,50 @@ // -*- C++ -*- #ifndef RIVET_NonHadronicFinalState_HH #define RIVET_NonHadronicFinalState_HH #include "Rivet/Tools/Logging.hh" #include "Rivet/Config/RivetCommon.hh" #include "Rivet/Particle.hh" #include "Rivet/Event.hh" #include "Rivet/Projection.hh" #include "Rivet/Projections/FinalState.hh" namespace Rivet { /// @brief Project only hadronic final state particles. class NonHadronicFinalState : public FinalState { public: /// Constructor: the supplied FinalState projection is assumed to live through the run. NonHadronicFinalState(FinalState& fsp) { setName("NonHadronicFinalState"); addProjection(fsp, "FS"); } NonHadronicFinalState(double mineta = -MAXDOUBLE, double maxeta = MAXDOUBLE, double minpt = 0.0*GeV) { setName("NonHadronicFinalState"); addProjection(FinalState(mineta, maxeta, minpt), "FS"); } /// Clone on the heap. DEFAULT_RIVET_PROJ_CLONE(NonHadronicFinalState); /// Apply the projection on the supplied event. void project(const Event& e); /// Compare projections. - int compare(const Projection& p) const; + CmpState compare(const Projection& p) const; }; } #endif diff --git a/include/Rivet/Projections/NonPromptFinalState.hh b/include/Rivet/Projections/NonPromptFinalState.hh --- a/include/Rivet/Projections/NonPromptFinalState.hh +++ b/include/Rivet/Projections/NonPromptFinalState.hh @@ -1,55 +1,55 @@ // -*- C++ -*- #ifndef RIVET_NonPromptFinalState_HH #define RIVET_NonPromptFinalState_HH #include "Rivet/Projections/FinalState.hh" namespace Rivet { /// @brief Find final state particles NOT directly connected to the hard process. /// /// See PromptFinalState for details. class NonPromptFinalState : public FinalState { public: /// @name Constructors //@{ // Constructor from a final state. NonPromptFinalState(const FinalState& fsp, bool accepttaudecays=false, bool acceptmudecays=false); /// Constructor from a Cut (and implicit general FS). NonPromptFinalState(const Cut& c, bool accepttaudecays=false, bool acceptmudecays=false); // /// Constructor from a Cut and optional FinalState. // NonPromptFinalState(const Cut& c, const FinalState& fsp=FinalState(), // bool accepttaudecays=false, bool acceptmudecays=false); /// Clone on the heap. DEFAULT_RIVET_PROJ_CLONE(NonPromptFinalState); //@} /// Treat particles from decays of prompt muons as non-prompt? void acceptMuonDecays(bool acc=true) { _acceptMuDecays = acc; } /// Treat particles from decays of prompt taus as non-prompt? void acceptTauDecays(bool acc=true) { _acceptTauDecays = acc; } /// Apply the projection on the supplied event. void project(const Event& e); /// Compare projections. - int compare(const Projection& p) const; + CmpState compare(const Projection& p) const; private: bool _acceptMuDecays, _acceptTauDecays; }; } #endif diff --git a/include/Rivet/Projections/ParisiTensor.hh b/include/Rivet/Projections/ParisiTensor.hh --- a/include/Rivet/Projections/ParisiTensor.hh +++ b/include/Rivet/Projections/ParisiTensor.hh @@ -1,100 +1,100 @@ // -*- C++ -*- #ifndef RIVET_ParisiTensor_HH #define RIVET_ParisiTensor_HH #include "Rivet/Projection.hh" #include "Rivet/Projections/FinalState.hh" #include "Rivet/Projections/Sphericity.hh" #include "Rivet/Event.hh" namespace Rivet { /// @brief Calculate the Parisi event shape tensor (or linear momentum tensor). /// /// The Parisi event shape C and D variables are derived from the eigenvalues of /// the linear momentum tensor /// \f[ /// \theta^{\alpha \beta} = /// \frac{\sum_i \frac{p_i^\alpha p_i^\beta}{|\mathbf{p}_i|}} /// {\sum_i |\mathbf{p}_i|} /// \f] /// which is actually a linearized (and hence infra-red safe) version of the /// {@link Sphericity} tensor. /// /// Defining the three eigenvalues of \f$\theta\f$ /// \f$ \lambda_1 \ge \lambda_2 \ge \lambda_3 \f$, with \f$ \lambda_1 + \lambda_2 + \lambda_3 = 1 \f$, /// the C and D parameters are defined as /// \f[ /// C = 3(\lambda_1\lambda_2 + \lambda_1\lambda_3 + \lambda_2\lambda_3) /// \f] /// and /// \f[ /// D = 27 \lambda_1\lambda_2\lambda_3 /// \f] /// /// Internally, this Projection uses the Sphericity projection with the generalising /// \f$r\f$ parameter set to 1. /// class ParisiTensor : public Projection { public: /// Constructor. The provided FinalState projection must live throughout the run. ParisiTensor(const FinalState& fsp) { setName("ParisiTensor"); addProjection(fsp, "FS"); addProjection(Sphericity(fsp, 1.0), "Sphericity"); clear(); } /// Clone on the heap. DEFAULT_RIVET_PROJ_CLONE(ParisiTensor); protected: /// Perform the projection on the Event. void project(const Event& e); /// Compare with other projections. - int compare(const Projection& p) const; + CmpState compare(const Projection& p) const; public: /// Clear the projection. void clear(); public: /// @name Access the C and D params. ///@{ double C() const { return _C; } double D() const { return _D; } ///@} /// @name Access the eigenvalues of \f$\theta\f$. ///@{ double lambda1() const { return _lambda[0]; } double lambda2() const { return _lambda[1]; } double lambda3() const { return _lambda[2]; } ///@} private: /// The Parisi event shape variables. double _C, _D; /// Eigenvalues. double _lambda[3]; }; } #endif diff --git a/include/Rivet/Projections/ParticleFinder.hh b/include/Rivet/Projections/ParticleFinder.hh --- a/include/Rivet/Projections/ParticleFinder.hh +++ b/include/Rivet/Projections/ParticleFinder.hh @@ -1,156 +1,156 @@ // -*- C++ -*- #ifndef RIVET_ParticleFinder_HH #define RIVET_ParticleFinder_HH #include "Rivet/Projection.hh" namespace Rivet { /// @brief Base class for projections which return subsets of an event's particles class ParticleFinder : public Projection { public: /// @name Object lifetime management //@{ /// Construction using Cuts object ParticleFinder(const Cut& c=Cuts::OPEN) : _cuts(c), _theParticles() { } /// Virtual destructor for inheritance virtual ~ParticleFinder() {} /// Clone on the heap. virtual unique_ptr clone() const = 0; //@} /// @name Particle accessors //@{ /// Count the final-state particles size_t size() const { return particles().size(); } /// Count the final-state particles after a Cut is applied size_t size(const Cut& c) const { return particles(c).size(); } /// Count the final-state particles after a selection functor is applied size_t size(const ParticleSelector& s) const { return particles(s).size(); } /// Is this final state empty? bool empty() const { return size() == 0; } /// Is this final state empty after a Cut is applied? bool empty(const Cut& c) const { return size(c) == 0; } /// Is this final state empty after a selection functor is applied? bool empty(const ParticleSelector& s) const { return size(s) == 0; } /// Get the particles in no particular order, with no cuts virtual const Particles& particles() const { return _theParticles; } /// Get the raw particles in no particular order, with no cuts /// /// @note Raw particles are the final-state constituents, as opposed to /// potentially composite particles returned as the finder's particles() Particles rawParticles() const { Particles rtn; for (const Particle& p : particles()) rtn += p.rawConstituents(); return rtn; } /// @brief Get the particles with selection cuts /// @note Returns a copy rather than a reference, due to the cuts. Particles particles(const Cut& c) const { return filter_select(particles(), c); } /// @brief Get the particles with selection cuts via a functor /// @note Returns a copy rather than a reference, due to the cuts. Particles particles(const ParticleSelector& selector) const { return filter_select(particles(), selector); } /// Get the particles, ordered by supplied sorting function object /// @note Returns a copy rather than a reference, due to cuts and sorting. Particles particles(const ParticleSorter& sorter, const Cut& c=Cuts::open()) const { return sortBy(particles(c), sorter); } /// Get the particles, ordered by supplied sorting function object /// @note Returns a copy rather than a reference, due to cuts and sorting. Particles particles(const Cut& c, const ParticleSorter& sorter) const { return sortBy(particles(c), sorter); } /// Get the particles, ordered by a sorting functor and filtered by a selection functor /// @note Returns a copy rather than a reference, due to cuts and sorting. Particles particles(const ParticleSelector& selector, const ParticleSorter& sorter) const { return sortBy(particles(selector), sorter); } /// Get the particles, ordered by a sorting functor and filtered by a selection functor /// @note Returns a copy rather than a reference, due to cuts and sorting. Particles particles(const ParticleSorter& sorter, const ParticleSelector& selector) const { return sortBy(particles(selector), sorter); } /// Get the particles, ordered by decreasing \f$ p_T \f$ and with optional cuts /// /// This is a very common use-case, so is available as syntatic sugar for particles(c, cmpMomByPt). Particles particlesByPt(const Cut& c=Cuts::open()) const { return particles(c, cmpMomByPt); } /// Get the particles, ordered by decreasing \f$ p_T \f$ and with optional cuts /// /// This is a very common use-case, so is available as syntatic sugar for particles(f, cmpMomByPt). Particles particlesByPt(const ParticleSelector& selector) const { return particles(selector, cmpMomByPt); } /// Get the particles, ordered by decreasing \f$ p_T \f$ and with a cut on minimum \f$ p_T \f$ /// /// This is a very common use-case, so is available as syntatic sugar for particles(Cuts::pT >= ptmin, cmpMomByPt). Particles particlesByPt(double ptmin) const { return particles(Cuts::pT >= ptmin, cmpMomByPt); } //@} /// @todo Replace with cuts() accessor ///virtual Cut cuts() const { return _cuts; } /// @name For JetAlg compatibility //@{ typedef Particle entity_type; typedef Particles collection_type; /// Template-usable interface common to JetAlg const collection_type& entities() const { return particles(); } //@} /// Apply the projection to the event virtual void project(const Event& e) = 0; /// Compare projections - virtual int compare(const Projection& p) const; + virtual CmpState compare(const Projection& p) const; protected: /// The kinematic cuts cuts Cut _cuts; /// The found particles returned by the particles() methods Particles _theParticles; }; } #endif diff --git a/include/Rivet/Projections/PartonicTops.hh b/include/Rivet/Projections/PartonicTops.hh --- a/include/Rivet/Projections/PartonicTops.hh +++ b/include/Rivet/Projections/PartonicTops.hh @@ -1,116 +1,116 @@ // -*- C++ -*- #ifndef RIVET_PartonicTops_HH #define RIVET_PartonicTops_HH #include "Rivet/Projections/ParticleFinder.hh" namespace Rivet { /// @brief Convenience finder of partonic top quarks /// /// @warning Requires there to be tops in the event record. A fiducial pseudo-top /// analysis approach is strongly recommended instead of this. class PartonicTops : public ParticleFinder { public: /// @brief Enum for categorising top quark decay modes /// /// More specifically, the decay mode of the W from the top. We presume top decay to a W and b quark. enum class DecayMode { ANY = 0, ALL = 0, ELECTRON, MUON, TAU, E_MU, E_MU_TAU, HADRONIC }; /// @name Constructors //@{ /// Constructor optionally taking cuts object PartonicTops(const Cut& c=Cuts::OPEN) : ParticleFinder(c), _decaymode(DecayMode::ALL), _emu_from_prompt_tau(true), _include_hadronic_taus(false) { } /// Constructor taking decay mode details (and an optional cuts object) PartonicTops(DecayMode decaymode, bool emu_from_prompt_tau=true, bool include_hadronic_taus=false, const Cut& c=Cuts::OPEN) : ParticleFinder(c), _decaymode(decaymode), _emu_from_prompt_tau(emu_from_prompt_tau), _include_hadronic_taus(include_hadronic_taus) { } /// Constructor taking decay mode details (and an optional cuts object) PartonicTops(DecayMode decaymode, const Cut& c, bool emu_from_prompt_tau=true, bool include_hadronic_taus=false) : ParticleFinder(c), _decaymode(decaymode), _emu_from_prompt_tau(emu_from_prompt_tau), _include_hadronic_taus(include_hadronic_taus) { } /// Clone on the heap. DEFAULT_RIVET_PROJ_CLONE(PartonicTops); //@} /// Access to the found partonic tops const Particles& tops() const { return _theParticles; } /// Clear the projection void clear() { _theParticles.clear(); } protected: /// Apply the projection on the supplied event. void project(const Event& event) { // Find partonic tops _theParticles = filter_select(event.allParticles(_cuts), lastParticleWith(isTop)); // Filtering by decay mode if (_decaymode != DecayMode::ALL) { const auto fn = [&](const Particle& t) { const Particles descendants = t.allDescendants(); const bool prompt_e = any(descendants, [&](const Particle& p){ return p.abspid() == PID::ELECTRON && p.isPrompt(_emu_from_prompt_tau) && !p.hasAncestor(PID::PHOTON, false); }); const bool prompt_mu = any(descendants, [&](const Particle& p){ return p.abspid() == PID::MUON && p.isPrompt(_emu_from_prompt_tau) && !p.hasAncestor(PID::PHOTON, false); }); if (prompt_e && (_decaymode == DecayMode::ELECTRON || _decaymode == DecayMode::E_MU || _decaymode == DecayMode::E_MU_TAU)) return true; if (prompt_mu && (_decaymode == DecayMode::MUON || _decaymode == DecayMode::E_MU || _decaymode == DecayMode::E_MU_TAU)) return true; const bool prompt_tau = any(descendants, [&](const Particle& p){ return p.abspid() == PID::TAU && p.isPrompt() && !p.hasAncestor(PID::PHOTON, false); }); const bool prompt_hadronic_tau = any(descendants, [&](const Particle& p){ return p.abspid() == PID::TAU && p.isPrompt() && !p.hasAncestor(PID::PHOTON, false) && none(p.children(), isChargedLepton); }); if (prompt_tau && (_decaymode == DecayMode::TAU || _decaymode == DecayMode::E_MU_TAU)) return (_include_hadronic_taus || !prompt_hadronic_tau); if (_decaymode == DecayMode::HADRONIC && (!prompt_e && !prompt_mu && (!prompt_tau || (_include_hadronic_taus && prompt_hadronic_tau)))) return true; //< logical hairiness... return false; }; ifilter_select(_theParticles, fn); } } /// Compare projections. - int compare(const Projection& p) const { + CmpState compare(const Projection& p) const { const PartonicTops& other = dynamic_cast(p); return cmp(_cuts, other._cuts) || cmp(_decaymode, other._decaymode) || cmp(_emu_from_prompt_tau, other._emu_from_prompt_tau) || cmp(_include_hadronic_taus, other._include_hadronic_taus); } private: DecayMode _decaymode; bool _emu_from_prompt_tau, _include_hadronic_taus; }; } #endif diff --git a/include/Rivet/Projections/PrimaryHadrons.hh b/include/Rivet/Projections/PrimaryHadrons.hh --- a/include/Rivet/Projections/PrimaryHadrons.hh +++ b/include/Rivet/Projections/PrimaryHadrons.hh @@ -1,55 +1,55 @@ // -*- C++ -*- #ifndef RIVET_PrimaryHadrons_HH #define RIVET_PrimaryHadrons_HH #include "Rivet/Projections/FinalState.hh" #include "Rivet/Projections/UnstableFinalState.hh" #include "Rivet/Particle.hh" #include "Rivet/Event.hh" namespace Rivet { /// @brief Project out the first hadrons from hadronisation. /// /// @todo Also be able to return taus? Prefer a separate tau finder. /// @todo This assumes that the primary hadrons are unstable... should we also look for stable primary hadrons? class PrimaryHadrons : public FinalState { public: /// @name Constructors and destructors. //@{ /// Constructor with cuts argument PrimaryHadrons(const Cut& c=Cuts::open()) { setName("PrimaryHadrons"); addProjection(UnstableFinalState(c), "UFS"); } /// Constructor with specification of the minimum and maximum pseudorapidity /// \f$ \eta \f$ and the min \f$ p_T \f$ (in GeV). PrimaryHadrons(double mineta, double maxeta, double minpt=0.0*GeV) { setName("PrimaryHadrons"); addProjection(UnstableFinalState(Cuts::etaIn(mineta, maxeta) && Cuts::pT > minpt), "UFS"); } /// Clone on the heap. DEFAULT_RIVET_PROJ_CLONE(PrimaryHadrons); //@} /// Apply the projection to the event. virtual void project(const Event& e); // /// Compare projections. - // int compare(const Projection& p) const; + // CmpState compare(const Projection& p) const; }; } #endif diff --git a/include/Rivet/Projections/PromptFinalState.hh b/include/Rivet/Projections/PromptFinalState.hh --- a/include/Rivet/Projections/PromptFinalState.hh +++ b/include/Rivet/Projections/PromptFinalState.hh @@ -1,67 +1,67 @@ // -*- C++ -*- #ifndef RIVET_PromptFinalState_HH #define RIVET_PromptFinalState_HH #include "Rivet/Projections/FinalState.hh" namespace Rivet { /// @brief Find final state particles directly connected to the hard process. /// /// The definition of "prompt" used in Rivet is that from high-scale physics, i.e. /// particles directly connected to the hard process in an interaction, regardless /// of realistic reconstructibility of displaced vertices, etc. By construction /// hadrons cannot be considered prompt as they will be colour connected to other /// parts of the event through non-perturbative effects: this projection can /// return electrons, muons, photons, and exotic particles which do not have a /// hadron in their post-hadronization ancestor chain. Flags exist to choose /// whether intermediate tau or muon decays invalidate a particle's promptness. /// /// @todo Decide how to treat brem photons off prompt leptons -- are they also prompt? "Decay" does not change the lepton PID... class PromptFinalState : public FinalState { public: /// @name Constructors //@{ /// Constructor without cuts PromptFinalState(bool accepttaudecays=false, bool acceptmudecays=false); /// Constructor from a Cut PromptFinalState(const Cut& c, bool accepttaudecays=false, bool acceptmudecays=false); // Constructor from a FinalState PromptFinalState(const FinalState& fsp, bool accepttaudecays=false, bool acceptmudecays=false); // /// Constructor from a Cut and optional FinalState. // PromptFinalState(const Cut& c, const FinalState& fsp=FinalState(), bool accepttaudecays, bool acceptmudecays); /// Clone on the heap. DEFAULT_RIVET_PROJ_CLONE(PromptFinalState); //@} /// Accept leptons from decays of prompt muons as themselves being prompt? void acceptMuonDecays(bool acc=true) { _acceptMuDecays = acc; } /// Accept leptons from decays of prompt taus as themselves being prompt? void acceptTauDecays(bool acc=true) { _acceptTauDecays = acc; } /// Apply the projection on the supplied event. void project(const Event& e); /// Compare projections. - int compare(const Projection& p) const; + CmpState compare(const Projection& p) const; private: bool _acceptMuDecays, _acceptTauDecays; }; } #endif diff --git a/include/Rivet/Projections/SmearedJets.hh b/include/Rivet/Projections/SmearedJets.hh --- a/include/Rivet/Projections/SmearedJets.hh +++ b/include/Rivet/Projections/SmearedJets.hh @@ -1,196 +1,196 @@ // -*- C++ -*- #ifndef RIVET_SmearedJets_HH #define RIVET_SmearedJets_HH #include "Rivet/Jet.hh" #include "Rivet/Particle.hh" #include "Rivet/Projection.hh" #include "Rivet/Projections/JetAlg.hh" #include "Rivet/Tools/SmearingFunctions.hh" #include namespace Rivet { // // Recursive variadic template arg decoding // namespace { // template // vector& toEffSmearFns(vector& v, const T& t) { // v.push_back(JetEffSmearFn(t)); // return v; // } // template // vector& toEffSmearFns(vector& v, const T& first, ARGS... args) { // v.push_back(JetEffSmearFn(first)); // toEffSmearFns(v, args...); // return v; // } // } /// Wrapper projection for smearing {@link Jet}s with detector resolutions and efficiencies class SmearedJets : public JetAlg { public: /// @name Constructors etc. //@{ /// @brief Constructor with a reco efficiency and optional tagging efficiencies SmearedJets(const JetAlg& ja, const JetSmearFn& smearFn, const JetEffFn& bTagEffFn=JET_BTAG_PERFECT, const JetEffFn& cTagEffFn=JET_CTAG_PERFECT) : SmearedJets(ja, vector{smearFn}, bTagEffFn, cTagEffFn) { } /// @brief Constructor with tagging efficiencies, plus an ordered init-list of efficiency and smearing functions SmearedJets(const JetAlg& ja, const JetEffFn& bTagEffFn=JET_BTAG_PERFECT, const JetEffFn& cTagEffFn=JET_CTAG_PERFECT, const initializer_list& effSmearFns={}) : SmearedJets(ja, vector{effSmearFns}, bTagEffFn, cTagEffFn) { } /// @brief Constructor with tagging efficiencies, plus an ordered vector of efficiency and smearing functions SmearedJets(const JetAlg& ja, const JetEffFn& bTagEffFn=JET_BTAG_PERFECT, const JetEffFn& cTagEffFn=JET_CTAG_PERFECT, const vector& effSmearFns={}) : SmearedJets(ja, effSmearFns, bTagEffFn, cTagEffFn) { } /// @brief Constructor with an ordered init-list of efficiency and smearing functions, plus optional tagging efficiencies SmearedJets(const JetAlg& ja, const initializer_list& effSmearFns, const JetEffFn& bTagEffFn=JET_BTAG_PERFECT, const JetEffFn& cTagEffFn=JET_CTAG_PERFECT) : SmearedJets(ja, vector{effSmearFns}, bTagEffFn, cTagEffFn) { } /// @brief Constructor with an ordered vector of efficiency and smearing functions, plus optional tagging efficiencies SmearedJets(const JetAlg& ja, const vector& effSmearFns, const JetEffFn& bTagEffFn=JET_BTAG_PERFECT, const JetEffFn& cTagEffFn=JET_CTAG_PERFECT) : _detFns(effSmearFns), _bTagEffFn(bTagEffFn), _cTagEffFn(cTagEffFn) { setName("SmearedJets"); addProjection(ja, "TruthJets"); } /// @brief Constructor with trailing efficiency arg /// @deprecated Use the version with pair-smearing list as 2nd argument SmearedJets(const JetAlg& ja, const JetSmearFn& smearFn, const JetEffFn& bTagEffFn, const JetEffFn& cTagEffFn, const JetEffFn& jetEffFn) : SmearedJets(ja, {jetEffFn,smearFn}, bTagEffFn, cTagEffFn) { } /// @todo How to include tagging effs? /// @todo Variadic eff/smear fn list? /// @todo Add a trailing Cut arg cf. SmearedParticles? -- wrap into an eff function /// Clone on the heap. DEFAULT_RIVET_PROJ_CLONE(SmearedJets); //@} /// Compare to another SmearedJets - int compare(const Projection& p) const { + CmpState compare(const Projection& p) const { // Compare truth jets definitions - const int teq = mkPCmp(p, "TruthJets"); - if (teq != EQUIVALENT) return teq; + const CmpState teq = mkPCmp(p, "TruthJets"); + if (teq != CmpState::EQ) return teq; // Compare lists of detector functions const SmearedJets& other = dynamic_cast(p); - const int nfeq = cmp(_detFns.size(), other._detFns.size()); - if (nfeq != EQUIVALENT) return nfeq; + const CmpState nfeq = cmp(_detFns.size(), other._detFns.size()); + if (nfeq != CmpState::EQ) return nfeq; for (size_t i = 0; i < _detFns.size(); ++i) { - const int feq = _detFns[i].cmp(other._detFns[i]); - if (feq != EQUIVALENT) return feq; + const CmpState feq = _detFns[i].cmp(other._detFns[i]); + if (feq != CmpState::EQ) return feq; } // If we got this far, we're equal - return EQUIVALENT; + return CmpState::EQ; } /// Perform the jet finding & smearing calculation void project(const Event& e) { // Copying and filtering const Jets& truthjets = apply(e, "TruthJets").jetsByPt(); _recojets.clear(); _recojets.reserve(truthjets.size()); // Apply jet smearing and efficiency transforms for (const Jet& j : truthjets) { Jet jdet = j; bool keep = true; MSG_DEBUG("Truth jet: " << "mom=" << jdet.mom()/GeV << " GeV, pT=" << jdet.pT()/GeV << ", eta=" << jdet.eta()); for (const JetEffSmearFn& fn : _detFns) { double jeff = -1; std::tie(jdet, jeff) = fn(jdet); // smear & eff // Re-add constituents & tags if (we assume accidentally) they were lost by the smearing function if (jdet.particles().empty() && !j.particles().empty()) jdet.particles() = j.particles(); if (jdet.tags().empty() && !j.tags().empty()) jdet.tags() = j.tags(); MSG_DEBUG(" ->" << "mom=" << jdet.mom()/GeV << " GeV, pT=" << jdet.pT()/GeV << ", eta=" << jdet.eta()); // MSG_DEBUG("New det jet: " // << "mom=" << jdet.mom()/GeV << " GeV, pT=" << jdet.pT()/GeV << ", eta=" << jdet.eta() // << ", b-tag=" << boolalpha << jdet.bTagged() // << ", c-tag=" << boolalpha << jdet.cTagged() // << " : eff=" << 100*jeff << "%"); if (jeff <= 0) { keep = false; break; } //< no need to roll expensive dice (and we deal with -ve probabilities, just in case) if (jeff < 1 && rand01() > jeff) { keep = false; break; } //< roll dice (and deal with >1 probabilities, just in case) } if (keep) _recojets.push_back(jdet); } // Apply tagging efficiencies, using smeared kinematics as input to the tag eff functions for (Jet& j : _recojets) { // Decide whether or not there should be a b-tag on this jet const double beff = _bTagEffFn ? _bTagEffFn(j) : j.bTagged(); const bool btag = beff == 1 || (beff != 0 && rand01() < beff); // Remove b-tags if needed, and add a dummy one if needed if (!btag && j.bTagged()) j.tags().erase(std::remove_if(j.tags().begin(), j.tags().end(), hasBottom), j.tags().end()); if (btag && !j.bTagged()) j.tags().push_back(Particle(PID::BQUARK, j.mom())); ///< @todo Or could use the/an actual clustered b-quark momentum? // Decide whether or not there should be a c-tag on this jet const double ceff = _cTagEffFn ? _cTagEffFn(j) : j.cTagged(); const bool ctag = ceff == 1 || (ceff != 0 && rand01() < beff); // Remove c-tags if needed, and add a dummy one if needed if (!ctag && j.cTagged()) j.tags().erase(std::remove_if(j.tags().begin(), j.tags().end(), hasCharm), j.tags().end()); if (ctag && !j.cTagged()) j.tags().push_back(Particle(PID::CQUARK, j.mom())); ///< @todo As above... ? } } /// Return the full jet list for the JetAlg methods to use Jets _jets() const { return _recojets; } /// Reset the projection. Smearing functions will be unchanged. void reset() { _recojets.clear(); } private: /// Smeared jets Jets _recojets; /// Stored efficiency & smearing functions vector _detFns; /// Stored efficiency functions JetEffFn _bTagEffFn, _cTagEffFn; }; } #endif diff --git a/include/Rivet/Projections/SmearedMET.hh b/include/Rivet/Projections/SmearedMET.hh --- a/include/Rivet/Projections/SmearedMET.hh +++ b/include/Rivet/Projections/SmearedMET.hh @@ -1,130 +1,130 @@ // -*- C++ -*- #ifndef RIVET_SmearedMET_HH #define RIVET_SmearedMET_HH #include "Rivet/Projection.hh" #include "Rivet/Projections/MissingMomentum.hh" #include "Rivet/Tools/SmearingFunctions.hh" #include namespace Rivet { /// Wrapper projection for smearing missing (transverse) energy/momentum with detector resolutions class SmearedMET : public Projection { public: /// @name Constructors etc. //@{ /// @brief Constructor from a MissingMomentum projection and a smearing function /// /// Smearing function maps a 3-vector MET and scalar SET to a new MET 3-vector: f(V3, double) -> V3 template SmearedMET(const MissingMomentum& mm, const V2VFN& metSmearFn) : _metSmearFn(metSmearFn) { setName("SmearedMET"); addProjection(mm, "TruthMET"); } /// @brief Constructor from a Cut (on the particles used to determine missing momentum) and a smearing function template SmearedMET(const V2VFN& metSmearFn, const Cut& cut) : _metSmearFn(metSmearFn) { setName("SmearedMET"); addProjection(MissingMomentum(cut), "TruthMET"); } /// Clone on the heap. DEFAULT_RIVET_PROJ_CLONE(SmearedMET); //@} /// Compare to another SmearedMET - int compare(const Projection& p) const { + CmpState compare(const Projection& p) const { const SmearedMET& other = dynamic_cast(p); if (get_address(_metSmearFn) == 0) return cmp((size_t)this, (size_t)&p); MSG_TRACE("Smear hashes = " << get_address(_metSmearFn) << "," << get_address(other._metSmearFn)); return mkPCmp(other, "TruthMET") || cmp(get_address(_metSmearFn), get_address(other._metSmearFn)); } /// Perform the MET finding & smearing calculation void project(const Event& e) { const auto& mm = apply(e, "TruthMET"); _vet = mm.vectorEt(); if (_metSmearFn) _vet = _metSmearFn(_vet, mm.scalarEt()); //< smearing } /// @name Transverse momentum functions /// @note This may be what you want, even if the paper calls it "missing Et"! /// @todo Move into a common base class for MissingMomentum and SmearedMET -- MomentumBalance, METFinder? //@{ /// The vector-summed visible transverse momentum in the event, as a 3-vector with z=0 /// @note Reverse this vector with operator- to get the missing pT vector. /// @todo Currently equivalent to vectorEt const Vector3& vectorPt() const { return vectorEt(); } /// Convenience vector MPT function const Vector3 vectorMissingPt() const { return -vectorPt(); } // Alias const Vector3 vectorMPT() const { return vectorMissingPt(); } /// The vector-summed missing transverse momentum in the event. double missingPt() const { return vectorPt().mod(); } // /// Alias for missingPt // double mpt() const { return missingPt(); } // /// The scalar-summed visible transverse momentum in the event. // double scalarPt() const { return _spt; } // // /// Alias for scalarPt // // double spt() const { return scalarPt(); } //@} /// @name Transverse energy functions /// @warning Despite the common names "MET" and "SET", what's often meant is the pT functions above! /// @todo Move into a common base class for MissingMomentum and SmearedMET -- MomentumBalance, METFinder? //@{ /// The vector-summed visible transverse energy in the event, as a 3-vector with z=0 /// @note Reverse this vector with operator- to get the missing ET vector. const Vector3& vectorEt() const { return _vet; } /// Convenience vector MET function const Vector3 vectorMissingEt() const { return -vectorEt(); } // Alias const Vector3 vectorMET() const { return vectorMissingEt(); } /// The vector-summed missing transverse energy in the event. double missingEt() const { return vectorEt().mod(); } /// Alias for missingEt double met() const { return missingEt(); } //@} /// Reset the projection. Smearing functions will be unchanged. void reset() { } private: Vector3 _vet; /// Stored smearing function std::function _metSmearFn; }; } #endif diff --git a/include/Rivet/Projections/SmearedParticles.hh b/include/Rivet/Projections/SmearedParticles.hh --- a/include/Rivet/Projections/SmearedParticles.hh +++ b/include/Rivet/Projections/SmearedParticles.hh @@ -1,173 +1,173 @@ // -*- C++ -*- #ifndef RIVET_SmearedParticles_HH #define RIVET_SmearedParticles_HH #include "Rivet/Particle.hh" #include "Rivet/Projection.hh" #include "Rivet/Projections/ParticleFinder.hh" #include "Rivet/Tools/SmearingFunctions.hh" namespace Rivet { // Recursive variadic template arg decoding namespace { template vector& toEffSmearFns(vector& v, const T& t) { v.push_back(ParticleEffSmearFn(t)); return v; } template vector& toEffSmearFns(vector& v, const T& first, ARGS... args) { v.push_back(ParticleEffSmearFn(first)); toEffSmearFns(v, args...); return v; } } /// Wrapper projection for smearing {@link Jet}s with detector resolutions and efficiencies class SmearedParticles : public ParticleFinder { public: /// @name Constructors etc. //@{ /// @brief Constructor with const efficiency SmearedParticles(const ParticleFinder& pf, double eff, const Cut& c=Cuts::open()) : SmearedParticles(pf, {{eff}}, c) { } /// @brief Constructor with an efficiency function SmearedParticles(const ParticleFinder& pf, const ParticleEffFn& effFn, const Cut& c=Cuts::open()) : SmearedParticles(pf, {{effFn}}, c) { } /// @brief Constructor with const efficiency followed by a smearing function SmearedParticles(const ParticleFinder& pf, double eff, const ParticleSmearFn& smearFn, const Cut& c=Cuts::open()) : SmearedParticles(pf, {eff, smearFn}, c) { } /// @brief Constructor with a smearing function followed by const efficiency SmearedParticles(const ParticleFinder& pf, const ParticleSmearFn& smearFn, double eff, const Cut& c=Cuts::open()) : SmearedParticles(pf, {smearFn, eff}, c) { } /// @brief Constructor with an efficiency function followed by a smearing function SmearedParticles(const ParticleFinder& pf, const ParticleEffFn& effFn, const ParticleSmearFn& smearFn, const Cut& c=Cuts::open()) : SmearedParticles(pf, {effFn, smearFn}, c) { } /// @brief Constructor with a smearing function followed by an efficiency function SmearedParticles(const ParticleFinder& pf, const ParticleSmearFn& smearFn, const ParticleEffFn& effFn, const Cut& c=Cuts::open()) : SmearedParticles(pf, {smearFn, effFn}, c) { } /// @brief Constructor with an ordered list of efficiency and/or smearing functions SmearedParticles(const ParticleFinder& pf, const vector& effSmearFns, const Cut& c=Cuts::open()) : ParticleFinder(c), _detFns(effSmearFns) { setName("SmearedParticles"); addProjection(pf, "TruthParticles"); } /// @brief Constructor with an ordered list of efficiency and/or smearing functions SmearedParticles(const ParticleFinder& pf, const initializer_list& effSmearFns, const Cut& c=Cuts::open()) : SmearedParticles(pf, vector{effSmearFns}, c) { } /// @brief Constructor with a variadic ordered list of efficiency and smearing function args /// @note The Cut must be provided *before* the eff/smearing functions /// @todo Wouldn't it be nice if the Cut could also go *after* the parameter pack? template SmearedParticles(const ParticleFinder& pf, const Cut& c, ARGS... effSmearFns) : SmearedParticles(pf, toEffSmearFns(_detFns, effSmearFns...), c) { } /// Clone on the heap. DEFAULT_RIVET_PROJ_CLONE(SmearedParticles); //@} /// Compare to another SmearedParticles - int compare(const Projection& p) const { + CmpState compare(const Projection& p) const { const SmearedParticles& other = dynamic_cast(p); // Compare truth particles definitions - const int teq = mkPCmp(other, "TruthParticles"); - if (teq != EQUIVALENT) return teq; + const CmpState teq = mkPCmp(other, "TruthParticles"); + if (teq != CmpState::EQ) return teq; // Compare lists of detector functions - const int nfeq = cmp(_detFns.size(), other._detFns.size()); - if (nfeq != EQUIVALENT) return nfeq; + const CmpState nfeq = cmp(_detFns.size(), other._detFns.size()); + if (nfeq != CmpState::EQ) return nfeq; for (size_t i = 0; i < _detFns.size(); ++i) { - const int feq = _detFns[i].cmp(other._detFns[i]); - if (feq != EQUIVALENT) return feq; + const CmpState feq = _detFns[i].cmp(other._detFns[i]); + if (feq != CmpState::EQ) return feq; } // If we got this far, we're equal - return EQUIVALENT; + return CmpState::EQ; } /// Perform the particle finding & smearing calculation void project(const Event& e) { // Copying and filtering const Particles& truthparticles = apply(e, "TruthParticles").particlesByPt(); _theParticles.clear(); _theParticles.reserve(truthparticles.size()); for (const Particle& p : truthparticles) { Particle pdet = p; double peff = -1; bool keep = true; for (const ParticleEffSmearFn& fn : _detFns) { std::tie(pdet, peff) = fn(pdet); // smear & eff MSG_DEBUG("New det particle: pid=" << pdet.pid() << ", mom=" << pdet.mom()/GeV << " GeV, " << "pT=" << pdet.pT()/GeV << ", eta=" << pdet.eta() << " : eff=" << 100*peff << "%"); if (peff <= 0) { keep = false; break; } //< no need to roll expensive dice (and we deal with -ve probabilities, just in case) if (peff < 1 && rand01() > peff) { keep = false; break; } //< roll dice (and deal with >1 probabilities, just in case) } if (keep) { pdet.addConstituent(p); //< record where the smearing was built from _theParticles.push_back(pdet); } } } /// Reset the projection. Smearing functions will be unchanged. void reset() { _theParticles.clear(); } private: /// Stored efficiency & smearing functions vector _detFns; }; } #endif diff --git a/include/Rivet/Projections/Sphericity.hh b/include/Rivet/Projections/Sphericity.hh --- a/include/Rivet/Projections/Sphericity.hh +++ b/include/Rivet/Projections/Sphericity.hh @@ -1,164 +1,164 @@ // -*- C++ -*- #ifndef RIVET_Sphericity_HH #define RIVET_Sphericity_HH #include "Rivet/Projection.hh" #include "Rivet/Projections/AxesDefinition.hh" #include "Rivet/Projections/FinalState.hh" #include "Rivet/Event.hh" #include "Rivet/Jet.fhh" namespace Rivet { /// @brief Calculate the sphericity event shape. /// /// The sphericity tensor (or quadratic momentum tensor) is defined as /// \f[ /// S^{\alpha \beta} = \frac{\sum_i p_i^\alpha p_i^\beta}{\sum_i |\mathbf{p}_i|^2} /// \f], /// where the Greek indices are spatial components and the Latin indices are used /// for sums over particles. From this, the sphericity, aplanarity and planarity can be /// calculated by combinations of eigenvalues. /// /// Defining the three eigenvalues /// \f$ \lambda_1 \ge \lambda_2 \ge \lambda_3 \f$, with \f$ \lambda_1 + \lambda_2 + \lambda_3 = 1 \f$, /// the sphericity is /// \f[ /// S = \frac{3}{2} (\lambda_2 + \lambda_3) /// \f] /// /// The aplanarity is \f$ A = \frac{3}{2}\lambda_3 \f$ and the planarity /// is \f$ P = \frac{2}{3}(S-2A) = \lambda_2 - \lambda_3 \f$. The eigenvectors define a /// set of spatial axes comparable with the thrust axes, but more sensitive to /// high momentum particles due to the quadratic sensitivity of the tensor to /// the particle momenta. /// /// Since the sphericity is quadratic in the particle momenta, it is not an /// infrared safe observable in perturbative QCD. This can be fixed by adding /// a regularizing power of \f$r\f$ to the definition: /// \f[ /// S^{\alpha \beta} = /// \frac{\sum_i |\mathbf{p}_i|^{r-2} p_i^\alpha p_i^\beta} /// {\sum_i |\mathbf{p}_i|^r} /// \f] /// /// \f$r\f$ is available as a constructor argument on this class and will be /// taken into account by the Cmp operation, so a single analysis /// can use several sphericity projections with different \f$r\f$ values without /// fear of a clash. /// class Sphericity : public AxesDefinition { public: /// @name Constructors etc. //@{ /// Constructor Sphericity(double rparam=2.0): _regparam(rparam){} Sphericity(const FinalState& fsp, double rparam=2.0); /// Clone on the heap. DEFAULT_RIVET_PROJ_CLONE(Sphericity); //@} protected: /// Perform the projection on the Event void project(const Event& e); /// Compare with other projections - int compare(const Projection& p) const; + CmpState compare(const Projection& p) const; public: /// Reset the projection void clear(); /// @name Access the event shapes by name //@{ /// Sphericity double sphericity() const { return 3.0 / 2.0 * (lambda2() + lambda3()); } /// Transverse sphericity double transSphericity() const { return 2.0 * lambda2() / ( lambda1() + lambda2() ); } /// Planarity double planarity() const { return 2 * (sphericity() - 2 * aplanarity()) / 3.0; } /// Aplanarity double aplanarity() const { return 3 / 2.0 * lambda3(); } //@} /// @name Access the sphericity basis vectors //@{ /// Sphericity axis const Vector3& sphericityAxis() const { return _sphAxes[0]; } /// Sphericity major axis const Vector3& sphericityMajorAxis() const { return _sphAxes[1]; } /// Sphericity minor axis const Vector3& sphericityMinorAxis() const { return _sphAxes[2]; } //@} /// @name AxesDefinition axis accessors //@{ const Vector3& axis1() const { return sphericityAxis(); } const Vector3& axis2() const { return sphericityMajorAxis(); } const Vector3& axis3() const { return sphericityMinorAxis(); } //@} /// @name Access the momentum tensor eigenvalues //@{ double lambda1() const { return _lambdas[0]; } double lambda2() const { return _lambdas[1]; } double lambda3() const { return _lambdas[2]; } //@} Vector3 mkEigenVector(Matrix3 A, const double &lambda); /// @name Direct methods /// Ways to do the calculation directly, without engaging the caching system //@{ /// Manually calculate the sphericity, without engaging the caching system void calc(const FinalState& fs); /// Manually calculate the sphericity, without engaging the caching system void calc(const Particles& particles); /// Manually calculate the sphericity, without engaging the caching system void calc(const Jets& jets); /// Manually calculate the sphericity, without engaging the caching system void calc(const vector& momenta); /// @brief Manually calculate the sphericity, without engaging the caching system /// /// This one actually does the calculation void calc(const vector& momenta); //@} private: /// Eigenvalues. vector _lambdas; /// Sphericity axes. vector _sphAxes; /// Regularizing parameter, used to force infra-red safety. const double _regparam; }; } #endif diff --git a/include/Rivet/Projections/Spherocity.hh b/include/Rivet/Projections/Spherocity.hh --- a/include/Rivet/Projections/Spherocity.hh +++ b/include/Rivet/Projections/Spherocity.hh @@ -1,134 +1,134 @@ // -*- C++ -*- #ifndef RIVET_Spherocity_HH #define RIVET_Spherocity_HH #include "Rivet/Projection.hh" #include "Rivet/Projections/AxesDefinition.hh" #include "Rivet/Projections/FinalState.hh" #include "Rivet/Event.hh" namespace Rivet { /// @brief Get the transverse spherocity scalars for hadron-colliders. /// /// @author Holger Schulz /// /// The scalar (minimum) transverse spherocity is defined as /// \f[ /// S = \frac{\pi^2}{4} \mathrm{min}_{\vec{n}_\perp} \left( \frac{\sum_i \left|\vec{p}_{\perp,i} \times \vec{n}_\perp \right|}{\sum_i |\vec{p}_{\perp,i}|} \right)^2 /// \f], /// with the direction of the unit vector \f$ \vec{n_\perp} \f$ which minimises \f$ T \f$ /// being identified as the spherocity axis. The unit vector which maximises the spherocity /// scalar in the plane perpendicular to \f$ \vec{n} \f$ is the "spherocity major" /// direction, and the vector perpendicular to both the spherocity and spherocity major directions /// is the spherocity minor. Both the major and minor directions have associated spherocity /// scalars. /// /// Care must be taken in the case of Drell-Yan processes - there we should use the /// newly proposed observable \f$ a_T \f$. class Spherocity : public AxesDefinition { public: // Default Constructor Spherocity() {} /// Constructor. Spherocity(const FinalState& fsp) : _calculatedSpherocity(false) { setName("Spherocity"); addProjection(fsp, "FS"); } /// Clone on the heap. DEFAULT_RIVET_PROJ_CLONE(Spherocity); protected: /// Perform the projection on the Event void project(const Event& e) { const vector ps = applyProjection(e, "FS").particles(); calc(ps); } /// Compare projections - int compare(const Projection& p) const { + CmpState compare(const Projection& p) const { return mkNamedPCmp(p, "FS"); } public: /// @name Spherocity scalar accessors //@{ /// The spherocity scalar, \f$ S \f$, (minimum spherocity). double spherocity() const { return _spherocities[0]; } //@} /// @name Spherocity axis accessors //@{ /// The spherocity axis. const Vector3& spherocityAxis() const { return _spherocityAxes[0]; } /// The spherocity major axis (axis of max spherocity perpendicular to spherocity axis). const Vector3& spherocityMajorAxis() const { return _spherocityAxes[1]; } /// The spherocity minor axis (axis perpendicular to spherocity and spherocity major). const Vector3& spherocityMinorAxis() const { return _spherocityAxes[2]; } //@} /// @name AxesDefinition axis accessors. //@{ const Vector3& axis1() const { return spherocityAxis(); } const Vector3& axis2() const { return spherocityMajorAxis(); } const Vector3& axis3() const { return spherocityMinorAxis(); } ///@} public: /// @name Direct methods /// Ways to do the calculation directly, without engaging the caching system //@{ /// Manually calculate the spherocity, without engaging the caching system void calc(const FinalState& fs); /// Manually calculate the spherocity, without engaging the caching system void calc(const vector& fsparticles); /// Manually calculate the spherocity, without engaging the caching system void calc(const vector& fsmomenta); /// Manually calculate the spherocity, without engaging the caching system void calc(const vector& threeMomenta); //@} private: /// The spherocity scalars. vector _spherocities; /// The spherocity axes. vector _spherocityAxes; /// Caching flag to avoid costly recalculations. bool _calculatedSpherocity; private: /// Explicitly calculate the spherocity values. void _calcSpherocity(const vector& fsmomenta); }; } #endif diff --git a/include/Rivet/Projections/TauFinder.hh b/include/Rivet/Projections/TauFinder.hh --- a/include/Rivet/Projections/TauFinder.hh +++ b/include/Rivet/Projections/TauFinder.hh @@ -1,72 +1,72 @@ #ifndef RIVET_TauFinder_HH #define RIVET_TauFinder_HH #include "Rivet/Projections/FinalState.hh" #include "Rivet/Projections/UnstableFinalState.hh" namespace Rivet { /// @brief Convenience finder of unstable taus /// /// @todo Convert to a general ParticleFinder, since it's not a true final state? Needs some care... class TauFinder : public FinalState { public: enum class DecayMode { ANY = 0, ALL = 0, LEPTONIC, HADRONIC }; static bool isHadronic(const Particle& tau) { assert(tau.abspid() == PID::TAU); return any(tau.stableDescendants(), isHadron); } static bool isLeptonic(const Particle& tau) { return !isHadronic(tau); } TauFinder(DecayMode decaymode, const Cut& cut=Cuts::open()) { /// @todo What about directness/promptness? setName("TauFinder"); _decmode = decaymode; addProjection(UnstableFinalState(cut), "UFS"); } /// Clone on the heap. DEFAULT_RIVET_PROJ_CLONE(TauFinder); const Particles& taus() const { return _theParticles; } protected: /// Apply the projection on the supplied event. void project(const Event& e); /// Compare with other projections. - virtual int compare(const Projection& p) const; + virtual CmpState compare(const Projection& p) const; private: /// The decaymode enum DecayMode _decmode; }; /// @todo Make this the canonical name in future using Taus = TauFinder; } #endif diff --git a/include/Rivet/Projections/Thrust.hh b/include/Rivet/Projections/Thrust.hh --- a/include/Rivet/Projections/Thrust.hh +++ b/include/Rivet/Projections/Thrust.hh @@ -1,140 +1,140 @@ // -*- C++ -*- #ifndef RIVET_Thrust_HH #define RIVET_Thrust_HH #include "Rivet/Projection.hh" #include "Rivet/Projections/AxesDefinition.hh" #include "Rivet/Projections/FinalState.hh" #include "Rivet/Event.hh" namespace Rivet { /** @brief Get the e+ e- thrust basis and the thrust, thrust major and thrust minor scalars. @author Andy Buckley The scalar (maximum) thrust is defined as \f[ T = \mathrm{max}_{\vec{n}} \frac{\sum_i \left|\vec{p}_i \cdot \vec{n} \right|}{\sum_i |\vec{p}_i|} \f], with the direction of the unit vector \f$ \vec{n} \f$ which maximises \f$ T \f$ being identified as the thrust axis. The unit vector which maximises the thrust scalar in the plane perpendicular to \f$ \vec{n} \f$ is the "thrust major" direction, and the vector perpendicular to both the thrust and thrust major directions is the thrust minor. Both the major and minor directions have associated thrust scalars. Thrust calculations have particularly simple forms for less than 4 particles, and in those cases this projection is computationally minimal. For 4 or more particles, a more general calculation must be carried out, based on the Brandt/Dahmen method from Z. Phys. C1 (1978). While a polynomial improvement on the exponential scaling of the naive method, this algorithm scales asymptotically as \f$ \mathcal{O}\left( n^3 \right) \f$. Be aware that the thrust may easily be the most computationally demanding projection in Rivet for large events! The Rivet implementation of thrust is based heavily on Stefan Gieseke's Herwig++ re-coding of the 'tasso' code from HERWIG. NB. special case with >= 4 coplanar particles will still fail. NB. Thrust assumes all momenta are in the CoM system: no explicit boost is performed. This can be dealt with by appropriate choice of the supplied FinalState. */ class Thrust : public AxesDefinition { public: /// Constructor. Thrust() {} Thrust(const FinalState& fsp) { setName("Thrust"); addProjection(fsp, "FS"); } /// Clone on the heap. DEFAULT_RIVET_PROJ_CLONE(Thrust); protected: /// Perform the projection on the Event void project(const Event& e) { const vector ps = applyProjection(e, "FS").particles(); calc(ps); } /// Compare projections - int compare(const Projection& p) const { + CmpState compare(const Projection& p) const { return mkNamedPCmp(p, "FS"); } public: ///@{ Thrust scalar accessors /// The thrust scalar, \f$ T \f$, (maximum thrust). double thrust() const { return _thrusts[0]; } /// The thrust major scalar, \f$ M \f$, (thrust along thrust major axis). double thrustMajor() const { return _thrusts[1]; } /// The thrust minor scalar, \f$ m \f$, (thrust along thrust minor axis). double thrustMinor() const { return _thrusts[2]; } /// The oblateness, \f$ O = M - m \f$ . double oblateness() const { return _thrusts[1] - _thrusts[2]; } ///@} ///@{ Thrust axis accessors /// The thrust axis. const Vector3& thrustAxis() const { return _thrustAxes[0]; } /// The thrust major axis (axis of max thrust perpendicular to thrust axis). const Vector3& thrustMajorAxis() const { return _thrustAxes[1]; } /// The thrust minor axis (axis perpendicular to thrust and thrust major). const Vector3& thrustMinorAxis() const { return _thrustAxes[2]; } ///@} ///@{ AxesDefinition axis accessors. const Vector3& axis1() const { return thrustAxis(); } const Vector3& axis2() const { return thrustMajorAxis(); } const Vector3& axis3() const { return thrustMinorAxis(); } ///@} public: /// @name Direct methods /// Ways to do the calculation directly, without engaging the caching system //@{ /// Manually calculate the thrust, without engaging the caching system void calc(const FinalState& fs); /// Manually calculate the thrust, without engaging the caching system void calc(const vector& fsparticles); /// Manually calculate the thrust, without engaging the caching system void calc(const vector& fsmomenta); /// Manually calculate the thrust, without engaging the caching system void calc(const vector& threeMomenta); //@} private: /// The thrust scalars. vector _thrusts; /// The thrust axes. vector _thrustAxes; private: /// Explicitly calculate the thrust values. void _calcThrust(const vector& fsmomenta); }; } #endif diff --git a/include/Rivet/Projections/TriggerCDFRun0Run1.hh b/include/Rivet/Projections/TriggerCDFRun0Run1.hh --- a/include/Rivet/Projections/TriggerCDFRun0Run1.hh +++ b/include/Rivet/Projections/TriggerCDFRun0Run1.hh @@ -1,55 +1,55 @@ // -*- C++ -*- #ifndef RIVET_TriggerCDFRun0Run1_HH #define RIVET_TriggerCDFRun0Run1_HH #include "Rivet/Projection.hh" #include "Rivet/Event.hh" #include "Rivet/Particle.hh" #include "Rivet/Projections/Beam.hh" namespace Rivet { /// @brief Access to the min bias triggers used by CDF in Run 0 and Run 1 class TriggerCDFRun0Run1 : public Projection { public: /// Default constructor. TriggerCDFRun0Run1() { setName("TriggerCDFRun0Run1"); addProjection(ChargedFinalState(-5.9, 5.9), "CFS"); } /// Clone on the heap. DEFAULT_RIVET_PROJ_CLONE(TriggerCDFRun0Run1); /// The trigger result bool minBiasDecision() const { return _decision_mb; } /// Project on to the Event void project(const Event& evt); protected: /// Compare with other projections. - virtual int compare(const Projection&) const { - return EQUIVALENT; + virtual CmpState compare(const Projection&) const { + return CmpState::EQ; } private: /// The min bias trigger decision bool _decision_mb; }; } #endif diff --git a/include/Rivet/Projections/TriggerCDFRun2.hh b/include/Rivet/Projections/TriggerCDFRun2.hh --- a/include/Rivet/Projections/TriggerCDFRun2.hh +++ b/include/Rivet/Projections/TriggerCDFRun2.hh @@ -1,55 +1,55 @@ // -*- C++ -*- #ifndef RIVET_TriggerCDFRun2_HH #define RIVET_TriggerCDFRun2_HH #include "Rivet/Projection.hh" #include "Rivet/Event.hh" #include "Rivet/Particle.hh" #include "Rivet/Projections/Beam.hh" namespace Rivet { /// @brief Access to the min bias triggers used by CDF in Run 0 and Run 1 class TriggerCDFRun2 : public Projection { public: /// Default constructor. TriggerCDFRun2() { setName("TriggerCDFRun2"); addProjection(ChargedFinalState(-4.7, 4.7), "CFS"); } /// Clone on the heap. DEFAULT_RIVET_PROJ_CLONE(TriggerCDFRun2); /// The trigger result bool minBiasDecision() const { return _decision_mb; } /// Project on to the Event void project(const Event& evt); protected: /// Compare with other projections. - virtual int compare(const Projection&) const { - return EQUIVALENT; + virtual CmpState compare(const Projection&) const { + return CmpState::EQ; } private: /// The min bias trigger decision bool _decision_mb; }; } #endif diff --git a/include/Rivet/Projections/TriggerUA5.hh b/include/Rivet/Projections/TriggerUA5.hh --- a/include/Rivet/Projections/TriggerUA5.hh +++ b/include/Rivet/Projections/TriggerUA5.hh @@ -1,78 +1,78 @@ // -*- C++ -*- #ifndef RIVET_TriggerUA5_HH #define RIVET_TriggerUA5_HH #include "Rivet/Projection.hh" #include "Rivet/Event.hh" #include "Rivet/Particle.hh" #include "Rivet/Projections/Beam.hh" namespace Rivet { /// @brief Access to the min bias triggers used by UA5 class TriggerUA5 : public Projection { public: /// Default constructor. TriggerUA5(); /// Clone on the heap. DEFAULT_RIVET_PROJ_CLONE(TriggerUA5); /// The trigger result for non-single diffractive (2 arm) trigger bool sdDecision() const { return _decision_sd; } /// The trigger result for non-single diffractive (2 arm) trigger bool nsdDecision() const { return _decision_nsd_1; } /// The trigger result for non-single diffractive (2 arm) trigger /// with special ">= 2" trigger for ppbar bg rejection bool nsd2Decision() const { return _decision_nsd_2; } /// The trigger result bool samebeams() const { return _samebeams; } /// Number of hits in <-,+> eta hodoscopes pair numHits() { return make_pair(_n_plus, _n_minus); } /// Project on to the event void project(const Event& evt); protected: /// Compare with other projections. - virtual int compare(const Projection&) const { - return EQUIVALENT; + virtual CmpState compare(const Projection&) const { + return CmpState::EQ; } private: /// The min bias trigger decisions bool _decision_sd, _decision_nsd_1, _decision_nsd_2; /// Is it a pp collision? bool _samebeams; /// Number of hits in hodoscopes unsigned int _n_plus, _n_minus; }; } #endif diff --git a/include/Rivet/Projections/VetoedFinalState.hh b/include/Rivet/Projections/VetoedFinalState.hh --- a/include/Rivet/Projections/VetoedFinalState.hh +++ b/include/Rivet/Projections/VetoedFinalState.hh @@ -1,181 +1,181 @@ // -*- C++ -*- #ifndef RIVET_VetoedFinalState_HH #define RIVET_VetoedFinalState_HH #include "Rivet/Projections/FinalState.hh" namespace Rivet { /// @brief FS modifier to exclude classes of particles from the final state. class VetoedFinalState : public FinalState { public: /// Typedef for a pair of back-to-back cuts. typedef pair BinaryCut; /// Typedef for a vetoing entry. typedef map VetoDetails; /// Typedef for a veto on a composite particle mass. typedef multimap CompositeVeto; /// @name Constructors //@{ /// Default constructor. VetoedFinalState() { setName("VetoedFinalState"); addProjection(FinalState(), "FS"); } /// Constructor with specific FinalState. VetoedFinalState(const FinalState& fsp) { setName("VetoedFinalState"); addProjection(fsp, "FS"); } /// You can add a map of ID plus a pair containing \f$ p_{Tmin} \f$ and /// \f$ p_{Tmax} \f$ - these define the range of particles to be vetoed. VetoedFinalState(const VetoDetails& vetocodes) : _vetoCodes(vetocodes) { setName("VetoedFinalState"); addProjection(FinalState(), "FS"); } /// You can add a map of ID plus a pair containing \f$ p_{Tmin} \f$ and /// \f$ p_{Tmax} \f$ - these define the range of particles to be vetoed. /// This version also supplies a specific FinalState to be used. VetoedFinalState(const FinalState& fsp, const VetoDetails& vetocodes) : _vetoCodes(vetocodes) { setName("VetoedFinalState"); addProjection(fsp, "FS"); } /// Clone on the heap. DEFAULT_RIVET_PROJ_CLONE(VetoedFinalState); //@} /// Get the list of particle IDs and \f$ p_T \f$ ranges to veto. const VetoDetails& vetoDetails() const { return _vetoCodes; } /// Add a particle ID and \f$ p_T \f$ range to veto. Particles with \f$ p_T \f$ /// IN the given range will be rejected. VetoedFinalState& addVetoDetail(const long id, const double ptmin, const double ptmax) { BinaryCut ptrange(ptmin, ptmax); _vetoCodes.insert(make_pair(id, ptrange)); return *this; } /// Add a particle/antiparticle pair to veto in a given \f$ p_T \f$ range. Given a single ID, both /// the particle and its conjugate antiparticle will be rejected if their \f$ p_T \f$ is IN the given range. VetoedFinalState& addVetoPairDetail(const long id, const double ptmin, const double ptmax) { addVetoDetail(id, ptmin, ptmax); addVetoDetail(-id, ptmin, ptmax); return *this; } /// Add a particle/antiparticle pair to veto. Given a single ID, both the particle and its corresponding /// antiparticle (for all \f$ p_T \f$ values) will be vetoed. VetoedFinalState& addVetoPairId(const long id) { addVetoId(id); addVetoId(-id); return *this; } /// Add a particle ID to veto (all \f$ p_T \f$ range will be vetoed). VetoedFinalState& addVetoId(const long id) { BinaryCut ptrange(0.0, std::numeric_limits::max()); _vetoCodes.insert(make_pair(id, ptrange)); return *this; } /// Veto all neutrinos (convenience method) VetoedFinalState& vetoNeutrinos() { addVetoPairId(PID::NU_E); addVetoPairId(PID::NU_MU); addVetoPairId(PID::NU_TAU); return *this; } /// Add a veto on composite masses within a given width. /// The composite mass is composed of nProducts decay products /// @ todo might we want to specify a range of pdg ids for the decay products? VetoedFinalState& addCompositeMassVeto(const double &mass, const double &width, int nProducts=2){ double halfWidth = 0.5*width; BinaryCut massRange(mass - halfWidth, mass + halfWidth); _compositeVetoes.insert(make_pair(nProducts, massRange)); _nCompositeDecays.insert(nProducts); return *this; } /// Veto the decay products of particle with pdg id /// @todo Need HepMC to sort themselves out and keep vector bosons from /// the hard vtx in the event record before this will work reliably for all pdg ids VetoedFinalState& addDecayProductsVeto(const long id) { _parentVetoes.insert(id); return *this; } /// Set the list of particle IDs and \f$ p_T \f$ ranges to veto. VetoedFinalState& setVetoDetails(const VetoDetails& ids) { _vetoCodes = ids; return *this; } /// Clear the list of particle IDs and ranges to veto. VetoedFinalState& reset() { _vetoCodes.clear(); return *this; } /// Veto particles from a supplied final state VetoedFinalState& addVetoOnThisFinalState(const ParticleFinder& fs) { const string name = "FS_" + to_str(_vetofsnames.size()); addProjection(fs, name); _vetofsnames.insert(name); return *this; } /// Apply the projection on the supplied event. void project(const Event& e); /// Compare projections. - int compare(const Projection& p) const; + CmpState compare(const Projection& p) const; private: /// The final-state particles. VetoDetails _vetoCodes; /// Composite particle masses to veto CompositeVeto _compositeVetoes; set _nCompositeDecays; typedef set ParentVetos; /// Set of decaying particle IDs to veto ParentVetos _parentVetoes; /// Set of finalstate to be vetoed set _vetofsnames; }; } #endif diff --git a/include/Rivet/Projections/VisibleFinalState.hh b/include/Rivet/Projections/VisibleFinalState.hh --- a/include/Rivet/Projections/VisibleFinalState.hh +++ b/include/Rivet/Projections/VisibleFinalState.hh @@ -1,55 +1,55 @@ // -*- C++ -*- #ifndef RIVET_VisibleFinalState_HH #define RIVET_VisibleFinalState_HH #include "Rivet/Tools/Logging.hh" #include "Rivet/Config/RivetCommon.hh" #include "Rivet/Particle.hh" #include "Rivet/Event.hh" #include "Rivet/Projection.hh" #include "Rivet/Projections/FinalState.hh" namespace Rivet { /// @brief Final state modifier excluding particles which are not experimentally visible class VisibleFinalState : public FinalState { public: /// @name Constructors //@{ /// Constructor with min and max pseudorapidity \f$ \eta \f$ and min \f$ p_T \f$ (in GeV). VisibleFinalState(double mineta = -MAXDOUBLE, double maxeta = MAXDOUBLE, double minpt = 0.0*GeV) { setName("VisibleFinalState"); addProjection(FinalState(mineta, maxeta, minpt), "FS"); } /// Constructor with specific FinalState. VisibleFinalState(const FinalState& fsp) { setName("VisibleFinalState"); addProjection(fsp, "FS"); } /// Clone on the heap. DEFAULT_RIVET_PROJ_CLONE(VisibleFinalState); //@} /// Apply the projection on the supplied event. void project(const Event& e); /// Compare projections. - int compare(const Projection& p) const; + CmpState compare(const Projection& p) const; }; } #endif diff --git a/include/Rivet/Projections/WFinder.hh b/include/Rivet/Projections/WFinder.hh --- a/include/Rivet/Projections/WFinder.hh +++ b/include/Rivet/Projections/WFinder.hh @@ -1,179 +1,179 @@ // -*- C++ -*- #ifndef RIVET_WFinder_HH #define RIVET_WFinder_HH #include "Rivet/Projections/FinalState.hh" #include "Rivet/Projections/MissingMomentum.hh" #include "Rivet/Projections/VetoedFinalState.hh" namespace Rivet { /// @brief Convenience finder of leptonically decaying W /// /// Chain together different projections as convenience for finding one W /// from one lepton and the missing E 4-vector in the final state, including photon clustering. class WFinder : public ParticleFinder { public: enum class ChargedLeptons { PROMPT, ALL }; enum class ClusterPhotons { NONE, NODECAY, ALL }; enum class AddPhotons { NO, YES }; enum class MassWindow { M, MT }; /// @name Constructors //@{ /// Constructor taking cuts object /// @param inputfs Input final state /// @param leptoncuts Charged lepton cuts /// @param pid Type of the charged lepton /// @param minmass,maxmass (Transverse) mass window /// @param missingET Minimal amount of missing ET (neutrinos) required /// @param dRmax Maximum dR of photons around charged lepton to take into account /// for W reconstruction (only relevant if one of the following are true) /// @param chLeptons Only use prompt charged leptons, or any charged leptons? /// @param clusterPhotons Whether such photons are supposed to be /// clustered to the lepton object and thus W mom /// @param trackPhotons Whether such photons should be added to _theParticles /// @param masstype Whether mass window should be applied using m or mT /// /// @todo Revisit AddPhotons::NO as default? WFinder(const FinalState& inputfs, const Cut& leptoncuts, PdgId pid, double minmass, double maxmass, double missingET, double dRmax=0.1, ChargedLeptons chLeptons=ChargedLeptons::PROMPT, ClusterPhotons clusterPhotons=ClusterPhotons::NODECAY, AddPhotons trackPhotons=AddPhotons::NO, MassWindow masstype=MassWindow::M, double masstarget=80.4*GeV); /// Backward-compatible constructor with implicit chLeptons mode = ChargedLeptons::PROMPT /// @deprecated Remove this and always use the constructor with chLeptons argument. WFinder(const FinalState& inputfs, const Cut& leptoncuts, PdgId pid, double minmass, double maxmass, double missingET, double dRmax, ClusterPhotons clusterPhotons, AddPhotons trackPhotons=AddPhotons::NO, MassWindow masstype=MassWindow::M, double masstarget=80.4*GeV) : WFinder(inputfs, leptoncuts, pid, minmass, maxmass, missingET, dRmax, ChargedLeptons::PROMPT, clusterPhotons, trackPhotons, masstype, masstarget) { } // /// Constructor with more convenient argument ordering and default args // /// // /// @todo Revisit AddPhotons::NO as default? // WFinder(const FinalState& inputfs, // const Cut& leptoncuts, // PdgId pid, // double minmass, double maxmass, // double missingET, // MassWindow masstype, // double masstarget=80.4*GeV, // ClusterPhotons clusterPhotons=ClusterPhotons::NODECAY, // double dRmax=0.1, // AddPhotons trackPhotons=AddPhotons::NO) // : WFinder(inputfs, leptoncuts, pid, minmass, maxmass, missingET, // dRmax, clusterPhotons, trackPhotons, masstype, masstarget) // { } /// Clone on the heap. DEFAULT_RIVET_PROJ_CLONE(WFinder); //@} /// @brief Access to the found bosons, equivalent to constituents() /// @note Currently either 0 or 1 boson can be found. const Particles& bosons() const { return particles(); } /// Access to the found boson (assuming it exists) /// @todo C++17 std::optional... const Particle& boson() const { return particles().front(); } /// @brief Access to the Ws' constituent clustered leptons /// @note Either size 0 if no boson was found or 1 if one boson was found const Particles& constituentLeptons() const { return _leptons; } /// brief Access to the W's constituent clustered lepton (assuming it exists) /// @todo C++17 std::optional... const Particle& constituentLepton() const { return _leptons.front(); } /// Access to the Ws' constituent neutrinos /// /// @note Either size 0 if no boson was found or 1 if one boson was found /// @note The neutrino can't be perfecly reconstructed -- this is a pseudo-nu from the MET. const Particles& constituentNeutrinos() const { return _neutrinos; } /// Access to the W's constituent neutrino (assuming it exists) /// @note The neutrino can't be perfecly reconstructed -- this is a pseudo-nu from the MET. const Particle& constituentNeutrino() const { return _neutrinos.front(); } /// Access to the particles other than the W leptons and clustered photons /// /// Useful for e.g. input to a jet finder const VetoedFinalState& remainingFinalState() const; /// Access to the missing momentum projection used to find the "neutrino" const MissingMomentum& missingMom() const; /// @brief Calculate the transverse mass of the W, from the charged lepton and neutrino /// /// Defined as sqrt(2 pT_l pT_nu (1.0 - cos(dphi_lnu))). Return -1 if no boson found. double mT() const { if (bosons().empty()) return -1; return Rivet::mT(constituentLepton().mom(), constituentNeutrino().mom()); } protected: /// Apply the projection on the supplied event. void project(const Event& e); /// Compare projections. - int compare(const Projection& p) const; + CmpState compare(const Projection& p) const; public: /// Clear the projection void clear() { _theParticles.clear(); } private: /// (Transverse) mass cuts double _minmass, _maxmass, _masstarget; /// Use transverse or complete mass? bool _useTransverseMass; /// Missing ET cut double _etMissMin; /// Switch for tracking of photons (whether to include them in the W particle) /// This is relevant when the clustered photons need to be excluded from e.g. a jet finder AddPhotons _trackPhotons; /// Charged lepton flavour PdgId _pid; /// Result caches. Will be filled by project() Particles _leptons, _neutrinos; }; } #endif diff --git a/include/Rivet/Projections/ZFinder.hh b/include/Rivet/Projections/ZFinder.hh --- a/include/Rivet/Projections/ZFinder.hh +++ b/include/Rivet/Projections/ZFinder.hh @@ -1,124 +1,124 @@ // -*- C++ -*- #ifndef RIVET_ZFinder_HH #define RIVET_ZFinder_HH #include "Rivet/Projections/FinalState.hh" #include "Rivet/Projections/DressedLeptons.hh" #include "Rivet/Projections/VetoedFinalState.hh" namespace Rivet { /// @brief Convenience finder of leptonically decaying Zs /// /// Chain together different projections as convenience for finding Z's /// from two leptons in the final state, including photon clustering. /// /// @todo Alias then rename as Dileptons class ZFinder : public ParticleFinder { public: enum class ChargedLeptons { PROMPT, ALL }; enum class ClusterPhotons { NONE, NODECAY, ALL }; enum class AddPhotons { NO, YES }; /// @name Constructors //@{ /// Constructor taking cuts object /// @param inputfs Input final state /// @param cuts lepton cuts /// @param pid type of the leptons /// @param minmass,maxmass mass window /// @param dRmax maximum dR of photons around leptons to take into account /// for Z reconstruction (only relevant if one of the following are true) /// @param clusterPhotons whether such photons are supposed to be /// clustered to the lepton objects and thus Z mom /// @param trackPhotons whether such photons should be added to _theParticles /// (cf. _trackPhotons) ZFinder(const FinalState& inputfs, const Cut& cuts, PdgId pid, double minmass, double maxmass, double dRmax=0.1, ChargedLeptons chLeptons=ChargedLeptons::PROMPT, ClusterPhotons clusterPhotons=ClusterPhotons::NODECAY, AddPhotons trackPhotons=AddPhotons::NO, double masstarget=91.2*GeV); /// Backward-compatible constructor with implicit chLeptons mode = PROMPTCHLEPTONS /// @deprecated Remove this and always use the constructor with chLeptons argument. ZFinder(const FinalState& inputfs, const Cut& cuts, PdgId pid, double minmass, double maxmass, double dRmax, ClusterPhotons clusterPhotons, AddPhotons trackPhotons=AddPhotons::NO, double masstarget=91.2*GeV) : ZFinder(inputfs, cuts, pid, minmass, maxmass, dRmax, ChargedLeptons::PROMPT, clusterPhotons, trackPhotons, masstarget) { } /// Clone on the heap. DEFAULT_RIVET_PROJ_CLONE(ZFinder); //@} /// Access to the found bosons /// /// @note Currently either 0 or 1 boson can be found. const Particles& bosons() const { return particles(); } /// Access to the found boson (assuming it exists). const Particle& boson() const { return bosons().front(); } /// Access to the Z constituent clustered leptons /// /// For example, to make more fine-grained cuts on the clustered leptons. /// The positive charge constituent is first in the list (if not empty), and /// the negative one second. const Particles & constituentLeptons() const; const Particles & constituents() const { return constituentLeptons(); } /// Access to the particles other than the Z leptons and clustered photons /// /// Useful for e.g. input to a jet finder const VetoedFinalState& remainingFinalState() const; protected: /// Apply the projection on the supplied event. void project(const Event& e); /// Compare projections. - int compare(const Projection& p) const; + CmpState compare(const Projection& p) const; public: /// Clear the projection void clear() { _theParticles.clear(); } private: /// Mass cuts to apply to clustered leptons (cf. InvMassFinalState) double _minmass, _maxmass, _masstarget; /// Switch for tracking of photons (whether to include them in the Z particle) /// This is relevant when the clustered photons need to be excluded from e.g. a jet finder AddPhotons _trackPhotons; /// Lepton flavour PdgId _pid; }; } #endif diff --git a/include/Rivet/Tools/CentralityBinner.hh b/include/Rivet/Tools/CentralityBinner.hh --- a/include/Rivet/Tools/CentralityBinner.hh +++ b/include/Rivet/Tools/CentralityBinner.hh @@ -1,827 +1,827 @@ // -*- C++ -*- #ifndef RIVET_CENTRALITYBINNER_HH #define RIVET_CENTRALITYBINNER_HH #include #include "Rivet/Config/RivetCommon.hh" #include "Rivet/Tools/RivetYODA.hh" namespace Rivet { /** @brief Base class for projections giving the value of an observable sensitive to the centrality of a collision. @author Leif Lönnblad The centrality of a collision is not really an observable, but the concept is anyway often used in the heavy ion community as if it were just that. This base class can be used to provide a an estimator for the centrality by projecting down to a single number which then can be used by a CentralityBinner object to select a histogram to be filled with another observable depending on centrality percentile. The estimate() should be a non-negative number with large values indicating a higher overlap than small ones. A negative value indicates that the centrality estimate could not be calculated. In the best of all worlds the centrality estimator should be a proper hadron-level observable corrected for detector effects, however, this base class only returns the inverse of the impact_parameter member of the GenHeavyIon object in an GenEvent if present and zero otherwise. */ class CentralityEstimator : public Projection { public: /// Constructor. CentralityEstimator(): _estimate(-1.0) {} /// Clone on the heap. DEFAULT_RIVET_PROJ_CLONE(CentralityEstimator); protected: /// Perform the projection on the Event void project(const Event& e) { _estimate = -1.0; const HepMC::HeavyIon * hi = e.genEvent()->heavy_ion(); if ( hi ) _estimate = hi->impact_parameter() > 0.0? 1.0/hi->impact_parameter(): numeric_limits::max(); } /// Compare projections - int compare(const Projection& p) const { + CmpState compare(const Projection& p) const { return mkNamedPCmp(p, "CentEst"); } public: /// The value of the centrality estimate. double estimate() const { return _estimate; } protected: /// The value of the centrality estimate. double _estimate; }; /// This is a traits class describing how to handle object handles by /// CentralityBinner. The default implementation basically describes /// what to do with Histo1DPtr. template struct CentralityBinTraits { /// Make a clone of the given object. static T clone(const T & t) { return T(t->newclone()); } /// Add the contents of @a o to @a t. static void add(T & t, const T & o) { *t += *o; } /// Scale the contents of a given object. static void scale(T & t, double f) { t->scaleW(f); } /// Normalize the AnalysisObject to the sum of weights in a /// centrality bin. static void normalize(T & t, double sumw) { if ( t->sumW() > 0.0 ) t->normalize(t->sumW()/sumw); } /// Return the path of an AnalysisObject. static string path(T t) { return t->path(); } }; /// The sole purpose of the MergeDistance class is to provide a /// "distance" for a potential merging of two neighboring bins in a /// CentralityBinner. struct MergeDistance { /// This function should return a generalized distance between two /// adjecent centrality bins to be merged. CentralityBinner will /// always try to merge bins with the smallest distance. @a cestLo /// and @cestHi are the lower and upper edges of resulting bin. @a /// weight is the resulting sum of event weights in the bin. @a /// centLo and @a centHi are the lower and upper prcentile limits /// where the two bins currently resides. The two last arguments are /// the total number of events in the two bins and the total number /// of previous mergers repectively. static double dist(double cestLo, double cestHi, double weight, double clo, double chi, double, double) { return (cestHi - cestLo)*weight/(cestHi*(chi - clo)); } }; /** * CentralityBinner contains a series of AnalysisObject of the same * quantity each in a different percentiles of another quantity. For * example, a CentralityBinner may e.g. contain histograms of the * cross section differential in \f$ p_T \f$ in different centrality * regions for heavy ion collisions based on forward energy flow. **/ template class CentralityBinner: public ProjectionApplier { public: /// Create a new empty CentralityBinner. @a maxbins is the maximum /// number of bins used by the binner. Default is 1000, which is /// typically enough. @a wlim is the mximum allowed error allowed /// for the centrality limits before a warning is emitted. CentralityBinner(int maxbins = 200, double wlim = 0.02) : _currentCEst(-1.0), _maxBins(maxbins), _warnlimit(wlim), _weightsum(0.0) { _percentiles.insert(0.0); _percentiles.insert(1.0); } /// Set the centrality projection to be used. Note that this /// projection must have already been declared to Rivet. void setProjection(const CentralityEstimator & p, string pname) { declare(p, pname); _estimator = pname; } /// Return the class name. virtual std::string name() const { return "Rivet::CentralityBinner"; } /// Add an AnalysisObject in the region between @a cmin and @a cmax to /// this set of CentralityBinners. The range represent /// percentiles and must be between 0 and 100. No overlaping bins /// are allowed. /// Note that (cmin=0, cmax=5), means the five percent MOST central /// events although the internal notation is reversed for /// convenience. /// Optionally supply corresponding limits @a cestmin and @a cestmax /// of the centrality extimator. void add(T t, double cmin, double cmax, double cestmin = -1.0, double cestmax = -1.0 ) { _percentiles.insert(max(1.0 - cmax/100.0, 0.0)); _percentiles.insert(min(1.0 - cmin/100.0, 1.0)); if ( _unfilled.empty() && _ready.empty() ) _devnull = CentralityBinTraits::clone(t); if ( cestmin < 0.0 ) _unfilled.push_back(Bin(t, 1.0 - cmax/100.0, 1.0 - cmin/100.0)); else _ready[t] = Bin(t, 1.0 - cmax/100.0, 1.0 - cmin/100.0, cestmin, cestmax); } /// Return one of the AnalysisObjects in the CentralityBinner for /// the given @a event. This version requires that a /// CentralityEstimator object has been assigned that can compute /// the value of the centrality estimator from the @a /// event. Optionally the @a weight of the event is given. This /// should be the weight that will be used to fill the /// AnalysisObject. If the centrality estimate is less than zero, /// the _devnull object will be returned. T select(const Event & event, double weight = 1.0) { return select(applyProjection (event, _estimator).estimate(), weight); } /// Return one of the AnalysisObjecsts in the Setup the /// CentralityBinner depending on the value of the centrality /// estimator, @a cest. Optionally the @a weight of the event is /// given. This should be the weight that will be used to fill the /// AnalysisObject. If the centrality estimate is less than zero, /// the _devnull object will be returned. T select(double cest, double weight = 1.0); /// At the end of the run, calculate the percentiles and fill the /// AnalysisObjectss provided with the add() function. This is /// typically called from the finalize method in an Analysis, but /// can also be called earlier in which case the the select /// functions can be continued to run as before with the edges /// between the centrality regions now fixed. void finalize(); /// Normalize each AnalysisObjects to the sum of event weights in the /// corresponding centrality bin. void normalizePerEvent() { for ( auto & b : _ready ) b.second.normalizePerEvent(); } /// Return a map bin edges of the centrality extimator indexed by /// the corresponing percentile. map edges() const { map ret; for ( auto & b : _ready ) { ret[1.0 - b.second._centLo] = b.second._cestLo; ret[1.0 - b.second._centHi] = b.second._cestHi; } return ret; } /// Return the current AnalysisObject from the latest call to select(). const T & current() const { return _currenT; } /// Return the value of the centrality estimator set in the latest /// call to select(). double estimator() const { return _currentCEst; } vector allObjects() { vector ret; for ( auto & fb : _flexiBins ) ret.push_back(fb._t); if ( !ret.empty() ) return ret; for ( auto b : _ready ) ret.push_back(b.second._t); return ret; } private: /// A flexible bin struct to be used to store temporary AnalysisObjects. struct FlexiBin { /// Construct with an initial centrality estimate and an event /// weight. FlexiBin(T & t, double cest = 0.0, double weight = 0.0) : _t(t), _cestLo(cest), _cestHi(cest), _weightsum(weight), _n(1), _m(0) {} /// Construct a temporary FlexiBin for finding a bin in a set. FlexiBin(double cest) : _cestLo(cest), _cestHi(cest), _weightsum(0.0), _n(0), _m(0) {} /// Merge in the contents of another FlexiBin into this. void merge(const FlexiBin & fb) { _cestLo = min(_cestLo, fb._cestLo); _cestHi = max(_cestHi, fb._cestHi); _weightsum += fb._weightsum; CentralityBinTraits::add(_t, fb._t); _n += fb._n; _m += fb._m + 1; } /// Comparisons for containers. bool operator< (const FlexiBin & fb) const { return _cestLo < fb._cestLo; } /// Return true if the given centrality estimate is in the range /// of this bin. bool inRange(double cest) const { return cest == _cestLo || ( _cestLo < cest && cest < _cestHi ); } /// The associated AnalysisObject. T _t; /// Current lower and upper edge of the centrality estimator for /// the fills in the associated AnalysiObject. double _cestLo, _cestHi; /// The sum of weights for all events entering the associated /// AnalysisObject. mutable double _weightsum; /// The number of times this bin has been selected. mutable int _n; /// The number of times this bin has been merged. mutable int _m; }; struct Bin { /// Construct a completely empty bin. Bin() : _centLo(-1.0), _centHi(-1.0), _cestLo(-1.0), _cestHi(-1.0), _weightsum(0.0), _underflow(0.0), _overflow(0.0), _ambiguous(0), _ambweight(0.0) {} /// Constructor taking an AnalysisObject and centrality interval /// as argument. Optionally the interval in the estimator can be /// given, in which case this bin is considered to be /// "final". Bin(T t, double centLo, double centHi, double cestLo = -1.0, double cestHi = -1.0) : _t(t), _centLo(centLo), _centHi(centHi), _cestLo(cestLo), _cestHi(cestHi), _weightsum(0.0), _underflow(0.0), _overflow(0.0), _ambiguous(0.0), _ambweight(0.0) {} /// Return true if the given centrality estimate is in the range /// of this AnalysisObject. bool inRange(double cest) const { return _cestLo >= 0 && _cestLo <= cest && ( _cestHi < 0.0 || cest <= _cestHi ); } /// Normalise the AnalysisObject to the tital cross section. void normalizePerEvent() { CentralityBinTraits::normalize(_t, _weightsum); } /// The AnalysisObject. T _t; /// The range in centrality. double _centLo, _centHi; /// The corresponding range in the centrality estimator. double _cestLo, _cestHi; /// The sum of event weights for this bin; double _weightsum; /// The weight in a final AnalysisObject that contains events /// below the centrality limit. double _underflow; /// The weight in a final AnalysisObject that contain events above /// the centrality limit. double _overflow; /// Number of ambiguous events in this bin. double _ambiguous; /// Sum of abmiguous weights. double _ambweight; }; protected: /// Convenient typedefs. typedef set FlexiBinSet; /// Find a bin corresponding to a given value of the centrality /// estimator. typename FlexiBinSet::iterator _findBin(double cest) { if ( _flexiBins.empty() ) return _flexiBins.end(); auto it = _flexiBins.lower_bound(FlexiBin(cest)); if ( it->_cestLo == cest ) return it; if ( it != _flexiBins.begin() ) --it; if ( it->_cestLo < cest && cest < it->_cestHi ) return it; return _flexiBins.end(); } /// The name of the CentralityEstimator projection to be used. string _estimator; /// The current temporary AnalysisObject selected for the centrality /// estimator calculated from the event presented in setup(). T _currenT; /// The current value of the centrality estimator. double _currentCEst; /// The oversampling of centrality bins. For each requested /// centrality bin this number of dynamic bins will be used. int _maxBins; /// If the fraction of events in a bin that comes from adjecent /// centrality bins exceeds this, emit a warning. double _warnlimit; /// The unfilled AnalysisObjectss where the esimator edges has not yet /// been determined. vector _unfilled; /// The dynamic bins for ranges of centrality estimators. FlexiBinSet _flexiBins; /// The sum of all event weights so far. double _weightsum; /// The requested percentile limits. set _percentiles; /// The filled AnalysisObjects where the estimator edges has been determined. map _ready; /// A special AnalysisObject which will be filled if the centrality /// estimate is out of range (negative). T _devnull; public: /// Print out the _flexiBins to cerr. void debug(); void fulldebug(); }; /// Traits specialization for Profile histograms. template <> struct CentralityBinTraits { typedef Profile1DPtr T; /// Make a clone of the given object. static T clone(const T & t) { return Profile1DPtr(t->newclone()); } /// Add the contents of @a o to @a t. static void add(T & t, const T & o) { *t += *o; } /// Scale the contents of a given object. static void scale(T & t, double f) { t->scaleW(f); } static void normalize(T & t, double sumw) {} /// Return the path of an AnalysisObject. static string path(T t) { return t->path(); } }; /// Traits specialization for Profile histograms. template <> struct CentralityBinTraits { typedef Profile2DPtr T; /// Make a clone of the given object. static T clone(const T & t) { return Profile2DPtr(t->newclone()); } /// Add the contents of @a o to @a t. static void add(T & t, const T & o) { *t += *o; } /// Scale the contents of a given object. static void scale(T & t, double f) { t->scaleW(f); } static void normalize(T & t, double sumw) {} /// Return the name of an AnalysisObject. static string path(T t) { return t->path(); } }; template struct CentralityBinTraits< vector > { /// Make a clone of the given object. static vector clone(const vector & tv) { vector rtv; for ( auto t : tv ) rtv.push_back(CentralityBinTraits::clone(t)); return rtv; } /// Add the contents of @a o to @a t. static void add(vector & tv, const vector & ov) { for ( int i = 0, N = tv.size(); i < N; ++i ) CentralityBinTraits::add(tv[i], ov[i]); } /// Scale the contents of a given object. static void scale(vector & tv, double f) { for ( auto t : tv ) CentralityBinTraits::scale(t, f); } static void normalize(vector & tv, double sumw) { for ( auto t : tv ) CentralityBinTraits::normalize(t, sumw); } /// Return the path of an AnalysisObject. static string path(const vector & tv) { string ret = "(vector:"; for ( auto t : tv ) { ret += " "; ret += CentralityBinTraits::path(t); } ret += ")"; return ret; } }; template struct TupleCentralityBinTraitsHelper { typedef tuple Tuple; typedef typename tuple_element::type T; static void clone(Tuple & ret, const Tuple & tup) { get(ret) = CentralityBinTraits::clone(get(tup)); TupleCentralityBinTraitsHelper::clone(ret, tup); } static void add(Tuple & tup, const Tuple & otup) { CentralityBinTraits::add(get(tup),get(otup)); TupleCentralityBinTraitsHelper::add(tup, otup); } static void scale(Tuple & tup, double f) { CentralityBinTraits::scale(get(tup), f); TupleCentralityBinTraitsHelper::scale(tup, f); } static void normalize(Tuple & tup, double sumw) { CentralityBinTraits::normalize(get(tup), sumw); TupleCentralityBinTraitsHelper::normalize(tup, sumw); } static string path(const Tuple & tup) { return " " + CentralityBinTraits::path(get(tup)) + TupleCentralityBinTraitsHelper::path(tup); } }; template struct TupleCentralityBinTraitsHelper<0,Types...> { typedef tuple Tuple; static void clone(Tuple &, const Tuple &) {} static void add(Tuple & tup, const Tuple & otup) {} static void scale(Tuple & tup, double f) {} static void normalize(Tuple & tup, double sumw) {} static string path(const Tuple & tup) {return "";} }; template struct CentralityBinTraits< tuple > { typedef tuple Tuple; static const size_t N = tuple_size::value; /// Make a clone of the given object. static Tuple clone(const Tuple & tup) { Tuple ret; TupleCentralityBinTraitsHelper::clone(ret, tup); return ret; } /// Add the contents of @a o to @a t. static void add(Tuple & tup, const Tuple & otup) { TupleCentralityBinTraitsHelper::add(tup, otup); } /// Scale the contents of a given object. static void scale(Tuple & tup, double f) { TupleCentralityBinTraitsHelper::scale(tup, f); } static void normalize(Tuple & tup, double sumw) { TupleCentralityBinTraitsHelper::normalize(tup, sumw); } /// Return the path of an AnalysisObject. static string path(const Tuple & tup) { string ret = "(tuple:"; ret += TupleCentralityBinTraitsHelper::path(tup); ret += ")"; return ret; } }; template T CentralityBinner::select(double cest, double weight) { _currenT = _devnull; _currentCEst = cest; _weightsum += weight; // If estimator is negative, something has gone wrong. if ( _currentCEst < 0.0 ) return _currenT; // If we already have finalized the limits on the centrality // estimator, we just add the weights to their bins and return the // corresponding AnalysisObject. if ( _unfilled.empty() ) { for ( auto & b : _ready ) if ( b.second.inRange(_currentCEst) ) { b.second._weightsum += weight; return b.second._t; } return _currenT; } auto it = _findBin(cest); if ( it == _flexiBins.end() ) { _currenT = CentralityBinTraits::clone(_unfilled.begin()->_t); it = _flexiBins.insert(FlexiBin(_currenT, _currentCEst, weight)).first; } else { it->_weightsum += weight; ++(it->_n); _currenT = it->_t; } if ( (int)_flexiBins.size() <= _maxBins ) return _currenT; set::iterator citn = _percentiles.begin(); set::iterator cit0 = citn++; auto selectit = _flexiBins.end(); double mindist = -1.0; double acc = 0.0; auto next = _flexiBins.begin(); auto prev = next++; for ( ; next != _flexiBins.end(); prev = next++ ) { acc += prev->_weightsum/_weightsum; if ( acc > *citn ) { cit0 = citn++; continue; } if ( acc + next->_weightsum/_weightsum > *citn ) continue; double dist = MDist::dist(prev->_cestLo, next->_cestHi, next->_weightsum + prev->_weightsum, *cit0, *citn, next->_n + prev->_n, next->_m + prev->_m); if ( mindist < 0.0 || dist < mindist ) { selectit = prev; mindist = dist; } } if ( selectit == _flexiBins.end() ) return _currenT; auto mergeit = selectit++; FlexiBin merged = *mergeit; merged.merge(*selectit); if ( merged.inRange(cest) || selectit->inRange(cest) ) _currenT = merged._t; _flexiBins.erase(mergeit); _flexiBins.erase(selectit); _flexiBins.insert(merged); return _currenT; } template void CentralityBinner::finalize() { // Take the contents of the dynamical binning and fill the original // AnalysisObjects. double clo = 0.0; for ( const FlexiBin & fb : _flexiBins ) { double chi = min(clo + fb._weightsum/_weightsum, 1.0); for ( Bin & bin : _unfilled ) { double olo = bin._centLo; double ohi = bin._centHi; if ( clo > ohi || chi <= olo ) continue; // If we only have partial overlap we need to scale double lo = max(olo, clo); double hi = min(ohi, chi); T t = CentralityBinTraits::clone(fb._t); double frac = (hi - lo)/(chi - clo); CentralityBinTraits::scale(t, frac); CentralityBinTraits::add(bin._t, t); bin._weightsum += fb._weightsum*frac; if ( clo <= olo ) bin._cestLo = fb._cestLo + (fb._cestHi - fb._cestLo)*(olo - clo)/(chi - clo); if ( clo < olo ) { bin._underflow = clo; bin._ambiguous += fb._n*frac; bin._ambweight += fb._weightsum*frac*(1.0 - frac); } if ( chi > ohi ) { bin._cestHi = fb._cestLo + (fb._cestHi - fb._cestLo)*(ohi - clo)/(chi - clo); bin._overflow = chi; bin._ambiguous += fb._n*frac; bin._ambweight += fb._weightsum*frac*(1.0 - frac); } } clo = chi; } _flexiBins.clear(); for ( Bin & bin : _unfilled ) { if ( bin._overflow == 0.0 ) bin._overflow = 1.0; _ready[bin._t] = bin; if ( bin._ambweight/bin._weightsum >_warnlimit ) MSG_WARNING("Analysis object \"" << CentralityBinTraits::path(bin._t) << "\", contains events with centralities between " << bin._underflow*100.0 << " and " << bin._overflow*100.0 << "% (" << int(bin._ambiguous + 0.5) << " ambiguous events with effectively " << 100.0*bin._ambweight/bin._weightsum << "% of the weights)." << "Consider increasing the number of bins."); } _unfilled.clear(); } template void CentralityBinner::fulldebug() { cerr << '\n'; double acc = 0.0; set::iterator citn = _percentiles.begin(); set::iterator cit0 = citn++; int i = 0; for ( auto it = _flexiBins.begin(); it != _flexiBins.end(); ) { ++i; auto curr = it++; double w = curr->_weightsum/_weightsum; acc += w; if ( curr == _flexiBins.begin() || it == _flexiBins.end() || acc > *citn ) cerr << "*"; else cerr << " "; if ( acc > *citn ) cit0 = citn++; cerr << setw(6) << i << setw(12) << acc - w << setw(12) << acc << setw(8) << curr->_n << setw(8) << curr->_m << setw(12) << curr->_cestLo << setw(12) << curr->_cestHi << '\n'; } cerr << "Number of sampler bins: " << _flexiBins.size() << '\n'; } template void CentralityBinner::debug() { cerr << '\n'; double acc = 0.0; int i = 0; set::iterator citn = _percentiles.begin(); set::iterator cit0 = citn++; for ( auto it = _flexiBins.begin(); it != _flexiBins.end(); ) { auto curr = it++; ++i; double w = curr->_weightsum/_weightsum; acc += w; if ( curr == _flexiBins.begin() || it == _flexiBins.end() || acc > *citn ) { if ( acc > *citn ) cit0 = citn++; cerr << setw(6) << i << setw(12) << acc - w << setw(12) << acc << setw(8) << curr->_n << setw(8) << curr->_m << setw(12) << curr->_cestLo << setw(12) << curr->_cestHi << '\n'; } } cerr << "Number of sampler bins: " << _flexiBins.size() << '\n'; } /// Example of CentralityEstimator projection that the generated /// centrality as given in the GenHeavyIon object in HepMC3. class GeneratedCentrality: public CentralityEstimator { public: /// Constructor. GeneratedCentrality() {} /// Clone on the heap. DEFAULT_RIVET_PROJ_CLONE(GeneratedCentrality); protected: /// Perform the projection on the Event void project(const Event& e) { _estimate = -1.0; #if HEPMC_VERSION_CODE >= 3000000 const HepMC::HeavyIon * hi = e.genEvent()->heavy_ion(); if ( hi ) _estimate = 100.0 - hi->centrality; // @TODO We don't really know how to interpret this number! #endif } /// Compare projections - int compare(const Projection& p) const { + CmpState compare(const Projection& p) const { return mkNamedPCmp(p, "GeneratedCentrality"); } }; } #endif diff --git a/include/Rivet/Tools/Cmp.fhh b/include/Rivet/Tools/Cmp.fhh --- a/include/Rivet/Tools/Cmp.fhh +++ b/include/Rivet/Tools/Cmp.fhh @@ -1,30 +1,18 @@ // -*- C++ -*- #ifndef RIVET_Cmp_FHH #define RIVET_Cmp_FHH namespace Rivet { // Forward-declare the Cmp template class template class Cmp; - - /// Enumerate the possible states of a Cmp object. - enum CmpState { - UNDEFINED = -2, ///< Undefined state. - ASC = -1, ///< The two objects are ordered (in ascending order). - ORDERED = -1, ///< The two objects are ordered (in ascending order). - EQUAL = 0, ///< The two objects are equivalent. - EQUIVALENT = 0, ///< The two objects are equivalent. - DESC = 1, ///< The two objects are anti-ordered (in descending order). - ANTIORDERED = 1, ///< The two objects are anti-ordered (in descending order). - UNORDERED = 1, ///< The two objects are anti-ordered (in descending order). // DEPRECATED! - UNEQUAL = 2, ///< The two objects are unequal, without ordering implications. - INEQUIVALENT = 2, ///< The two objects are unequal, without ordering implications. + enum class CmpState { + UNDEF, LT, EQ, GT }; - } #endif diff --git a/include/Rivet/Tools/Cmp.hh b/include/Rivet/Tools/Cmp.hh --- a/include/Rivet/Tools/Cmp.hh +++ b/include/Rivet/Tools/Cmp.hh @@ -1,333 +1,302 @@ // -*- C++ -*- #ifndef RIVET_Cmp_HH #define RIVET_Cmp_HH #include "Rivet/Config/RivetCommon.hh" #include "Rivet/Projection.hh" #include "Cmp.fhh" #include namespace Rivet { /// Helper class when checking the ordering of two objects. /// /// Cmp is a helper class to be used when checking the ordering of two /// objects. When implicitly converted to an integer the value will be /// negative if the two objects used in the constructor are ordered and /// positive if they are not. Zero will be returned if they are equal. /// /// The main usage of the Cmp class is if several variables should be /// checked for ordering in which case several Cmp objects can be /// combined as follows: cmp(a1, a2) || cmp(b1, b2) || cmp(c1, /// c2) where cmp is a global function for easy creation of Cmp /// objects. template - class Cmp { + class Cmp final { public: /// @name Standard constructors etc. //@{ /// The default constructor. Cmp(const T& t1, const T& t2) - : _value(UNDEFINED), _objects(&t1, &t2) { } + : _value(CmpState::UNDEF), _objects(&t1, &t2) { } /// The copy constructor. template Cmp(const Cmp& x) - : _value(x), _objects(0, 0) { } - - /// The destructor is not virtual since this is not intended to be a base class. - ~Cmp() { }; + : _value(x._value), _objects(nullptr, nullptr) { } /// The assignment operator. template const Cmp& operator=(const Cmp& x) { _value = x; return *this; } //@} public: /// Automatically convert to an enum. operator CmpState() const { _compare(); return _value; } - /// Automatically convert to an integer. - operator int() const { - _compare(); - return _value; - } - /// If this state is equivalent, set this state to the state of \a c. template const Cmp& operator||(const Cmp& c) const { _compare(); - if (_value == EQUIVALENT) _value = c; + if (_value == CmpState::EQ) _value = c; return *this; } private: /// Perform the actual comparison if necessary. void _compare() const { - if (_value == UNDEFINED) { + if (_value == CmpState::UNDEF) { std::less l; - if ( l(*_objects.first, *_objects.second) ) _value = ORDERED; - else if ( l(*_objects.second, *_objects.first) ) _value = UNORDERED; - else _value = EQUIVALENT; + if ( l(*_objects.first, *_objects.second) ) _value = CmpState::LT; + else if ( l(*_objects.second, *_objects.first) ) _value = CmpState::GT; + else _value = CmpState::EQ; } } /// The state of this object. mutable CmpState _value; /// The objects to be compared. - pair _objects; + const pair _objects; }; /// @brief Specialization of Cmp for checking the ordering of two @a {Projection}s. /// /// Specialization of the Cmp helper class to be used when checking the /// ordering of two Projection objects. When implicitly converted to an /// integer the value will be negative if the two objects used in the /// constructor are ordered and positive if they are not. Zero will be /// returned if they are equal. This specialization uses directly the /// virtual compare() function in the Projection class. /// /// The main usage of the Cmp class is if several variables should be /// checked for ordering in which case several Cmp objects can be /// combined as follows: cmp(a1, a2) || cmp(b1, b2) || cmp(c1, /// c2) where cmp is a global function for easy creation of Cmp /// objects. template <> - class Cmp { + class Cmp final { public: /// @name Standard constructors and destructors. //@{ /// The default constructor. Cmp(const Projection& p1, const Projection& p2) - : _value(UNDEFINED), _objects(&p1, &p2) + : _value(CmpState::UNDEF), _objects(&p1, &p2) { } /// The copy constructor. template Cmp(const Cmp& x) - : _value(x), _objects(0, 0) + : _value(x), _objects(nullptr, nullptr) { } - /// The destructor is not virtual since this is not intended to be a base class. - ~Cmp() { }; - /// The assignment operator. template const Cmp& operator=(const Cmp& x) { _value = x; return *this; } //@} public: /// Automatically convert to an enum. operator CmpState() const { _compare(); return _value; } - - /// Automatically convert to an integer. - operator int() const { - _compare(); - return _value; - } - /// If this state is equivalent, set this state to the state of \a c. template const Cmp& operator||(const Cmp& c) const { _compare(); - if (_value == EQUIVALENT) _value = c; + if (_value == CmpState::EQ) _value = c; return *this; } private: /// Perform the actual comparison if necessary. void _compare() const { - if (_value == UNDEFINED) { + if (_value == CmpState::UNDEF) { const std::type_info& id1 = typeid(*_objects.first); const std::type_info& id2 = typeid(*_objects.second); - if (id1.before(id2)) _value = ORDERED; - else if (id2.before(id1)) _value = UNORDERED; + if (id1.before(id2)) _value = CmpState::LT; + else if (id2.before(id1)) _value = CmpState::GT; else { - int c = _objects.first->compare(*_objects.second); - if (c < 0) _value = ORDERED; - else if (c > 0) _value = UNORDERED; - else _value = EQUIVALENT; + _value = _objects.first->compare(*_objects.second); } } } private: /// The state of this object. mutable CmpState _value; /// The objects to be compared. - pair _objects; + const pair _objects; }; /// @brief Specialization of Cmp for checking the ordering of two floating point numbers. /// /// When implicitly converted to an integer the value will be negative if the /// two objects used in the constructor are ordered and positive if they are /// not. Zero will be returned if they are equal. This specialization uses the /// Rivet fuzzyEquals function to indicate equivalence protected from /// numerical precision effects. /// /// The main usage of the Cmp class is if several variables should be /// checked for ordering in which case several Cmp objects can be /// combined as follows: cmp(a1, a2) || cmp(b1, b2) || cmp(c1, /// c2) where cmp is a global function for easy creation of Cmp /// objects. template <> - class Cmp { + class Cmp final { public: /// @name Standard constructors and destructors. //@{ /// The default constructor. Cmp(const double p1, const double p2) - : _value(UNDEFINED), _numA(p1), _numB(p2) + : _value(CmpState::UNDEF), _numA(p1), _numB(p2) { } /// The copy constructor. template Cmp(const Cmp& x) : _value(x), _numA(0.0), _numB(0.0) { } - /// The destructor is not virtual since this is not intended to be a base class. - ~Cmp() { } - /// The assignment operator. template const Cmp& operator=(const Cmp& x) { _value = x; return *this; } //@} public: /// Automatically convert to an enum. operator CmpState() const { _compare(); return _value; } - /// Automatically convert to an integer. - operator int() const { - _compare(); - return _value; - } - /// If this state is equivalent, set this state to the state of \a c. template const Cmp& operator||(const Cmp& c) const { _compare(); - if (_value == EQUIVALENT) _value = c; + if (_value == CmpState::EQ) _value = c; return *this; } private: /// Perform the actual comparison if necessary. void _compare() const { - if (_value == UNDEFINED) { - if (fuzzyEquals(_numA,_numB)) _value = EQUIVALENT; - else if (_numA < _numB) _value = ORDERED; - else _value = UNORDERED; + if (_value == CmpState::UNDEF) { + if (fuzzyEquals(_numA,_numB)) _value = CmpState::EQ; + else if (_numA < _numB) _value = CmpState::LT; + else _value = CmpState::GT; } } private: /// The state of this object. mutable CmpState _value; /// The objects to be compared. - double _numA, _numB; + const double _numA, _numB; }; /////////////////////////////////////////////////////////////////// /// Global helper function for easy creation of Cmp objects. template inline Cmp cmp(const T& t1, const T& t2) { return Cmp(t1, t2); } /// Typedef for Cmp - typedef Cmp PCmp; + using PCmp = Cmp; /// Global helper function for easy creation of Cmp objects. inline Cmp pcmp(const Projection& p1, const Projection& p2) { return Cmp(p1, p2); } /// Global helper function for easy creation of Cmp objects from /// two parent projections and their common name for the projection to be compared. inline Cmp pcmp(const Projection& parent1, const Projection& parent2, const string& pname) { return Cmp(parent1.getProjection(pname), parent2.getProjection(pname)); } /// Global helper function for easy creation of Cmp objects from /// two parent projections and their common name for the projection to be compared. /// This version takes one parent as a pointer. inline Cmp pcmp(const Projection* parent1, const Projection& parent2, const string& pname) { assert(parent1); return Cmp(parent1->getProjection(pname), parent2.getProjection(pname)); } /// Global helper function for easy creation of Cmp objects from /// two parent projections and their common name for the projection to be compared. /// This version takes one parent as a pointer. inline Cmp pcmp(const Projection& parent1, const Projection* parent2, const string& pname) { assert(parent2); return Cmp(parent1.getProjection(pname), parent2->getProjection(pname)); } /// Global helper function for easy creation of Cmp objects from /// two parent projections and their common name for the projection to be compared. inline Cmp pcmp(const Projection* parent1, const Projection* parent2, const string& pname) { assert(parent1); assert(parent2); return Cmp(parent1->getProjection(pname), parent2->getProjection(pname)); } } #endif diff --git a/include/Rivet/Tools/JetSmearingFunctions.hh b/include/Rivet/Tools/JetSmearingFunctions.hh --- a/include/Rivet/Tools/JetSmearingFunctions.hh +++ b/include/Rivet/Tools/JetSmearingFunctions.hh @@ -1,137 +1,137 @@ // -*- C++ -*- #ifndef RIVET_JetSmearingFunctions_HH #define RIVET_JetSmearingFunctions_HH #include "Rivet/Jet.hh" #include "Rivet/Tools/MomentumSmearingFunctions.hh" #include "Rivet/Tools/ParticleSmearingFunctions.hh" #include "Rivet/Tools/Random.hh" namespace Rivet { /// @name Jet filtering, efficiency and smearing utils //@{ /// @name Typedef for Jet smearing functions/functors typedef function JetSmearFn; /// @name Typedef for Jet efficiency functions/functors typedef function JetEffFn; /// Return a constant 0 given a Jet as argument inline double JET_EFF_ZERO(const Jet& p) { return 0; } /// Return a constant 1 given a Jet as argument inline double JET_EFF_ONE(const Jet& p) { return 1; } /// Take a Jet and return a constant efficiency struct JET_EFF_CONST { JET_EFF_CONST(double eff) : _eff(eff) {} double operator () (const Jet& ) const { return _eff; } double _eff; }; /// Return 1 if the given Jet contains a b, otherwise 0 inline double JET_BTAG_PERFECT(const Jet& j) { return j.bTagged() ? 1 : 0; } /// Return 1 if the given Jet contains a c, otherwise 0 inline double JET_CTAG_PERFECT(const Jet& j) { return j.cTagged() ? 1 : 0; } /// @brief b-tagging efficiency functor, for more readable b-tag effs and mistag rates /// Note several constructors, allowing for optional specification of charm, tau, and light jet mistag rates struct JET_BTAG_EFFS { JET_BTAG_EFFS(double eff_b, double eff_light=0) : _eff_b(eff_b), _eff_c(-1), _eff_t(-1), _eff_l(eff_light) { } JET_BTAG_EFFS(double eff_b, double eff_c, double eff_light) : _eff_b(eff_b), _eff_c(eff_c), _eff_t(-1), _eff_l(eff_light) { } JET_BTAG_EFFS(double eff_b, double eff_c, double eff_tau, double eff_light) : _eff_b(eff_b), _eff_c(eff_c), _eff_t(eff_tau), _eff_l(eff_light) { } inline double operator () (const Jet& j) { if (j.bTagged()) return _eff_b; if (_eff_c >= 0 && j.cTagged()) return _eff_c; if (_eff_t >= 0 && j.tauTagged()) return _eff_t; return _eff_l; } double _eff_b, _eff_c, _eff_t, _eff_l; }; /// Take a jet and return an unmodified copy /// @todo Modify constituent particle vectors for consistency /// @todo Set a null PseudoJet if the Jet is smeared? inline Jet JET_SMEAR_IDENTITY(const Jet& j) { return j; } /// Alias for JET_SMEAR_IDENTITY inline Jet JET_SMEAR_PERFECT(const Jet& j) { return j; } /// @brief Functor for simultaneous efficiency-filtering and smearing of Jets /// /// A central element of the SmearedJets system /// /// @todo Include tagging efficiency functions? struct JetEffSmearFn { JetEffSmearFn(const JetSmearFn& s, const JetEffFn& e) : sfn(s), efn(e) { } JetEffSmearFn(const JetEffFn& e, const JetSmearFn& s) : sfn(s), efn(e) { } JetEffSmearFn(const JetSmearFn& s) : sfn(s), efn(JET_EFF_ONE) { } JetEffSmearFn(const JetEffFn& e) : sfn(JET_SMEAR_IDENTITY), efn(e) { } JetEffSmearFn(double eff) : JetEffSmearFn(JET_EFF_CONST(eff)) { } /// Smear and calculate an efficiency for the given jet pair operator() (const Jet& j) const { return make_pair(sfn(j), efn(j)); } /// Compare to another, for use in the projection system - int cmp(const JetEffSmearFn& other) const { + CmpState cmp(const JetEffSmearFn& other) const { // cout << "Eff hashes = " << get_address(efn) << "," << get_address(other.efn) << "; " // << "smear hashes = " << get_address(sfn) << "," << get_address(other.sfn) << '\n'; - if (get_address(sfn) == 0 || get_address(other.sfn) == 0) return UNDEFINED; - if (get_address(efn) == 0 || get_address(other.efn) == 0) return UNDEFINED; + if (get_address(sfn) == 0 || get_address(other.sfn) == 0) return CmpState::UNDEF; + if (get_address(efn) == 0 || get_address(other.efn) == 0) return CmpState::UNDEF; return Rivet::cmp(get_address(sfn), get_address(other.sfn)) || Rivet::cmp(get_address(efn), get_address(other.efn)); } /// Automatic conversion to a smearing function operator JetSmearFn () { return sfn; } /// Automatic conversion to an efficiency function /// @todo Ambiguity re. whether reco eff or a tagging efficiency... // operator JetEffFn () { return efn; } // Stored functions/functors JetSmearFn sfn; JetEffFn efn; }; /// Return true if Jet @a j is chosen to survive a random efficiency selection template inline bool efffilt(const Jet& j, FN& feff) { return rand01() < feff(j); } /// A functor to return true if Jet @a j survives a random efficiency selection struct JetEffFilter { template JetEffFilter(const FN& feff) : _feff(feff) {} JetEffFilter(double eff) : JetEffFilter( [&](const Jet& j){return eff;} ) {} bool operator () (const Jet& j) const { return efffilt(j, _feff); } private: const JetEffFn _feff; }; using jetEffFilter = JetEffFilter; //@} } #endif diff --git a/include/Rivet/Tools/ParticleSmearingFunctions.hh b/include/Rivet/Tools/ParticleSmearingFunctions.hh --- a/include/Rivet/Tools/ParticleSmearingFunctions.hh +++ b/include/Rivet/Tools/ParticleSmearingFunctions.hh @@ -1,118 +1,118 @@ // -*- C++ -*- #ifndef RIVET_ParticleSmearingFunctions_HH #define RIVET_ParticleSmearingFunctions_HH #include "Rivet/Particle.hh" #include "Rivet/Tools/MomentumSmearingFunctions.hh" #include "Rivet/Tools/Random.hh" namespace Rivet { /// @name Particle filtering, efficiency and smearing utils //@{ /// @name Typedef for Particle smearing functions/functors typedef function ParticleSmearFn; /// @name Typedef for Particle efficiency functions/functors typedef function ParticleEffFn; /// Take a Particle and return 0 inline double PARTICLE_EFF_ZERO(const Particle& ) { return 0; } /// Alias for PARTICLE_EFF_ZERO inline double PARTICLE_EFF_0(const Particle& ) { return 0; } /// Alias for PARTICLE_EFF_ZERO inline double PARTICLE_FN0(const Particle& ) { return 0; } /// Take a Particle and return 1 inline double PARTICLE_EFF_ONE(const Particle& ) { return 1; } /// Alias for PARTICLE_EFF_ONE inline double PARTICLE_EFF_1(const Particle& ) { return 1; } /// Alias for PARTICLE_EFF_ONE inline double PARTICLE_EFF_PERFECT(const Particle& ) { return 1; } /// Alias for PARTICLE_EFF_ONE inline double PARTICLE_FN1(const Particle& ) { return 1; } /// Take a Particle and return a constant number struct PARTICLE_EFF_CONST { PARTICLE_EFF_CONST(double x) : _x(x) {} double operator () (const Particle& ) const { return _x; } double _x; }; /// Take a Particle and return it unmodified inline Particle PARTICLE_SMEAR_IDENTITY(const Particle& p) { return p; } /// Alias for PARTICLE_SMEAR_IDENTITY inline Particle PARTICLE_SMEAR_PERFECT(const Particle& p) { return p; } /// @brief Functor for simultaneous efficiency-filtering and smearing of Particles /// /// A central element of the SmearedParticles system struct ParticleEffSmearFn { ParticleEffSmearFn(const ParticleSmearFn& s, const ParticleEffFn& e) : sfn(s), efn(e) { } ParticleEffSmearFn(const ParticleEffFn& e, const ParticleSmearFn& s) : sfn(s), efn(e) { } ParticleEffSmearFn(const ParticleSmearFn& s) : sfn(s), efn(PARTICLE_EFF_ONE) { } ParticleEffSmearFn(const ParticleEffFn& e) : sfn(PARTICLE_SMEAR_IDENTITY), efn(e) { } ParticleEffSmearFn(double eff) : ParticleEffSmearFn(PARTICLE_EFF_CONST(eff)) { } /// Smear and calculate an efficiency for the given particle pair operator() (const Particle& p) const { return make_pair(sfn(p), efn(p)); } /// Compare to another, for use in the projection system - int cmp(const ParticleEffSmearFn& other) const { + CmpState cmp(const ParticleEffSmearFn& other) const { // cout << "Eff hashes = " << get_address(efn) << "," << get_address(other.efn) << "; " // << "smear hashes = " << get_address(sfn) << "," << get_address(other.sfn) << '\n'; - if (get_address(sfn) == 0 || get_address(other.sfn) == 0) return UNDEFINED; - if (get_address(efn) == 0 || get_address(other.efn) == 0) return UNDEFINED; + if (get_address(sfn) == 0 || get_address(other.sfn) == 0) return CmpState::UNDEF; + if (get_address(efn) == 0 || get_address(other.efn) == 0) return CmpState::UNDEF; return Rivet::cmp(get_address(sfn), get_address(other.sfn)) || Rivet::cmp(get_address(efn), get_address(other.efn)); } /// Automatic conversion to a smearing function operator ParticleSmearFn () { return sfn; } /// Automatic conversion to an efficiency function operator ParticleEffFn () { return efn; } // Stored functions/functors const ParticleSmearFn sfn; const ParticleEffFn efn; }; /// Return true if Particle @a p is chosen to survive a random efficiency selection inline bool efffilt(const Particle& p, const ParticleEffFn& feff) { return rand01() < feff(p); } /// A functor to return true if Particle @a p survives a random efficiency selection /// @deprecated Prefer struct ParticleEffFilter { template ParticleEffFilter(const FN& feff) : _feff(feff) {} ParticleEffFilter(double eff) : ParticleEffFilter( [&](const Particle& p){return eff;} ) {} bool operator () (const Particle& p) const { return efffilt(p, _feff); } private: const ParticleEffFn _feff; }; using particleEffFilter = ParticleEffFilter; //@} } #endif diff --git a/src/Core/Jet.cc b/src/Core/Jet.cc --- a/src/Core/Jet.cc +++ b/src/Core/Jet.cc @@ -1,224 +1,185 @@ #include "Rivet/Jet.hh" #include "Rivet/Tools/Cuts.hh" #include "Rivet/Tools/ParticleName.hh" #include "Rivet/Tools/Logging.hh" #include "Rivet/Tools/ParticleIdUtils.hh" namespace Rivet { Jet& Jet::clear() { _momentum = FourMomentum(); _pseudojet.reset(0,0,0,0); _particles.clear(); return *this; } Jet& Jet::setState(const FourMomentum& mom, const Particles& particles, const Particles& tags) { clear(); _momentum = mom; _pseudojet = fastjet::PseudoJet(mom.px(), mom.py(), mom.pz(), mom.E()); _particles = particles; _tags = tags; return *this; } Jet& Jet::setState(const fastjet::PseudoJet& pj, const Particles& particles, const Particles& tags) { clear(); _pseudojet = pj; _momentum = FourMomentum(pj.e(), pj.px(), pj.py(), pj.pz()); _particles = particles; _tags = tags; // if (_particles.empty()) { // for (const fastjet::PseudoJet pjc : _pseudojet.constituents()) { // // If there is no attached user info, we can't create a meaningful particle, so skip // if (!pjc.has_user_info()) continue; // const RivetFJInfo& fjinfo = pjc.user_info(); // // Don't add ghosts to the particles list // if (fjinfo.isGhost) continue; // // Otherwise construct a Particle from the PseudoJet, preferably from an associated GenParticle // ?if (fjinfo.genParticle != NULL) { // _particles.push_back(Particle(fjinfo.genParticle)); // } else { // if (fjinfo.pid == 0) continue; // skip if there is a null PID entry in the FJ info // const FourMomentum pjcmom(pjc.e(), pjc.px(), pjc.py(), pjc.pz()); // _particles.push_back(Particle(fjinfo.pid, pjcmom)); // } // } // } return *this; } Jet& Jet::setParticles(const Particles& particles) { _particles = particles; return *this; } bool Jet::containsParticle(const Particle& particle) const { const int barcode = particle.genParticle()->barcode(); for (const Particle& p : particles()) { if (p.genParticle()->barcode() == barcode) return true; } return false; } bool Jet::containsParticleId(PdgId pid) const { for (const Particle& p : particles()) { if (p.pid() == pid) return true; } return false; } bool Jet::containsParticleId(const vector& pids) const { for (const Particle& p : particles()) { for (PdgId pid : pids) { if (p.pid() == pid) return true; } } return false; } /// @todo Jet::containsMatch(Matcher m) { ... if m(pid) return true; ... } Jet& Jet::transformBy(const LorentzTransform& lt) { _momentum = lt.transform(_momentum); for (Particle& p : _particles) p.transformBy(lt); for (Particle& t : _tags) t.transformBy(lt); _pseudojet.reset(_momentum.px(), _momentum.py(), _momentum.pz(), _momentum.E()); //< lose ClusterSeq etc. return *this; } double Jet::neutralEnergy() const { double e_neutral = 0.0; for (const Particle& p : particles()) { const PdgId pid = p.pid(); if (PID::threeCharge(pid) == 0) { e_neutral += p.E(); } } return e_neutral; } double Jet::hadronicEnergy() const { double e_hadr = 0.0; for (const Particle& p : particles()) { const PdgId pid = p.pid(); if (PID::isHadron(pid)) { e_hadr += p.E(); } } return e_hadr; } - - bool Jet::containsCharm(bool include_decay_products) const { - for (const Particle& p : particles()) { - const PdgId pid = p.pid(); - if (abs(pid) == PID::CQUARK) return true; - if (PID::isHadron(pid) && PID::hasCharm(pid)) return true; - if (include_decay_products) { - const HepMC::GenVertex* gv = p.genParticle()->production_vertex(); - if (gv) { - for (const GenParticle* pi : Rivet::particles(gv, HepMC::ancestors)) { - const PdgId pid2 = pi->pdg_id(); - if (PID::isHadron(pid2) && PID::hasCharm(pid2)) return true; - } - } - } - } - return false; - } - - - bool Jet::containsBottom(bool include_decay_products) const { - for (const Particle& p : particles()) { - const PdgId pid = p.pid(); - if (abs(pid) == PID::BQUARK) return true; - if (PID::isHadron(pid) && PID::hasBottom(pid)) return true; - if (include_decay_products) { - const HepMC::GenVertex* gv = p.genParticle()->production_vertex(); - if (gv) { - for (const GenParticle* pi : Rivet::particles(gv, HepMC::ancestors)) { - const PdgId pid2 = pi->pdg_id(); - if (PID::isHadron(pid2) && PID::hasBottom(pid2)) return true; - } - } - } - } - return false; - } - - Particles Jet::tags(const Cut& c) const { return filter_select(tags(), c); } Particles Jet::bTags(const Cut& c) const { Particles rtn; for (const Particle& tp : tags()) { if (hasBottom(tp) && c->accept(tp)) rtn.push_back(tp); } return rtn; } Particles Jet::cTags(const Cut& c) const { Particles rtn; for (const Particle& tp : tags()) { /// @todo Is making b and c tags exclusive the right thing to do? if (hasCharm(tp) && !hasBottom(tp) && c->accept(tp)) rtn.push_back(tp); } return rtn; } Particles Jet::tauTags(const Cut& c) const { Particles rtn; for (const Particle& tp : tags()) { if (isTau(tp) && c->accept(tp)) rtn.push_back(tp); } return rtn; } ////////////////////// /// Jets copy constructor from vector Jets::Jets(const std::vector& vjs) : base(vjs) {} /// Jets -> FourMomenta cast/conversion operator Jets::operator FourMomenta () const { // FourMomenta rtn(this->begin(), this->end()); FourMomenta rtn; rtn.reserve(this->size()); for (size_t i = 0; i < this->size(); ++i) rtn.push_back((*this)[i]); return rtn; } /// Jets concatenation operator Jets operator + (const Jets& a, const Jets& b) { Jets rtn(a); rtn += b; return rtn; } /// Allow a Jet to be passed to an ostream. std::ostream& operator << (std::ostream& os, const Jet& j) { using std::boolalpha; os << "Jet<" << j.mom()/GeV << " GeV; Nparticles=" << j.size() << "; "; os << "bTag=" << boolalpha << j.bTagged() << ", "; os << "cTag=" << boolalpha << j.cTagged() << ", "; os << "tauTag=" << boolalpha << j.tauTagged() << ">"; return os; } } diff --git a/src/Core/Projection.cc b/src/Core/Projection.cc --- a/src/Core/Projection.cc +++ b/src/Core/Projection.cc @@ -1,60 +1,60 @@ // -*- C++ -*- #include "Rivet/Event.hh" #include "Rivet/Projection.hh" #include "Rivet/Tools/Logging.hh" #include "Rivet/Tools/BeamConstraint.hh" #include "Rivet/Tools/Cmp.hh" namespace Rivet { Projection::Projection() : _name("BaseProjection") { addPdgIdPair(PID::ANY, PID::ANY); } - Projection:: ~Projection() { } + Projection:: ~Projection() = default; Projection& Projection::operator = (const Projection&) { return *this; } bool Projection::before(const Projection& p) const { const std::type_info& thisid = typeid(*this); const std::type_info& otherid = typeid(p); if (thisid == otherid) { - const bool cmp = compare(p) < 0; + const bool cmp = compare(p) == CmpState::LT; MSG_TRACE("Comparing projections of same RTTI type: " << this << " < " << &p << " = " << cmp); return cmp; } else { const bool cmp = thisid.before(otherid); MSG_TRACE("Ordering projections of different RTTI type: " << this << " < " << &p << " = " << cmp); return cmp; } } const set Projection::beamPairs() const { set ret = _beamPairs; set projs = getProjections(); for (set::const_iterator ip = projs.begin(); ip != projs.end(); ++ip) { ConstProjectionPtr p = *ip; getLog() << Log::TRACE << "Proj addr = " << p << '\n'; if (p) ret = intersection(ret, p->beamPairs()); } return ret; } Cmp Projection::mkNamedPCmp(const Projection& otherparent, const string& pname) const { return pcmp(*this, otherparent, pname); } Cmp Projection::mkPCmp(const Projection& otherparent, const string& pname) const { return pcmp(*this, otherparent, pname); } } diff --git a/src/Core/ProjectionHandler.cc b/src/Core/ProjectionHandler.cc --- a/src/Core/ProjectionHandler.cc +++ b/src/Core/ProjectionHandler.cc @@ -1,267 +1,267 @@ // -*- C++ -*- #include "Rivet/Config/RivetCommon.hh" #include "Rivet/ProjectionHandler.hh" #include "Rivet/Tools/Cmp.hh" #include #include using std::cerr; namespace { // Get a logger. Rivet::Log& getLog() { return Rivet::Log::getLog("Rivet.ProjectionHandler"); } } namespace Rivet { // Take a Projection, compare it to the others on record, and return (by // reference) an equivalent Projection which is guaranteed to be the // (persistent) version that will be applied to an event. const Projection& ProjectionHandler::registerProjection(const ProjectionApplier& parent, const Projection& proj, const string& name) { getLog() << Log::TRACE << "Trying to register" << " projection " << &proj << " (" << proj.name() << ")" << " for parent " << &parent << " (" << parent.name() << ")" << " with name '" << name << "'" << '\n'; // Check for duplicate use of "name" on "parent" const bool dupOk = _checkDuplicate(parent, proj, name); if (!dupOk) { cerr << "Duplicate name '" << name << "' in parent '" << parent.name() << "'." << '\n'; exit(1); } // Choose which version of the projection to register with this parent and name ProjHandle ph = _getEquiv(proj); if ( ph ) { const Projection & ret = _register(parent, ph, name); return ret; } else { unique_ptr p = _clone(proj); const Projection & ret = _register(parent, move(p), name); // Return registered proj return ret; } } // Clone neatly unique_ptr ProjectionHandler::_clone(const Projection& proj) { // Clone a new copy of the passed projection on the heap getLog() << Log::TRACE << "Cloning projection " << proj.name() << " from " << &proj << "..." << '\n'; unique_ptr newproj = proj.clone(); getLog() << Log::TRACE << "...cloned to " << proj.name() << " at " << newproj.get() << '\n'; // Copy all the child ProjHandles when cloning, since otherwise links to "stack parents" // will be generated by their children, without any connection to the cloned parent if (&proj != newproj.get()) { auto nps = _namedprojs.find(&proj); if (nps != _namedprojs.end()) { getLog() << Log::TRACE << "Cloning registered projections list: " << &proj << " -> " << newproj.get() << '\n'; getLog() << Log::TRACE << "** creates " << newproj.get() << " -> (map from " << nps->first << ")\n"; _namedprojs[newproj.get()] = nps->second; } } return newproj; } // Take a Projection, and register it in the registry. const Projection& ProjectionHandler::_register(const ProjectionApplier& parent, ProjHandle p, const string& name) { // here we take ownership of the projection getLog() << Log::TRACE << "Registering new projection at " << p.get() << ". Starting refcount: " << p.use_count() << '\n'; // Add the passed Projection to _projs _projs.insert(p); getLog() << Log::TRACE << "** inserted " << p.get() << " to lookup. Refcount: " << p.use_count() << '\n'; // Add the ProjApplier* => name location to the associative container _namedprojs[&parent][name] = p; getLog() << Log::TRACE << "** created " << &parent << " -> (" << name << ',' << p.get() << "). Refcount: " << p.use_count() << '\n'; p->markAsOwned(); return *p; } // Try to find a equivalent projection in the system ProjHandle ProjectionHandler::_getEquiv(const Projection& proj) const { // Get class type using RTTI const std::type_info& newtype = typeid(proj); getLog() << Log::TRACE << "RTTI type of " << &proj << " is " << newtype.name() << '\n'; // Compare to ALL projections via _projs collection getLog() << Log::TRACE << "Comparing " << &proj << " with " << _projs.size() << " registered projection" << (_projs.size() == 1 ? "" : "s") << '\n'; for (const ProjHandle& ph : _projs) { // Make sure the concrete types match, using RTTI. const std::type_info& regtype = typeid(*ph); getLog() << Log::TRACE << " RTTI type comparison with " << ph << ": " << newtype.name() << " vs. " << regtype.name() << '\n'; if (newtype != regtype) continue; getLog() << Log::TRACE << " RTTI type matches with " << ph << '\n'; // Test for semantic match - if (pcmp(*ph, proj) != EQUIVALENT) { + if (pcmp(*ph, proj) != CmpState::EQ) { getLog() << Log::TRACE << " Projections at " << &proj << " and " << ph << " are not equivalent" << '\n'; } else { getLog() << Log::TRACE << " MATCH! Projections at " << &proj << " and " << ph << " are equivalent" << '\n'; return ph; } } getLog() << Log::TRACE << " Nothing matches." << '\n'; // If no match, just return a null pointer return nullptr; } string ProjectionHandler::_getStatus() const { std::ostringstream msg; msg << "Current projection hierarchy:" << '\n'; for (const NamedProjsMap::value_type& nps : _namedprojs) { //const string parentname = nps.first->name(); msg << nps.first << '\n'; //"(" << parentname << ")" << '\n'; for (const NamedProjs::value_type& np : nps.second) { msg << " " << np.second << " (" << np.second->name() << ", locally called '" << np.first << "')" << '\n'; } msg << '\n'; } return msg.str(); } // Check that the same parent hasn't already used this name for something else bool ProjectionHandler::_checkDuplicate(const ProjectionApplier& parent, const Projection& proj, const string& name) const { auto listedParent = _namedprojs.find(&parent); if (listedParent != _namedprojs.end()) { const NamedProjs pnps = listedParent->second; const NamedProjs::const_iterator ipph = pnps.find(name); if (ipph != pnps.end()) { const ProjHandle pph = ipph->second; getLog() << Log::ERROR << "Projection clash! " << parent.name() << " (" << &parent << ") " << "is trying to overwrite its registered '" << name << "' " << "projection (" << pph << "=" << pph->name() << ") with a non-equivalent projection " << "(" << &proj << "=" << proj.name() << ")" << '\n'; getLog() << Log::ERROR << _getStatus(); return false; } } return true; } void ProjectionHandler::removeProjectionApplier(ProjectionApplier& parent) { auto npi = _namedprojs.find(&parent); if (npi != _namedprojs.end()) { getLog() << Log::TRACE << "REMOVE Projection at " << &parent << " from map" << '\n'; _namedprojs.erase(npi); } // auto pAsProj = dynamic_cast(&parent); if (pAsProj) { auto pi = find_if(_projs.begin(), _projs.end(), [pAsProj](ProjHandle h)->bool { return h.get() == pAsProj; } ); if (pi != _projs.end()) { getLog() << Log::TRACE << "REMOVE Projection at " << pAsProj << " from lookup" << '\n'; _projs.erase(pi); } } } set ProjectionHandler::getChildProjections(const ProjectionApplier& parent, ProjDepth depth) const { set toplevel; NamedProjs nps = _namedprojs.find(&parent)->second; for (NamedProjs::value_type& np : nps) { toplevel.insert(np.second.get()); } if (depth == SHALLOW) { // Only return the projections directly contained within the top level return toplevel; } else { // Return recursively built projection list set alllevels = toplevel; for (const Projection* p : toplevel) { set allsublevels = getChildProjections(*p, DEEP); alllevels.insert(allsublevels.begin(), allsublevels.end()); } return alllevels; } } bool ProjectionHandler::hasProjection(const ProjectionApplier& parent, const string& name) const { MSG_TRACE("Searching for child projection '" << name << "' of " << &parent); NamedProjsMap::const_iterator nps = _namedprojs.find(&parent); if (nps == _namedprojs.end()) return false; NamedProjs::const_iterator np = nps->second.find(name); return !(np == nps->second.end()); } const Projection& ProjectionHandler::getProjection(const ProjectionApplier& parent, const string& name) const { MSG_TRACE("Searching for child projection '" << name << "' of " << &parent); NamedProjsMap::const_iterator nps = _namedprojs.find(&parent); if (nps == _namedprojs.end()) { std::ostringstream msg; msg << "No projections registered for parent " << &parent; throw Error(msg.str()); } NamedProjs::const_iterator np = nps->second.find(name); if (np == nps->second.end()) { std::ostringstream msg; msg << "No projection '" << name << "' found for parent " << &parent; throw Error(msg.str()); } MSG_TRACE("Found projection '" << name << "' of " << &parent << " -> " << np->second); // If it's registered with the projection handler, we must be able to safely // dereference the Projection pointer to a reference... return *(np->second); } } diff --git a/src/Projections/ChargedFinalState.cc b/src/Projections/ChargedFinalState.cc --- a/src/Projections/ChargedFinalState.cc +++ b/src/Projections/ChargedFinalState.cc @@ -1,48 +1,48 @@ // -*- C++ -*- #include "Rivet/Projections/ChargedFinalState.hh" namespace Rivet { ChargedFinalState::ChargedFinalState(const FinalState& fsp) { setName("ChargedFinalState"); addProjection(fsp, "FS"); } ChargedFinalState::ChargedFinalState(const Cut& c) { setName("ChargedFinalState"); addProjection(FinalState(c), "FS"); } ChargedFinalState::ChargedFinalState(double mineta, double maxeta, double minpt) { setName("ChargedFinalState"); addProjection(FinalState(mineta, maxeta, minpt), "FS"); } - int ChargedFinalState::compare(const Projection& p) const { + CmpState ChargedFinalState::compare(const Projection& p) const { return mkNamedPCmp(p, "FS"); } } namespace { inline bool chargedParticleFilter(const Rivet::Particle& p) { return Rivet::PID::threeCharge(p.pdgId()) == 0; } } namespace Rivet { void ChargedFinalState::project(const Event& e) { const FinalState& fs = applyProjection(e, "FS"); _theParticles.clear(); std::remove_copy_if(fs.particles().begin(), fs.particles().end(), std::back_inserter(_theParticles), chargedParticleFilter); MSG_DEBUG("Number of charged final-state particles = " << _theParticles.size()); if (getLog().isActive(Log::TRACE)) { for (vector::iterator p = _theParticles.begin(); p != _theParticles.end(); ++p) { MSG_TRACE("Selected: " << p->pdgId() << ", charge = " << PID::threeCharge(p->pdgId())/3.0); } } } } diff --git a/src/Projections/ChargedLeptons.cc b/src/Projections/ChargedLeptons.cc --- a/src/Projections/ChargedLeptons.cc +++ b/src/Projections/ChargedLeptons.cc @@ -1,26 +1,26 @@ // -*- C++ -*- #include "Rivet/Projections/ChargedLeptons.hh" namespace Rivet { - int ChargedLeptons::compare(const Projection& other) const { + CmpState ChargedLeptons::compare(const Projection& other) const { return mkNamedPCmp(other, "ChFS"); } void ChargedLeptons::project(const Event& evt) { // Reset result _theParticles.clear(); // Loop over charged particles and fill vector with leptons const FinalState& fs = applyProjection(evt, "ChFS"); for (const Particle& p : fs.particles()) { if (PID::isChargedLepton(p.pid())) _theParticles += Particle(p); } sortBy(_theParticles, cmpMomByPt); } } diff --git a/src/Projections/DISKinematics.cc b/src/Projections/DISKinematics.cc --- a/src/Projections/DISKinematics.cc +++ b/src/Projections/DISKinematics.cc @@ -1,80 +1,80 @@ // -*- C++ -*- #include "Rivet/Projections/DISKinematics.hh" #include "Rivet/Math/Constants.hh" namespace Rivet { void DISKinematics::project(const Event& e) { // Find appropriate DIS leptons const DISLepton& dislep = applyProjection(e, "Lepton"); _outLepton = dislep.out(); // Identify beam hadron const ParticlePair& inc = applyProjection(e, "Beam").beams(); const bool firstIsHadron = PID::isHadron(inc.first.pid()); const bool secondIsHadron = PID::isHadron(inc.second.pid()); if (firstIsHadron && !secondIsHadron) { _inHadron = inc.first; _inLepton = dislep.in(); // inc.second; } else if (!firstIsHadron && secondIsHadron) { _inHadron = inc.second; _inLepton = dislep.in(); // inc.first; } else { throw Error("DISKinematics could not find the correct beam hadron"); } // Get the DIS lepton and store some of its properties const FourMomentum pHad = _inHadron.momentum(); const FourMomentum pLepIn = _inLepton.momentum(); const FourMomentum pLepOut = _outLepton.momentum(); const FourMomentum pGamma = pLepIn - pLepOut; const FourMomentum tothad = pGamma + pHad; _theQ2 = -pGamma.mass2(); _theW2 = tothad.mass2(); _theX = Q2()/(2.0 * pGamma * pHad); _theY = (pGamma * pHad) / (pLepIn * pHad); _theS = invariant(pLepIn + pHad); // Calculate boost vector for boost into HCM-system LorentzTransform tmp; tmp.setBetaVec(-tothad.boostVector()); // Rotate so the photon is in x-z plane in HCM rest frame FourMomentum pGammaHCM = tmp.transform(pGamma); tmp.preMult(Matrix3(Vector3::mkZ(), -pGammaHCM.azimuthalAngle())); pGammaHCM = tmp.transform(pGamma); assert(isZero(dot(pGammaHCM.vector3(), Vector3::mkY()))); // Rotate so the photon is along the positive z-axis const double rot_angle = pGammaHCM.polarAngle() * (pGammaHCM.px() >= 0 ? -1 : 1); tmp.preMult(Matrix3(Vector3::mkY(), rot_angle)); // Check that final HCM photon lies along +ve z as expected pGammaHCM = tmp.transform(pGamma); assert(isZero(dot(pGammaHCM.vector3(), Vector3::mkX()), 1e-3)); assert(isZero(dot(pGammaHCM.vector3(), Vector3::mkY()), 1e-3)); assert(isZero(angle(pGammaHCM.vector3(), Vector3::mkZ()), 1e-3)); // Finally rotate so outgoing lepton at phi = 0 FourMomentum pLepOutHCM = tmp.transform(pLepOut); tmp.preMult(Matrix3(Vector3::mkZ(), -pLepOutHCM.azimuthalAngle())); assert(isZero(tmp.transform(pLepOut).azimuthalAngle())); _hcm = tmp; // Boost to Breit frame (use opposite convention for photon --- along *minus* z) tmp.preMult(Matrix3(Vector3::mkX(), PI)); const double bz = 1 - 2*x(); _breit = LorentzTransform::mkObjTransformFromBeta(Vector3::mkZ() * bz).combine(tmp); assert(isZero(angle(_breit.transform(pGamma).vector3(), -Vector3::mkZ()), 1e-3)); assert(isZero(_breit.transform(pLepOut).azimuthalAngle(), 1e-3)); } - int DISKinematics::compare(const Projection & p) const { + CmpState DISKinematics::compare(const Projection & p) const { const DISKinematics& other = pcast(p); return mkNamedPCmp(other, "Lepton"); } } 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,74 @@ // -*- C++ -*- #include "Rivet/Projections/DISLepton.hh" namespace Rivet { - int DISLepton::compare(const Projection& p) const { + CmpState DISLepton::compare(const Projection& p) const { const DISLepton& other = pcast(p); return mkNamedPCmp(other, "Beam") || mkNamedPCmp(other, "FS"); } 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 /// @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()) { _outgoing = sfleptons.front(); } else if (!fsleptons.empty()) { _outgoing = fsleptons.front(); } else { throw Error("Could not find the scattered lepton"); } } } diff --git a/src/Projections/DressedLeptons.cc b/src/Projections/DressedLeptons.cc --- a/src/Projections/DressedLeptons.cc +++ b/src/Projections/DressedLeptons.cc @@ -1,137 +1,137 @@ // -*- C++ -*- #include "Rivet/Projections/DressedLeptons.hh" namespace Rivet { // On DressedLepton helper class //{ DressedLepton::DressedLepton(const Particle& dlepton) : Particle(dlepton) { setConstituents({{dlepton}}); //< bare lepton is first constituent } DressedLepton::DressedLepton(const Particle& lepton, const Particles& photons, bool momsum) : Particle(lepton.pid(), lepton.momentum()) { setConstituents({{lepton}}); //< bare lepton is first constituent addConstituents(photons, momsum); } void DressedLepton::addPhoton(const Particle& p, bool momsum) { if (p.pid() != PID::PHOTON) throw Error("Clustering a non-photon on to a DressedLepton:"+to_string(p.pid())); addConstituent(p, momsum); } const Particle& DressedLepton::bareLepton() const { const Particle& l = constituents().front(); if (!l.isChargedLepton()) throw Error("First constituent of a DressedLepton is not a bare lepton: oops"); return l; } //} // Separate-FS version DressedLeptons::DressedLeptons(const FinalState& photons, const FinalState& bareleptons, double dRmax, const Cut& cut, bool useDecayPhotons) : FinalState(cut), _dRmax(dRmax), _fromDecay(useDecayPhotons) { setName("DressedLeptons"); IdentifiedFinalState photonfs(photons, PID::PHOTON); addProjection(photonfs, "Photons"); IdentifiedFinalState leptonfs(bareleptons); leptonfs.acceptIdPairs({PID::ELECTRON, PID::MUON, PID::TAU}); addProjection(leptonfs, "Leptons"); } // Single-FS version DressedLeptons::DressedLeptons(const FinalState& barefs, double dRmax, const Cut& cut, bool useDecayPhotons) : DressedLeptons(barefs, barefs, dRmax, cut, useDecayPhotons) { } - int DressedLeptons::compare(const Projection& p) const { + CmpState DressedLeptons::compare(const Projection& p) const { // Compare the two as final states (for pT and eta cuts) const DressedLeptons& other = dynamic_cast(p); - int fscmp = FinalState::compare(other); - if (fscmp != EQUIVALENT) return fscmp; + CmpState fscmp = FinalState::compare(other); + if (fscmp != CmpState::EQ) return fscmp; const PCmp phcmp = mkNamedPCmp(p, "Photons"); - if (phcmp != EQUIVALENT) return phcmp; + if (phcmp != CmpState::EQ) return phcmp; const PCmp sigcmp = mkNamedPCmp(p, "Leptons"); - if (sigcmp != EQUIVALENT) return sigcmp; + if (sigcmp != CmpState::EQ) return sigcmp; return (cmp(_dRmax, other._dRmax) || cmp(_fromDecay, other._fromDecay)); } void DressedLeptons::project(const Event& e) { _theParticles.clear(); // Get bare leptons const FinalState& signal = applyProjection(e, "Leptons"); Particles bareleptons = signal.particles(); if (bareleptons.empty()) return; // Initialise DL collection with bare leptons vector allClusteredLeptons; allClusteredLeptons.reserve(bareleptons.size()); for (const Particle& bl : bareleptons) { Particle dl(bl.pid(), bl.momentum()); dl.setConstituents({bl}); allClusteredLeptons += dl; } // If the radius is 0 or negative, don't even attempt to cluster if (_dRmax > 0) { // Match each photon to its closest charged lepton within the dR cone const FinalState& photons = applyProjection(e, "Photons"); for (const Particle& photon : photons.particles()) { // Ignore photon if it's from a hadron/tau decay and we're avoiding those if (!_fromDecay && photon.fromDecay()) continue; const FourMomentum& p_P = photon.momentum(); double dRmin = _dRmax; int idx = -1; for (size_t i = 0; i < bareleptons.size(); ++i) { const Particle& bl = bareleptons[i]; // Only cluster photons around *charged* signal particles if (bl.charge3() == 0) continue; // Find the closest lepton double dR = deltaR(bl, p_P); if (dR < dRmin) { dRmin = dR; idx = i; } } if (idx > -1) allClusteredLeptons[idx].addConstituent(photon, true); } } // Fill the canonical particles collection with the composite DL Particles for (const Particle& lepton : allClusteredLeptons) { const bool acc = accept(lepton); MSG_TRACE("Clustered lepton " << lepton << " with constituents = " << lepton.constituents() << ", cut-pass = " << std::boolalpha << acc); if (acc) _theParticles.push_back(lepton); } MSG_DEBUG("#dressed leptons = " << allClusteredLeptons.size() << " -> " << _theParticles.size() << " after cuts"); } } diff --git a/src/Projections/FastJets.cc b/src/Projections/FastJets.cc --- a/src/Projections/FastJets.cc +++ b/src/Projections/FastJets.cc @@ -1,214 +1,214 @@ // -*- C++ -*- #include "Rivet/Config/RivetCommon.hh" #include "Rivet/Tools/Logging.hh" #include "Rivet/Projections/FastJets.hh" #include "Rivet/Projections/HeavyHadrons.hh" #include "Rivet/Projections/TauFinder.hh" namespace Rivet { void FastJets::_initBase() { setName("FastJets"); addProjection(HeavyHadrons(), "HFHadrons"); addProjection(TauFinder(TauFinder::DecayMode::HADRONIC), "Taus"); } void FastJets::_initJdef(Algo alg, double rparameter, double seed_threshold) { MSG_DEBUG("JetAlg = " << static_cast(alg)); MSG_DEBUG("R parameter = " << rparameter); MSG_DEBUG("Seed threshold = " << seed_threshold); if (alg == KT) { _jdef = fastjet::JetDefinition(fastjet::kt_algorithm, rparameter, fastjet::E_scheme); } else if (alg == CAM) { _jdef = fastjet::JetDefinition(fastjet::cambridge_algorithm, rparameter, fastjet::E_scheme); } else if (alg == ANTIKT) { _jdef = fastjet::JetDefinition(fastjet::antikt_algorithm, rparameter, fastjet::E_scheme); } else if (alg == DURHAM) { _jdef = fastjet::JetDefinition(fastjet::ee_kt_algorithm, fastjet::E_scheme); } else if (alg == GENKTEE) { _jdef = fastjet::JetDefinition(fastjet::ee_genkt_algorithm, rparameter, -1); } else { // Plugins: if (alg == SISCONE) { const double OVERLAP_THRESHOLD = 0.75; _plugin.reset(new fastjet::SISConePlugin(rparameter, OVERLAP_THRESHOLD)); // } else if (alg == PXCONE) { // string msg = "PxCone currently not supported, since FastJet doesn't install it by default. "; // msg += "Please notify the Rivet authors if this behaviour should be changed."; // throw Error(msg); // _plugin.reset(new fastjet::PxConePlugin(rparameter)); } else if (alg == ATLASCONE) { const double OVERLAP_THRESHOLD = 0.5; _plugin.reset(new fastjet::ATLASConePlugin(rparameter, seed_threshold, OVERLAP_THRESHOLD)); } else if (alg == CMSCONE) { _plugin.reset(new fastjet::CMSIterativeConePlugin(rparameter, seed_threshold)); } else if (alg == CDFJETCLU) { const double OVERLAP_THRESHOLD = 0.75; _plugin.reset(new fastjet::CDFJetCluPlugin(rparameter, OVERLAP_THRESHOLD, seed_threshold)); } else if (alg == CDFMIDPOINT) { const double OVERLAP_THRESHOLD = 0.5; _plugin.reset(new fastjet::CDFMidPointPlugin(rparameter, OVERLAP_THRESHOLD, seed_threshold)); } else if (alg == D0ILCONE) { const double min_jet_Et = 6.0; _plugin.reset(new fastjet::D0RunIIConePlugin(rparameter, min_jet_Et)); } else if (alg == JADE) { _plugin.reset(new fastjet::JadePlugin()); } else if (alg == TRACKJET) { _plugin.reset(new fastjet::TrackJetPlugin(rparameter)); } _jdef = fastjet::JetDefinition(_plugin.get()); } } - int FastJets::compare(const Projection& p) const { + CmpState FastJets::compare(const Projection& p) const { const FastJets& other = dynamic_cast(p); return \ cmp(_useMuons, other._useMuons) || cmp(_useInvisibles, other._useInvisibles) || mkNamedPCmp(other, "FS") || cmp(_jdef.jet_algorithm(), other._jdef.jet_algorithm()) || cmp(_jdef.recombination_scheme(), other._jdef.recombination_scheme()) || cmp(_jdef.plugin(), other._jdef.plugin()) || cmp(_jdef.R(), other._jdef.R()) || cmp(_adef, other._adef); } // STATIC PseudoJets FastJets::mkClusterInputs(const Particles& fsparticles, const Particles& tagparticles) { PseudoJets pjs; /// @todo Use FastJet3's UserInfo system to store Particle pointers directly? // Store 4 vector data about each particle into FastJet's PseudoJets for (size_t i = 0; i < fsparticles.size(); ++i) { fastjet::PseudoJet pj = fsparticles[i]; pj.set_user_index(i+1); pjs.push_back(pj); } // And the same for ghost tagging particles (with negative user indices) for (size_t i = 0; i < tagparticles.size(); ++i) { fastjet::PseudoJet pj = tagparticles[i]; pj *= 1e-20; ///< Ghostify the momentum pj.set_user_index(-i-1); pjs.push_back(pj); } return pjs; } // STATIC Jet FastJets::mkJet(const PseudoJet& pj, const Particles& fsparticles, const Particles& tagparticles) { const PseudoJets pjconstituents = pj.constituents(); Particles constituents, tags; constituents.reserve(pjconstituents.size()); for (const fastjet::PseudoJet& pjc : pjconstituents) { // Pure ghosts don't have corresponding particles if (pjc.has_area() && pjc.is_pure_ghost()) continue; // Default user index = 0 doesn't give valid particle lookup if (pjc.user_index() == 0) continue; // Split by index sign into constituent & tag lookup if (pjc.user_index() > 0) { // Find constituents if index > 0 const size_t i = pjc.user_index() - 1; if (i >= fsparticles.size()) throw RangeError("FS particle lookup failed in jet construction"); constituents.push_back(fsparticles.at(i)); } else if (!tagparticles.empty()) { // Find tags if index < 0 const size_t i = abs(pjc.user_index()) - 1; if (i >= tagparticles.size()) throw RangeError("Tag particle lookup failed in jet construction"); tags.push_back(tagparticles.at(i)); } } return Jet(pj, constituents, tags); } // STATIC Jets FastJets::mkJets(const PseudoJets& pjs, const Particles& fsparticles, const Particles& tagparticles) { Jets rtn; rtn.reserve(pjs.size()); for (const PseudoJet pj : pjs) { rtn.push_back(FastJets::mkJet(pj, fsparticles, tagparticles)); } return rtn; } void FastJets::project(const Event& e) { // Assemble final state particles const string fskey = (_useInvisibles == JetAlg::Invisibles::NONE) ? "VFS" : "FS"; Particles fsparticles = applyProjection(e, fskey).particles(); // Remove prompt invisibles if needed (already done by VFS if using NO_INVISIBLES) if (_useInvisibles == JetAlg::Invisibles::DECAY) { ifilter_discard(fsparticles, [](const Particle& p) { return !(p.isVisible() || p.fromDecay()); }); } // Remove prompt/all muons if needed if (_useMuons == JetAlg::Muons::DECAY) { ifilter_discard(fsparticles, [](const Particle& p) { return isMuon(p) && !p.fromDecay(); }); } else if (_useMuons == JetAlg::Muons::NONE) { ifilter_discard(fsparticles, isMuon); } // Tagging particles const Particles chadrons = applyProjection(e, "HFHadrons").cHadrons(); const Particles bhadrons = applyProjection(e, "HFHadrons").bHadrons(); const Particles taus = applyProjection(e, "Taus").particles(); calc(fsparticles, chadrons+bhadrons+taus); } void FastJets::calc(const Particles& fsparticles, const Particles& tagparticles) { MSG_DEBUG("Finding jets from " << fsparticles.size() << " input particles + " << tagparticles.size() << " tagging particles"); _fsparticles = fsparticles; _tagparticles = tagparticles; // Make pseudojets, with mapping info to Rivet FS and tag particles PseudoJets pjs = mkClusterInputs(_fsparticles, _tagparticles); // Run either basic or area-calculating cluster sequence as reqd. if (_adef) { _cseq.reset(new fastjet::ClusterSequenceArea(pjs, _jdef, *_adef)); } else { _cseq.reset(new fastjet::ClusterSequence(pjs, _jdef)); } MSG_DEBUG("ClusterSequence constructed; Njets_tot = " << _cseq->inclusive_jets().size() << ", Njets(pT > 10 GeV) = " << _cseq->inclusive_jets(10*GeV).size()); } void FastJets::reset() { _yscales.clear(); _fsparticles.clear(); _tagparticles.clear(); /// @todo _cseq = fastjet::ClusterSequence(); } Jets FastJets::_jets() const { /// @todo Cache? return mkJets(pseudojets(), _fsparticles, _tagparticles); } Jet FastJets::trimJet(const Jet& input, const fastjet::Filter& trimmer) const { if (input.pseudojet().associated_cluster_sequence() != clusterSeq().get()) throw Error("To trim a Rivet::Jet, its associated PseudoJet must have come from this FastJets' ClusterSequence"); PseudoJet pj = trimmer(input); return mkJet(pj, _fsparticles, _tagparticles); } PseudoJets FastJets::pseudoJets(double ptmin) const { return clusterSeq() ? clusterSeq()->inclusive_jets(ptmin) : PseudoJets(); } } diff --git a/src/Projections/FinalState.cc b/src/Projections/FinalState.cc --- a/src/Projections/FinalState.cc +++ b/src/Projections/FinalState.cc @@ -1,101 +1,101 @@ // -*- C++ -*- #include "Rivet/Projections/FinalState.hh" namespace Rivet { FinalState::FinalState(const Cut& c) : ParticleFinder(c) { setName("FinalState"); const bool isopen = (c == Cuts::open()); MSG_TRACE("Check for open FS conditions: " << std::boolalpha << isopen); if (!isopen) addProjection(FinalState(), "OpenFS"); } FinalState::FinalState(const FinalState& fsp, const Cut& c) : ParticleFinder(c) { setName("FinalState"); MSG_TRACE("Registering base FSP as 'PrevFS'"); addProjection(fsp, "PrevFS"); } /// @deprecated, keep for backwards compatibility for now. FinalState::FinalState(double mineta, double maxeta, double minpt) { setName("FinalState"); const bool openpt = isZero(minpt); const bool openeta = (mineta <= -MAXDOUBLE && maxeta >= MAXDOUBLE); MSG_TRACE("Check for open FS conditions:" << std::boolalpha << " eta=" << openeta << ", pt=" << openpt); if (openpt && openeta) { _cuts = Cuts::open(); } else { addProjection(FinalState(), "OpenFS"); if (openeta) _cuts = (Cuts::pT >= minpt); else if ( openpt ) _cuts = Cuts::etaIn(mineta, maxeta); else _cuts = (Cuts::etaIn(mineta, maxeta) && Cuts::pT >= minpt); } } - int FinalState::compare(const Projection& p) const { + CmpState FinalState::compare(const Projection& p) const { const FinalState& other = dynamic_cast(p); // First check if there is a PrevFS and it it matches - if (hasProjection("PrevFS") != other.hasProjection("PrevFS")) return UNDEFINED; + if (hasProjection("PrevFS") != other.hasProjection("PrevFS")) return CmpState::UNDEF; if (hasProjection("PrevFS")) { const PCmp prevcmp = mkPCmp(other, "PrevFS"); - if (prevcmp != EQUIVALENT) return prevcmp; + if (prevcmp != CmpState::EQ) return prevcmp; } // Then check the extra cuts const bool cutcmp = _cuts == other._cuts; MSG_TRACE(_cuts << " VS " << other._cuts << " -> EQ == " << std::boolalpha << cutcmp); - if (!cutcmp) return UNDEFINED; + if (!cutcmp) return CmpState::UNDEF; // Checks all passed: these FSes are equivalent - return EQUIVALENT; + return CmpState::EQ; } void FinalState::project(const Event& e) { _theParticles.clear(); // Handle "open FS" special case, which should not/cannot recurse if (_cuts == Cuts::OPEN) { MSG_TRACE("Open FS processing: should only see this once per event (" << e.genEvent()->event_number() << ")"); for (const GenParticle* p : Rivet::particles(e.genEvent())) { if (p->status() == 1) { MSG_TRACE("FS GV = " << p->production_vertex()); _theParticles.push_back(Particle(*p)); } } return; } // Base the calculation on PrevFS if available, otherwise OpenFS /// @todo In general, we'd like to calculate a restrictive FS based on the most restricted superset FS. const Particles& allstable = applyProjection(e, (hasProjection("PrevFS") ? "PrevFS" : "OpenFS")).particles(); for (const Particle& p : allstable) { const bool passed = accept(p); MSG_TRACE("Choosing: ID = " << p.pid() << ", pT = " << p.pT()/GeV << " GeV" << ", eta = " << p.eta() << ": result = " << std::boolalpha << passed); if (passed) _theParticles.push_back(p); } MSG_TRACE("Number of final-state particles = " << _theParticles.size()); } /// Decide if a particle is to be accepted or not. bool FinalState::accept(const Particle& p) const { // Not having status == 1 should never happen! assert(p.genParticle() == NULL || p.genParticle()->status() == 1); return _cuts->accept(p); } } diff --git a/src/Projections/FoxWolframMoments.cc b/src/Projections/FoxWolframMoments.cc --- a/src/Projections/FoxWolframMoments.cc +++ b/src/Projections/FoxWolframMoments.cc @@ -1,62 +1,62 @@ // -*- C++ -*- #include "Rivet/Projections/FoxWolframMoments.hh" namespace Rivet { - int FoxWolframMoments::compare(const Projection& p) const { + CmpState FoxWolframMoments::compare(const Projection& p) const { return mkNamedPCmp(p, "FS"); } void FoxWolframMoments::project(const Event& e) { // Project into final state and get total visible momentum const FinalState& fs = applyProjection(e, "VFS"); // remember: # pairs = N! / ( r! * (N-r)! ) // N.B.: Autocorrelations are included! Treat them separately as diagonal elements. // see: http://cepa.fnal.gov/psm/simulation/mcgen/lund/pythia_manual/pythia6.3/pythia6301/node215.html double sumEnergy = 0.0; for (Particles::const_iterator pi = fs.particles().begin(); pi != fs.particles().end(); ++pi) { sumEnergy += pi->momentum().E(); const FourMomentum pi_4 = pi->momentum(); for (Particles::const_iterator pj = pi+1; pj != fs.particles().end(); ++pj) { const FourMomentum pj_4 = pj->momentum(); // Calculate x_ij = cos(theta_ij) double x_ij = 1.0; if ( pi != pj ) { double denom = pi_4.vector3().mod() * pj_4.vector3().mod(); x_ij = pi_4.vector3().dot( pj_4.vector3() ) / denom; } //const double core = fabs( pi_4 * pj_4 ); // / sumet2 ; const double core = pi_4.vector3().mod() * pi_4.vector3().mod(); for (int order = 0; order < MAXMOMENT; ++order) { // enter a factor 2.0 because ij = ji. Use symmetry to speed up! _fwmoments[order] += 2.0 * core * gsl_sf_legendre_Pl( order, x_ij ) ; } } // end loop over p_j // Now add autocorrelations // Obviously cos(theta_ij) = 1.0 // Note that P_l(1) == 1 for each l for (int order = 0; order < MAXMOMENT; ++order) { _fwmoments[order] += fabs( pi_4 * pi_4 ); } } // end loop over p_i MSG_DEBUG("sumEnergy = " << sumEnergy); for (int order = 0; order < MAXMOMENT; ++order) { _fwmoments[order] /= (sumEnergy*sumEnergy); } // Normalize to H0 for (int order = 1; order < MAXMOMENT; ++order) { _fwmoments[order] /= _fwmoments[0]; } } } diff --git a/src/Projections/HadronicFinalState.cc b/src/Projections/HadronicFinalState.cc --- a/src/Projections/HadronicFinalState.cc +++ b/src/Projections/HadronicFinalState.cc @@ -1,26 +1,26 @@ // -*- C++ -*- #include "Rivet/Projections/HadronicFinalState.hh" namespace Rivet { - int HadronicFinalState::compare(const Projection& p) const { + CmpState HadronicFinalState::compare(const Projection& p) const { return FinalState::compare(p); } bool hadronFilter(const Particle& p) { return ! PID::isHadron(p.pid()); } void HadronicFinalState::project(const Event& e) { const FinalState& fs = applyProjection(e, "FS"); _theParticles.clear(); std::remove_copy_if(fs.particles().begin(), fs.particles().end(), std::back_inserter(_theParticles), hadronFilter); MSG_DEBUG("Number of hadronic final-state particles = " << _theParticles.size()); } } diff --git a/src/Projections/IdentifiedFinalState.cc b/src/Projections/IdentifiedFinalState.cc --- a/src/Projections/IdentifiedFinalState.cc +++ b/src/Projections/IdentifiedFinalState.cc @@ -1,85 +1,72 @@ // -*- C++ -*- #include "Rivet/Projections/IdentifiedFinalState.hh" namespace Rivet { IdentifiedFinalState::IdentifiedFinalState(const FinalState& fsp, const vector& pids) { setName("IdentifiedFinalState"); addProjection(fsp, "FS"); acceptIds(pids); } - IdentifiedFinalState::IdentifiedFinalState(const vector& pids, const FinalState& fsp) { - setName("IdentifiedFinalState"); - addProjection(fsp, "FS"); - acceptIds(pids); - } - IdentifiedFinalState::IdentifiedFinalState(const FinalState& fsp, PdgId pid) { setName("IdentifiedFinalState"); addProjection(fsp, "FS"); acceptId(pid); } - IdentifiedFinalState::IdentifiedFinalState(PdgId pid, const FinalState& fsp) { - setName("IdentifiedFinalState"); - addProjection(fsp, "FS"); - acceptId(pid); - } - - IdentifiedFinalState::IdentifiedFinalState(const Cut& c, const vector& pids) { setName("IdentifiedFinalState"); addProjection(FinalState(c), "FS"); acceptIds(pids); } IdentifiedFinalState::IdentifiedFinalState(const vector& pids, const Cut& c) { setName("IdentifiedFinalState"); addProjection(FinalState(c), "FS"); acceptIds(pids); } IdentifiedFinalState::IdentifiedFinalState(const Cut& c, PdgId pid) { setName("IdentifiedFinalState"); addProjection(FinalState(c), "FS"); acceptId(pid); } IdentifiedFinalState::IdentifiedFinalState(PdgId pid, const Cut& c) { setName("IdentifiedFinalState"); addProjection(FinalState(c), "FS"); acceptId(pid); } - int IdentifiedFinalState::compare(const Projection& p) const { + CmpState IdentifiedFinalState::compare(const Projection& p) const { const PCmp fscmp = mkNamedPCmp(p, "FS"); - if (fscmp != EQUIVALENT) return fscmp; + if (fscmp != CmpState::EQ) return fscmp; const IdentifiedFinalState& other = dynamic_cast(p); - int pidssize = cmp(_pids.size(), other._pids.size()); - if (pidssize != EQUIVALENT) return pidssize; + CmpState pidssize = cmp(_pids.size(), other._pids.size()); + if (pidssize != CmpState::EQ) return pidssize; return cmp(_pids, other._pids); } void IdentifiedFinalState::project(const Event& e) { const FinalState& fs = applyProjection(e, "FS"); _theParticles.clear(); _theParticles.reserve(fs.particles().size()); _remainingParticles.clear(); _remainingParticles.reserve(fs.particles().size()); for (const Particle& p : fs.particles()) { if (acceptedIds().find(p.pid()) != acceptedIds().end()) { _theParticles.push_back(p); // Identified } else { _remainingParticles.push_back(p); // Remaining } } } } diff --git a/src/Projections/InitialQuarks.cc b/src/Projections/InitialQuarks.cc --- a/src/Projections/InitialQuarks.cc +++ b/src/Projections/InitialQuarks.cc @@ -1,61 +1,61 @@ // -*- C++ -*- #include "Rivet/Projections/InitialQuarks.hh" namespace Rivet { - int InitialQuarks::compare(const Projection& p) const { - return EQUIVALENT; + CmpState InitialQuarks::compare(const Projection& p) const { + return CmpState::EQ; } void InitialQuarks::project(const Event& e) { _theParticles.clear(); for (const GenParticle* p : Rivet::particles(e.genEvent())) { const GenVertex* pv = p->production_vertex(); const GenVertex* dv = p->end_vertex(); const PdgId pid = abs(p->pdg_id()); bool passed = inRange((long)pid, 1, 6); if (passed) { if (pv != 0) { for (const GenParticle* pp : particles_in(pv)) { // Only accept if parent is electron or Z0 const PdgId pid = abs(pp->pdg_id()); passed = (pid == PID::ELECTRON || abs(pp->pdg_id()) == PID::ZBOSON || abs(pp->pdg_id()) == PID::GAMMA); } } else { passed = false; } } if (getLog().isActive(Log::TRACE)) { const int st = p->status(); const double pT = p->momentum().perp(); const double eta = p->momentum().eta(); MSG_TRACE(std::boolalpha << "ID = " << p->pdg_id() << ", status = " << st << ", pT = " << pT << ", eta = " << eta << ": result = " << passed); if (pv != 0) { for (const GenParticle* pp : particles_in(pv)) { MSG_TRACE(std::boolalpha << " parent ID = " << pp->pdg_id()); } } if (dv != 0) { for (const GenParticle* pp : particles_out(dv)) { MSG_TRACE(std::boolalpha << " child ID = " << pp->pdg_id()); } } } if (passed) _theParticles.push_back(Particle(*p)); } MSG_DEBUG("Number of initial quarks = " << _theParticles.size()); if (!_theParticles.empty()) { for (size_t i = 0; i < _theParticles.size(); i++) { MSG_DEBUG("Initial quark[" << i << "] = " << _theParticles[i].pid()); } } } } diff --git a/src/Projections/InvMassFinalState.cc b/src/Projections/InvMassFinalState.cc --- a/src/Projections/InvMassFinalState.cc +++ b/src/Projections/InvMassFinalState.cc @@ -1,185 +1,185 @@ // -*- C++ -*- #include "Rivet/Projections/InvMassFinalState.hh" namespace Rivet { InvMassFinalState::InvMassFinalState(const FinalState& fsp, const pair& idpair, // pair of decay products double minmass, // min inv mass double maxmass, // max inv mass double masstarget) : _minmass(minmass), _maxmass(maxmass), _masstarget(masstarget), _useTransverseMass(false) { setName("InvMassFinalState"); addProjection(fsp, "FS"); _decayids.push_back(idpair); } InvMassFinalState::InvMassFinalState(const FinalState& fsp, const vector >& idpairs, // vector of pairs of decay products double minmass, // min inv mass double maxmass, // max inv mass double masstarget) : _decayids(idpairs), _minmass(minmass), _maxmass(maxmass), _masstarget(masstarget), _useTransverseMass(false) { setName("InvMassFinalState"); addProjection(fsp, "FS"); } InvMassFinalState::InvMassFinalState(const pair& idpair, // pair of decay products double minmass, // min inv mass double maxmass, // max inv mass double masstarget) : _minmass(minmass), _maxmass(maxmass), _masstarget(masstarget), _useTransverseMass(false) { setName("InvMassFinalState"); _decayids.push_back(idpair); } InvMassFinalState::InvMassFinalState(const vector >& idpairs, // vector of pairs of decay products double minmass, // min inv mass double maxmass, // max inv mass double masstarget) : _decayids(idpairs), _minmass(minmass), _maxmass(maxmass), _masstarget(masstarget), _useTransverseMass(false) { setName("InvMassFinalState"); } - int InvMassFinalState::compare(const Projection& p) const { + CmpState InvMassFinalState::compare(const Projection& p) const { // First compare the final states we are running on - int fscmp = mkNamedPCmp(p, "FS"); - if (fscmp != EQUIVALENT) return fscmp; + CmpState fscmp = mkNamedPCmp(p, "FS"); + if (fscmp != CmpState::EQ) return fscmp; // Then compare the two as final states const InvMassFinalState& other = dynamic_cast(p); fscmp = FinalState::compare(other); - if (fscmp != EQUIVALENT) return fscmp; + if (fscmp != CmpState::EQ) return fscmp; // Compare the mass limits - int masstypecmp = cmp(_useTransverseMass, other._useTransverseMass); - if (masstypecmp != EQUIVALENT) return masstypecmp; - int massllimcmp = cmp(_minmass, other._minmass); - if (massllimcmp != EQUIVALENT) return massllimcmp; - int masshlimcmp = cmp(_maxmass, other._maxmass); - if (masshlimcmp != EQUIVALENT) return masshlimcmp; + CmpState masstypecmp = cmp(_useTransverseMass, other._useTransverseMass); + if (masstypecmp != CmpState::EQ) return masstypecmp; + CmpState massllimcmp = cmp(_minmass, other._minmass); + if (massllimcmp != CmpState::EQ) return massllimcmp; + CmpState masshlimcmp = cmp(_maxmass, other._maxmass); + if (masshlimcmp != CmpState::EQ) return masshlimcmp; // Compare the decay species - int decaycmp = cmp(_decayids, other._decayids); - if (decaycmp != EQUIVALENT) return decaycmp; + CmpState decaycmp = cmp(_decayids, other._decayids); + if (decaycmp != CmpState::EQ) return decaycmp; // Finally compare them as final states return FinalState::compare(other); } void InvMassFinalState::project(const Event& e) { const FinalState& fs = applyProjection(e, "FS"); calc(fs.particles()); } void InvMassFinalState::calc(const Particles& inparticles) { _theParticles.clear(); _particlePairs.clear(); // Containers for the particles of type specified in the pair vector type1, type2; // Get all the particles of the type specified in the pair from the particle list for (const Particle& ipart : inparticles) { // Loop around possible particle pairs for (const PdgIdPair& ipair : _decayids) { if (ipart.pid() == ipair.first) { if (accept(ipart)) type1 += &ipart; } else if (ipart.pid() == ipair.second) { if (accept(ipart)) type2 += &ipart; } } } if (type1.empty() || type2.empty()) return; // Temporary container of selected particles iterators // Useful to compare iterators and avoid double occurrences of the same // particle in case it matches with more than another particle vector tmp; // Now calculate the inv mass pair > closestPair; closestPair.first = 1e30; for (const Particle* i1 : type1) { for (const Particle* i2 : type2) { // Check this is actually a pair // (if more than one pair in vector particles can be unrelated) bool found = false; for (const PdgIdPair& ipair : _decayids) { if (i1->pid() == ipair.first && i2->pid() == ipair.second) { found = true; break; } } if (!found) continue; FourMomentum v4 = i1->momentum() + i2->momentum(); if (v4.mass2() < 0) { MSG_DEBUG("Constructed negative inv mass2: skipping!"); continue; } bool passedMassCut = false; if (_useTransverseMass) { passedMassCut = inRange(mT(i1->momentum(), i2->momentum()), _minmass, _maxmass); } else { passedMassCut = inRange(v4.mass(), _minmass, _maxmass); } if (passedMassCut) { MSG_DEBUG("Selecting particles with IDs " << i1->pid() << " & " << i2->pid() << " and mass = " << v4.mass()/GeV << " GeV"); // Store accepted particles, avoiding duplicates if (find(tmp.begin(), tmp.end(), i1) == tmp.end()) { tmp.push_back(i1); _theParticles += *i1; } if (find(tmp.begin(), tmp.end(), i2) == tmp.end()) { tmp.push_back(i2); _theParticles += *i2; } // Store accepted particle pairs _particlePairs += make_pair(*i1, *i2); if (_masstarget>0.0) { double diff=fabs(v4.mass()-_masstarget); if (diff 0.0 && closestPair.first < 1e30) { _theParticles.clear(); _particlePairs.clear(); _theParticles += closestPair.second.first; _theParticles += closestPair.second.second; _particlePairs += closestPair.second; } MSG_DEBUG("Selected " << _theParticles.size() << " particles " << "(" << _particlePairs.size() << " pairs)"); if (getLog().isActive(Log::TRACE)) { for (const Particle& p : _theParticles) { MSG_TRACE("ID: " << p.pid() << ", barcode: " << p.genParticle()->barcode()); } } } /// Constituent pairs const std::vector >& InvMassFinalState::particlePairs() const { return _particlePairs; } } diff --git a/src/Projections/JetShape.cc b/src/Projections/JetShape.cc --- a/src/Projections/JetShape.cc +++ b/src/Projections/JetShape.cc @@ -1,114 +1,114 @@ // -*- C++ -*- #include "Rivet/Tools/Logging.hh" #include "Rivet/Projections/JetShape.hh" namespace Rivet { // Constructor. JetShape::JetShape(const JetAlg& jetalg, double rmin, double rmax, size_t nbins, double ptmin, double ptmax, double absrapmin, double absrapmax, RapScheme rapscheme) : _rapscheme(rapscheme) { setName("JetShape"); _binedges = linspace(nbins, rmin, rmax); _ptcuts = make_pair(ptmin, ptmax); _rapcuts = make_pair(absrapmin, absrapmax); addProjection(jetalg, "Jets"); } // Constructor. JetShape::JetShape(const JetAlg& jetalg, vector binedges, double ptmin, double ptmax, double absrapmin, double absrapmax, RapScheme rapscheme) : _binedges(binedges), _rapscheme(rapscheme) { setName("JetShape"); _ptcuts = make_pair(ptmin, ptmax); _rapcuts = make_pair(absrapmin, absrapmax); addProjection(jetalg, "Jets"); } - int JetShape::compare(const Projection& p) const { - const int jcmp = mkNamedPCmp(p, "Jets"); - if (jcmp != EQUIVALENT) return jcmp; + CmpState JetShape::compare(const Projection& p) const { + const CmpState jcmp = mkNamedPCmp(p, "Jets"); + if (jcmp != CmpState::EQ) return jcmp; const JetShape& other = pcast(p); - const int ptcmp = cmp(ptMin(), other.ptMin()) || cmp(ptMax(), other.ptMax()); - if (ptcmp != EQUIVALENT) return ptcmp; - const int rapcmp = cmp(_rapcuts.first, other._rapcuts.first) || cmp(_rapcuts.second, other._rapcuts.second); - if (rapcmp != EQUIVALENT) return rapcmp; - int bincmp = cmp(numBins(), other.numBins()); - if (bincmp != EQUIVALENT) return bincmp; + const CmpState ptcmp = cmp(ptMin(), other.ptMin()) || cmp(ptMax(), other.ptMax()); + if (ptcmp != CmpState::EQ) return ptcmp; + const CmpState rapcmp = cmp(_rapcuts.first, other._rapcuts.first) || cmp(_rapcuts.second, other._rapcuts.second); + if (rapcmp != CmpState::EQ) return rapcmp; + CmpState bincmp = cmp(numBins(), other.numBins()); + if (bincmp != CmpState::EQ) return bincmp; for (size_t i = 0; i < _binedges.size(); ++i) { bincmp = cmp(_binedges[i], other._binedges[i]); - if (bincmp != EQUIVALENT) return bincmp; + if (bincmp != CmpState::EQ) return bincmp; } - return EQUIVALENT; + return CmpState::EQ; } void JetShape::clear() { _diffjetshapes.clear(); } void JetShape::calc(const Jets& jets) { clear(); for (const Jet& j : jets) { // Apply jet cuts const FourMomentum& pj = j.momentum(); if (!inRange(pj.pT(), _ptcuts)) continue; /// @todo Use Cut for better eta/y selection if (_rapscheme == PSEUDORAPIDITY && !inRange(fabs(pj.eta()), _rapcuts)) continue; if (_rapscheme == RAPIDITY && !inRange(fabs(pj.rapidity()), _rapcuts)) continue; // Fill bins vector bins(numBins(), 0.0); for (const Particle& p : j.particles()) { const double dR = deltaR(pj, p.momentum(), _rapscheme); const int dRindex = binIndex(dR, _binedges); if (dRindex == -1) continue; ///< Out of histo range bins[dRindex] += p.pT(); } // Add bin vector for this jet to the diffjetshapes container _diffjetshapes += bins; } // Normalize to total pT for (vector& binsref : _diffjetshapes) { double integral = 0.0; for (size_t i = 0; i < numBins(); ++i) { integral += binsref[i]; } if (integral > 0) { for (size_t i = 0; i < numBins(); ++i) { binsref[i] /= integral; } } else { // It's just-about conceivable that a jet would have no particles in the given Delta(r) range... MSG_DEBUG("No pT contributions in jet Delta(r) range: weird!"); } } } void JetShape::project(const Event& e) { const Jets jets = applyProjection(e, "Jets").jets(Cuts::ptIn(_ptcuts.first, _ptcuts.second) & ((_rapscheme == PSEUDORAPIDITY) ? Cuts::etaIn(-_rapcuts.second, _rapcuts.second) : Cuts::rapIn(-_rapcuts.second, _rapcuts.second)) ); calc(jets); } } diff --git a/src/Projections/LeadingParticlesFinalState.cc b/src/Projections/LeadingParticlesFinalState.cc --- a/src/Projections/LeadingParticlesFinalState.cc +++ b/src/Projections/LeadingParticlesFinalState.cc @@ -1,85 +1,85 @@ #include "Rivet/Projections/LeadingParticlesFinalState.hh" #include "Rivet/Particle.hh" namespace Rivet { - int LeadingParticlesFinalState::compare(const Projection& p) const { + CmpState LeadingParticlesFinalState::compare(const Projection& p) const { // First compare the final states we are running on - int fscmp = mkNamedPCmp(p, "FS"); - if (fscmp != EQUIVALENT) return fscmp; + CmpState fscmp = mkNamedPCmp(p, "FS"); + if (fscmp != CmpState::EQ) return fscmp; // Then compare the two as final states const LeadingParticlesFinalState& other = dynamic_cast(p); fscmp = FinalState::compare(other); - if (fscmp != EQUIVALENT) return fscmp; + if (fscmp != CmpState::EQ) return fscmp; - int locmp = cmp(_leading_only, other._leading_only); - if (locmp != EQUIVALENT) return locmp; + CmpState locmp = cmp(_leading_only, other._leading_only); + if (locmp != CmpState::EQ) return locmp; // Finally compare the IDs - if (_ids < other._ids) return ORDERED; - else if (other._ids < _ids) return UNORDERED; - return EQUIVALENT; + if (_ids < other._ids) return CmpState::LT; + else if (other._ids < _ids) return CmpState::GT; + return CmpState::EQ; } void LeadingParticlesFinalState::project(const Event & e) { _theParticles.clear(); const FinalState& fs = applyProjection(e, "FS"); // Temporary container map tmp; const Particles& particles = fs.particles(); MSG_DEBUG("Original final state particles size " << particles.size()); Particles::const_iterator ifs; for (ifs = particles.begin(); ifs != particles.end(); ++ifs) { if (inList(*ifs) && FinalState::accept(*ifs->genParticle())) { // Look for an existing particle in tmp container map < long, Particles::const_iterator >::const_iterator itmp = tmp.find(ifs->pid()); if (itmp != tmp.end()) { // if a particle with this type has been already selected // If the new pT is higher than the previous one, then substitute... if (ifs->pT() > itmp->second->pT()) { tmp[ifs->pid()] = ifs; } // ...otherwise insert in the container } else { tmp[ifs->pid()] = ifs; } } } // Loop on the tmp container and fill _theParticles map::const_iterator i; for (i = tmp.begin(); i != tmp.end(); ++i) { MSG_DEBUG("LeadingParticlesFinalState is accepting particle ID " << i->second->pid() << " with momentum " << i->second->momentum()); _theParticles.push_back(*(i->second)); } if (_leading_only) { double ptmax=0.0; Particle pmax; for (const Particle& p : _theParticles) { if (p.pT() > ptmax) { ptmax = p.pT(); pmax = p; } } _theParticles.clear(); _theParticles.push_back(pmax); } } bool LeadingParticlesFinalState::inList(const Particle & particle) const { std::set < long >::const_iterator ilist = _ids.find(particle.pid()); if (ilist != _ids.end()) return true; return false; } } diff --git a/src/Projections/MergedFinalState.cc b/src/Projections/MergedFinalState.cc --- a/src/Projections/MergedFinalState.cc +++ b/src/Projections/MergedFinalState.cc @@ -1,41 +1,41 @@ // -*- C++ -*- #include "Rivet/Projections/MergedFinalState.hh" namespace Rivet { - int MergedFinalState::compare(const Projection& p) const { + CmpState MergedFinalState::compare(const Projection& p) const { /// @todo: Currently A+B is not recognised to be the same as B+A. return mkNamedPCmp(p, "FSA") || mkNamedPCmp(p, "FSB"); } void MergedFinalState::project(const Event& e) { const FinalState& fsa = applyProjection(e, "FSA"); const FinalState& fsb = applyProjection(e, "FSB"); _theParticles.clear(); for (const Particle& pa : fsa.particles()){ _theParticles.push_back(pa); } for (const Particle& pb : fsb.particles()){ const GenParticle* originalb = pb.genParticle(); bool notfound = true; for (const Particle& pa : fsa.particles()){ const GenParticle* originala = pa.genParticle(); if (originala == originalb) { notfound = false; break; } } if (notfound) { _theParticles.push_back(pb); } } MSG_DEBUG("Number of particles in the two final states to be merged: = \n" << " 1st final state = " << fsa.particles().size() << "\n" << " 2nd final state = " << fsb.particles().size()); MSG_DEBUG("Number of merged final-state particles = " << _theParticles.size()); } } diff --git a/src/Projections/MissingMomentum.cc b/src/Projections/MissingMomentum.cc --- a/src/Projections/MissingMomentum.cc +++ b/src/Projections/MissingMomentum.cc @@ -1,48 +1,48 @@ // -*- C++ -*- #include "Rivet/Projections/MissingMomentum.hh" namespace Rivet { - int MissingMomentum::compare(const Projection& p) const { + CmpState MissingMomentum::compare(const Projection& p) const { return mkNamedPCmp(p, "VisibleFS"); } void MissingMomentum::clear() { _momentum = FourMomentum(); _set = 0.0; _spt = 0.0; _vet = Vector3(); _vpt = Vector3(); } void MissingMomentum::project(const Event& e) { clear(); // Project into final state const FinalState& vfs = applyProjection(e, "VisibleFS"); for (const Particle& p : vfs.particles()) { const FourMomentum& mom = p.momentum(); const Vector3 ptunit = mom.vector3().setZ(0.0).unit(); _momentum += mom; _set += mom.Et(); _spt += mom.pT(); _vet += mom.Et() * ptunit; _vpt += mom.pT() * ptunit; } } const FourMomentum MissingMomentum::visibleMomentum(double mass) const { /// @todo Couldn't we just reset the internal _momentum's mass and return by value? Would require mutable, though FourMomentum p4 = _momentum; const double pmod2 = p4.p3().mod2(); const double new_energy = sqrt(pmod2 + sqr(mass)); p4.setE(new_energy); return p4; } } diff --git a/src/Projections/NeutralFinalState.cc b/src/Projections/NeutralFinalState.cc --- a/src/Projections/NeutralFinalState.cc +++ b/src/Projections/NeutralFinalState.cc @@ -1,29 +1,29 @@ // -*- C++ -*- #include "Rivet/Projections/NeutralFinalState.hh" namespace Rivet { - int NeutralFinalState::compare(const Projection& p) const { + CmpState NeutralFinalState::compare(const Projection& p) const { const NeutralFinalState& other = dynamic_cast(p); return mkNamedPCmp(other, "FS") || cmp(_Etmin, other._Etmin); } void NeutralFinalState::project(const Event& e) { const FinalState& fs = applyProjection(e, "FS"); _theParticles.clear(); for (const Particle& p : fs.particles()) { if (p.charge3() == 0 && p.Et() > _Etmin) { _theParticles.push_back(p); MSG_TRACE("Selected: ID = " << p.pid() << ", Et = " << p.Et() << ", eta = " << p.eta() << ", charge = " << p.charge()); } } MSG_DEBUG("Number of neutral final-state particles = " << _theParticles.size()); } } diff --git a/src/Projections/NonHadronicFinalState.cc b/src/Projections/NonHadronicFinalState.cc --- a/src/Projections/NonHadronicFinalState.cc +++ b/src/Projections/NonHadronicFinalState.cc @@ -1,25 +1,25 @@ // -*- C++ -*- #include "Rivet/Projections/NonHadronicFinalState.hh" namespace Rivet { - int NonHadronicFinalState::compare(const Projection& p) const { + CmpState NonHadronicFinalState::compare(const Projection& p) const { return FinalState::compare(p); } bool nonHadronFilter(const Particle& p) { return PID::isHadron(p.pid()); } void NonHadronicFinalState::project(const Event& e) { const FinalState& fs = applyProjection(e, "FS"); _theParticles.clear(); std::remove_copy_if(fs.particles().begin(), fs.particles().end(), std::back_inserter(_theParticles), nonHadronFilter); MSG_DEBUG("Number of non-hadronic final-state particles = " << _theParticles.size()); } } diff --git a/src/Projections/NonPromptFinalState.cc b/src/Projections/NonPromptFinalState.cc --- a/src/Projections/NonPromptFinalState.cc +++ b/src/Projections/NonPromptFinalState.cc @@ -1,46 +1,46 @@ // -*- C++ -*- #include "Rivet/Projections/NonPromptFinalState.hh" namespace Rivet { NonPromptFinalState::NonPromptFinalState(const FinalState& fsp, bool accepttaudecays, bool acceptmudecays) : _acceptMuDecays(acceptmudecays), _acceptTauDecays(accepttaudecays) { setName("NonPromptFinalState"); addProjection(fsp, "FS"); } NonPromptFinalState::NonPromptFinalState(const Cut& c, bool accepttaudecays, bool acceptmudecays) : _acceptMuDecays(acceptmudecays), _acceptTauDecays(accepttaudecays) { setName("NonPromptFinalState"); addProjection(FinalState(c), "FS"); } - int NonPromptFinalState::compare(const Projection& p) const { + CmpState NonPromptFinalState::compare(const Projection& p) const { const PCmp fscmp = mkNamedPCmp(p, "FS"); - if (fscmp != EQUIVALENT) return fscmp; + if (fscmp != CmpState::EQ) return fscmp; const NonPromptFinalState& other = dynamic_cast(p); return cmp(_acceptMuDecays, other._acceptMuDecays) || cmp(_acceptTauDecays, other._acceptTauDecays); } void NonPromptFinalState::project(const Event& e) { _theParticles.clear(); const Particles& particles = applyProjection(e, "FS").particles(); for (const Particle& p : particles) if (!isPrompt(p, !_acceptTauDecays, !_acceptMuDecays)) _theParticles.push_back(p); MSG_DEBUG("Number of final state particles from hadron decays = " << _theParticles.size()); if (getLog().isActive(Log::TRACE)) { for (const Particle& p : _theParticles) MSG_TRACE("Selected: " << p.pid() << ", charge = " << p.charge()); } } } diff --git a/src/Projections/ParisiTensor.cc b/src/Projections/ParisiTensor.cc --- a/src/Projections/ParisiTensor.cc +++ b/src/Projections/ParisiTensor.cc @@ -1,36 +1,36 @@ // -*- C++ -*- #include "Rivet/Projections/ParisiTensor.hh" namespace Rivet { - int ParisiTensor::compare(const Projection& p) const { + CmpState ParisiTensor::compare(const Projection& p) const { return mkNamedPCmp(p, "Sphericity"); } void ParisiTensor::clear() { _lambda[0] = 0; _lambda[1] = 0; _lambda[2] = 0; _C = 0; _D = 0; } void ParisiTensor::project(const Event & e) { clear(); // Apply sphericity projection to event Sphericity sph = applyProjection(e, "Sphericity"); // Set parameters _lambda[0] = sph.lambda1(); _lambda[1] = sph.lambda2(); _lambda[2] = sph.lambda3(); _C = 3 * ( lambda1()*lambda2() + lambda1()*lambda3() + lambda2()*lambda3() ); _D = 27 * lambda1() * lambda2() * lambda3(); } } diff --git a/src/Projections/ParticleFinder.cc b/src/Projections/ParticleFinder.cc --- a/src/Projections/ParticleFinder.cc +++ b/src/Projections/ParticleFinder.cc @@ -1,30 +1,12 @@ // -*- C++ -*- #include "Rivet/Projections/ParticleFinder.hh" namespace Rivet { /// @todo HOW DO WE COMPARE CUTS OBJECTS? - int ParticleFinder::compare(const Projection& p) const { + CmpState ParticleFinder::compare(const Projection& p) const { const ParticleFinder& other = dynamic_cast(p); - - //MSG_TRACE("FS::compare: " << 1 << " " << this << " " << &p); - // std::vector > eta1(_etaRanges); - //std::vector > eta2(other._etaRanges); - //std::sort(eta1.begin(), eta1.end()); - //std::sort(eta2.begin(), eta2.end()); - - //MSG_TRACE("FS::compare: " << 2 << " " << this << " " << &p); - //if (eta1 < eta2) return ORDERED; - //else if (eta2 < eta1) return UNORDERED; - - //MSG_TRACE("FS::compare: " << 3 << " " << this << " " << &p); - //return cmp(_ptmin, other._ptmin); - return _cuts == other._cuts ? EQUIVALENT : UNDEFINED; + return _cuts == other._cuts ? CmpState::EQ : CmpState::UNDEF; } - // void ParticleFinder::project(const Event& e) { - // _theParticles.clear(); - // } - - } diff --git a/src/Projections/PromptFinalState.cc b/src/Projections/PromptFinalState.cc --- a/src/Projections/PromptFinalState.cc +++ b/src/Projections/PromptFinalState.cc @@ -1,53 +1,53 @@ // -*- C++ -*- #include "Rivet/Projections/PromptFinalState.hh" namespace Rivet { PromptFinalState::PromptFinalState(bool accepttaudecays, bool acceptmudecays) : _acceptMuDecays(acceptmudecays), _acceptTauDecays(accepttaudecays) { setName("PromptFinalState"); addProjection(FinalState(), "FS"); } PromptFinalState::PromptFinalState(const Cut& c, bool accepttaudecays, bool acceptmudecays) : _acceptMuDecays(acceptmudecays), _acceptTauDecays(accepttaudecays) { setName("PromptFinalState"); addProjection(FinalState(c), "FS"); } PromptFinalState::PromptFinalState(const FinalState& fsp, bool accepttaudecays, bool acceptmudecays) : _acceptMuDecays(acceptmudecays), _acceptTauDecays(accepttaudecays) { setName("PromptFinalState"); addProjection(fsp, "FS"); } - int PromptFinalState::compare(const Projection& p) const { + CmpState PromptFinalState::compare(const Projection& p) const { const PCmp fscmp = mkNamedPCmp(p, "FS"); - if (fscmp != EQUIVALENT) return fscmp; + if (fscmp != CmpState::EQ) return fscmp; const PromptFinalState& other = dynamic_cast(p); return cmp(_acceptMuDecays, other._acceptMuDecays) || cmp(_acceptTauDecays, other._acceptTauDecays); } void PromptFinalState::project(const Event& e) { _theParticles.clear(); const Particles& particles = applyProjection(e, "FS").particles(); for (const Particle& p : particles) if (isPrompt(p, _acceptTauDecays, _acceptMuDecays)) _theParticles.push_back(p); MSG_DEBUG("Number of final state particles not from hadron decays = " << _theParticles.size()); if (getLog().isActive(Log::TRACE)) { for (const Particle& p : _theParticles) MSG_TRACE("Selected: " << p.pid() << ", charge = " << p.charge()); } } } diff --git a/src/Projections/Sphericity.cc b/src/Projections/Sphericity.cc --- a/src/Projections/Sphericity.cc +++ b/src/Projections/Sphericity.cc @@ -1,178 +1,178 @@ // -*- C++ -*- #include "Rivet/Projections/Sphericity.hh" #include "Rivet/Jet.hh" namespace Rivet { Sphericity::Sphericity(const FinalState& fsp, double rparam) : _regparam(rparam) { setName("Sphericity"); addProjection(fsp, "FS"); clear(); } void Sphericity::clear() { _lambdas = vector(3, 0); _sphAxes = vector(3, Vector3()); } - int Sphericity::compare(const Projection& p) const { + CmpState Sphericity::compare(const Projection& p) const { PCmp fscmp = mkNamedPCmp(p, "FS"); - if (fscmp != EQUIVALENT) return fscmp; + if (fscmp != CmpState::EQ) return fscmp; const Sphericity& other = dynamic_cast(p); - if (fuzzyEquals(_regparam, other._regparam)) return 0; + if (fuzzyEquals(_regparam, other._regparam)) return CmpState::EQ; return cmp(_regparam, other._regparam); } void Sphericity::project(const Event& e) { const Particles prts = applyProjection(e, "FS").particles(); calc(prts); } void Sphericity::calc(const FinalState& fs) { calc(fs.particles()); } void Sphericity::calc(const Particles& particles) { vector threeMomenta; transform(particles, threeMomenta, p3); calc(threeMomenta); } void Sphericity::calc(const Jets& jets) { vector threeMomenta; transform(jets, threeMomenta, p3); calc(threeMomenta); } void Sphericity::calc(const vector& momenta) { vector threeMomenta; transform(momenta, threeMomenta, [](const FourMomentum& p4){return p4.vector3();}); calc(threeMomenta); } Vector3 Sphericity::mkEigenVector(Matrix3 A, const double &lambda) { const double b = A.get(0,1); const double c = A.get(0,2); const double d = A.get(1,1); const double e = A.get(1,2); const double f = A.get(2,2); const double denom = b*e -c*d + c*lambda; double x = e*(b*f -c*e - b*lambda)/denom/c + (lambda -f)/c; double y = (c*e -b*f +b*lambda)/denom; Vector3 E(x,y,1); return E.unit(); } void Sphericity::calc(const vector& momenta) { MSG_DEBUG("Calculating sphericity with r = " << _regparam); // Return (with "safe nonsense" sphericity params) if there are no final state particles if (momenta.empty()) { MSG_DEBUG("Not enough momenta given..."); clear(); return; } // Iterate over all the final state particles. Matrix3 mMom; double totalMomentum = 0.0; MSG_DEBUG("Number of particles = " << momenta.size()); for (const Vector3& p3 : momenta) { // Build the (regulated) normalising factor. totalMomentum += pow(p3.mod(), _regparam); // Build (regulated) quadratic momentum components. const double regfactor = pow(p3.mod(), _regparam-2); if (!fuzzyEquals(regfactor, 1.0)) { MSG_TRACE("Regfactor (r=" << _regparam << ") = " << regfactor); } Matrix3 mMomPart; for (size_t i = 0; i < 3; ++i) { for (size_t j = 0; j < 3; ++j) { mMomPart.set(i,j, p3[i]*p3[j]); } } mMom += regfactor * mMomPart; } if (mMom.get(2,0) == 0 && mMom.get(2,1) == 0 && mMom.get(2,2) == 0) { MSG_DEBUG("No longitudinal momenta given..."); clear(); return; } // Normalise to total (regulated) momentum. mMom /= totalMomentum; MSG_DEBUG("Momentum tensor = " << "\n" << mMom); // Check that the matrix is symmetric. const bool isSymm = mMom.isSymm(); if (!isSymm) { MSG_ERROR("Error: momentum tensor not symmetric (r=" << _regparam << ")"); MSG_ERROR("[0,1] vs. [1,0]: " << mMom.get(0,1) << ", " << mMom.get(1,0)); MSG_ERROR("[0,2] vs. [2,0]: " << mMom.get(0,2) << ", " << mMom.get(2,0)); MSG_ERROR("[1,2] vs. [2,1]: " << mMom.get(1,2) << ", " << mMom.get(2,1)); } // If not symmetric, something's wrong (we made sure the error msg appeared first). assert(isSymm); // Eigenvalues const double q = mMom.trace()/3.; const double p1 = mMom.get(0,1)*mMom.get(0,1) + mMom.get(0,2)*mMom.get(0,2) + mMom.get(1,2)*mMom.get(1,2); const double p2 = (mMom.get(0,0) - q)*(mMom.get(0,0) - q) + (mMom.get(1,1) - q)*(mMom.get(1,1) - q) + (mMom.get(2,2) - q)*(mMom.get(2,2) - q) + 2.*p1; const double p = sqrt(p2/6.); Matrix3 I3 = Matrix3::mkIdentity(); const double r = ( 1./p * (mMom - q*I3)).det()/2.; double phi(0); if (r <= -1) phi = M_PI / 3.; else if (r >= 1) phi = 0; else phi = acos(r) / 3.; const double l1 = q + 2 * p * cos(phi); const double l3 = q + 2 * p * cos(phi + (2*M_PI/3.)); const double l2 = 3 * q - l1 - l3; if (l1 == 0 || l2 == 0 || l3 == 0) { MSG_DEBUG("Zero eigenvalue..."); clear(); return; } _lambdas.clear(); _sphAxes.clear(); _sphAxes.push_back(mkEigenVector(mMom, l1)); _sphAxes.push_back(mkEigenVector(mMom, l2)); _sphAxes.push_back(mkEigenVector(mMom, l3)); _lambdas.push_back(l1); _lambdas.push_back(l2); _lambdas.push_back(l3); // Debug output. MSG_DEBUG("Lambdas = (" << lambda1() << ", " << lambda2() << ", " << lambda3() << ")"); MSG_DEBUG("Sum of lambdas = " << lambda1() + lambda2() + lambda3()); MSG_DEBUG("Vectors = " << sphericityAxis() << ", " << sphericityMajorAxis() << ", " << sphericityMinorAxis() << ")"); } } diff --git a/src/Projections/TauFinder.cc b/src/Projections/TauFinder.cc --- a/src/Projections/TauFinder.cc +++ b/src/Projections/TauFinder.cc @@ -1,28 +1,28 @@ // -*- C++ -*- #include "Rivet/Projections/TauFinder.hh" #include "Rivet/Projections/UnstableFinalState.hh" namespace Rivet { void TauFinder::project(const Event& e) { _theParticles.clear(); const UnstableFinalState& ufs = applyProjection(e, "UFS"); for (const Particle& p : ufs.particles()) { if (p.abspid() != PID::TAU) continue; if (_decmode == DecayMode::ANY || (_decmode == DecayMode::LEPTONIC && isLeptonic(p)) || (_decmode == DecayMode::HADRONIC && isHadronic(p)) ) _theParticles.push_back(p); } } - int TauFinder::compare(const Projection& p) const { + CmpState TauFinder::compare(const Projection& p) const { const PCmp fscmp = mkNamedPCmp(p, "UFS"); - if (fscmp != EQUIVALENT) return fscmp; + if (fscmp != CmpState::EQ) return fscmp; const TauFinder& other = dynamic_cast(p); return cmp(_decmode, other._decmode); } } diff --git a/src/Projections/VetoedFinalState.cc b/src/Projections/VetoedFinalState.cc --- a/src/Projections/VetoedFinalState.cc +++ b/src/Projections/VetoedFinalState.cc @@ -1,144 +1,144 @@ // -*- C++ -*- #include "Rivet/Projections/VetoedFinalState.hh" namespace Rivet { - int VetoedFinalState::compare(const Projection& p) const { + CmpState VetoedFinalState::compare(const Projection& p) const { const PCmp fscmp = mkNamedPCmp(p, "FS"); - if (fscmp != EQUIVALENT) return fscmp; + if (fscmp != CmpState::EQ) return fscmp; /// @todo We can do better than this... - if (_vetofsnames.size() != 0) return UNDEFINED; + if (_vetofsnames.size() != 0) return CmpState::UNDEF; const VetoedFinalState& other = dynamic_cast(p); return \ cmp(_vetoCodes, other._vetoCodes) || cmp(_compositeVetoes, other._compositeVetoes) || cmp(_parentVetoes, other._parentVetoes); } void VetoedFinalState::project(const Event& e) { const FinalState& fs = applyProjection(e, "FS"); _theParticles.clear(); _theParticles.reserve(fs.particles().size()); // Veto by PID code if (getLog().isActive(Log::TRACE)) { /// @todo Should be PdgId, but _vetoCodes is currently a long vector codes; for (auto& code : _vetoCodes) codes += code.first; MSG_TRACE("Veto codes = " << codes << " (" << codes.size() << ")"); } if (_vetoCodes.empty()) { _theParticles = fs.particles(); } else { // Test every particle against the codes for (const Particle& p : fs.particles()) { VetoDetails::iterator iter = _vetoCodes.find(p.pid()); if (iter == _vetoCodes.end()) { // MSG_TRACE("Storing with PDG code = " << p.pid() << ", pT = " << p.pT()); _theParticles.push_back(p); } else { // This particle code is listed as a possible veto... check pT. // Make sure that the pT range is sensible: BinaryCut ptrange = iter->second; assert(ptrange.first <= ptrange.second); std::stringstream rangess; if (ptrange.first < std::numeric_limits::max()) rangess << ptrange.second; rangess << " - "; if (ptrange.second < std::numeric_limits::max()) rangess << ptrange.second; MSG_TRACE("ID = " << p.pid() << ", pT range = " << rangess.str()); std::stringstream debugline; debugline << "with PDG code = " << p.pid() << " pT = " << p.pT(); if (p.pT() < ptrange.first || p.pT() > ptrange.second) { MSG_TRACE("Storing " << debugline.str()); _theParticles.push_back(p); } else { MSG_TRACE("Vetoing " << debugline.str()); } } } } /// @todo What is this block? Mass vetoing? set toErase; for (set::iterator nIt = _nCompositeDecays.begin(); nIt != _nCompositeDecays.end() && !_theParticles.empty(); ++nIt) { map, FourMomentum> oldMasses; map, FourMomentum> newMasses; set start; start.insert(_theParticles.begin()); oldMasses.insert(pair, FourMomentum>(start, _theParticles.begin()->momentum())); for (int nParts = 1; nParts != *nIt; ++nParts) { for (map, FourMomentum>::iterator mIt = oldMasses.begin(); mIt != oldMasses.end(); ++mIt) { Particles::iterator pStart = *(mIt->first.rbegin()); for (Particles::iterator pIt = pStart + 1; pIt != _theParticles.end(); ++pIt) { FourMomentum cMom = mIt->second + pIt->momentum(); set pList(mIt->first); pList.insert(pIt); newMasses[pList] = cMom; } } oldMasses = newMasses; newMasses.clear(); } for (map, FourMomentum>::iterator mIt = oldMasses.begin(); mIt != oldMasses.end(); ++mIt) { double mass2 = mIt->second.mass2(); if (mass2 >= 0.0) { double mass = sqrt(mass2); for (CompositeVeto::iterator cIt = _compositeVetoes.lower_bound(*nIt); cIt != _compositeVetoes.upper_bound(*nIt); ++cIt) { BinaryCut massRange = cIt->second; if (mass < massRange.second && mass > massRange.first) { for (set::iterator lIt = mIt->first.begin(); lIt != mIt->first.end(); ++lIt) { toErase.insert(*lIt); } } } } } } for (set::reverse_iterator p = toErase.rbegin(); p != toErase.rend(); ++p) { _theParticles.erase(*p); } // Remove particles whose parents match entries in the parent veto PDG ID codes list /// @todo There must be a nice way to do this -- an STL algorithm (or we provide a nicer wrapper) for (PdgId vetoid : _parentVetoes) { for (Particles::iterator ip = _theParticles.begin(); ip != _theParticles.end(); ++ip) { const GenVertex* startVtx = ip->genParticle()->production_vertex(); if (startVtx == NULL) continue; // Loop over parents and test their IDs /// @todo Could use any() here? for (const GenParticle* parent : Rivet::particles(startVtx, HepMC::ancestors)) { if (vetoid == parent->pdg_id()) { ip = _theParticles.erase(ip); --ip; //< Erase this _theParticles entry break; } } } } // Finally veto on the registered FSes for (const string& ifs : _vetofsnames) { const ParticleFinder& vfs = applyProjection(e, ifs); const Particles& pvetos = vfs.rawParticles(); ifilter_discard(_theParticles, [&](const Particle& pcheck) { if (pcheck.genParticle() == nullptr) return false; for (const Particle& pveto : pvetos) { if (pveto.genParticle() == nullptr) continue; if (pveto.genParticle() == pcheck.genParticle()) { MSG_TRACE("Vetoing: " << pcheck); return true; } } return false; }); } MSG_DEBUG("FS vetoing from #particles = " << fs.size() << " -> " << _theParticles.size()); } } diff --git a/src/Projections/VisibleFinalState.cc b/src/Projections/VisibleFinalState.cc --- a/src/Projections/VisibleFinalState.cc +++ b/src/Projections/VisibleFinalState.cc @@ -1,28 +1,28 @@ // -*- C++ -*- #include "Rivet/Projections/VisibleFinalState.hh" namespace Rivet { - int VisibleFinalState::compare(const Projection& p) const { + CmpState VisibleFinalState::compare(const Projection& p) const { return mkNamedPCmp(p, "FS"); } // Since we remove invisibles from the FinalState in project(), // we need a filter where invisible --> true namespace { bool isInvisible(const Particle& p) { return !p.isVisible(); } } void VisibleFinalState::project(const Event& e) { const FinalState& fs = applyProjection(e, "FS"); _theParticles.clear(); std::remove_copy_if(fs.particles().begin(), fs.particles().end(), std::back_inserter(_theParticles), isInvisible); MSG_DEBUG("Number of visible final-state particles = " << _theParticles.size()); } } diff --git a/src/Projections/WFinder.cc b/src/Projections/WFinder.cc --- a/src/Projections/WFinder.cc +++ b/src/Projections/WFinder.cc @@ -1,163 +1,163 @@ // -*- C++ -*- #include "Rivet/Projections/WFinder.hh" #include "Rivet/Projections/ChargedFinalState.hh" #include "Rivet/Projections/PromptFinalState.hh" #include "Rivet/Projections/InvMassFinalState.hh" #include "Rivet/Projections/MergedFinalState.hh" #include "Rivet/Projections/DressedLeptons.hh" #include "Rivet/Projections/VetoedFinalState.hh" #include "Rivet/Projections/Beam.hh" namespace Rivet { WFinder::WFinder(const FinalState& inputfs, const Cut& leptoncuts, PdgId pid, double minmass, double maxmass, double missingET, double dRmax, ChargedLeptons chLeptons, ClusterPhotons clusterPhotons, AddPhotons trackPhotons, MassWindow masstype, double masstarget) { setName("WFinder"); _etMissMin = missingET; _minmass = minmass; _maxmass = maxmass; _masstarget = masstarget; _pid = abs(pid); _trackPhotons = trackPhotons; _useTransverseMass = (masstype == MassWindow::MT); // Check that the arguments are legal if (_pid != PID::ELECTRON && _pid != PID::MUON) throw Error("Invalid charged lepton PID given to WFinder"); // Identify bare leptons for dressing // Bit of a code nightmare -- FS projection copy constructors don't work? /// @todo Fix FS copy constructors!! if (chLeptons == ChargedLeptons::PROMPT) { PromptFinalState inputfs_prompt(inputfs); IdentifiedFinalState bareleptons(inputfs_prompt); bareleptons.acceptIdPair(_pid); declare(bareleptons, "BareLeptons"); } else { IdentifiedFinalState bareleptons(inputfs); bareleptons.acceptIdPair(_pid); declare(bareleptons, "BareLeptons"); } // Dress the bare leptons const bool doClustering = (clusterPhotons != ClusterPhotons::NONE); const bool useDecayPhotons = (clusterPhotons == ClusterPhotons::ALL); DressedLeptons leptons(inputfs, get("BareLeptons"), (doClustering ? dRmax : -1.), leptoncuts, useDecayPhotons); addProjection(leptons, "DressedLeptons"); // Add MissingMomentum proj to calc MET MissingMomentum vismom(inputfs); addProjection(vismom, "MissingET"); // Identify the non-Z part of the event VetoedFinalState remainingFS; remainingFS.addVetoOnThisFinalState(*this); addProjection(remainingFS, "RFS"); } ///////////////////////////////////////////////////// const VetoedFinalState& WFinder::remainingFinalState() const { return getProjection("RFS"); } const MissingMomentum& WFinder::missingMom() const { return getProjection("MissingET"); } - int WFinder::compare(const Projection& p) const { + CmpState WFinder::compare(const Projection& p) const { PCmp dlcmp = mkNamedPCmp(p, "DressedLeptons"); - if (dlcmp != EQUIVALENT) return dlcmp; + if (dlcmp != CmpState::EQ) return dlcmp; const WFinder& other = dynamic_cast(p); return (cmp(_minmass, other._minmass) || cmp(_maxmass, other._maxmass) || cmp(_useTransverseMass, other._useTransverseMass) || cmp(_etMissMin, other._etMissMin) || cmp(_pid, other._pid) || cmp(_trackPhotons, other._trackPhotons)); } void WFinder::project(const Event& e) { clear(); _leptons.clear(); _neutrinos.clear(); // Check missing ET const MissingMomentum& missmom = applyProjection(e, "MissingET"); const double met = missmom.vectorEt().mod(); MSG_TRACE("MET = " << met/GeV << " GeV vs. required > " << _etMissMin/GeV << " GeV"); if (met < _etMissMin) { MSG_DEBUG("Not enough missing ET: " << met/GeV << " GeV vs. required > " << _etMissMin/GeV << " GeV"); return; } // Get lepton const DressedLeptons& leptons = applyProjection(e, "DressedLeptons"); if ( leptons.dressedLeptons().empty() ) { MSG_DEBUG("No dressed leptons"); return; } MSG_DEBUG("Found at least one dressed lepton: " << leptons.dressedLeptons().front().momentum() ); // Get missing momentum 4-vector, assuming a massless invisible particle const FourMomentum pmiss = missmom.missingMomentum(0*GeV); MSG_DEBUG("Found missing 4-momentum: " << pmiss); // Compute an invariant mass final state for the W decay leptons (using pseudo-neutrinos from ETmiss) PdgId _nu_pid = _pid + 1; assert(_nu_pid == PID::NU_E || _nu_pid == PID::NU_MU); vector > l_nu_ids; l_nu_ids += make_pair(_pid, -_nu_pid); l_nu_ids += make_pair(-_pid, _nu_pid); InvMassFinalState imfs(l_nu_ids, _minmass, _maxmass, _masstarget); imfs.useTransverseMass(_useTransverseMass); Particles tmp = leptons.particles(); tmp += { Particle( _nu_pid, pmiss), Particle(-_nu_pid, pmiss) }; // fake (anti)neutrinos from ETmiss vector imfs.calc(tmp); if (imfs.particlePairs().size() < 1) return; // Assemble a pseudo-W particle const ParticlePair Wconstituents = imfs.particlePairs().front(); const Particle& p1(Wconstituents.first), p2(Wconstituents.second); const FourMomentum pW = p1.momentum() + p2.momentum(); const int wcharge3 = p1.charge3() + p2.charge3(); assert(abs(wcharge3) == 3); const int wcharge = wcharge3/3; const PdgId wpid = (wcharge == 1) ? PID::WPLUSBOSON : PID::WMINUSBOSON; Particle w(wpid, pW); MSG_DEBUG(w << " reconstructed from: " << p1 << " + " << p2); // Add (dressed) lepton constituents to the W (skipping photons if requested) /// @todo Do we need to add all used invisibles to _theParticles ? const Particle l = p1.isChargedLepton() ? p1 : p2; _leptons += (_trackPhotons == AddPhotons::YES) ? l : l.constituents().front(); w.addConstituent(_leptons.back()); const Particle nu = p1.isNeutrino() ? p1 : p2; _neutrinos += nu; w.addConstituent(nu); // Register the completed W _theParticles.push_back(w); } } diff --git a/src/Projections/ZFinder.cc b/src/Projections/ZFinder.cc --- a/src/Projections/ZFinder.cc +++ b/src/Projections/ZFinder.cc @@ -1,118 +1,118 @@ // -*- C++ -*- #include "Rivet/Projections/ZFinder.hh" #include "Rivet/Projections/PromptFinalState.hh" #include "Rivet/Projections/InvMassFinalState.hh" #include "Rivet/Projections/VetoedFinalState.hh" namespace Rivet { ZFinder::ZFinder(const FinalState& inputfs, const Cut & fsCut, PdgId pid, double minmass, double maxmass, double dRmax, ChargedLeptons chLeptons, ClusterPhotons clusterPhotons, AddPhotons trackPhotons, double masstarget) { setName("ZFinder"); _minmass = minmass; _maxmass = maxmass; _masstarget = masstarget; _pid = abs(pid); _trackPhotons = trackPhotons; // Identify bare leptons for dressing // Bit of a code nightmare -- FS projection copy constructors don't work? /// @todo Fix FS copy constructors!! if (chLeptons == ChargedLeptons::PROMPT) { PromptFinalState inputfs_prompt(inputfs); IdentifiedFinalState bareleptons = IdentifiedFinalState(inputfs_prompt); bareleptons.acceptIdPair(_pid); declare(bareleptons, "BareLeptons"); } else { IdentifiedFinalState bareleptons = IdentifiedFinalState(inputfs); bareleptons.acceptIdPair(_pid); declare(bareleptons, "BareLeptons"); } // Dress the bare leptons const bool doClustering = (clusterPhotons != ClusterPhotons::NONE); const bool useDecayPhotons = (clusterPhotons == ClusterPhotons::ALL); DressedLeptons leptons(inputfs, get("BareLeptons"), (doClustering ? dRmax : -1.0), fsCut, useDecayPhotons); addProjection(leptons, "DressedLeptons"); // Identify the non-Z part of the event VetoedFinalState remainingFS; remainingFS.addVetoOnThisFinalState(*this); addProjection(remainingFS, "RFS"); } ///////////////////////////////////////////////////// const Particles & ZFinder::constituentLeptons() const { static const Particles none; if (empty()) return none; return boson().constituents(); } const VetoedFinalState& ZFinder::remainingFinalState() const { return getProjection("RFS"); } - int ZFinder::compare(const Projection& p) const { + CmpState ZFinder::compare(const Projection& p) const { PCmp LCcmp = mkNamedPCmp(p, "DressedLeptons"); - if (LCcmp != EQUIVALENT) return LCcmp; + if (LCcmp != CmpState::EQ) return LCcmp; const ZFinder& other = dynamic_cast(p); return (cmp(_minmass, other._minmass) || cmp(_maxmass, other._maxmass) || cmp(_pid, other._pid) || cmp(_trackPhotons, other._trackPhotons)); } void ZFinder::project(const Event& e) { clear(); // Get leptons and find an acceptable invariant mass OSSF pair const DressedLeptons& leptons = applyProjection(e, "DressedLeptons"); InvMassFinalState imfs({_pid, -_pid}, _minmass, _maxmass, _masstarget); imfs.calc(leptons.particles()); if (imfs.particlePairs().empty()) { MSG_TRACE("No acceptable inv-mass lepton/antilepton pairs found"); return; } // Assemble a pseudo-Z particle const ParticlePair& Zconstituents = imfs.particlePairs().front(); const Particle& p1(Zconstituents.first), p2(Zconstituents.second); const FourMomentum pZ = p1.momentum() + p2.momentum(); assert(p1.charge3() + p2.charge3() == 0); Particle z(PID::Z0BOSON, pZ); MSG_DEBUG(z << " reconstructed from: " << p1 << " + " << p2); // Add (dressed) lepton constituents to the Z (skipping photons if requested) // Keep the DressedLeptons found by the ZFinder const Particle& l1 = p1.charge() > 0 ? p1 : p2; const Particle& l2 = p2.charge() < 0 ? p2 : p1; MSG_TRACE("l1 = " << l1.constituents()); MSG_TRACE("l2 = " << l2.constituents()); z.addConstituent(_trackPhotons == AddPhotons::YES ? l1 : l1.constituents().front()); z.addConstituent(_trackPhotons == AddPhotons::YES ? l2 : l2.constituents().front()); MSG_DEBUG("Number of stored raw Z constituents = " << z.rawConstituents().size() << " " << z.rawConstituents()); // Register the completed Z _theParticles.push_back(z); } } diff --git a/test/testCmp.cc b/test/testCmp.cc --- a/test/testCmp.cc +++ b/test/testCmp.cc @@ -1,26 +1,42 @@ #include #include #include "Rivet/Tools/Cmp.hh" using namespace std; +ostream & operator<<(ostream & os, Rivet::CmpState c) { + string s; + switch (c) { + case Rivet::CmpState::UNDEF : s = "UNDEF"; break; + case Rivet::CmpState::LT : s = "LT"; break; + case Rivet::CmpState::EQ : s = "EQ"; break; + case Rivet::CmpState::GT : s = "GT"; break; + } + os << s; + return os; +} + int main() { using namespace Rivet; - CmpState cs = UNDEFINED; + CmpState cs = CmpState::UNDEF; cs = cmp(0.5, 0.6); cout << "cmp(0.5, 0.6) = " << cs << '\n'; - assert(cs == ORDERED); + assert(cs == CmpState::LT); cs = cmp(0.5, 0.5); cout << "cmp(0.5, 0.5) = " << cs << '\n'; - assert(cs == EQUIVALENT); + assert(cs == CmpState::EQ); cs = cmp(0.6, 0.5); cout << "cmp(0.6, 0.5) = " << cs << '\n'; - assert(cs == UNORDERED); + assert(cs == CmpState::GT); + + cs = cmp(1.,1.) || cmp(0.6, 0.5); + cout << "cmp(1.,1.) || cmp(0.6, 0.5) = " << cs << '\n'; + assert(cs == CmpState::GT); return EXIT_SUCCESS; }