122 def makeAlgs (self, config) :
123
124 log = logging.getLogger('OutputAnalysisConfig')
125
126 containers = dict(self.containers)
127 branchVars =
set(self.vars)
128 metVars =
set(self.metVars)
129 truthMetVars =
set(self.truthMetVars)
130 nonContainers = list(self.nonContainers)
131 commands = list(self.commands)
132
133
134 overlapping_keys =
set(containers.keys()).
intersection(self.containersFullMET.keys())
135 if overlapping_keys:
136
137 keys_message = [repr(key) for key in overlapping_keys]
138 raise KeyError(f"containersFullMET would overwrite the following container keys: {', '.join(keys_message)}")
139
140 containers.update(self.containersFullMET)
141
142
143 if config.dataType() is not DataType.Data:
144 branchVars |=
set(self.varsOnlyForMC)
145
146
147
148 overlapping_keys =
set(containers.keys()).
intersection(self.containersOnlyForMC.keys())
149 if overlapping_keys:
150
151 keys_message = [repr(key) for key in overlapping_keys]
152 raise KeyError(f"containersOnlyForMC would overwrite the following container keys: {', '.join(keys_message)}")
153
154
155 containers.update(self.containersOnlyForMC)
156
157
158 if self.containersOnlyForDSIDs:
159 for container, dsid_filters in self.containersOnlyForDSIDs.items():
160 if container not in containers:
161 log.warning("Skipping unrecognised container prefix '%s' for DSID-filtering in OutputAnalysisConfig...", container)
162 continue
163 if not filter_dsids (dsid_filters, config):
164
165 log.info("Skipping container prefix '%s' due to DSID filtering...", container)
166
167 for var
in set(branchVars):
168 var_container = var.split(
'.')[0].
replace(
'_NOSYS',
'').
replace(
'_%SYS%',
'')
169 if var_container == containers[container]:
170 branchVars.remove(var)
171 log.info("Skipping branch definition '%s' for excluded container %s...", var, var_container)
172
173 for var
in set(metVars):
174 var_container = var.split(
'.')[0].
replace(
'_NOSYS',
'').
replace(
'_%SYS%',
'')
175 if var_container == containers[container]:
176 metVars.remove(var)
177 log.info("Skipping MET branch definition '%s' for excluded container %s...", var, var_container)
178
179 for var
in set(truthMetVars):
180 var_container = var.split(
'.')[0].
replace(
'_NOSYS',
'').
replace(
'_%SYS%',
'')
181 if var_container == containers[container]:
182 truthMetVars.remove(var)
183 log.info("Skipping truth MET branch definition '%s' for excluded container %s...", var, var_container)
184
185 containers.pop (container)
186
187 if self.varsOnlyForDSIDs:
188 for var_pattern, dsid_filters in self.varsOnlyForDSIDs.items():
189 if not filter_dsids(dsid_filters, config):
190
191 for var
in set(branchVars):
192 if var_pattern in var:
193 branchVars.remove(var)
194 log.info("Skipping branch definition '%s' due to variable-level DSID filtering...", var)
195 for var
in set(metVars):
196 if var_pattern in var:
197 metVars.remove(var)
198 log.info("Skipping MET branch definition '%s' due to variable-level DSID filtering...", var)
199 for var
in set(truthMetVars):
200 if var_pattern in var:
201 truthMetVars.remove(var)
202 log.info("Skipping truth MET branch definition '%s' due to variable-level DSID filtering...", var)
203
204
205 for prefix, container in containers.items():
206 origName = config.getOutputContainerOrigin(container)
207 if config.getContainerMeta(origName, "nonContainer", False):
208 if origName not in nonContainers:
209 nonContainers.append(origName)
210
211 if self.storeSelectionFlags:
212 self.createSelectionFlagBranches(config, containers)
213
214 outputConfigs = {}
215 for prefix in containers.keys() :
216 containerName = containers[prefix]
217 outputDict = config.getOutputVars (containerName)
218 for outputName in outputDict :
219 outputConfig = copy.deepcopy (outputDict[outputName])
220 outputConfig.outputContainerName = config.readName(containerName)
221 outputConfig.prefix = prefix
222
223
224 if prefix in self.containersFullMET and outputConfig.variableName == 'name':
225 outputConfig.enabled = True
226 outputConfigs[prefix + outputName] = outputConfig
227
228
229 for dsid, dsid_commands in self.commandsOnlyForDSIDs.items():
230 if filter_dsids([dsid], config):
231 commands += dsid_commands
232
233 outputConfigsRename = {}
234 for command in commands :
235 words = command.split (' ')
236 if len (words) == 0 :
237 raise ValueError ('received empty command for "commands" option')
238 optional = words[0] == 'optional'
239 if optional :
240 words = words[1:]
241 if words[0] == 'enable' :
242 if len (words) != 2 :
243 raise ValueError ('enable takes exactly one argument: ' + command)
244 used = False
245 for name in outputConfigs :
246 if re.match (words[1], name) :
247 outputConfigs[name].enabled = True
248 used = True
249 if not used and not optional and config.dataType() is not DataType.Data:
250 raise KeyError ('unknown branch pattern for enable: ' + words[1])
251 elif words[0] == 'disable' :
252 if len (words) != 2 :
253 raise ValueError ('disable takes exactly one argument: ' + command)
254 used = False
255 for name in outputConfigs :
256 if re.match (words[1], name) :
257 outputConfigs[name].enabled = False
258 used = True
259 if not used and not optional and config.dataType() is not DataType.Data:
260 raise KeyError ('unknown branch pattern for disable: ' + words[1])
261 elif words[0] == 'rename' :
262 if len (words) != 3 :
263 raise ValueError ('rename takes exactly two arguments: ' + command)
264 used = False
265 for name in outputConfigs :
266 if re.match (words[1], name) :
267 new_name = re.sub (words[1], words[2], name)
268 outputConfigsRename[new_name] = copy.deepcopy(outputConfigs[name])
269 outputConfigs[name].enabled = False
270 used = True
271 if not used and not optional and config.dataType() is not DataType.Data:
272 raise KeyError ('unknown branch pattern for rename: ' + words[1])
273 else :
274 raise KeyError ('unknown command for "commands" option: ' + words[0])
275
276
277 outputConfigs.update(outputConfigsRename)
278
281 autoTruthMetVars =
set()
282 for outputName, outputConfig in outputConfigs.items():
283 if outputConfig.enabled :
284 if config.isMetContainer (outputConfig.origContainerName) and outputConfig.prefix not in self.containersFullMET:
285 if "Truth" in outputConfig.origContainerName:
286 myVars = autoTruthMetVars
287 else:
288 myVars = autoMetVars
289 else :
290 myVars = autoVars
291 if outputConfig.noSys :
292 outputConfig.outputContainerName = outputConfig.outputContainerName.replace ('%SYS%', 'NOSYS')
293 outputConfig.variableName = outputConfig.variableName.replace ('%SYS%', 'NOSYS')
294 if self.alwaysAddNosys :
295 outputName += "_NOSYS"
296 else :
297 outputName += '_%SYS%'
298 branchDecl = f"{outputConfig.outputContainerName}.{outputConfig.variableName} -> {outputName}"
299 if outputConfig.auxType is not None :
300 branchDecl += f" type={outputConfig.auxType}"
301 if config.isMetContainer (outputConfig.origContainerName) and outputConfig.prefix not in self.containersFullMET:
302 if "Truth" in outputConfig.origContainerName:
303 branchDecl += f" metTerm={self.truthMetTermName}"
304 else:
305 branchDecl += f" metTerm={self.metTermName}"
306 myVars.add(branchDecl)
307
308
310 allBranches |= branchVars
311 allBranches |= autoVars
312
314 if metVars:
315 for var in metVars:
316 userMetVars.add(var + " metTerm=" + self.metTermName)
317 allBranches |= userMetVars
318 allBranches |= autoMetVars
319
320 userTruthMetVars =
set()
321 if config.dataType() is not DataType.Data:
322 if truthMetVars:
323 for var in truthMetVars:
324 userTruthMetVars.add(var + " metTerm=" + self.truthMetTermName)
325 allBranches |= userTruthMetVars
326 allBranches |= autoTruthMetVars
327
328 selections = []
329 if self.splitBySelection:
330
331 selections = [selection for selection in config.getContainerMeta('EventInfo', 'eventSelectionNames', failOnMiss=True)
332 if not selection.startswith('pass_SUB')]
333
334
335 outputs = [('', self.streamName, '')]
336 if len(selections) > 1:
337 outputs = []
338 for selection in selections:
339 name = selection.removeprefix('pass_').removesuffix('_%SYS%')
340 outputs.append((f'_{name}', f'{self.streamName}_{name}', f'{selection},as_char'))
341 for _, streamName, _ in outputs:
342 config.requestOutputStream(streamName)
343
344
345 if self.outputFormat == 'RNTuple':
346 branchList = list(allBranches)
347 branchList.sort(key=self.branchSortOrder)
348 branchList_nosys = [branch for branch in branchList if "%SYS%" not in branch]
349 branchList_sys = [branch for branch in branchList if "%SYS%" in branch]
350
351 for suffix, streamName, eventSelection in outputs:
352 alg = config.createAlgorithm('CP::RNtupleTreeMakerAlg', 'RNtupleMaker' + suffix)
353 alg.TreeName = self.treeName
354 alg.RootStreamName = streamName
355 alg.OutputStreamName = streamName
356 alg.NonContainers = list(nonContainers)
357 alg.ApproxZippedClusterSize = self.RNTupleApproxZippedClusterSize
358 alg.MaxUnzippedClusterSize = self.RNTupleMaxUnzippedClusterSize
359 alg.Branches = branchList_nosys + branchList_sys
360 if eventSelection:
361 alg.EventSelection = eventSelection
362
363 return
364
365 for suffix, streamName, eventSelection in outputs:
366
367 treeMaker = config.createAlgorithm( 'CP::TreeMakerAlg', 'TreeMaker' + suffix )
368 treeMaker.TreeName = self.treeName
369 treeMaker.RootStreamName = streamName
370
371
372
373 if branchVars or autoVars:
374 self.createOutputAlgs(config, 'NTupleMaker' + suffix, branchVars | autoVars, nonContainers, streamName)
375
376 if metVars or autoMetVars:
377 self.createOutputAlgs(config, 'MetNTupleMaker' + suffix, userMetVars | autoMetVars, nonContainers, streamName)
378
379 if config.dataType() is not DataType.Data and (truthMetVars or autoTruthMetVars):
380 self.createOutputAlgs(config, 'TruthMetNTupleMaker' + suffix, userTruthMetVars | autoTruthMetVars, nonContainers, streamName)
381
382 treeFiller = config.createAlgorithm( 'CP::TreeFillerAlg', 'TreeFiller' + suffix )
383 treeFiller.TreeName = self.treeName
384 treeFiller.RootStreamName = streamName
385 if eventSelection:
386 treeFiller.EventSelection = eventSelection
387
388
389
std::vector< std::string > intersection(std::vector< std::string > &v1, std::vector< std::string > &v2)
std::string replace(std::string s, const std::string &s2, const std::string &s3)