ATLAS Offline Software
Loading...
Searching...
No Matches
python.OutputAnalysisConfig.OutputAnalysisConfig Class Reference
Inheritance diagram for python.OutputAnalysisConfig.OutputAnalysisConfig:
Collaboration diagram for python.OutputAnalysisConfig.OutputAnalysisConfig:

Public Member Functions

 __init__ (self)
 instanceName (self)
 createOutputAlgs (self, config, name, vars)
 makeAlgs (self, config)
 createSelectionFlagBranches (self, config)
 makeSelectionSummaryAlg (self, config, containerName, selectionName)

Static Public Member Functions

 branchSortOrder (rule)

Public Attributes

bool validated = False
 containers = dict(self.containers)
 vars = set(self.vars)
 varsOnlyForMC = set(self.varsOnlyForMC)
 metVars = set(self.metVars)
 truthMetVars = set(self.truthMetVars)
 containersFullMET
 containersOnlyForMC
 containersOnlyForDSIDs
 storeSelectionFlags
 commands
 alwaysAddNosys
 metTermName
 truthMetTermName
str outputFormat = 'RNTuple':

Detailed Description

the ConfigBlock for the MET configuration

Definition at line 10 of file OutputAnalysisConfig.py.

Constructor & Destructor Documentation

◆ __init__()

python.OutputAnalysisConfig.OutputAnalysisConfig.__init__ ( self)

Definition at line 13 of file OutputAnalysisConfig.py.

13 def __init__ (self) :
14 super (OutputAnalysisConfig, self).__init__ ()
15 self.addOption ('postfix', '', type=str,
16 info="a postfix to apply to decorations and algorithm names. "
17 "Typically not needed here.")
18 self.addOption ('vars', [], type=list,
19 info="a list of mappings (list of strings) between containers and "
20 "decorations to output branches.")
21 self.addOption ('varsOnlyForMC', [], type=list,
22 info="same as `vars`, but for MC-only variables so as to avoid a "
23 "crash when running on data.")
24 self.addOption ('metVars', [], type=list,
25 info="a list of mappings (list of strings) between containers "
26 "and decorations to output branches. Specficially for MET "
27 "variables, where only the final MET term is retained.")
28 self.addOption ('truthMetVars', [], type=list,
29 info="a list of mappings (list of strings) between containers "
30 "and decorations to output branches for truth MET.")
31 self.addOption ('containers', {}, type=dict,
32 info="a dictionary mapping prefixes (key) to container names "
33 "(values) to be used when saving to the output tree. Branches "
34 "are then of the form `prefix_decoration`.")
35 self.addOption ('containersFullMET', {}, type=dict,
36 info="same as `containers`, but for MET containers that should be "
37 "saved with all terms (as opposed to just the final term). This "
38 "is useful for special studies. A container can appear both here and "
39 "in containers (with different prefixes).")
40 self.addOption ('containersOnlyForMC', {}, type=dict,
41 info="same as `containers`, but for MC-only containers so as to avoid "
42 "a crash when running on data.")
43 self.addOption ('containersOnlyForDSIDs', {}, type=dict,
44 info="specify which DSIDs are allowed to produce a given container. "
45 "This works like `onlyForDSIDs`: pass a list of DSIDs or regexps.")
46 self.addOption ('nonContainers', ['EventInfo'], type=list,
47 info="a list of container names that are not actual containers but should be treated as non-containers.")
48 self.addOption ('treeName', 'analysis', type=str,
49 info="name of the output TTree to save.")
50 self.addOption ('streamName', 'ANALYSIS', type=str,
51 info="name of the output stream to save the tree in.")
52 self.addOption ('metTermName', 'Final', type=str,
53 info="the name of the MET term to save, turning the MET "
54 "container into a single object.")
55 self.addOption ('truthMetTermName', 'NonInt', type=str,
56 info="the name of the truth MET term to save, turning the MET "
57 "container into a single object.")
58 self.addOption ('storeSelectionFlags', True, type=bool,
59 info="whether to store one branch for each object selection.")
60 self.addOption ('selectionFlagPrefix', 'select', type=str,
61 info="the prefix used when naming selection branches.")
62 self.addOption ('commands', [], type=list,
63 info="a list of strings containing commands (regexp strings "
64 "prefaced by the keywords `enable` or `disable`) to turn on/off the "
65 "writing of branches to the output ntuple. If left empty, do not modify "
66 "the scheduled output branches.")
67 self.addOption ('commandsOnlyForDSIDs', {}, type=dict,
68 info="a dictionary with individual DSIDs as keys, and a list of strings "
69 "like for the `commands` option as items. These `commands` will only be run "
70 "for the corresponding DSID.")
71 self.addOption ('alwaysAddNosys', False, type=bool,
72 info="If set to `True`, all branches will be given a systematics suffix, "
73 "even if they have no systematics (beyond the nominal).")
74 self.addOption ('skipRedundantSelectionFlags', True, type=bool,
75 info="remove the redundant 'outputSelect' branches created by the Thinning step. "
76 "These could however be used to simplify downstream workflows, as in Easyjet. "
77 "The default is True.")
78 self.addOption ('outputFormat', 'TTree', type=str,
79 info="The output format. The default is 'TTree'.")
80 self.addOption ('defaultBasketSize', None, type=int,
81 info="default basket size for all branches in the output tree. "
82 "If not set (the default), no basket size is configured and ROOT's "
83 "default will be used.")
84 # helper to protect for second pass
85 self.validated = False
86

