ATLAS Offline Software
Loading...
Searching...
No Matches
CalcWPartonHistory.cxx
Go to the documentation of this file.
1/*
2 Copyright (C) 2002-2026 CERN for the benefit of the ATLAS collaboration
3*/
4
7
11
12namespace CP {
13using ROOT::Math::PtEtaPhiMVector;
14
15bool CalcPartonHistory::getW(const std::string& str_lep,
16 const std::string& str_nu, PtEtaPhiMVector& p1,
17 int& pdgId1, PtEtaPhiMVector& p2, int& pdgId2) {
18 // Off-shell / non-resonant W reconstruction from lepton + neutrino
19 // candidates. Loops over all (lepton, neutrino) pairs and returns the first
20 // pair that passes the three conditions below. The caller is responsible for
21 // passing the correct lepton/neutrino flavour keys (e.g. MC_lbar + MC_nu for
22 // W+).
23 std::vector<const xAOD::TruthParticle*> W_offshell_decay1_candidates;
24 std::vector<const xAOD::TruthParticle*> W_offshell_decay2_candidates;
25 // str_lep/str_nu are full m_particleMap keys (caller passes m_prefix + "_" +
26 // ...)
27 bool has_candidates =
28 (RetrieveParticleInfo(str_lep, W_offshell_decay1_candidates) &&
29 RetrieveParticleInfo(str_nu, W_offshell_decay2_candidates));
30 if (has_candidates) {
31 for (const auto* particle_1 : W_offshell_decay1_candidates) {
32 for (const auto* particle_2 : W_offshell_decay2_candidates) {
33 // Condition 1: Opposite charge — lepton and neutrino must have
34 // opposite-sign pdgIds (e.g. e- has pdgId=11, νe has pdgId=12; product
35 // is positive, so we require the product to be negative for a valid W
36 // decay pair).
37 if ((particle_1->pdgId() * particle_2->pdgId()) > 0)
38 continue;
39 // Condition 2: Same lepton generation — |pdgId| of lepton and neutrino
40 // must differ by exactly 1 (e.g. 11 & 12, 13 & 14, 15 & 16).
41 if (std::abs(particle_1->absPdgId() - particle_2->absPdgId()) != 1)
42 continue;
43 // Condition 3: Reject shower particles — particles produced during
44 // parton showering are assigned UIDs above 10100 by the generator.
45 // We require at least one of the pair to be a hard-scatter particle
46 // (UID ≤ 10100) to avoid picking up shower leptons.
47 if (particle_1->uid() > 10100 && particle_2->uid() > 10100)
48 continue;
49
50 p1 = GetPtEtaPhiMfromTruth(particle_1);
51 pdgId1 = particle_1->pdgId();
52 p2 = GetPtEtaPhiMfromTruth(particle_2);
53 pdgId2 = particle_2->pdgId();
54 return true;
55 }
56 }
57 }
58 return false;
59}
60
61void CalcPartonHistory::setW(const std::string& fsr, int nWs) {
62 PtEtaPhiMVector W;
63 PtEtaPhiMVector Wm, Wm_decay1, Wm_decay2;
64 PtEtaPhiMVector Wp, Wp_decay1, Wp_decay2;
65 int Wm_decay1_pdgId, Wm_decay2_pdgId;
66 int Wp_decay1_pdgId, Wp_decay2_pdgId;
67
68 if (nWs == 1) {
69 // W+: pass full m_particleMap keys to getW; bare names to m_dec.*
70 bool has_Wp =
71 getW(m_prefix + "_" + "MC_lbar_" + fsr, m_prefix + "_" + "MC_nu_" + fsr,
72 Wp_decay1, Wp_decay1_pdgId, Wp_decay2, Wp_decay2_pdgId);
73 if (has_Wp) {
74 Wp = Wp_decay1 + Wp_decay2;
75 m_dec.decorateParticle("MC_W_" + fsr, Wp, 24);
76 m_dec.decorateParticle("MC_Wdecay1_" + fsr, Wp_decay1, Wp_decay1_pdgId);
77 m_dec.decorateParticle("MC_Wdecay2_" + fsr, Wp_decay2, Wp_decay2_pdgId);
78 }
79 // W-
80 bool has_Wm =
81 getW(m_prefix + "_" + "MC_l_" + fsr, m_prefix + "_" + "MC_nubar_" + fsr,
82 Wm_decay1, Wm_decay1_pdgId, Wm_decay2, Wm_decay2_pdgId);
83 if (has_Wm) {
84 Wm = Wm_decay1 + Wm_decay2;
85 m_dec.decorateParticle("MC_W_" + fsr, Wm, -24);
86 m_dec.decorateParticle("MC_Wdecay1_" + fsr, Wm_decay1, Wm_decay1_pdgId);
87 m_dec.decorateParticle("MC_Wdecay2_" + fsr, Wm_decay2, Wm_decay2_pdgId);
88 }
89 } else if (nWs == 2) {
90 // W+
91 bool has_Wp =
92 getW(m_prefix + "_" + "MC_lbar_" + fsr, m_prefix + "_" + "MC_nu_" + fsr,
93 Wp_decay1, Wp_decay1_pdgId, Wp_decay2, Wp_decay2_pdgId);
94 if (has_Wp) {
95 Wp = Wp_decay1 + Wp_decay2;
96 m_dec.decorateParticle("MC_W1_" + fsr, Wp, 24);
97 m_dec.decorateParticle("MC_W1decay1_" + fsr, Wp_decay1, Wp_decay1_pdgId);
98 m_dec.decorateParticle("MC_W1decay2_" + fsr, Wp_decay2, Wp_decay2_pdgId);
99 }
100 // W-
101 bool has_Wm =
102 getW(m_prefix + "_" + "MC_l_" + fsr, m_prefix + "_" + "MC_nubar_" + fsr,
103 Wm_decay1, Wm_decay1_pdgId, Wm_decay2, Wm_decay2_pdgId);
104 if (has_Wm) {
105 Wm = Wm_decay1 + Wm_decay2;
106 m_dec.decorateParticle("MC_W2_" + fsr, Wm, -24);
107 m_dec.decorateParticle("MC_W2decay1_" + fsr, Wm_decay1, Wm_decay1_pdgId);
108 m_dec.decorateParticle("MC_W2decay2_" + fsr, Wm_decay2, Wm_decay2_pdgId);
109 }
110 }
111}
112
113void CalcPartonHistory::FillWPartonHistory(const std::string& parent, int nWs,
114 const std::string& mode) {
115 std::string parentstring = parent.empty() ? "" : "_from_" + parent;
116 // Bare suffix for FillGenericPartonHistory (it prepends m_prefix + "_"
117 // internally).
118 std::string prefix = "MC_" + (parent.empty() ? "W" : parent + "_W");
119
120 if (mode == "resonant") {
121 if (nWs == 1) {
122 FillGenericPartonHistory(prefix + "_beforeFSR",
123 "MC_W_beforeFSR" + parentstring, 0);
124 FillGenericPartonHistory(prefix + "Decay1_beforeFSR",
125 "MC_Wdecay1_beforeFSR" + parentstring, 0);
126 FillGenericPartonHistory(prefix + "Decay2_beforeFSR",
127 "MC_Wdecay2_beforeFSR" + parentstring, 0);
128 FillGenericPartonHistory(prefix + "_afterFSR",
129 "MC_W_afterFSR" + parentstring, 0);
130 FillGenericPartonHistory(prefix + "Decay1_afterFSR",
131 "MC_Wdecay1_afterFSR" + parentstring, 0);
132 FillGenericPartonHistory(prefix + "Decay2_afterFSR",
133 "MC_Wdecay2_afterFSR" + parentstring, 0);
134 } else {
135 for (int idx = 0; idx < nWs; idx++) {
136 const std::string idxStr = std::to_string(idx + 1);
137 FillGenericPartonHistory(prefix + "_beforeFSR",
138 "MC_W" + idxStr + "_beforeFSR" + parentstring,
139 0);
141 prefix + "Decay1_beforeFSR",
142 "MC_W" + idxStr + "decay1_beforeFSR" + parentstring, 0);
144 prefix + "Decay2_beforeFSR",
145 "MC_W" + idxStr + "decay2_beforeFSR" + parentstring, 0);
146 FillGenericPartonHistory(prefix + "_afterFSR",
147 "MC_W" + idxStr + "_afterFSR" + parentstring,
148 0);
150 prefix + "Decay1_afterFSR",
151 "MC_W" + idxStr + "decay1_afterFSR" + parentstring, 0);
153 prefix + "Decay2_afterFSR",
154 "MC_W" + idxStr + "decay2_afterFSR" + parentstring, 0);
155 }
156 }
157 } else if (mode == "non_resonant") {
158 setW("beforeFSR", nWs);
159 setW("afterFSR", nWs);
160 }
161}
162} // namespace CP
ROOT::Math::PtEtaPhiMVector GetPtEtaPhiMfromTruth(const xAOD::TruthParticle *TruthParticle)
bool RetrieveParticleInfo(const std::string &prefix, std::vector< const xAOD::TruthParticle * > &particles)
void FillWPartonHistory(const std::string &parent, int nWs=1, const std::string &mode="resonant")
bool getW(const std::string &str_lep, const std::string &str_nu, PtEtaPhiMVector &p1, int &pdgId1, PtEtaPhiMVector &p2, int &pdgId2)
std::string m_prefix
prefix applied to all decorator and m_particleMap names
void setW(const std::string &fsr, int nWs)
void FillGenericPartonHistory(const std::string &retrievalstring, const std::string &decorationstring, const int idx)
Select isolated Photons, Electrons and Muons.
@ W
FillWPartonHistory(history, parent, dec, count, mode).