ATLAS Offline Software
Loading...
Searching...
No Matches
HadronOriginClassifier.cxx
Go to the documentation of this file.
1/*
2 Copyright (C) 2002-2026 CERN for the benefit of the ATLAS collaboration
3*/
7
8namespace {
10 struct Sample {
12
14 Sample(int low, int high, GEN_id gen) :
15 low(low), high(high), gen(gen) {}
16
18 Sample(int id, GEN_id gen) :
19 Sample(id, id, gen) {}
20
21 int low{};
22 int high{};
23 GEN_id gen{GEN_id::Pythia6};
24 };
25}
26
27namespace DerivationFramework{
28
29 HadronOriginClassifier::HadronOriginClassifier(const std::string& t, const std::string& n, const IInterface* p):
30 AthAlgTool(t,n,p)
31 {
32 }
33
35
37 ATH_MSG_INFO("Initialize " );
38 ATH_MSG_INFO("DSID " << m_DSID );
39
40 ATH_CHECK(m_mcName.initialize());
41 ATH_CHECK(m_truthParticlesKey.initialize());
42 ATH_CHECK(m_truthVerticesKey.initialize());
43
44 static const std::vector<Sample> samples = {
45 // all Herwig++/Herwig7 showered samples
46 {346346, 346348, GEN_id::HerwigPP},
47 {410003, GEN_id::HerwigPP}, {410008, GEN_id::HerwigPP}, //aMC@NLO+Hpp
48 {410004, GEN_id::HerwigPP}, {410163, GEN_id::HerwigPP}, //Powheg+Hpp
49 {410232, 410233, GEN_id::HerwigPP}, //first attempt for Powheg+H7 / aMC@NLO+H7
50 {410525, 410530, GEN_id::HerwigPP}, //New Powheg+H7 samples
51 {407037, 407040, GEN_id::HerwigPP}, //Powheg+Hpp MET/HT sliced
52 {410536, 410537, GEN_id::HerwigPP}, {410245, GEN_id::HerwigPP}, //aMC@NLO+H++ , ttbb
53 {410557, 410559, GEN_id::HerwigPP}, // new Powheg+H7, mc16
54 {411082, 411090, GEN_id::HerwigPP}, //Powheg+H7 HF-filtered
55 {407354, 407356, GEN_id::HerwigPP}, //Powheg+H7 ttbar HT-filtered
56 {411233, 411234, GEN_id::HerwigPP}, //Powheg+H7.1.3 ttbar
57 {411316, GEN_id::HerwigPP}, //Powheg+H7 allhad ttbar
58 {411329, 411334, GEN_id::HerwigPP}, //Powheg+H7.1.3 ttbar HF-filtered
59 {411335, 411337, GEN_id::HerwigPP}, //Powheg+H7.1.3 ttbar HT-filtered
60 {412116, 412117, GEN_id::HerwigPP}, //amc@NLO+H7.1.3 ttbar
61 {504329, GEN_id::HerwigPP}, {504333, GEN_id::HerwigPP}, {504341, GEN_id::HerwigPP}, //amc@NLO+H7.2.1 refined ttZ
62 {601239, 601240, GEN_id::HerwigPP},
63 {601668, GEN_id::HerwigPP},
64 {603905, 603906, GEN_id::HerwigPP}, // ttbb Powheg+H7 dilep, ljet, allhad
65 {504337, GEN_id::HerwigPP}, {504345, GEN_id::HerwigPP}, // aMC@NLO+H7 ttZ
66 {526034, GEN_id::HerwigPP}, // aMC@NLO+H7 4tops
67 {600666, 600667, GEN_id::HerwigPP}, // Powheg+H7 ttbar H7UE
68 {607432, GEN_id::HerwigPP}, {601414, 601415, GEN_id::HerwigPP}, // Powheg+H7 ttbar A14
69 {602635, 602635, GEN_id::HerwigPP}, // Powheg+H7 ttH PDF4LHC21
70 {602846, 602849, GEN_id::HerwigPP}, // Powheg+H7 ttW NNPDF30NLO EW
71
72 // all Pythia8 showered samples
73 {304014, GEN_id::Pythia8}, // amc@NLO+P8 3top
74 {346229, 346234, GEN_id::Pythia8}, // amc@NLO+P8 tHjb
75 {410006, GEN_id::Pythia8}, //Powheg+P8 old main31
76 {410081, GEN_id::Pythia8}, //amc@NLO+P8 ttV
77 {410500, GEN_id::Pythia8}, //Powheg+P8 new main31, hdamp=mt
78 {410501, 410508, GEN_id::Pythia8}, //Powheg+P8 new main31, hdamp=1.5m // Boosted samples are included 410507 410508
79 {410511, 410524, GEN_id::Pythia8}, //Powheg+P8 new main31, hdamp=1.5mt, radiation systematics
80 {410531, 410535, GEN_id::Pythia8}, //Powheg+P8 allhad samples
81 {346343, 346345, GEN_id::Pythia8}, //Powheg+P8 ttH
82 {412123, GEN_id::Pythia8}, // MG+P8 ttW
83 {410155, GEN_id::Pythia8}, // aMC@NlO+P8 ttW
84 {410159, 410160, GEN_id::Pythia8}, //aMC@NLO+P8, old settings
85 {410218, 410220, GEN_id::Pythia8}, // aMC@NlO+P8 ttZ
86 {410276, 410278, GEN_id::Pythia8}, // aMC@NlO+P8 ttZ_lowMass
87 {410225, 410227, GEN_id::Pythia8}, {410274, 410275, GEN_id::Pythia8}, //aMC@NLO+P8, new settings
88 {410568, 410569, GEN_id::Pythia8}, // nonallhad boosted c-filtered
89 {410244, GEN_id::Pythia8}, //aMC@NLO+P8, ttbb (old)
90 {410441, 410442, GEN_id::Pythia8}, //new aMC@NLO+P8 mc16, new shower starting scale
91 {410464, 410466, GEN_id::Pythia8}, //new aMC@NLO+P8 mc16, new shower starting scale, no shower weights
92 {410470, 410472, GEN_id::Pythia8}, {410480, 410482, GEN_id::Pythia8}, //new Powheg+P8 mc16
93 {410452, GEN_id::Pythia8}, //new aMC@NLO+P8 FxFx mc16
94 {411073, 411081, GEN_id::Pythia8}, //Powheg+P8 HF-filtered
95 {412043, 412044, GEN_id::Pythia8}, {500326, GEN_id::Pythia8}, //aMC@NLO+P8 4top
96 {412066, 412074, GEN_id::Pythia8}, //aMC@NLO+P8 HF-filtered
97 {411068, 411070, GEN_id::Pythia8}, //Powheg+P8 ttbb
98 {410265, 410267, GEN_id::Pythia8}, //aMC@NLO+P8 ttbb
99 {411178, 411180, GEN_id::Pythia8}, {411275, GEN_id::Pythia8}, //Powheg+P8 ttbb OTF production - ATLMCPROD-7240
100 {501720, GEN_id::Pythia8}, // aMC@NLO+P8 FxFx ttW
101 {600791, 600792, GEN_id::Pythia8}, //Powheg+P8 ttbb - ATLMCPROD-9179
102 {607428, GEN_id::Pythia8}, {600737, 600738, GEN_id::Pythia8}, //mc20 Powheg+P8 ttbb - ATLMCPROD-9179, ATLMCPROD-12356
103 {607430, GEN_id::Pythia8}, {603872, 603873, GEN_id::Pythia8}, //mc23 Powheg+P8 ttbb
104 {601226, 601228, GEN_id::Pythia8}, // Powheg+P8 ttbb bornzerodamp cut 5, ATLMCPROD-9694
105 {407342, 407344, GEN_id::Pythia8}, {411391, GEN_id::Pythia8}, //Powheg+P8 ttbar HT-filtered
106 {407345, 407347, GEN_id::Pythia8}, //Powheg+P8 ttbar MET-filtered
107 {407348, 407350, GEN_id::Pythia8}, //aMC@NLO+P8 ttbar HT-filtered
108 {504330, 504332, GEN_id::Pythia8}, {504334, 504336, GEN_id::Pythia8}, {504338, GEN_id::Pythia8}, {504342, 504344, GEN_id::Pythia8}, {504346, GEN_id::Pythia8}, //aMC@NLO+P8 refined ttZ
109 {601491, 601492, GEN_id::Pythia8}, //Pow+Py8 ttbar pTHard variations - ATLMCPROD-10168
110 {601495, 601498, GEN_id::Pythia8}, //Pow+Py8 ttbar pTHard variations - ATLMCPROD-10168
111 {601229, 601230, GEN_id::Pythia8}, // mc23 ttbar dilep, singlelep
112 {601237, GEN_id::Pythia8}, // mc23 ttbar allhad
113 {607431, GEN_id::Pythia8}, {601398, 601399, GEN_id::Pythia8}, // mc23 ttbar dilep, singlelep hdamp517p5
114 {601491, GEN_id::Pythia8}, {601495, GEN_id::Pythia8}, {601497, GEN_id::Pythia8}, // mc23 ttbar pThard variations, dilep, singlelep, allhad
115 {601783, 601784, GEN_id::Pythia8}, // Powheg+P8 ttbb bornzerodamp cut 5 pThard variations - ATLMCPROD-10527
116 {603003, 603004, GEN_id::Pythia8}, // Powheg+P8 ttbb nominal and pthard1 allhad
117 {603190, 603193, GEN_id::Pythia8}, // Powheg+P8 ttbb nominal and pthard1 dilep, ljet
118 {607433, GEN_id::Pythia8}, {604482, 604483, GEN_id::Pythia8}, // mc23 Powheg+P8 ttbar recoilToTop
119 {411369, 411374, GEN_id::Pythia8}, // PP8 ttbar Var1
120 {411290, GEN_id::Pythia8}, // PP8 ttbar rb1p05
121 {508792, GEN_id::Pythia8}, // aMC@NLO+P8 ttbar smeftsim
122 {510203, GEN_id::Pythia8}, // aMC@NLO+P8 4tops
123 {522035, 522038, GEN_id::Pythia8}, // aMC@NLO+P8 ttZqq
124 {523243, GEN_id::Pythia8}, // aMC@NLO+P8 4tops
125 {607429, GEN_id::Pythia8}, {601356, 601357, GEN_id::Pythia8}, // PP8 ttbar Trec
126 {602067, 602072, GEN_id::Pythia8}, // PP8 ttH pthard1/2
127 {602637, GEN_id::Pythia8}, // PP8 ttH PDF4LHC21
128 {602852, 602853, GEN_id::Pythia8}, // PP8 ttH PDF4LHC21 pthard1
129 {602886, 602889, GEN_id::Pythia8}, // PP8 ttW NNPDF23
130 {603851, 603854, GEN_id::Pythia8}, // PP8 ggH
131 {604224, GEN_id::Pythia8}, // PP8 ttH allhad HTop
132 {604225, GEN_id::HerwigPP},// mc23 PhH7 ttH allHad HTop
133 {604226, GEN_id::Pythia8}, // mc23 PhPy8 pThard1 ttH allHad HTop
134
135 // all Sherpa showered samples
136 {410186, 410189, GEN_id::Sherpa}, //Sherpa 2.2.0
137 {410249, 410252, GEN_id::Sherpa}, //Sherpa 2.2.1
138 {410342, 410347, GEN_id::Sherpa}, //Sherpa 2.2.1 sys
139 {410350, 410355, GEN_id::Sherpa}, //Sherpa 2.2.1 sys
140 {410357, 410359, GEN_id::Sherpa}, //Sherpa 2.2.1 sys
141 {410361, 410367, GEN_id::Sherpa}, //Sherpa 2.2.1 sys
142 {410281, 410283, GEN_id::Sherpa}, //Sherpa BFilter
143 {410051, GEN_id::Sherpa}, //Sherpa ttbb (ICHEP sample)
144 {410323, 410325, GEN_id::Sherpa}, {410369, GEN_id::Sherpa}, //New Sherpa 2.2.1 ttbb
145 {364345, 364348, GEN_id::Sherpa}, //Sherpa 2.2.4 (test)
146 {410424, 410427, GEN_id::Sherpa}, //Sherpa 2.2.4
147 {410661, 410664, GEN_id::Sherpa}, //Sherpa 2.2.4 ttbb
148 {421152, 421158, GEN_id::Sherpa}, //Sherpa2.2.8 ttbar
149 {413023, GEN_id::Sherpa}, // sherpa 2.2.1 ttZ
150 {700000, GEN_id::Sherpa}, // Sherpa 2.2.8 ttW
151 {700168, GEN_id::Sherpa}, // Sherpa 2.2.10 ttW
152 {700205, GEN_id::Sherpa}, // Sherpa 2.2.10 ttW EWK
153 {700309, GEN_id::Sherpa}, // Sherpa 2.2.11 ttZ
154 {700051, 700054, GEN_id::Sherpa}, //Sherpa2.2.8 ttbb
155 {700121, 700124, GEN_id::Sherpa}, //Sherpa2.2.10 ttbar
156 {700164, 700167, GEN_id::Sherpa}, //Sherpa2.2.10 ttbb
157 {700807, 700809, GEN_id::Sherpa}, //Sherpa2.2.14 ttbar
158 {700659, 700662, GEN_id::Sherpa}, // Sherpa 2.2.12 ttbar maxHTavrgTopPT
159 {700712, GEN_id::Sherpa}, // Sherpa 2.2.14 4tops muQHT2
160 {700986, 700997, GEN_id::Sherpa}, // Sherpa 2.2.14 ttW
161 {701251, 701259, GEN_id::Sherpa}, // Sherpa ttW
162
163 // everything else from HFDSIDList
164 // and the mc20/mc23 central pages as of Sept 2025
165 {301528, 301532, GEN_id::Pythia6},
166 {301539, GEN_id::Sherpa},
167 {302910, 302924, GEN_id::Sherpa},
168 {303480, 303487, GEN_id::Sherpa},
169 {303722, 303726, GEN_id::Pythia6},
170 {306600, 306617, GEN_id::Sherpa},
171 {307479, 307502, GEN_id::Sherpa},
172 {343362, GEN_id::Pythia6},
173 {343431, 343434, GEN_id::Pythia8},
174 {343637, GEN_id::Pythia6},
175 {343852, 343854, GEN_id::Pythia8},
176 {344171, GEN_id::Pythia6},
177 {345935, GEN_id::Pythia8},
178 {345951, GEN_id::Pythia8},
179 {346031, GEN_id::Pythia8},
180 {407009, 407012, GEN_id::Pythia6},
181 {407029, 407036, GEN_id::Pythia6},
182 {407041, 407048, GEN_id::Pythia8},
183 {407200, 407204, GEN_id::Pythia8},
184 {407320, 407321, GEN_id::Pythia8},
185 {407322, 407323, GEN_id::Pythia6},
186 {407324, 407335, GEN_id::Pythia8},
187 {407351, 407353, GEN_id::Pythia8},
188 {407357, 407359, GEN_id::HerwigPP},
189 {410000, 410002, GEN_id::Pythia6},
190 {410007, GEN_id::Pythia6},
191 {410009, GEN_id::Pythia6},
192 {410021, 410024, GEN_id::Sherpa},
193 {410028, 410029, GEN_id::Pythia8},
194 {410037, 410046, GEN_id::Pythia6},
195 {410052, 410058, GEN_id::Sherpa},
196 {410060, GEN_id::HerwigPP},
197 {410066, 410070, GEN_id::Pythia8},
198 {410073, GEN_id::Pythia8},
199 {410075, GEN_id::Pythia8},
200 {410082, 410084, GEN_id::Pythia8},
201 {410087, 410089, GEN_id::Pythia8},
202 {410111, 410116, GEN_id::Pythia8},
203 {410120, 410121, GEN_id::Pythia6},
204 {410142, 410144, GEN_id::Sherpa},
205 {410156, 410157, GEN_id::Pythia8},
206 {410161, 410162, GEN_id::Pythia6},
207 {410175, 410176, GEN_id::Pythia8},
208 {410178, 410179, GEN_id::Pythia8},
209 {410181, 410182, GEN_id::Pythia8},
210 {410184, 410185, GEN_id::Sherpa},
211 {410190, 410213, GEN_id::Pythia8},
212 {410234, GEN_id::Pythia8},
213 {410248, GEN_id::Pythia8},
214 {410257, 410262, GEN_id::Pythia8},
215 {410284, 410322, GEN_id::Pythia8},
216 {410326, 410339, GEN_id::Sherpa},
217 {410368, GEN_id::Pythia8},
218 {410370, 410394, GEN_id::Pythia8},
219 {410395, 410396, GEN_id::HerwigPP},
220 {410397, 410399, GEN_id::Pythia8},
221 {410404, 410405, GEN_id::Pythia8},
222 {410410, 410413, GEN_id::Pythia8},
223 {410420, 410423, GEN_id::Sherpa},
224 {410428, 410431, GEN_id::Pythia8},
225 {410432, 410433, GEN_id::HerwigPP},
226 {410434, 410435, GEN_id::Pythia8},
227 {410444, 410445, GEN_id::Pythia8},
228 {410446, GEN_id::HerwigPP},
229 {410447, GEN_id::Pythia8},
230 {410467, GEN_id::Pythia8},
231 {410468, GEN_id::HerwigPP},
232 {410469, GEN_id::Pythia8},
233 {410491, 410498, GEN_id::Pythia8},
234 {410509, GEN_id::Pythia8},
235 {410542, GEN_id::Pythia8},
236 {410544, GEN_id::Pythia8},
237 {410545, 410546, GEN_id::HerwigPP},
238 {410555, GEN_id::HerwigPP},
239 {410633, 410637, GEN_id::Pythia8},
240 {410690, 410691, GEN_id::Pythia8},
241 {411000, 411005, GEN_id::Pythia8},
242 {411044, 411059, GEN_id::Pythia8},
243 {411125, 411142, GEN_id::HerwigPP},
244 {411143, 411160, GEN_id::Pythia8},
245 {411168, GEN_id::HerwigPP},
246 {411169, GEN_id::Pythia8},
247 {411235, 411268, GEN_id::Pythia8},
248 {411269, GEN_id::HerwigPP},
249 {411278, GEN_id::Pythia6},
250 {411279, 411281, GEN_id::Pythia8},
251 {411282, GEN_id::HerwigPP},
252 {411286, GEN_id::Pythia8},
253 {411288, 411289, GEN_id::Pythia8},
254 {411292, 411307, GEN_id::Pythia8},
255 {411310, GEN_id::Pythia8},
256 {412008, 412014, GEN_id::Pythia8},
257 {412017, 412025, GEN_id::Pythia8},
258 {412028, 412036, GEN_id::Pythia8},
259 {412039, 412040, GEN_id::Pythia8},
260 {412090, 412092, GEN_id::HerwigPP},
261 {412112, 412114, GEN_id::Pythia8},
262 {412175, GEN_id::HerwigPP},
263 {413005, GEN_id::Sherpa},
264 {413008, GEN_id::Sherpa},
265 {413022, GEN_id::Sherpa},
266 {426072, GEN_id::Pythia6},
267 {426075, 426078, GEN_id::Pythia6},
268 {426082, GEN_id::Pythia6},
269 {426085, 426088, GEN_id::Pythia6},
270 {426090, 426097, GEN_id::Pythia6},
271 {500462, 500463, GEN_id::Pythia8},
272 {500800, GEN_id::Pythia8},
273 {502957, 502958, GEN_id::Pythia8},
274 {504553, GEN_id::HerwigPP},
275 {504554, GEN_id::Pythia8},
276 {504689, GEN_id::HerwigPP},
277 {508772, 508773, GEN_id::Pythia8},
278 {508780, GEN_id::HerwigPP},
279 {508781, GEN_id::Pythia8},
280 {508985, 508986, GEN_id::Pythia8},
281 {510212, 510213, GEN_id::Pythia8},
282 {521379, 521380, GEN_id::Pythia8},
283 {521384, 521385, GEN_id::Pythia8},
284 {522023, 522026, GEN_id::Pythia8},
285 {522027, GEN_id::HerwigPP},
286 {522028, 522030, GEN_id::Pythia8},
287 {522031, GEN_id::HerwigPP},
288 {522032, 522034, GEN_id::Pythia8},
289 {522039, GEN_id::HerwigPP},
290 {522040, 522042, GEN_id::Pythia8},
291 {542859, 542860, GEN_id::Pythia8},
292 {542867, 542868, GEN_id::Pythia8},
293 {545023, 545024, GEN_id::Pythia8},
294 {545025, 545026, GEN_id::HerwigPP},
295 {545790, 545791, GEN_id::Pythia8},
296 {561980, GEN_id::Pythia8},
297 {561982, 561990, GEN_id::Pythia8},
298 {600031, GEN_id::Pythia8},
299 {600638, 600639, GEN_id::Pythia8},
300 {600642, 600643, GEN_id::Pythia8},
301 {600644, 600645, GEN_id::HerwigPP},
302 {600668, GEN_id::HerwigPP},
303 {600787, 600790, GEN_id::HerwigPP},
304 {600793, 600796, GEN_id::Pythia8},
305 {601284, GEN_id::Pythia8},
306 {601403, GEN_id::Pythia8},
307 {601407, GEN_id::Pythia8},
308 {601412, 601413, GEN_id::Pythia8},
309 {601607, GEN_id::HerwigPP},
310 {601656, GEN_id::Pythia8},
311 {601669, 601670, GEN_id::Pythia8},
312 {601672, GEN_id::Pythia8},
313 {601708, GEN_id::Pythia8},
314 {602423, GEN_id::Pythia8},
315 {602636, GEN_id::HerwigPP},
316 {602638, GEN_id::Pythia8},
317 {602646, 602647, GEN_id::Pythia8},
318 {602687, 602688, GEN_id::Pythia8},
319 {602843, 602844, GEN_id::Pythia8},
320 {602850, 602851, GEN_id::Pythia8},
321 {603011, 603013, GEN_id::Pythia8},
322 {603855, 603856, GEN_id::HerwigPP},
323 {603986, 603989, GEN_id::Pythia8},
324 {604008, 604009, GEN_id::HerwigPP},
325 {604018, 604021, GEN_id::Pythia8},
326 {604468, 604481, GEN_id::Pythia8},
327 {700706, GEN_id::Sherpa},
328 {700737, 700756, GEN_id::Sherpa},
329 {700810, GEN_id::Sherpa},
330 {701260, 701262, GEN_id::Sherpa},
331 {701265, 701282, GEN_id::Sherpa},
332 {802380, 802381, GEN_id::Pythia8},
333 {950787, GEN_id::Pythia8},
334 };
335
336 // Linear search for sample and assign properties:
337 for (const auto& s : samples) {
338 if (m_DSID>=s.low && m_DSID<=s.high) {
339 m_GenUsed = s.gen;
340 return StatusCode::SUCCESS;
341 }
342 }
343
344 // the default is Pythia6, so no need to list the Pythia6 showered samples
345 // these are:
346 // 410000-410002
347 // 410007, 410009, 410120-410121
348 // 301528-301532
349 // 303722-303726
350 // 407009-407012
351 // 407029-407036
352 // 410120
353 // 426090-426097
354 // 429007
356
357 return StatusCode::SUCCESS;
358 }
359
360 /*
361 --------------------------------------------------------------------------------------------------------------------------------------
362 ------------------------------------------------------------- Hadron Map -------------------------------------------------------------
363 --------------------------------------------------------------------------------------------------------------------------------------
364 */
365
366 // Define the function GetOriginMap that determines the origin of the hadrons.
367 std::map<const xAOD::TruthParticle*, DerivationFramework::HadronOriginClassifier::HF_id> HadronOriginClassifier::GetOriginMap(const EventContext& ctx) const {
368 // Create a set of maps to store the information about the hadrons and the partons
369 std::map<const xAOD::TruthParticle*, int> mainHadronMap; // Map with main hadrons and their flavor.
370 std::map<const xAOD::TruthParticle*, HF_id> partonsOrigin; // Map with partons and their category (from top, W, H, MPI, FSR, extra).
371 std::map<const xAOD::TruthParticle*, const xAOD::TruthParticle*> hadronsPartons; // Map with hadrons and their matched parton.
372 std::map<const xAOD::TruthParticle*, HF_id> hadronsOrigin; // Map with hadrons and their category (from top, W, H, MPI, FSR, extra)
373 // Fill the maps mainHadronMap and partonsOrigin
374 buildPartonsHadronsMaps(ctx, mainHadronMap, partonsOrigin);
375 // Create two maps to know which partons and hadrons have already been matched.
376 std::vector<const xAOD::TruthParticle*> matched_partons;
377 std::vector<const xAOD::TruthParticle*> matched_hadrons;
378 // Use a while to go through the HF hadrons in mainHadronMap and partons in partonsOrigin.
379 while (matched_partons.size()<partonsOrigin.size() && matched_hadrons.size()<mainHadronMap.size()){
380 // Create a float variable to store the DeltaR between a parton and the closest hadron.
381 float dR=999.;
382 // Create two pointers for TruthParticle type to go through the partons and hadrons.
383 const xAOD::TruthParticle* hadron=nullptr;
384 const xAOD::TruthParticle* parton=nullptr;
385 // Use a for to go through the partonsOrigin.
386 for(std::map<const xAOD::TruthParticle*, HF_id>::iterator itr = partonsOrigin.begin(); itr!=partonsOrigin.end(); ++itr){
387 // Check if the parton has already been matched to an hadron.
388 if(std::find(matched_partons.begin(), matched_partons.end(), (*itr).first) != matched_partons.end()) continue;
389 // Extract the pt of the parton.
390 TVector3 v, vtmp;
391 if ((*itr).first->pt()>0.)
392 v.SetPtEtaPhi((*itr).first->pt(),(*itr).first->eta(),(*itr).first->phi());
393 else // Protection against FPE from eta and phi calculation
394 v.SetXYZ(0.,0.,(*itr).first->pz());
395 // Use a for to go through the HF hadrons in mainHadronMap.
396 for(std::map<const xAOD::TruthParticle*, int>::iterator it = mainHadronMap.begin(); it!=mainHadronMap.end(); ++it){
397 // Check if the hadron has already been matched to a parton.
398 if(std::find(matched_hadrons.begin(), matched_hadrons.end(), (*it).first) != matched_hadrons.end()) continue;
399 // Check if the hadron's flavour matches the one of the parton.
400 if((*it).second != (*itr).first->absPdgId()) continue;
401 // Extract the pt of the hadron.
402 vtmp.SetPtEtaPhi((*it).first->pt(),(*it).first->eta(),(*it).first->phi());
403 // Compute Delta R between hadron and parton and store in dR if it is smaller than the current value.
404 // Also store the parton and hadron in the pointers that have been previous created.
405 if(vtmp.DeltaR(v) < dR){
406 dR = vtmp.DeltaR(v);
407 hadron = (*it).first;
408 parton = (*itr).first;
409 }
410 }//loop hadrons
411 }//loop partons
412 // Add the matched part-hadron pair in the corresponding maps.
413 matched_partons.push_back(parton);
414 matched_hadrons.push_back(hadron);
415 hadronsPartons[ hadron ] = parton;
416 }
417
418 // Use a for to go through the HF hadrons in mainHadronMap.
419 for(std::map<const xAOD::TruthParticle*, int>::iterator it = mainHadronMap.begin(); it!=mainHadronMap.end(); ++it){
420 // Extract the current hadron.
421 const xAOD::TruthParticle* hadron = (*it).first;
422 // Check if the hadron has been matched to a parton.
423 // If it has been matched to any hadron, use it to determine the origin.
424 // Otherwise, the hadron is considered extra.
425 if(hadronsPartons.find(hadron)!=hadronsPartons.end()){
426 hadronsOrigin[hadron] = partonsOrigin[ hadronsPartons[hadron] ];
427 } else{
428 hadronsOrigin[hadron] = extrajet;
429 }
430 }
431 return hadronsOrigin;
432 }
433
434 // Define the function buildPartonsHadronsMaps that determines the flavour of the hadrons and the origin of the partons.
435 void HadronOriginClassifier::buildPartonsHadronsMaps(const EventContext& ctx, std::map<const xAOD::TruthParticle*,int>& mainHadronMap, std::map<const xAOD::TruthParticle*,HF_id>& partonsOrigin) const {
436 // Extract the TruthParticles container.
437 SG::ReadHandle<xAOD::TruthEventContainer> xTruthEventContainer(m_mcName, ctx);
438 if (!xTruthEventContainer.isValid()) {
439 ATH_MSG_WARNING("Could not retrieve " <<m_mcName);
440 }
441
442 // Create a container with TruthParticles to store the hadrons that has already been saved.
443 std::set<const xAOD::TruthParticle*> usedHadron;
444 for ( const auto* truthevent : *xTruthEventContainer ) {
445 // Use a for to go through the TruthParticles.
446 for(unsigned int i = 0; i < truthevent->nTruthParticles(); i++){
447 // Extract the i-th particle.
448 const xAOD::TruthParticle* part = truthevent->truthParticle(i);
449 if(!part) continue;
450 // Simulated particles are not considered.
451 if(HepMC::is_simulation_particle(part)) break;
452 // Create a set of boolean variables to indicate the type of particle.
453 bool isbquark = false; // The particle is a b-quark.
454 bool iscquark = false; // The particle is a c-quark.
455 bool isHFhadron = false; // The particle is a HF hadron.
456 // Extract the pdgid of the particle and use it to determine the type of particle.
457 int pdgid = part->absPdgId();
458 if( MC::isBottom(pdgid) ){
459 isbquark=true;
460 }
461 else if( MC::isCharm(pdgid) ){
462 iscquark=true;
463 }
464 else if(MC::isBottomHadron(part) || MC::isCharmHadron(part)){
465 isHFhadron=true;
466 }
467 else{
468 continue;
469 }
470 // For HF quarks (b or c), check their category.
471 // The category is determined looking for the parents.
472 if(isbquark){
473 // In this case, the parton is a b-quark.
474 // Check the category of the b-quark.
475 if(isDirectlyFromWTop(part)){
476 partonsOrigin[ part ] = b_from_W;
477 }
478 else if(isDirectlyFromTop(part)){
479 partonsOrigin[ part ] = b_from_top;
480 }
481 else if((IsHerwigPP()||IsSherpa())&&isDirectlyFSR(part)){
482 partonsOrigin[ part ] = b_FSR;
483 }
484 else if(IsPythia8()&&isDirectlyFSRPythia8(part)){
485 partonsOrigin[ part ] = b_FSR;
486 }
487 else if(IsPythia6()&&isDirectlyFSRPythia6(part)){
488 partonsOrigin[ part ] = b_FSR;
489 }
490 else if(IsPythia6()&&isDirectlyMPIPythia6(part)){
491 partonsOrigin[ part ] = b_MPI;
492 }
493 else if(IsPythia8()&&isDirectlyMPIPythia8(part)){
494 partonsOrigin[ part ] = b_MPI;
495 }
496 else if(IsSherpa()&&isDirectlyMPISherpa(part)){
497 partonsOrigin[ part ] = b_MPI;
498 }
499 }
500 if(iscquark){
501 // In this case, the parton is a c-quark.
502 // Check the category of the b-quark.
503 if(isDirectlyFromWTop(part)){
504 partonsOrigin[ part ] = c_from_W;
505 }
506 else if(isDirectlyFromTop(part)){
507 partonsOrigin[ part ] = c_from_top;
508 }
509 else if((IsHerwigPP()||IsSherpa())&&isDirectlyFSR(part)){
510 partonsOrigin[ part ] = c_FSR;
511 }
512 else if(IsPythia8()&&isDirectlyFSRPythia8(part)){
513 partonsOrigin[ part ] = c_FSR;
514 }
515 else if(IsPythia6()&&isDirectlyFSRPythia6(part)){
516 partonsOrigin[ part ] = c_FSR;
517 }
518 else if(IsPythia6()&&isDirectlyMPIPythia6(part)){
519 partonsOrigin[ part ] = c_MPI;
520 }
521 else if(IsPythia8()&&isDirectlyMPIPythia8(part)){
522 partonsOrigin[ part ] = c_MPI;
523 }
524 else if(IsSherpa()&&isDirectlyMPISherpa(part)){
525 partonsOrigin[ part ] = c_MPI;
526 }
527 }
528 // The HF hadrons are stored in the map mainHadronMap if they are not repeated.
529 if(isHFhadron && !isCHadronFromB(part)){
530 // In this case, the particle is a HF hadron but not a C-Hadron from a B-hadron.
531 // If the hadron is not in usedHadron, then add it in mainHadronMap with fillHadronMap function.
532 if(usedHadron.insert(part).second) {
533 fillHadronMap(usedHadron, mainHadronMap,part,part);
534 }
535 }
536 }//loop on particles
537 }//loop on truthevent container
538 }
539
540 /*
541 ---------------------------------------------------------------------------------------------------------------------------------------
542 ------------------------------------------------------------ Particle Type ------------------------------------------------------------
543 ---------------------------------------------------------------------------------------------------------------------------------------
544 */
545 bool HadronOriginClassifier::isCHadronFromB(const xAOD::TruthParticle* part, std::shared_ptr<std::set<const xAOD::TruthParticle*>> checked ) const{
546 if(!MC::isCharmHadron(part)) return false;
547 if (!checked) checked = std::make_shared<std::set<const xAOD::TruthParticle*>>();
548 checked ->insert(part);
549
550 for(unsigned int i=0; i<part->nParents(); ++i){
551 const xAOD::TruthParticle* parent = part->parent(i);
552 if(!parent) continue;
553 if(checked->count(parent)) continue;
554 checked->insert(parent);
555 if( MC::isBottomHadron(parent) ){
556 return true;
557 }
558 if(MC::isCharmHadron(parent)){
559 if(isCHadronFromB(parent))return true;
560 }
561 }
562
563 return false;
564 }
565
566 // Define the function fillHadronMap that fills the map of hadrons with their flavour.
567 void HadronOriginClassifier::fillHadronMap(std::set<const xAOD::TruthParticle*>& usedHadron, std::map<const xAOD::TruthParticle*,int>& mainHadronMap, const xAOD::TruthParticle* mainhad, const xAOD::TruthParticle* ihad, bool decayed) const {
568 // Fist, check that the consdired hadron has a non-null pointer
569 if (!ihad) return;
570 usedHadron.insert(ihad);
571 // Create two variables to indicate the flavour of the parents and childrens particles that will be considered.
572 // Create a boolean to indicate if the particles considered are from the final state.
573 int parent_flav,child_flav;
574 bool isFinal = true;
575 // Check if the considered hadron has children.
576 if(!ihad->nChildren()) return;
577 // Use a for to go through the children.
578 for(unsigned int j=0; j<ihad->nChildren(); ++j){
579 // Extract the j-th children.
580 const xAOD::TruthParticle* child = ihad->child(j);
581 if(!child) continue;
582 if(decayed){
583 fillHadronMap(usedHadron, mainHadronMap,mainhad,child,true);
584 isFinal=false;
585 }
586 else{
587 child_flav = std::abs(MC::leadingQuark(child));
588 if(child_flav!=4 && child_flav!=5) continue;
589 parent_flav = std::abs(MC::leadingQuark(mainhad));
590 if(child_flav!=parent_flav) continue;
591 fillHadronMap(usedHadron, mainHadronMap,mainhad,child);
592 isFinal=false;
593 }
594 }
595
596 if(isFinal && !decayed){
597 mainHadronMap[mainhad]=std::abs(MC::leadingQuark(mainhad));
598 for(unsigned int j=0; j<ihad->nChildren(); ++j){
599 const xAOD::TruthParticle* child = ihad->child(j);
600 if(!child) continue;
601 fillHadronMap(usedHadron, mainHadronMap,mainhad,child,true);
602 }
603 }
604 }
605
606 /*
607 ---------------------------------------------------------------------------------------------------------------------------------------
608 ----------------------------------------------------------- Particle Origin -----------------------------------------------------------
609 ---------------------------------------------------------------------------------------------------------------------------------------
610 */
611
612 // Define the function isFromTop that indicates if a particle comes from top.
613
615 // Find the first parent of the considered particle that is different from the particle.
616 const xAOD::TruthParticle* initpart = findInitial(part);
617 // Check if this parent comes from the top with function isDirectlyFromTop.
618 return isDirectlyFromTop(initpart);
619 }
620
621 // Define the function isDirectlyFromTop that indicates if a particle comes from the direct decay of top.
623 // First, make sure the consdired particle has a non-null pointer and it has parents.
624 // Otherwise, return false.
625 if(!part || !part->nParents()) return false;
626 // Go through the parents of the particle.
627 for(unsigned int i=0; i<part->nParents(); ++i){
628 // Extract the i-th parent.
629 const xAOD::TruthParticle* parent = part->parent(i);
630 if(!parent) continue;
631 // If the i-th parent is a top, then return true
632 if( MC::isTop(parent) ) return true;
633 }
634 // If a top is no the parent, then return false.
635 return false;
636 }
637
638 // Define the function isFromWTop that indicates if a particle comes from the decay chain t->Wb.
639
641 // Find the first parent of the considered particle that is different from the particle.
642 const xAOD::TruthParticle* initpart = findInitial(part);
643 return isDirectlyFromWTop(initpart);
644 }
645
646 // Define the function isDirectlyFromWTop that indicates if a particle comes from the direct decay of a W from a top.
648 // First, make sure the consdired particle has a non-null pointer and it has parents.
649 // Otherwise, return false.
650 if(!part || !part->nParents()) return false;
651 // Use a for to go though the parents.
652 for(unsigned int i=0; i<part->nParents(); ++i){
653 // Get the i-th parent.
654 const xAOD::TruthParticle* parent = part->parent(i);
655 if(!parent) continue;
656 if( MC::isW(parent)){
657 if( isFromTop(parent) ) return true;
658 }
659 }
660 // In this case, none of the parents of the particle is a W from top.
661 // Hence, return false.
662 return false;
663 }
664
666 if(!part->nParents()) return false;
667 for(unsigned int i=0; i<part->nParents(); ++i){
668 const xAOD::TruthParticle* parent = part->parent(i);
669 if(!parent) continue;
670 if( MC::isPhoton(parent) || parent->absPdgId()<MC::BQUARK ) return true;
671 }
672 return false;
673 }
674
676 const xAOD::TruthParticle* initpart = findInitial(part);
677 return isDirectlyFromGluonQuark(initpart);
678 }
679
681 if(!part->nParents()) return false;
682 for(unsigned int i=0; i<part->nParents(); ++i){
683 const xAOD::TruthParticle* parent = part->parent(i);
684 if(!parent) continue;
685 if(!MC::isW(parent)) continue;
686 if(MC::isCharm(part)){
687 //trick to get at least 50% of PowhegPythia c from FSR
688 if(part->pdgId()==-(parent->pdgId())/6){
689 if( isFromGluonQuark(parent) ) return true;
690 }
691 }
692 else{
693 if( isFromGluonQuark(parent) ) return true;
694 }
695 }
696 return false;
697 }
698
700 if(!part->nParents()) return false;
701 for(unsigned int i=0; i<part->nParents(); ++i){
702 const xAOD::TruthParticle* parent = part->parent(i);
703 if(!parent) continue;
704 if( MC::isPhoton(parent) || MC::isGluon(parent) ){
705 if( isFromQuarkTop( parent ) ) return true;
706 }
707 }
708 return false;
709 }
710
712 if(!part->nParents()) return false;
713 for(unsigned int i=0; i<part->nParents(); ++i){
714 const xAOD::TruthParticle* parent = part->parent(i);
715 if(!parent) continue;
716 if( parent->absPdgId()<MC::TQUARK ) {
717 if(isFromTop(parent)){
718 return true;
719 }
720 else if(isFromWTop(parent)){
721 return true;
722 }
723 }
724 }
725
726 return false;
727 }
728
730 const xAOD::TruthParticle* initpart = findInitial(part);
731 return isDirectlyFromQuarkTop(initpart);
732 }
733
734 // Define the function isDirectlyFSRPythia8 that indicates if a particle comes from Final State Radiation in samples generated with Pythia8.
735
737 // First, check if the particle has parents and return false if it does not.
738 if(!part->nParents()) return false;
739 // Use a for to go through the parents.
740 for(unsigned int i=0; i<part->nParents(); ++i){
741
742 // Extract the i-th parent.
743
744 const xAOD::TruthParticle* parent = part->parent(i);
745 if(!parent) continue;
746 if( MC::isPhoton(parent) || MC::isGluon(parent) ){
747 if( isFromQuarkTopPythia8( parent ) ) return true;
748 }
749 }
750 // In this case, no parent from the particle is a gluon or a photon coming from a top
751 // Hence, the particle is not from FSR and false is not returned.
752 return false;
753 }
754
755 // Define the function isDirectlyFromQuarkTopPythia8 that indicates if a particle comes from direct decay of the top in samples generated with Pythia8.
757 // First, make sure the consdired particle has a non-null pointer and it has parents.
758 // Otherwise, return false.
759 if(!part->nParents()) return false;
760 // Use a for to go through the parents.
761 for(unsigned int i=0; i<part->nParents(); ++i){
762 // Extract the i-th parent.
763 const xAOD::TruthParticle* parent = part->parent(i);
764 if(!parent) continue;
765 // Check if the parent is a quark different from the top.
766 if( parent->absPdgId()<MC::TQUARK ) {
767 // In this case, the parent is a quark different from top.
768 // Check if it comes from the decay chain of the t->Wb.
769 // If it is the case, return true.
770 if(isFromWTop(parent)){
771 return true;
772 }
773 }
774 }
775 // In this case, any of the parents of the particle comes from t->Wb chaing.
776 // Hence, the particle does not come from the top directly and false is returned.
777 return false;
778 }
779
780 // Define the function isFromQuarkTopPythia8 that indicates if a particle comes from top in samples generated with Pythia8.
782 // Find the first parent of the considered particle that is different from the particle.
783 const xAOD::TruthParticle* initpart = findInitial(part);
784 // Check if this parent comes from the top with function isDirectlyFromQuarkTopPythia8.
785 return isDirectlyFromQuarkTopPythia8(initpart);
786 }
787
789 if(!part->nParents()) return false;
790 for(unsigned int i=0; i<part->nParents(); ++i){
791 const xAOD::TruthParticle* parent = part->parent(i);
792 if(!parent) continue;
793 if( parent->absPdgId() == MC::PROTON && MC::isPhysical(part) ) return true;
794 }
795 return false;
796 }
797
799 const xAOD::TruthParticle* initpart = findInitial(part);
800 return MC::Pythia8::isConditionC(initpart);
801 }
802
804 if(!part->hasProdVtx()) return false;
805 const xAOD::TruthVertex* vertex = part->prodVtx();
806 return HepMC::status(vertex) == 2;
807 }
808
809 /*
810 --------------------------------------------------------------------------------------------------------------------------------------
811 ---------------------------------------------------------- Particle Parents ----------------------------------------------------------
812 --------------------------------------------------------------------------------------------------------------------------------------
813 */
814
815 // Define the function findInitial which finds the first parent of a particle that is not the particle itself.
816 const xAOD::TruthParticle* HadronOriginClassifier::findInitial(const xAOD::TruthParticle* part, std::shared_ptr<std::set<const xAOD::TruthParticle*>> checked ) const{
817 // If the particle has no parent, return the particle.
818 if(!part->nParents()) return part;
819 if (!checked) checked = std::make_shared<std::set<const xAOD::TruthParticle*>>();
820 // Use a for to go through the parents.
821 for(unsigned int i=0; i<part->nParents(); ++i){
822 // Extract the i-th parent.
823 const xAOD::TruthParticle* parent = part->parent(i);
824 if(!parent) continue;
825 if(checked->count(parent)) continue;
826 checked->insert(parent);
827 // If the parent has the same pdgId as the particle, then it means that the parent is the same as the considered particle.
828 // This happens if the particle irradiates for example.
829 // In this case, try to look for the first parent of i-th parent that is being considered.
830 // Repeat the process until you find a particle different from the considred one or that has no parent.
831
832 if( part->pdgId() == parent->pdgId() ){
833 return findInitial(parent, std::move(checked));
834 }
835 }
836 // In this case, no parent different from the considered particle has been found.
837 // Hence, return the particle.
838 return part;
839 }
840
841}//namespace
#define ATH_CHECK
Evaluate an expression and check for errors.
#define ATH_MSG_WARNING(x,...)
#define ATH_MSG_INFO(x,...)
ATLAS-specific HepMC functions.
Handle class for reading from StoreGate.
AthAlgTool(const std::string &type, const std::string &name, const IInterface *parent)
Constructor with parameters:
void buildPartonsHadronsMaps(const EventContext &ctx, std::map< const xAOD::TruthParticle *, int > &mainHadronMap, std::map< const xAOD::TruthParticle *, HF_id > &partonsOrigin) const
static bool isDirectlyMPIPythia6(const xAOD::TruthParticle *part)
bool isDirectlyFromQuarkTop(const xAOD::TruthParticle *part) const
static bool isDirectlyFromTop(const xAOD::TruthParticle *part)
HadronOriginClassifier(const std::string &t, const std::string &n, const IInterface *p)
bool isFromGluonQuark(const xAOD::TruthParticle *part) const
bool isCHadronFromB(const xAOD::TruthParticle *part, std::shared_ptr< std::set< const xAOD::TruthParticle * > > checked=nullptr) const
bool isFromQuarkTop(const xAOD::TruthParticle *part) const
const xAOD::TruthParticle * findInitial(const xAOD::TruthParticle *part, std::shared_ptr< std::set< const xAOD::TruthParticle * > > checked=nullptr) const
bool isDirectlyMPIPythia8(const xAOD::TruthParticle *part) const
bool isFromTop(const xAOD::TruthParticle *part) const
bool isDirectlyFSRPythia8(const xAOD::TruthParticle *part) const
static bool isDirectlyFromGluonQuark(const xAOD::TruthParticle *part)
bool isFromQuarkTopPythia8(const xAOD::TruthParticle *part) const
std::map< const xAOD::TruthParticle *, HF_id > GetOriginMap(const EventContext &ctx) const
bool isDirectlyFromWTop(const xAOD::TruthParticle *part) const
SG::ReadHandleKey< xAOD::TruthParticleContainer > m_truthParticlesKey
bool isDirectlyFSR(const xAOD::TruthParticle *part) const
SG::ReadHandleKey< xAOD::TruthEventContainer > m_mcName
bool isDirectlyFSRPythia6(const xAOD::TruthParticle *part) const
SG::ReadHandleKey< xAOD::TruthVertexContainer > m_truthVerticesKey
bool isFromWTop(const xAOD::TruthParticle *part) const
void fillHadronMap(std::set< const xAOD::TruthParticle * > &usedHadron, std::map< const xAOD::TruthParticle *, int > &mainHadronMap, const xAOD::TruthParticle *mainhad, const xAOD::TruthParticle *ihad, bool decayed=false) const
bool isDirectlyFromQuarkTopPythia8(const xAOD::TruthParticle *part) const
static bool isDirectlyMPISherpa(const xAOD::TruthParticle *part)
virtual bool isValid() override final
Can the handle be successfully dereferenced?
const TruthParticle_v1 * child(size_t i) const
Retrieve the i-th mother (TruthParticle) of this TruthParticle.
size_t nChildren() const
Number of children of this particle.
THE reconstruction tool.
int status(const T &p)
bool is_simulation_particle(const T &p)
Method to establish if a particle was created during the simulation (based on the status value).
bool isConditionC(const T &p)
Match positive statuses 31-39, the Pythia range for subsequent-subprocess particles: 31: incoming par...
bool isCharmHadron(const T &p)
bool isCharm(const T &p)
bool isBottom(const T &p)
bool isPhoton(const T &p)
bool isW(const T &p)
static const int TQUARK
bool isBottomHadron(const T &p)
int leadingQuark(const T &p)
bool isTop(const T &p)
static const int BQUARK
bool isGluon(const T &p)
static const int PROTON
bool isPhysical(const T &p)
Identify if the particle is physical, i.e. is stable or decayed.
TruthVertex_v1 TruthVertex
Typedef to implementation.
Definition TruthVertex.h:15
TruthParticle_v1 TruthParticle
Typedef to implementation.