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
151 effective = resolve_optional_columns(self._classified, events)
152
153
154 buffer_dict = extract_buffers(events, effective)
155
156
157 allocate_outputs(effective, buffer_dict)
158
159
160 for container_name, info in effective.items():
161
162 self._handle[container_name] = np.asarray(buffer_dict[container_name])
163
164
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
175 for col in info["inputs"]:
176 self._handle[col.name] = np.asarray(buffer_dict[col.name])
177
178
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
187 if systematic is not None:
188 self.apply_systematic_variation("")