ATLAS Offline Software
Toggle main menu visibility
Loading...
Searching...
No Matches
PhysicsAnalysis
Columnar
ColumnarToolWrapperPython
python
tool.py
Go to the documentation of this file.
1
# Copyright (C) 2002-2026 CERN for the benefit of the ATLAS collaboration
2
#
3
# @author Giordon Stark
4
5
# High-level Tool wrapper around PythonToolHandle.
6
# Automates buffer extraction, column setting, calling, and output
7
# reconstruction using ColumnInfo metadata.
8
9
import
awkward
as
ak
10
import
numpy
as
np
11
12
from
ColumnarToolWrapperPython.buffers
import
(
13
_branch_name_for_column,
14
allocate_outputs,
15
classify_columns,
16
extract_buffers,
17
reconstruct_output,
18
resolve_optional_columns,
19
)
20
from
ColumnarToolWrapperPython.python_tool_handle
import
PythonToolHandle
21
22
23
class
Tool
:
24
"""High-level wrapper around PythonToolHandle.
25
26
Handles the boilerplate of classifying columns, extracting awkward-array
27
buffers, allocating outputs, setting columns on the handle, calling the
28
tool, and reconstructing the output awkward array.
29
30
Parameters
31
----------
32
type_and_name:
33
Tool type and instance name, e.g. "CP::MuonEfficiencyScaleFactors/myTool".
34
properties:
35
Optional dict of tool properties to set before initialization.
36
rename_containers:
37
Optional mapping from canonical container names (e.g. "Muons") to the
38
branch-name prefix used in the input arrays (e.g. "AnalysisMuonsAuxDyn").
39
This is passed to PythonToolHandle.rename_containers *after* initialize
40
so that ColumnInfo.name values match input array fields.
41
"""
42
43
def
__init__
(self, type_and_name, properties=None, rename_containers=None):
44
self.
_handle
= PythonToolHandle()
45
self.
_handle
.set_type_and_name(type_and_name)
46
self.
_properties
= dict(properties)
if
properties
else
{}
47
48
for
key, value
in
self.
_properties
.items():
49
self.
_handle
.set_property(key, value)
50
51
self.
_handle
.
initialize
()
52
53
if
rename_containers:
54
self.
_handle
.rename_containers(rename_containers)
55
56
# Cache classified column topology once after initialization
57
self.
_classified
= classify_columns(self.
_handle
.columns)
58
59
@property
60
def
properties
(self):
61
"""Dict of properties set on this tool at construction time."""
62
return
self.
_properties
63
64
@property
65
def
columns
(self):
66
"""All ColumnInfo objects reported by the tool."""
67
return
self.
_handle
.columns
68
69
@property
70
def
input_columns
(self):
71
"""Input (non-offset) ColumnInfo objects, including nested-vector data columns."""
72
cols = []
73
for
info
in
self.
_classified
.values():
74
cols.extend(info[
"inputs"
])
75
for
nested
in
info[
"nested_offsets"
].values():
76
cols.extend(nested[
"inputs"
])
77
return
cols
78
79
@property
80
def
output_columns
(self):
81
"""Output ColumnInfo objects, including nested-vector outputs (currently unsupported)."""
82
cols = []
83
for
info
in
self.
_classified
.values():
84
cols.extend(info[
"outputs"
])
85
for
nested
in
info[
"nested_offsets"
].values():
86
cols.extend(nested[
"outputs"
])
87
return
cols
88
89
@property
90
def
required_input_branch_names
(self):
91
"""Deduplicated uproot branch names needed to fill non-optional inputs.
92
93
For nested-vector inputs, the trailing ``.data`` suffix is stripped so
94
the returned name matches the actual ROOT branch (e.g.
95
``"Particles.NumTrkPt500"`` instead of ``"Particles.NumTrkPt500.data"``).
96
Optional inputs are excluded.
97
"""
98
seen = []
99
seen_set =
set
()
100
for
col
in
self.
input_columns
:
101
if
col.is_optional:
102
continue
103
branch = _branch_name_for_column(col.name)
104
if
branch
not
in
seen_set:
105
seen_set.add(branch)
106
seen.append(branch)
107
return
seen
108
109
@property
110
def
recommended_systematics
(self):
111
"""List of recommended systematic variation names."""
112
return
self.
_handle
.get_recommended_systematics()
113
114
def
apply_systematic_variation
(self, sys_name):
115
"""Apply a systematic variation by name.
116
117
Parameters
118
----------
119
sys_name:
120
Systematic variation name, e.g. ``"MUON_EFF_RECO_SYS__1up"``.
121
Pass ``""`` to reset to the nominal.
122
"""
123
self.
_handle
.
apply_systematic_variation
(sys_name)
124
125
def
__call__
(self, events, systematic=None):
126
"""Run the tool on events and return output columns as an ak.Array.
127
128
Parameters
129
----------
130
events:
131
An ak.Array with fields matching the tool's input column names
132
(after any rename_containers mapping).
133
systematic:
134
Optional systematic variation name (e.g. "MUON_EFF_RECO_SYS__1up").
135
If provided, applied before running the tool and reset to nominal
136
after execution.
137
138
Returns
139
-------
140
ak.Array
141
Record array with one field per output column, each a
142
variable-length list over the per-particle values.
143
"""
144
if
systematic
is
not
None
:
145
self.
apply_systematic_variation
(systematic)
146
147
try
:
148
num_events = int(ak.num(events, axis=0))
149
150
# Resolve optional columns against the actual fields present
151
effective = resolve_optional_columns(self.
_classified
, events)
152
153
# Extract flat buffers from the awkward array
154
buffer_dict = extract_buffers(events, effective)
155
156
# Allocate zero-filled output arrays (added into buffer_dict in-place)
157
allocate_outputs(effective, buffer_dict)
158
159
# Set all columns on the handle
160
for
container_name, info
in
effective.items():
161
# Container offset (always immutable)
162
self.
_handle
[container_name] = np.asarray(buffer_dict[container_name])
163
164
# Nested-vector offsets and their data inputs/outputs
165
for
nested_offset_name, nested
in
info[
"nested_offsets"
].items():
166
self.
_handle
[nested_offset_name] = np.asarray(
167
buffer_dict[nested_offset_name]
168
)
169
for
col
in
nested[
"inputs"
]:
170
self.
_handle
[col.name] = np.asarray(buffer_dict[col.name])
171
for
col
in
nested[
"outputs"
]:
172
self.
_handle
.set_column_void(col.name, buffer_dict[col.name],
False
)
173
174
# Flat input data columns (immutable)
175
for
col
in
info[
"inputs"
]:
176
self.
_handle
[col.name] = np.asarray(buffer_dict[col.name])
177
178
# Flat output data columns (mutable)
179
for
col
in
info[
"outputs"
]:
180
self.
_handle
.set_column_void(col.name, buffer_dict[col.name],
False
)
181
182
self.
_handle
.call()
183
184
return
reconstruct_output(effective, buffer_dict, num_events)
185
finally
:
186
# Reset to nominal if systematic was applied
187
if
systematic
is
not
None
:
188
self.
apply_systematic_variation
(
""
)
python.tool.Tool
Definition
tool.py:23
python.tool.Tool.apply_systematic_variation
apply_systematic_variation(self, sys_name)
Definition
tool.py:114
python.tool.Tool.output_columns
output_columns(self)
Definition
tool.py:80
python.tool.Tool._properties
_properties
Definition
tool.py:46
python.tool.Tool.__init__
__init__(self, type_and_name, properties=None, rename_containers=None)
Definition
tool.py:43
python.tool.Tool.recommended_systematics
recommended_systematics(self)
Definition
tool.py:110
python.tool.Tool.input_columns
input_columns
Definition
tool.py:100
python.tool.Tool.required_input_branch_names
required_input_branch_names(self)
Definition
tool.py:90
python.tool.Tool._classified
_classified
Definition
tool.py:57
python.tool.Tool.properties
properties(self)
Definition
tool.py:60
python.tool.Tool._handle
_handle
Definition
tool.py:44
python.tool.Tool.columns
columns(self)
Definition
tool.py:65
python.tool.Tool.__call__
__call__(self, events, systematic=None)
Definition
tool.py:125
set
STL class.
initialize
void initialize()
Definition
run_EoverP.cxx:894
Generated on
for ATLAS Offline Software by
1.17.0