diff --git a/include/Rivet/Tools/Cuts.hh b/include/Rivet/Tools/Cuts.hh --- a/include/Rivet/Tools/Cuts.hh +++ b/include/Rivet/Tools/Cuts.hh @@ -1,119 +1,126 @@ #ifndef RIVET_Cuts_HH #define RIVET_Cuts_HH #include "Rivet/Tools/Cuts.fhh" #include namespace Rivet { class CutBase { public: /// Main work method, checking whether the cut is passed /// @internal Forwards the received object to @ref accept_, wrapped in the Cuttable converter template bool accept(const ClassToCheck&) const; /// @brief Call operator alias for @a accept /// @note A bit subtle, because this gets wrapped in a shared_ptr so you need to dereference to get the functor template bool operator () (const ClassToCheck& x) const { return accept(x); } /// Comparison to another Cut virtual bool operator == (const Cut&) const = 0; /// Default destructor virtual ~CutBase() {} + /// Description of a cut + virtual std::string description() const = 0; + protected: /// @internal Actual accept implementation, overloadable by various cut combiners virtual bool _accept(const CuttableBase&) const = 0; }; /// Compare two cuts for equality, forwards to the cut-specific implementation inline bool operator == (const Cut& a, const Cut& b) { return *a == b; } /// Namespace used for ambiguous identifiers. namespace Cuts { /// Available categories of cut objects enum Quantity { pT=0, pt=0, Et=1, et=1, mass, rap, absrap, eta, abseta, phi, pid, abspid, charge, abscharge, charge3, abscharge3 }; /// Fully open cut singleton, accepts everything const Cut& open(); //< access by factory function extern const Cut& OPEN; //= open(); //< access by constant extern const Cut& NOCUT; //= open(); //< access by constant /// @name Shortcuts for common cuts //@{ Cut range(Quantity, double m, double n); inline Cut etaIn(double m, double n) { return range(eta,m,n); } inline Cut rapIn(double m, double n) { return range(rap,m,n); } inline Cut absetaIn(double m, double n) { return range(abseta,m,n); } inline Cut absrapIn(double m, double n) { return range(absrap,m,n); } inline Cut ptIn(double m, double n) { return range(pT,m,n); } inline Cut etIn(double m, double n) { return range(Et,m,n); } inline Cut massIn(double m, double n) { return range(mass,m,n); } //@} } /// @name Cut constructors //@{ Cut operator == (Cuts::Quantity, double); Cut operator != (Cuts::Quantity, double); Cut operator < (Cuts::Quantity, double); Cut operator > (Cuts::Quantity, double); Cut operator <= (Cuts::Quantity, double); Cut operator >= (Cuts::Quantity, double); /// @internal Overload helpers for integer arguments //@{ inline Cut operator == (Cuts::Quantity qty, int i) { return qty == double(i); } inline Cut operator != (Cuts::Quantity qty, int i) { return qty != double(i); } // Cut operator == (Cuts::Quantity qty, int i); // Cut operator != (Cuts::Quantity qty, int i); inline Cut operator < (Cuts::Quantity qty, int i) { return qty < double(i); } inline Cut operator > (Cuts::Quantity qty, int i) { return qty > double(i); } inline Cut operator <= (Cuts::Quantity qty, int i) { return qty <= double(i); } inline Cut operator >= (Cuts::Quantity qty, int i) { return qty >= double(i); } //@} //@} /// @name Cut combiners //@{ /// Logical AND operation on two cuts /// @note No comparison short-circuiting for overloaded &&! Cut operator && (const Cut & aptr, const Cut & bptr); /// Logical OR operation on two cuts /// @note No comparison short-circuiting for overloaded ||! Cut operator || (const Cut & aptr, const Cut & bptr); /// Logical NOT operation on a cut Cut operator ! (const Cut & cptr); /// Logical AND operation on two cuts Cut operator & (const Cut & aptr, const Cut & bptr); /// Logical OR operation on two cuts Cut operator | (const Cut & aptr, const Cut & bptr); /// Logical NOT operation on a cut Cut operator ~ (const Cut & cptr); /// Logical XOR operation on two cuts Cut operator ^ (const Cut & aptr, const Cut & bptr); //@} - + /// Get quantity name used in cut + std::string toString(Cuts::Quantity qty); + /// Get quantity value as a string + std::string toString(double val); + } #endif diff --git a/src/Tools/Cuts.cc b/src/Tools/Cuts.cc --- a/src/Tools/Cuts.cc +++ b/src/Tools/Cuts.cc @@ -1,449 +1,522 @@ #include "Rivet/Tools/Cuts.hh" #include "Rivet/Particle.hh" #include "Rivet/Jet.hh" #include "Rivet/Math/Vectors.hh" #include "fastjet/PseudoJet.hh" #include "HepMC/SimpleVector.h" /// @todo Identify what can go into anonymous namespace namespace Rivet { // Base for all wrapper classes that translate ClassToCheck to Cuttable class CuttableBase { public: virtual double getValue(Cuts::Quantity) const = 0; virtual ~CuttableBase() {} }; // Cuttables can be directly passed to @ref _accept template <> bool CutBase::accept(const CuttableBase& t) const { return _accept(t); } // Open Cut singleton class Open_Cut : public CutBase { public: bool operator==(const Cut& c) const { std::shared_ptr cc = dynamic_pointer_cast(c); return bool(cc); } + // Description method for open cut + virtual std::string description() const { + return "true"; + } protected: // open cut accepts everything bool _accept(const CuttableBase&) const { return true; } }; const Cut& Cuts::open() { // Only ever need one static open cut object static const Cut open = std::make_shared(); return open; } // Constants for convenient access const Cut& Cuts::OPEN = Cuts::open(); const Cut& Cuts::NOCUT = Cuts::open(); // Cut constructor for == class Cut_Eq : public CutBase { public: Cut_Eq(const Cuts::Quantity qty, double val) : _qty(qty), _val(val) {} bool operator==(const Cut& c) const { std::shared_ptr cc = dynamic_pointer_cast(c); return cc && _qty == cc->_qty && _val == cc->_val; } + // Description method for == + virtual std::string description() const { + return "(" + toString(_qty) + " == " + toString(_val) + ")"; + } protected: bool _accept(const CuttableBase& o) const { return o.getValue(_qty) == _val; } private: Cuts::Quantity _qty; int _val; }; // Cut constructor for != class Cut_NEq : public CutBase { public: Cut_NEq(const Cuts::Quantity qty, double val) : _qty(qty), _val(val) {} bool operator==(const Cut& c) const { std::shared_ptr cc = dynamic_pointer_cast(c); return cc && _qty == cc->_qty && _val == cc->_val; } + // Description method for != + virtual std::string description() const { + return "(" + toString(_qty) + " != " + toString(_val) + ")"; + } protected: bool _accept(const CuttableBase& o) const { return o.getValue(_qty) != _val; } private: Cuts::Quantity _qty; int _val; }; // Cut constructor for >= class Cut_GtrEq : public CutBase { public: Cut_GtrEq(const Cuts::Quantity qty, double val) : _qty(qty), _val(val) {} bool operator==(const Cut& c) const { std::shared_ptr cc = dynamic_pointer_cast(c); return cc && _qty == cc->_qty && _val == cc->_val; } + // Description method for >= + virtual std::string description() const { + return "(" + toString(_qty) + " >= " + toString(_val) + ")"; + } protected: bool _accept(const CuttableBase& o) const { return o.getValue(_qty) >= _val; } private: Cuts::Quantity _qty; double _val; }; // Cut constructor for < class Cut_Less : public CutBase { public: Cut_Less(const Cuts::Quantity qty, const double val) : _qty(qty), _val(val) {} bool operator==(const Cut& c) const { std::shared_ptr cc = dynamic_pointer_cast(c); return cc && _qty == cc->_qty && _val == cc->_val; } + // Description method for < + virtual std::string description() const { + return "(" + toString(_qty) + " < " + toString(_val) + ")"; + } protected: bool _accept(const CuttableBase& o) const { return o.getValue(_qty) < _val; } private: Cuts::Quantity _qty; double _val; }; // Cut constructor for > class Cut_Gtr : public CutBase { public: Cut_Gtr(const Cuts::Quantity qty, const double val) : _qty(qty), _val(val) {} bool operator==(const Cut& c) const { std::shared_ptr cc = dynamic_pointer_cast(c); return cc && _qty == cc->_qty && _val == cc->_val; } + // Description method for > + virtual std::string description() const { + return "(" + toString(_qty) + " > " + toString(_val) + ")"; + } protected: bool _accept(const CuttableBase& o) const { return o.getValue(_qty) > _val; } private: Cuts::Quantity _qty; double _val; }; // Cut constructor for <= class Cut_LessEq : public CutBase { public: Cut_LessEq(const Cuts::Quantity qty, const double val) : _qty(qty), _val(val) {} bool operator==(const Cut& c) const { std::shared_ptr cc = dynamic_pointer_cast(c); return cc && _qty == cc->_qty && _val == cc->_val; } + // Description method for <= + virtual std::string description() const { + return "(" + toString(_qty) + " <= " + toString(_val) + ")"; + } protected: bool _accept(const CuttableBase& o) const { return o.getValue(_qty) <= _val; } private: Cuts::Quantity _qty; double _val; }; template inline Cut make_cut(T t) { return std::make_shared(t); } Cut operator == (Cuts::Quantity qty, double n) { return make_cut(Cut_Eq(qty, n)); } Cut operator != (Cuts::Quantity qty, double n) { return make_cut(Cut_NEq(qty, n)); } Cut operator < (Cuts::Quantity qty, double n) { return make_cut(Cut_Less(qty, n)); } Cut operator >= (Cuts::Quantity qty, double n) { return make_cut(Cut_GtrEq(qty, n)); } Cut operator <= (Cuts::Quantity qty, double n) { return make_cut(Cut_LessEq(qty, n)); } Cut operator > (Cuts::Quantity qty, double n) { return make_cut(Cut_Gtr(qty, n)); } Cut Cuts::range(Cuts::Quantity qty, double m, double n) { if (m > n) std::swap(m,n); return (qty >= m) && (qty < n); } ////////////// /// Combiners /// AND, OR, NOT, and XOR objects for combining cuts class CutsOr : public CutBase { public: CutsOr(const Cut& c1, const Cut& c2) : cut1(c1), cut2(c2) {} bool operator==(const Cut& c) const { std::shared_ptr cc = dynamic_pointer_cast(c); return cc && ( ( cut1 == cc->cut1 && cut2 == cc->cut2 ) || ( cut1 == cc->cut2 && cut2 == cc->cut1 )); } + // Description method + std::string description() const { + return "(" + cut1->description() + " || " + cut2->description() + ")"; + } protected: bool _accept(const CuttableBase& o) const { return cut1->accept(o) || cut2->accept(o); } private: const Cut cut1; const Cut cut2; }; class CutsAnd : public CutBase { public: CutsAnd(const Cut& c1, const Cut& c2) : cut1(c1), cut2(c2) {} bool operator==(const Cut& c) const { std::shared_ptr cc = dynamic_pointer_cast(c); return cc && ( ( cut1 == cc->cut1 && cut2 == cc->cut2 ) || ( cut1 == cc->cut2 && cut2 == cc->cut1 )); } + // Description method + std::string description() const { + return "(" + cut1->description() + " && " + cut2->description() + ")"; + } protected: bool _accept(const CuttableBase& o) const { return cut1->accept(o) && cut2->accept(o); } private: const Cut cut1; const Cut cut2; }; class CutInvert : public CutBase { public: CutInvert(const Cut& c1) : cut(c1) {} bool operator==(const Cut& c) const { std::shared_ptr cc = dynamic_pointer_cast(c); return cc && cut == cc->cut; } + // Description method + std::string description() const { + return "(!" + cut->description() + ")"; + } protected: bool _accept(const CuttableBase& o) const { return !cut->accept(o); } private: const Cut cut; }; class CutsXor : public CutBase { public: CutsXor(const Cut& c1, const Cut& c2) : cut1(c1), cut2(c2) {} bool operator==(const Cut& c) const { std::shared_ptr cc = dynamic_pointer_cast(c); return cc && ( ( cut1 == cc->cut1 && cut2 == cc->cut2 ) || ( cut1 == cc->cut2 && cut2 == cc->cut1 )); } + // Description method + std::string description() const { + return "(" + cut1->description() + " XOR " + cut2->description() + ")"; + } protected: bool _accept(const CuttableBase& o) const { bool A_and_B = cut1->accept(o) && cut2->accept(o); bool A_or_B = cut1->accept(o) || cut2->accept(o); return A_or_B && (! A_and_B); } private: const Cut cut1; const Cut cut2; }; //////////// ///Operators Cut operator && (const Cut& aptr, const Cut& bptr) { return make_cut(CutsAnd(aptr, bptr)); } Cut operator || (const Cut& aptr, const Cut& bptr) { return make_cut(CutsOr(aptr, bptr)); } Cut operator ! (const Cut& cptr) { return make_cut(CutInvert(cptr)); } Cut operator & (const Cut& aptr, const Cut& bptr) { return make_cut(CutsAnd(aptr, bptr)); } Cut operator | (const Cut& aptr, const Cut& bptr) { return make_cut(CutsOr(aptr, bptr)); } Cut operator ~ (const Cut& cptr) { return make_cut(CutInvert(cptr)); } Cut operator ^ (const Cut& aptr, const Cut& bptr) { return make_cut(CutsXor(aptr, bptr)); } /////////////////////// /// Cuts // Non-functional Cuttable template class. Must be specialized below. template class Cuttable; // Non-cuttables need to be wrapped into a Cuttable first #define SPECIALISE_ACCEPT(TYPENAME) \ template <> \ bool CutBase::accept(const TYPENAME& t) const { \ return _accept(Cuttable(t)); \ } \ inline void qty_not_found() { throw Exception("Missing implementation for a Cuts::Quantity."); } template<> class Cuttable : public CuttableBase { public: Cuttable(const Particle& p) : p_(p) {} double getValue(Cuts::Quantity qty) const { switch ( qty ) { case Cuts::pT: return p_.pT(); case Cuts::Et: return p_.Et(); case Cuts::mass: return p_.mass(); case Cuts::rap: return p_.rap(); case Cuts::absrap: return p_.absrap(); case Cuts::eta: return p_.eta(); case Cuts::abseta: return p_.abseta(); case Cuts::phi: return p_.phi(); case Cuts::pid: return p_.pid(); case Cuts::abspid: return p_.abspid(); case Cuts::charge: return p_.charge(); case Cuts::abscharge: return p_.abscharge(); case Cuts::charge3: return p_.charge3(); case Cuts::abscharge3: return p_.abscharge3(); default: qty_not_found(); } return -999.; } private: const Particle& p_; }; SPECIALISE_ACCEPT(Particle) template<> class Cuttable : public CuttableBase { public: Cuttable(const FourMomentum& fm) : fm_(fm) {} double getValue(Cuts::Quantity qty) const { switch ( qty ) { case Cuts::pT: return fm_.pT(); case Cuts::Et: return fm_.Et(); case Cuts::mass: return fm_.mass(); case Cuts::rap: return fm_.rap(); case Cuts::absrap: return fm_.absrap(); case Cuts::eta: return fm_.eta(); case Cuts::abseta: return fm_.abseta(); case Cuts::phi: return fm_.phi(); default: qty_not_found(); } return -999.; } private: const FourMomentum& fm_; }; SPECIALISE_ACCEPT(FourMomentum) template<> class Cuttable : public CuttableBase { public: Cuttable(const Jet& jet) : jet_(jet) {} double getValue(Cuts::Quantity qty) const { switch ( qty ) { case Cuts::pT: return jet_.momentum().pT(); case Cuts::Et: return jet_.momentum().Et(); case Cuts::mass: return jet_.momentum().mass(); case Cuts::rap: return jet_.momentum().rapidity(); case Cuts::absrap: return std::abs(jet_.momentum().rapidity()); case Cuts::eta: return jet_.momentum().pseudorapidity(); case Cuts::abseta: return std::abs(jet_.momentum().pseudorapidity()); case Cuts::phi: return jet_.momentum().phi(); default: qty_not_found(); } return -999.; } private: const Jet& jet_; }; SPECIALISE_ACCEPT(Jet) template<> class Cuttable : public CuttableBase { public: Cuttable(const fastjet::PseudoJet& pjet) : pjet_(pjet) {} double getValue(Cuts::Quantity qty) const { switch ( qty ) { case Cuts::pT: return pjet_.perp(); case Cuts::Et: return pjet_.Et(); case Cuts::mass: return pjet_.m(); case Cuts::rap: return pjet_.rap(); case Cuts::absrap: return std::abs(pjet_.rap()); case Cuts::eta: return pjet_.eta(); case Cuts::abseta: return std::abs(pjet_.eta()); case Cuts::phi: return pjet_.phi(); default: qty_not_found(); } return -999.; } private: const fastjet::PseudoJet& pjet_; }; SPECIALISE_ACCEPT(fastjet::PseudoJet) template<> class Cuttable : public CuttableBase { public: Cuttable(const HepMC::FourVector& vec) : vec_(vec) {} double getValue(Cuts::Quantity qty) const { switch ( qty ) { case Cuts::pT: return vec_.perp(); /// @todo case Cuts::Et: return vec_.perp(); case Cuts::mass: return vec_.m(); case Cuts::rap: return 0.5*std::log((vec_.t()+vec_.z())/(vec_.t()-vec_.z())); case Cuts::absrap: return std::abs(getValue(Cuts::rap)); case Cuts::eta: return vec_.pseudoRapidity(); case Cuts::abseta: return std::abs(vec_.pseudoRapidity()); case Cuts::phi: return vec_.phi(); default: qty_not_found(); } return -999.; } private: const HepMC::FourVector& vec_; }; SPECIALISE_ACCEPT(HepMC::FourVector) + // Get the name of quantity used in cut + std::string toString(Cuts::Quantity qty) { + switch (qty) { + case Cuts::pT : return "pT"; + case Cuts::Et : return "Et"; + case Cuts::mass : return "mass"; + case Cuts::rap : return "rap"; + case Cuts::absrap : return "absrap"; + case Cuts::eta : return "eta"; + case Cuts::abseta : return "abseta"; + case Cuts::phi : return "phi"; + case Cuts::pid : return "pid"; + case Cuts::abspid : return "abspid"; + case Cuts::charge : return "charge"; + case Cuts::abscharge : return "abscharge"; + case Cuts::charge3 : return "charge3"; + case Cuts::abscharge3 : return "abscharge3"; + default: qty_not_found(); + } + return "unknown"; + } + // Convert the quantity value to string with a specified precision + std::string toString(double val) { + std::stringstream buff; + buff << std::setprecision(3); + buff << val; + return buff.str(); + } + }