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