ATLAS Offline Software
Toggle main menu visibility
Loading...
Searching...
No Matches
PhysicsAnalysis
Algorithms
TruthPartonLevelAnalysisAlgorithms
python
PartonHistoryConfig.py
Go to the documentation of this file.
1
# Copyright (C) 2002-2026 CERN for the benefit of the ATLAS collaboration
2
3
from
AnalysisAlgorithmsConfig.ConfigBlock
import
ConfigBlock
4
5
6
# ---------------------------------------------------------------------------
7
# Helpers
8
# ---------------------------------------------------------------------------
9
10
KINEMATIC_VARS = (
"pt"
,
"eta"
,
"phi"
,
"m"
)
11
INT_SUFFIXES = frozenset((
"pdgId"
,
"IsOnShell"
,
"origin"
))
12
VECTOR_PREFIXES = (
"MC_b_"
,
"MC_bbar_"
,
"MC_c_"
,
"MC_cbar_"
)
13
VECTOR_HISTORIES = frozenset((
"Ttbarbbbar"
,
"Ttbarccbar"
))
14
15
def
_get_aux_type
(branch: str, prefix: str) -> str:
16
# Handle specific cases where vectors are returned for each particle type
17
# In those cases, only external particles can be vectors, there is still
18
# a single particle allowed in named positions within decay chains
19
is_vector = prefix
in
VECTOR_HISTORIES
and
branch.startswith(VECTOR_PREFIXES)
and
"_from_"
not
in
branch
20
21
if
is_vector:
22
return
"vector_int"
if
any(branch.endswith(s)
for
s
in
INT_SUFFIXES)
else
"vector_float"
23
else
:
24
return
"int"
if
any(branch.endswith(s)
for
s
in
INT_SUFFIXES)
else
"float"
25
26
def
_make_particle_branches
(
27
prefix: str,
28
*,
29
include_pdgid: bool =
True
,
30
stages: tuple =
None
,
31
extra: tuple = (),
32
) -> list:
33
"""Generate standard kinematic branch names for a particle.
34
35
Parameters
36
----------
37
prefix:
38
Particle label as it appears in the branch name, e.g. ``"t"`` ->
39
``MC_t_beforeFSR_pt``. When the prefix already encodes the FSR stage
40
(e.g. ``"W_beforeFSR_from_t"``), pass ``stages=()``.
41
include_pdgid:
42
Append ``pdgId`` after the kinematic variables for each stage.
43
stages:
44
FSR stage tokens to iterate over. Defaults to
45
``("beforeFSR", "afterFSR")``. Pass ``()`` when the FSR stage is
46
already embedded in prefix — branches become ``MC_{prefix}_{var}``.
47
extra:
48
Additional branch suffixes appended verbatim, e.g. ``("IsOnShell",)``.
49
"""
50
if
stages
is
None
:
51
stages = (
"beforeFSR"
,
"afterFSR"
)
52
result = []
53
if
stages:
54
for
stage
in
stages:
55
for
var
in
KINEMATIC_VARS:
56
result.append(f
"MC_{prefix}_{stage}_{var}"
)
57
if
include_pdgid:
58
result.append(f
"MC_{prefix}_{stage}_pdgId"
)
59
else
:
60
for
var
in
KINEMATIC_VARS:
61
result.append(f
"MC_{prefix}_{var}"
)
62
if
include_pdgid:
63
result.append(f
"MC_{prefix}_pdgId"
)
64
for
suffix
in
extra:
65
result.append(f
"MC_{prefix}_{suffix}"
)
66
return
result
67
68
69
def
_replace_in_list
(string_list: list[str], old: str, new: str) -> list[str]:
70
return
[item.replace(old, new)
for
item
in
string_list]
71
72
73
# ---------------------------------------------------------------------------
74
# Per-particle branch lists
75
# ---------------------------------------------------------------------------
76
77
78
def
_t_branches
(suffix: str =
"t"
) -> list:
79
"""Branches for a top quark and its full decay chain.
80
81
Sub-particles carry the FSR stage in their prefix so we pass ``stages=()``
82
to avoid appending a spurious stage token to the variable name.
83
For tbar, the b-quark is named 'bbar'.
84
"""
85
b_name =
"bbar"
if
suffix ==
"tbar"
else
"b"
86
sub_particles = (
"W"
, b_name,
"Wdecay1"
,
"Wdecay2"
)
87
result =
_make_particle_branches
(suffix)
88
for
particle
in
sub_particles:
89
for
stage
in
(
"beforeFSR"
,
"afterFSR"
):
90
result +=
_make_particle_branches
(
91
f
"{particle}_{stage}_from_{suffix}"
, stages=()
92
)
93
return
result
94
95
def
_t_FCNC_branches
(suffix: str =
"t"
) -> list:
96
"""Branches for a top quark undergoing FCNC decay t -> q X, X -> decay1 decay2.
97
98
Sub-particles carry the FSR stage in their prefix so we pass ``stages=()``
99
to avoid appending a spurious stage token to the variable name.
100
For tbar, the q-quark is named 'qbar'.
101
"""
102
q_name =
"qbar"
if
suffix ==
"tbar"
else
"q"
103
sub_particles = (
"X"
, q_name,
"Xdecay1"
,
"Xdecay2"
)
104
result =
_make_particle_branches
(suffix)
105
for
particle
in
sub_particles:
106
for
stage
in
(
"beforeFSR"
,
"afterFSR"
):
107
result +=
_make_particle_branches
(
108
f
"{particle}_{stage}_from_{suffix}"
, stages=()
109
)
110
return
result
111
112
BRANCHES: dict[str, list[str]] = {
113
"t"
:
_t_branches
(
"t"
),
114
"tbar"
:
_t_branches
(
"tbar"
),
115
"t_FCNC"
:
_t_FCNC_branches
(
"t"
),
116
"tbar_FCNC"
:
_t_FCNC_branches
(
"tbar"
),
117
"ttbar"
: (
118
_make_particle_branches
(
"ttbar"
, include_pdgid=
False
)
119
+
_make_particle_branches
(
"ttbar_fromDecay"
, include_pdgid=
False
)
120
),
121
"b"
:
_make_particle_branches
(
"b"
),
122
"bbar"
:
_make_particle_branches
(
"bbar"
),
123
"c"
:
_make_particle_branches
(
"c"
),
124
"cbar"
:
_make_particle_branches
(
"cbar"
),
125
"Z"
: (
126
_make_particle_branches
(
"Z"
, extra=(
"IsOnShell"
,))
127
+
_make_particle_branches
(
"Zdecay1"
)
128
+
_make_particle_branches
(
"Zdecay2"
)
129
),
130
"Z_extended"
: (
131
_make_particle_branches
(
"Z"
, extra=(
"IsOnShell"
,))
132
+
_make_particle_branches
(
"Zdecay1"
)
133
+
_make_particle_branches
(
"Zdecay1_decay1"
)
134
+
_make_particle_branches
(
"Zdecay1_decay2"
)
135
+
_make_particle_branches
(
"Zdecay1_decay3"
)
136
+
_make_particle_branches
(
"Zdecay2"
)
137
+
_make_particle_branches
(
"Zdecay2_decay1"
)
138
+
_make_particle_branches
(
"Zdecay2_decay2"
)
139
+
_make_particle_branches
(
"Zdecay2_decay3"
)
140
),
141
"W"
: (
142
_make_particle_branches
(
"W"
, extra=(
"IsOnShell"
,))
143
+
_make_particle_branches
(
"Wdecay1"
)
144
+
_make_particle_branches
(
"Wdecay2"
)
145
),
146
"Photon"
: [
147
"MC_gamma_m"
,
148
"MC_gamma_pt"
,
149
"MC_gamma_eta"
,
150
"MC_gamma_phi"
,
151
"MC_gamma_origin"
,
152
"MC_gamma_pdgId"
,
153
],
154
"Higgs"
: (
155
_make_particle_branches
(
"H"
)
156
+
_make_particle_branches
(
"Hdecay1"
)
157
+
_make_particle_branches
(
"Hdecay2"
)
158
+
_make_particle_branches
(
"Hdecay1_decay1"
)
159
+
_make_particle_branches
(
"Hdecay1_decay2"
)
160
+
_make_particle_branches
(
"Hdecay2_decay1"
)
161
+
_make_particle_branches
(
"Hdecay2_decay2"
)
162
),
163
}
164
165
_TTBAR = BRANCHES[
"t"
] + BRANCHES[
"tbar"
] + BRANCHES[
"ttbar"
]
166
167
TRUTH_BRANCHES: dict[str, list[str]] = {
168
"Ttbar"
: _TTBAR,
169
"TtbarFCNC"
: BRANCHES[
"t_FCNC"
] + BRANCHES[
"tbar_FCNC"
] + BRANCHES[
"ttbar"
],
170
"Ttbarbbbar"
: _TTBAR + BRANCHES[
"b"
] + BRANCHES[
"bbar"
],
171
"Ttbarccbar"
: _TTBAR + BRANCHES[
"c"
] + BRANCHES[
"cbar"
],
172
"Ttz"
: _TTBAR + BRANCHES[
"Z"
],
173
"Ttw"
: _TTBAR + BRANCHES[
"W"
],
174
"Tth"
: _TTBAR + BRANCHES[
"Higgs"
],
175
"Ttgamma"
: _TTBAR + BRANCHES[
"Photon"
],
176
"Tzq"
: BRANCHES[
"t"
] + BRANCHES[
"Z"
] + BRANCHES[
"b"
],
177
"Thq"
: BRANCHES[
"t"
] + BRANCHES[
"Higgs"
] + BRANCHES[
"b"
] + BRANCHES[
"W"
],
178
"Tqgamma"
: BRANCHES[
"t"
] + BRANCHES[
"Photon"
] + BRANCHES[
"b"
],
179
"Wtb"
: BRANCHES[
"t"
] + BRANCHES[
"W"
] + BRANCHES[
"b"
],
180
"FourTop"
: (
181
_replace_in_list
(BRANCHES[
"t"
],
"t_"
,
"t1_"
)
182
+
_replace_in_list
(BRANCHES[
"t"
],
"t_"
,
"t2_"
)
183
+
_replace_in_list
(BRANCHES[
"tbar"
],
"tbar_"
,
"tbar1_"
)
184
+
_replace_in_list
(BRANCHES[
"tbar"
],
"tbar_"
,
"tbar2_"
)
185
),
186
"HWW"
: BRANCHES[
"Higgs"
],
187
"WW_nonresonant"
: (
188
_replace_in_list
(BRANCHES[
"W"
],
"W"
,
"W1"
)
189
+
_replace_in_list
(BRANCHES[
"W"
],
"W"
,
"W2"
)
190
),
191
"HWW_nonresonant"
: BRANCHES[
"Higgs"
],
192
"HZZ"
: BRANCHES[
"Higgs"
],
193
"Zb"
: BRANCHES[
"Z"
] + BRANCHES[
"b"
] + BRANCHES[
"bbar"
],
194
"Ztautau"
: BRANCHES[
"Z_extended"
],
195
}
196
197
# ---------------------------------------------------------------------------
198
# Config block
199
# ---------------------------------------------------------------------------
200
201
202
class
PartonHistoryBlock
(ConfigBlock):
203
"""ConfigBlock for truth/parton-level resonant histories."""
204
205
def
__init__
(self):
206
super().
__init__
()
207
self.addOption(
208
"history"
,
209
None
,
210
type=str,
211
required=
True
,
212
info=
"parton-level interpretation of the MC truth record. Possible values:"
213
+
", "
.join(sorted(TRUTH_BRANCHES))
214
+
"."
,
215
)
216
# Always skip on data
217
self.setOptionValue(
"skipOnData"
,
True
)
218
219
def
makeAlgs
(self, config):
220
if
self.history
not
in
TRUTH_BRANCHES:
221
valid =
", "
.join(sorted(TRUTH_BRANCHES))
222
raise
ValueError(
223
f
"Unknown parton history '{self.history}'. Valid options: {valid}"
224
)
225
226
alg = config.createAlgorithm(
227
"CP::RunPartonHistoryAlg"
, f
"PartonHistory{self.history}"
228
)
229
alg.partonScheme = self.history
230
231
for
branch
in
TRUTH_BRANCHES[self.history]:
232
config.addOutputVar(
233
"EventInfo"
,
234
f
"{self.history}_{branch}"
,
235
f
"{self.history}_{branch}"
,
236
noSys=
True
,
237
auxType=
_get_aux_type
(branch, self.history),
238
)
PartonHistoryConfig.PartonHistoryBlock
Definition
PartonHistoryConfig.py:202
PartonHistoryConfig.PartonHistoryBlock.makeAlgs
makeAlgs(self, config)
Definition
PartonHistoryConfig.py:219
PartonHistoryConfig.PartonHistoryBlock.__init__
__init__(self)
Definition
PartonHistoryConfig.py:205
PartonHistoryConfig._t_FCNC_branches
list _t_FCNC_branches(str suffix="t")
Definition
PartonHistoryConfig.py:95
PartonHistoryConfig._t_branches
list _t_branches(str suffix="t")
Definition
PartonHistoryConfig.py:78
PartonHistoryConfig._get_aux_type
str _get_aux_type(str branch, str prefix)
Definition
PartonHistoryConfig.py:15
PartonHistoryConfig._make_particle_branches
list _make_particle_branches(str prefix, *, bool include_pdgid=True, tuple stages=None, tuple extra=())
Definition
PartonHistoryConfig.py:32
PartonHistoryConfig._replace_in_list
list[str] _replace_in_list(list[str] string_list, str old, str new)
Definition
PartonHistoryConfig.py:69
Generated on
for ATLAS Offline Software by
1.17.0