Member Function Documentation

◆ branchSortOrder()

python.OutputAnalysisConfig.OutputAnalysisConfig.branchSortOrder ( rule)
static

Definition at line 94 of file OutputAnalysisConfig.py.

94 def branchSortOrder (rule):
95 return rule.split('->')[1].strip()
96

◆ createOutputAlgs()

python.OutputAnalysisConfig.OutputAnalysisConfig.createOutputAlgs ( self,
config,
name,
vars )
A helper function to create output algorithm

Definition at line 97 of file OutputAnalysisConfig.py.

97 def createOutputAlgs (self, config, name, vars):
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)
104 branchList.sort(key=self.branchSortOrder)
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
110 return alg
111

◆ createSelectionFlagBranches()

python.OutputAnalysisConfig.OutputAnalysisConfig.createSelectionFlagBranches ( self,
config )
For each container and for each selection, create a single pass variable in output NTuple,
which aggregates all the selections flag of the given selection. For example, this can include
pT, eta selections, some object ID selection, overlap removal, etc.
The goal is to have only one flag per object and working point in the output NTuple.

Definition at line 342 of file OutputAnalysisConfig.py.

342 def createSelectionFlagBranches(self, config):
343 """
344 For each container and for each selection, create a single pass variable in output NTuple,
345 which aggregates all the selections flag of the given selection. For example, this can include
346 pT, eta selections, some object ID selection, overlap removal, etc.
347 The goal is to have only one flag per object and working point in the output NTuple.
348 """
349 originalContainersSeen = []
350 for prefix in self.containers.keys() :
351 outputContainerName = self.containers[prefix]
352 containerName = config.getOutputContainerOrigin(outputContainerName)
353 if containerName in originalContainersSeen:
354 continue
355 else:
356 originalContainersSeen.append(containerName)
357
358 # EventInfo is one obvious example of a container that has no object selections
359 if containerName == 'EventInfo':
360 continue
361
362 # Get the selection names, except the systematic-dependent version of the FTAG
363 # selection flag, as it's already saved as a systematic-independent output branch
364 selectionNames = config.getSelectionNames(containerName, excludeFrom={'ftag'})
365 for selectionName in selectionNames:
366 # skip default selection
367 if selectionName == '':
368 continue
369 # skip selection coming from the Thinning block
370 if self.skipRedundantSelectionFlags and "outputSelect" in selectionName:
371 continue
372 self.makeSelectionSummaryAlg(config, containerName, selectionName)
373

◆ instanceName()

python.OutputAnalysisConfig.OutputAnalysisConfig.instanceName ( self)
Return the instance name for this block

Definition at line 87 of file OutputAnalysisConfig.py.

87 def instanceName (self) :
88 """Return the instance name for this block"""
89 if self.postfix is not None and self.postfix != '':
90 return self.postfix
91 return self.treeName
92

◆ makeAlgs()

python.OutputAnalysisConfig.OutputAnalysisConfig.makeAlgs ( self,
config )

Definition at line 112 of file OutputAnalysisConfig.py.

