Back to home page

EIC code displayed by LXR

 
 

    


File indexing completed on 2025-05-12 09:05:03

0001 // -*- C++ -*-
0002 #ifndef RIVET_PartonicTops_HH
0003 #define RIVET_PartonicTops_HH
0004 
0005 #include "Rivet/Projections/ParticleFinder.hh"
0006 
0007 namespace Rivet {
0008 
0009 
0010   /// @brief Enum for categorising top quark decay modes
0011   ///
0012   /// More specifically, the decay mode of the W from the top. We presume top decay to a W and b quark.
0013   enum class TopDecay {
0014     ANY=0, ALL=0,
0015     ELECTRON,
0016     MUON,
0017     TAU,
0018     E_MU,
0019     E_MU_TAU,
0020     HADRONIC
0021   };
0022 
0023   /// @brief Enum for categorising which top quark to be selected: last (weakly decaying) or first?
0024   enum class WhichTop { FIRST, LAST };
0025 
0026   enum class PromptEMuFromTau { YES, NO };
0027 
0028   enum class InclHadronicTau { YES, NO };
0029 
0030 
0031   /// @brief Convenience finder of partonic top quarks
0032   ///
0033   /// @warning This projection requires there to be tops in the event record:
0034   /// there is no guarantee of this, especially where the top quark is treated
0035   /// (correctly) as a resonance rather than on-shell. Further, there is no
0036   /// guarantee that the kinematics assigned to such tops are consistent,
0037   /// physical, or even associated with the lab frame. A fiducial pseudo-top
0038   /// analysis approach is *strongly* recommended instead.
0039   class PartonicTops : public ParticleFinder {
0040   public:
0041 
0042     /// @name Constructors
0043     /// @{
0044 
0045     /// Constructor taking decay mode details (and an optional cuts object)
0046     PartonicTops(TopDecay decaymode,
0047          PromptEMuFromTau emu_from_prompt_tau=PromptEMuFromTau::YES,
0048          InclHadronicTau include_hadronic_taus=InclHadronicTau::NO,
0049          const Cut& c=Cuts::OPEN, WhichTop whichtop=WhichTop::LAST)
0050       : ParticleFinder(c), _topmode(whichtop), _decaymode(decaymode),
0051         _emu_from_prompt_tau(emu_from_prompt_tau == PromptEMuFromTau::YES),
0052     _include_hadronic_taus(include_hadronic_taus == InclHadronicTau::YES)
0053     {  }
0054 
0055     /// Constructor taking decay mode details (and a non-optional cuts object)
0056     PartonicTops(TopDecay decaymode, const Cut& c,
0057          PromptEMuFromTau emu_from_prompt_tau=PromptEMuFromTau::YES,
0058          InclHadronicTau include_hadronic_taus=InclHadronicTau::NO,
0059          WhichTop whichtop=WhichTop::LAST)
0060       : PartonicTops(decaymode, emu_from_prompt_tau, include_hadronic_taus, c, whichtop)
0061     {  }
0062 
0063     /// Simple constructor optionally taking cuts object
0064     PartonicTops(const Cut& c=Cuts::OPEN, WhichTop whichtop=WhichTop::LAST)
0065       : PartonicTops(TopDecay::ALL, PromptEMuFromTau::YES, InclHadronicTau::NO, c, whichtop)
0066     {  }
0067 
0068 
0069     /// Clone on the heap.
0070     RIVET_DEFAULT_PROJ_CLONE(PartonicTops);
0071 
0072     /// @}
0073 
0074 
0075     /// Import to avoid warnings about overload-hiding
0076     using Projection::operator =;
0077 
0078 
0079     /// Access to the found partonic tops
0080     const Particles& tops() const { return _theParticles; }
0081 
0082 
0083     /// Clear the projection
0084     void clear() {
0085       _theParticles.clear();
0086     }
0087 
0088 
0089   protected:
0090 
0091     /// Apply the projection on the supplied event.
0092     void project(const Event& event) {
0093 
0094       // Warn about how terrible this is, the first time it's called!
0095       static bool donerubric = false;
0096       if (!donerubric) {
0097         MSG_WARNING("PartonicTops is not recommended: MC generators do not guarantee physical properties for, or even the existence of, partonic event-record entries. Caveat emptor!");
0098         donerubric = true;
0099       }
0100 
0101       // Find partonic tops
0102       _theParticles = select(event.allParticles(_cuts), (_topmode == WhichTop::LAST ? lastParticleWith(isTop) : firstParticleWith(isTop)));
0103 
0104       // Filtering by decay mode
0105       if (_decaymode != TopDecay::ALL) {
0106         const auto decaycheck = [&](const Particle& t) {
0107           const Particles descendants = t.allDescendants();
0108           const bool prompt_e = any(descendants, [&](const Particle& p){ return p.abspid() == PID::ELECTRON && p.isPrompt(_emu_from_prompt_tau) && !p.hasAncestorWith(Cuts::pid == PID::PHOTON, false); });
0109           const bool prompt_mu = any(descendants, [&](const Particle& p){ return p.abspid() == PID::MUON && p.isPrompt(_emu_from_prompt_tau) && !p.hasAncestorWith(Cuts::pid == PID::PHOTON, false); });
0110           if (prompt_e && (_decaymode == TopDecay::ELECTRON || _decaymode == TopDecay::E_MU || _decaymode == TopDecay::E_MU_TAU)) return true;
0111           if (prompt_mu && (_decaymode == TopDecay::MUON || _decaymode == TopDecay::E_MU || _decaymode == TopDecay::E_MU_TAU)) return true;
0112           const bool prompt_tau = any(descendants, [&](const Particle& p){ return p.abspid() == PID::TAU && p.isPrompt()  && !p.hasAncestorWith(Cuts::pid == PID::PHOTON, false); });
0113           const bool prompt_hadronic_tau = any(descendants, [&](const Particle& p){ return p.abspid() == PID::TAU && p.isPrompt() && !p.hasAncestorWith(Cuts::pid == PID::PHOTON, false) && none(p.children(), isChargedLepton); });
0114           if (prompt_tau && (_decaymode == TopDecay::TAU || _decaymode == TopDecay::E_MU_TAU)) return (_include_hadronic_taus || !prompt_hadronic_tau);
0115           if (_decaymode == TopDecay::HADRONIC && (!prompt_e && !prompt_mu && (!prompt_tau || (_include_hadronic_taus && prompt_hadronic_tau)))) return true; //< logical hairiness...
0116           return false;
0117         };
0118         iselect(_theParticles, decaycheck);
0119       }
0120 
0121       // Filtering and warning about unphysical partonic tops
0122       const auto physcheck = [&](const Particle& t) {
0123         if (t.E() < 0 || t.mass() < 0) {
0124           MSG_WARNING("Unphysical partonic top with negative E or m found: " << t.mom());
0125           return false;
0126         }
0127         return true;
0128       };
0129       iselect(_theParticles, physcheck);
0130     }
0131 
0132 
0133     /// Compare projections.
0134     CmpState compare(const Projection& p) const {
0135       const PartonicTops& other = dynamic_cast<const PartonicTops&>(p);
0136       return cmp(_cuts, other._cuts) ||
0137         cmp(_topmode, other._topmode) ||
0138         cmp(_decaymode, other._decaymode) ||
0139         cmp(_emu_from_prompt_tau, other._emu_from_prompt_tau) ||
0140         cmp(_include_hadronic_taus, other._include_hadronic_taus);
0141     }
0142 
0143 
0144   protected:
0145 
0146     WhichTop _topmode;
0147 
0148     TopDecay _decaymode;
0149 
0150     bool _emu_from_prompt_tau, _include_hadronic_taus;
0151 
0152   };
0153 
0154 
0155 }
0156 
0157 #endif