98 """A helper function to create output algorithm"""
99 alg = config.createAlgorithm(
'CP::AsgxAODNTupleMakerAlg', name)
100 alg.TreeName = self.treeName
101 alg.RootStreamName = self.streamName
102 alg.NonContainers = list(self.nonContainers)
103 branchList = list(vars)
105 branchList_nosys = [branch
for branch
in branchList
if "%SYS%" not in branch]
106 branchList_sys = [branch
for branch
in branchList
if "%SYS%" in branch]
107 alg.Branches = branchList_nosys + branchList_sys
108 if self.defaultBasketSize
is not None:
109 alg.DefaultBasketSize = self.defaultBasketSize
114 log = logging.getLogger(
'OutputAnalysisConfig')
129 keys_message = [repr(key)
for key
in overlapping_keys]
130 raise KeyError(f
"containersFullMET would overwrite the following container keys: {', '.join(keys_message)}")
135 if config.dataType()
is not DataType.Data:
143 keys_message = [repr(key)
for key
in overlapping_keys]
144 raise KeyError(f
"containersOnlyForMC would overwrite the following container keys: {', '.join(keys_message)}")
155 log.warning(
"Skipping unrecognised container prefix '%s' for DSID-filtering in OutputAnalysisConfig...", container)
157 if not filter_dsids (dsid_filters, config):
159 log.info(
"Skipping container prefix '%s' due to DSID filtering...", container)
162 var_container = var.split(
'.')[0].
replace(
'_NOSYS',
'').
replace(
'_%SYS%',
'')
163 if var_container == self.
containers[container]:
164 self.
vars.remove(var)
165 log.info(
"Skipping branch definition '%s' for excluded container %s...", var, var_container)
168 var_container = var.split(
'.')[0].
replace(
'_NOSYS',
'').
replace(
'_%SYS%',
'')
169 if var_container == self.
containers[container]:
171 log.info(
"Skipping MET branch definition '%s' for excluded container %s...", var, var_container)
174 var_container = var.split(
'.')[0].
replace(
'_NOSYS',
'').
replace(
'_%SYS%',
'')
175 if var_container == self.
containers[container]:
177 log.info(
"Skipping truth MET branch definition '%s' for excluded container %s...", var, var_container)
183 for prefix, container
in self.
containers.items():
184 origName = config.getOutputContainerOrigin(container)
185 if config.getContainerMeta(origName,
"nonContainer",
False):
186 self.nonContainers.append(origName)
197 outputDict = config.getOutputVars (containerName)
198 for outputName
in outputDict :
199 outputConfig = copy.deepcopy (outputDict[outputName])
200 if containerName != outputConfig.origContainerName
or config.checkOutputContainer(containerName):
201 outputConfig.outputContainerName = containerName +
'_%SYS%'
203 outputConfig.outputContainerName = config.readName(containerName)
204 outputConfig.prefix = prefix
208 outputConfig.enabled =
True
209 outputConfigs[prefix + outputName] = outputConfig
212 for dsid, dsid_commands
in self.commandsOnlyForDSIDs.items():
213 if filter_dsids([dsid], config):
216 outputConfigsRename = {}
218 words = command.split (
' ')
219 if len (words) == 0 :
220 raise ValueError (
'received empty command for "commands" option')
221 optional = words[0] ==
'optional'
224 if words[0] ==
'enable' :
225 if len (words) != 2 :
226 raise ValueError (
'enable takes exactly one argument: ' + command)
228 for name
in outputConfigs :
229 if re.match (words[1], name) :
230 outputConfigs[name].enabled =
True
232 if not used
and not optional
and config.dataType()
is not DataType.Data:
233 raise KeyError (
'unknown branch pattern for enable: ' + words[1])
234 elif words[0] ==
'disable' :
235 if len (words) != 2 :
236 raise ValueError (
'disable takes exactly one argument: ' + command)
238 for name
in outputConfigs :
239 if re.match (words[1], name) :
240 outputConfigs[name].enabled =
False
242 if not used
and not optional
and config.dataType()
is not DataType.Data:
243 raise KeyError (
'unknown branch pattern for disable: ' + words[1])
244 elif words[0] ==
'rename' :
245 if len (words) != 3 :
246 raise ValueError (
'rename takes exactly two arguments: ' + command)
248 for name
in outputConfigs :
249 if re.match (words[1], name) :
250 new_name = re.sub (words[1], words[2], name)
251 outputConfigsRename[new_name] = copy.deepcopy(outputConfigs[name])
252 outputConfigs[name].enabled =
False
254 if not used
and not optional
and config.dataType()
is not DataType.Data:
255 raise KeyError (
'unknown branch pattern for rename: ' + words[1])
257 raise KeyError (
'unknown command for "commands" option: ' + words[0])
260 outputConfigs.update(outputConfigsRename)
264 autoTruthMetVars =
set()
265 for outputName, outputConfig
in outputConfigs.items():
266 if outputConfig.enabled :
267 if config.isMetContainer (outputConfig.origContainerName)
and outputConfig.prefix
not in self.
containersFullMET:
268 if "Truth" in outputConfig.origContainerName:
269 myVars = autoTruthMetVars
274 if outputConfig.noSys :
275 outputConfig.outputContainerName = outputConfig.outputContainerName.replace (
'%SYS%',
'NOSYS')
276 outputConfig.variableName = outputConfig.variableName.replace (
'%SYS%',
'NOSYS')
278 outputName +=
"_NOSYS"
280 outputName +=
'_%SYS%'
281 branchDecl = f
"{outputConfig.outputContainerName}.{outputConfig.variableName} -> {outputName}"
282 if outputConfig.auxType
is not None :
283 branchDecl += f
" type={outputConfig.auxType}"
284 if config.isMetContainer (outputConfig.origContainerName)
and outputConfig.prefix
not in self.
containersFullMET:
285 if "Truth" in outputConfig.origContainerName:
286 branchDecl += f
" metTerm={self.truthMetTermName}"
288 branchDecl += f
" metTerm={self.metTermName}"
289 myVars.add(branchDecl)
293 allBranches |= self.
vars
294 allBranches |= autoVars
300 allBranches |= userMetVars
301 allBranches |= autoMetVars
303 userTruthMetVars =
set()
304 if config.dataType()
is not DataType.Data:
308 allBranches |= userTruthMetVars
309 allBranches |= autoTruthMetVars
313 alg = config.createAlgorithm(
'CP::RNtupleTreeMakerAlg',
'RNtupleMaker')
314 alg.TreeName = self.treeName
315 alg.RootStreamName = self.streamName
316 alg.OutputStreamName = self.streamName
317 alg.NonContainers = list(self.nonContainers)
319 branchList = list(allBranches)
321 alg.Branches = branchList
326 treeMaker = config.createAlgorithm(
'CP::TreeMakerAlg',
'TreeMaker' )
327 treeMaker.TreeName = self.treeName
328 treeMaker.RootStreamName = self.streamName
332 if self.
vars or autoVars:
335 if self.
metVars or autoMetVars:
338 if config.dataType()
is not DataType.Data
and (self.
truthMetVars or autoTruthMetVars):
339 self.
createOutputAlgs(config,
'TruthMetNTupleMaker', userTruthMetVars | autoTruthMetVars)
341 treeFiller = config.createAlgorithm(
'CP::TreeFillerAlg',
'TreeFiller' )
342 treeFiller.TreeName = self.treeName
343 treeFiller.RootStreamName = self.streamName
349 For each container and for each selection, create a single pass variable in output NTuple,
350 which aggregates all the selections flag of the given selection. For example, this can include
351 pT, eta selections, some object ID selection, overlap removal, etc.
352 The goal is to have only one flag per object and working point in the output NTuple.
354 originalContainersSeen = []
357 containerName = config.getOutputContainerOrigin(outputContainerName)
358 if containerName
in originalContainersSeen:
361 originalContainersSeen.append(containerName)
364 if containerName ==
'EventInfo':
369 selectionNames = config.getSelectionNames(containerName, excludeFrom={
'ftag'})
370 for selectionName
in selectionNames:
372 if selectionName ==
'':
375 if self.skipRedundantSelectionFlags
and "outputSelect" in selectionName:
381 Schedule an algorithm to pick up all cut flags for a given selectionName.
382 The summary selection flag is written to output as selectionFlagPrefix_selectionName.
384 alg = config.createAlgorithm(
'CP::AsgSelectionAlg',
385 f
'ObjectSelectionSummary_{containerName}_{selectionName}')
386 selectionDecoration = f
'baselineSelection_{selectionName}_%SYS%'
387 alg.selectionDecoration = f
'{selectionDecoration},as_char'
388 alg.particles = config.readName (containerName)
389 alg.preselection = config.getFullSelection (containerName, selectionName)
390 config.addOutputVar (containerName, selectionDecoration, self.selectionFlagPrefix +
'_' + selectionName)