112 def makeAlgs (self, config) :
113
114 log = logging.getLogger('OutputAnalysisConfig')
115
116 # do some transformations of the options we should only do once
117 if not self.validated:
118
119 self.containers = dict(self.containers)
120 self.vars = set(self.vars)
121 self.varsOnlyForMC = set(self.varsOnlyForMC)
122 self.metVars = set(self.metVars)
123 self.truthMetVars = set(self.truthMetVars)
124
125 # check for overlaps between containers and containersFullMET
126 overlapping_keys = set(self.containers.keys()).intersection(self.containersFullMET.keys())
127 if overlapping_keys:
128 # convert the set of overlapping keys to a list of strings for the message (represents the empty string too!)
129 keys_message = [repr(key) for key in overlapping_keys]
130 raise KeyError(f"containersFullMET would overwrite the following container keys: {', '.join(keys_message)}")
131 # move items in self.containersFullMET to containers
132 self.containers.update(self.containersFullMET)
133
134 # merge the MC-specific branches and containers into the main list/dictionary only if we are not running on data
135 if config.dataType() is not DataType.Data:
136 self.vars |= self.varsOnlyForMC
137
138 # protect 'containers' against being overwritten
139 # find overlapping keys
140 overlapping_keys = set(self.containers.keys()).intersection(self.containersOnlyForMC.keys())
141 if overlapping_keys:
142 # convert the set of overlapping keys to a list of strings for the message (represents the empty string too!)
143 keys_message = [repr(key) for key in overlapping_keys]
144 raise KeyError(f"containersOnlyForMC would overwrite the following container keys: {', '.join(keys_message)}")
145
146 # move items in self.containersOnlyForMC to self.containers
147 self.containers.update(self.containersOnlyForMC)
148 # clear the dictionary to avoid overlapping key error during the second pass
149 self.containersOnlyForMC.clear()
150
151 # now filter the containers depending on DSIDs
152 if self.containersOnlyForDSIDs:
153 for container, dsid_filters in self.containersOnlyForDSIDs.items():
154 if container not in self.containers:
155 log.warning("Skipping unrecognised container prefix '%s' for DSID-filtering in OutputAnalysisConfig...", container)
156 continue
157 if not filter_dsids (dsid_filters, config):
158 # if current DSID is not allowed for this container, remove it
159 log.info("Skipping container prefix '%s' due to DSID filtering...", container)
160 # filter branches for validated containers
161 for var in set(self.vars): # make a copy of the list to avoid modifying it while iterating
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)
166 # filter branches for MET variables
167 for var in set(self.metVars): # make a copy of the list to avoid modifying it while iterating
168 var_container = var.split('.')[0].replace('_NOSYS', '').replace('_%SYS%', '')
169 if var_container == self.containers[container]:
170 self.metVars.remove(var)
171 log.info("Skipping MET branch definition '%s' for excluded container %s...", var, var_container)
172 # filter branches for truth MET variables
173 for var in set(self.truthMetVars): # make a copy of the list to avoid modifying it while iterating
174 var_container = var.split('.')[0].replace('_NOSYS', '').replace('_%SYS%', '')
175 if var_container == self.containers[container]:
176 self.truthMetVars.remove(var)
177 log.info("Skipping truth MET branch definition '%s' for excluded container %s...", var, var_container)
178 # remove the container from the list at the end
179 self.containers.pop (container)
180 # clear the dictionary to avoid warnings during the second pass
181 self.containersOnlyForDSIDs.clear()
182
183 # at this point we are OK
184 self.validated = True
185
186 if self.storeSelectionFlags:
187 self.createSelectionFlagBranches(config)
188
189 outputConfigs = {}
190 for prefix in self.containers.keys() :
191 containerName = self.containers[prefix]
192 outputDict = config.getOutputVars (containerName)
193 for outputName in outputDict :
194 outputConfig = copy.deepcopy (outputDict[outputName])
195 if containerName != outputConfig.origContainerName or config.checkOutputContainer(containerName):
196 outputConfig.outputContainerName = containerName + '_%SYS%'
197 else:
198 outputConfig.outputContainerName = config.readName(containerName)
199 outputConfig.prefix = prefix
200 # if the container is a MET container with all terms, we
201 # also need to write out the name of each MET term
202 if prefix in self.containersFullMET and outputConfig.variableName == 'name':
203 outputConfig.enabled = True
204 outputConfigs[prefix + outputName] = outputConfig
205
206 # check for DSID-specific commands
207 for dsid, dsid_commands in self.commandsOnlyForDSIDs.items():
208 if filter_dsids([dsid], config):
209 self.commands += dsid_commands
210
211 outputConfigsRename = {}
212 for command in self.commands :
213 words = command.split (' ')
214 if len (words) == 0 :
215 raise ValueError ('received empty command for "commands" option')
216 optional = words[0] == 'optional'
217 if optional :
218 words = words[1:] # remove the 'optional' keyword
219 if words[0] == 'enable' :
220 if len (words) != 2 :
221 raise ValueError ('enable takes exactly one argument: ' + command)
222 used = False
223 for name in outputConfigs :
224 if re.match (words[1], name) :
225 outputConfigs[name].enabled = True
226 used = True
227 if not used and not optional and config.dataType() is not DataType.Data:
228 raise KeyError ('unknown branch pattern for enable: ' + words[1])
229 elif words[0] == 'disable' :
230 if len (words) != 2 :
231 raise ValueError ('disable takes exactly one argument: ' + command)
232 used = False
233 for name in outputConfigs :
234 if re.match (words[1], name) :
235 outputConfigs[name].enabled = False
236 used = True
237 if not used and not optional and config.dataType() is not DataType.Data:
238 raise KeyError ('unknown branch pattern for disable: ' + words[1])
239 elif words[0] == 'rename' :
240 if len (words) != 3 :
241 raise ValueError ('rename takes exactly two arguments: ' + command)
242 used = False
243 for name in outputConfigs :
244 if re.match (words[1], name) :
245 new_name = re.sub (words[1], words[2], name)
246 outputConfigsRename[new_name] = copy.deepcopy(outputConfigs[name])
247 outputConfigs[name].enabled = False
248 used = True
249 if not used and not optional and config.dataType() is not DataType.Data:
250 raise KeyError ('unknown branch pattern for rename: ' + words[1])
251 else :
252 raise KeyError ('unknown command for "commands" option: ' + words[0])
253
254 # update the outputConfigs with renamed branches
255 outputConfigs.update(outputConfigsRename)
256
257 autoVars = set()
258 autoMetVars = set()
259 autoTruthMetVars = set()
260 for outputName, outputConfig in outputConfigs.items():
261 if outputConfig.enabled :
262 if config.isMetContainer (outputConfig.origContainerName) and outputConfig.prefix not in self.containersFullMET:
263 if "Truth" in outputConfig.origContainerName:
264 myVars = autoTruthMetVars
265 else:
266 myVars = autoMetVars
267 else :
268 myVars = autoVars
269 if outputConfig.noSys :
270 outputConfig.outputContainerName = outputConfig.outputContainerName.replace ('%SYS%', 'NOSYS')
271 outputConfig.variableName = outputConfig.variableName.replace ('%SYS%', 'NOSYS')
272 if self.alwaysAddNosys :
273 outputName += "_NOSYS"
274 else :
275 outputName += '_%SYS%'
276 branchDecl = f"{outputConfig.outputContainerName}.{outputConfig.variableName} -> {outputName}"
277 if outputConfig.auxType is not None :
278 branchDecl += f" type={outputConfig.auxType}"
279 if config.isMetContainer (outputConfig.origContainerName) and outputConfig.prefix not in self.containersFullMET:
280 if "Truth" in outputConfig.origContainerName:
281 branchDecl += f" metTerm={self.truthMetTermName}"
282 else:
283 branchDecl += f" metTerm={self.metTermName}"
284 myVars.add(branchDecl)
285
286 # Unified branch collection for all output formats
287 allBranches = set()
288 allBranches |= self.vars
289 allBranches |= autoVars
290 # Add MET branches
291 userMetVars = set()
292 if self.metVars:
293 for var in self.metVars:
294 userMetVars.add(var + " metTerm=" + self.metTermName)
295 allBranches |= userMetVars
296 allBranches |= autoMetVars
297 # Add truth MET branches (for MC)
298 userTruthMetVars = set()
299 if config.dataType() is not DataType.Data:
300 if self.truthMetVars:
301 for var in self.truthMetVars:
302 userTruthMetVars.add(var + " metTerm=" + self.truthMetTermName)
303 allBranches |= userTruthMetVars
304 allBranches |= autoTruthMetVars
305
306 # Create the output algorithm based on outputFormat
307 if self.outputFormat == 'RNTuple':
308 alg = config.createAlgorithm('CP::RNtupleTreeMakerAlg', 'RNtupleMaker')
309 alg.TreeName = self.treeName
310 alg.RootStreamName = self.streamName
311 alg.OutputStreamName = self.streamName
312 alg.NonContainers = list(self.nonContainers)
313
314 branchList = list(allBranches)
315 branchList.sort(key=self.branchSortOrder)
316 alg.Branches = branchList
317
318 return
319
320 # Add an ntuple dumper algorithm:
321 treeMaker = config.createAlgorithm( 'CP::TreeMakerAlg', 'TreeMaker' )
322 treeMaker.TreeName = self.treeName
323 treeMaker.RootStreamName = self.streamName
324 # the auto-flush setting still needs to be figured out
325 #treeMaker.TreeAutoFlush = 0
326
327 if self.vars or autoVars:
328 self.createOutputAlgs(config, 'NTupleMaker', self.vars | autoVars)
329
330 if self.metVars or autoMetVars:
331 self.createOutputAlgs(config, 'MetNTupleMaker', userMetVars | autoMetVars)
332
333 if config.dataType() is not DataType.Data and (self.truthMetVars or autoTruthMetVars):
334 self.createOutputAlgs(config, 'TruthMetNTupleMaker', userTruthMetVars | autoTruthMetVars)
335
336 treeFiller = config.createAlgorithm( 'CP::TreeFillerAlg', 'TreeFiller' )
337 treeFiller.TreeName = self.treeName
338 treeFiller.RootStreamName = self.streamName
339
340
341
void clear()
Empty the pool.
STL class.
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)
Definition hcg.cxx:312

◆ makeSelectionSummaryAlg()

python.OutputAnalysisConfig.OutputAnalysisConfig.makeSelectionSummaryAlg ( self,
config,
containerName,
selectionName )
Schedule an algorithm to pick up all cut flags for a given selectionName.
The summary selection flag is written to output as selectionFlagPrefix_selectionName.

Definition at line 374 of file OutputAnalysisConfig.py.

374 def makeSelectionSummaryAlg(self, config, containerName, selectionName):
375 """
376 Schedule an algorithm to pick up all cut flags for a given selectionName.
377 The summary selection flag is written to output as selectionFlagPrefix_selectionName.
378 """
379 alg = config.createAlgorithm( 'CP::AsgSelectionAlg',
380 f'ObjectSelectionSummary_{containerName}_{selectionName}')
381 selectionDecoration = f'baselineSelection_{selectionName}_%SYS%'
382 alg.selectionDecoration = f'{selectionDecoration},as_char'
383 alg.particles = config.readName (containerName)
384 alg.preselection = config.getFullSelection (containerName, selectionName)
385 config.addOutputVar (containerName, selectionDecoration, self.selectionFlagPrefix + '_' + selectionName)

Member Data Documentation

◆ alwaysAddNosys

python.OutputAnalysisConfig.OutputAnalysisConfig.alwaysAddNosys

Definition at line 272 of file OutputAnalysisConfig.py.

◆ commands

python.OutputAnalysisConfig.OutputAnalysisConfig.commands

Definition at line 212 of file OutputAnalysisConfig.py.

◆ containers

python.OutputAnalysisConfig.OutputAnalysisConfig.containers = dict(self.containers)

Definition at line 119 of file OutputAnalysisConfig.py.

◆ containersFullMET

python.OutputAnalysisConfig.OutputAnalysisConfig.containersFullMET

Definition at line 132 of file OutputAnalysisConfig.py.

◆ containersOnlyForDSIDs

python.OutputAnalysisConfig.OutputAnalysisConfig.containersOnlyForDSIDs

Definition at line 152 of file OutputAnalysisConfig.py.

◆ containersOnlyForMC

python.OutputAnalysisConfig.OutputAnalysisConfig.containersOnlyForMC

Definition at line 147 of file OutputAnalysisConfig.py.

◆ metTermName

python.OutputAnalysisConfig.OutputAnalysisConfig.metTermName

Definition at line 294 of file OutputAnalysisConfig.py.

◆ metVars

python.OutputAnalysisConfig.OutputAnalysisConfig.metVars = set(self.metVars)

Definition at line 122 of file OutputAnalysisConfig.py.

◆ outputFormat

str python.OutputAnalysisConfig.OutputAnalysisConfig.outputFormat = 'RNTuple':

Definition at line 307 of file OutputAnalysisConfig.py.

◆ storeSelectionFlags

python.OutputAnalysisConfig.OutputAnalysisConfig.storeSelectionFlags

Definition at line 186 of file OutputAnalysisConfig.py.

◆ truthMetTermName

python.OutputAnalysisConfig.OutputAnalysisConfig.truthMetTermName

Definition at line 302 of file OutputAnalysisConfig.py.

◆ truthMetVars

python.OutputAnalysisConfig.OutputAnalysisConfig.truthMetVars = set(self.truthMetVars)

Definition at line 123 of file OutputAnalysisConfig.py.

◆ validated

bool python.OutputAnalysisConfig.OutputAnalysisConfig.validated = False

Definition at line 85 of file OutputAnalysisConfig.py.

◆ vars

python.OutputAnalysisConfig.OutputAnalysisConfig.vars = set(self.vars)

Definition at line 120 of file OutputAnalysisConfig.py.

◆ varsOnlyForMC

python.OutputAnalysisConfig.OutputAnalysisConfig.varsOnlyForMC = set(self.varsOnlyForMC)

Definition at line 121 of file OutputAnalysisConfig.py.


The documentation for this class was generated from the following file: