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, isMet=False)
 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

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=None,
19 info="a list of mappings (list of strings) between containers and "
20 "decorations to output branches. The default is [] (empty list).")
21 self.addOption ('varsOnlyForMC', [], type=None,
22 info="same as vars, but for MC-only variables so as to avoid a "
23 "crash when running on data. The default is [] (empty list).")
24 self.addOption ('metVars', [], type=None,
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 "The default is [] (empty list).")
29 self.addOption ('truthMetVars', [], type=None,
30 info="a list of mappings (list of strings) between containers "
31 "and decorations to output branches for truth MET. "
32 "The default is [] (empty list).")
33 self.addOption ('containers', {}, type=None,
34 info="a dictionary mapping prefixes (key) to container names "
35 "(values) to be used when saving to the output tree. Branches "
36 "are then of the form prefix_decoration.")
37 self.addOption ('containersFullMET', {}, type=None,
38 info="same as containers, but for MET containers that should be "
39 "saved with all terms (as opposed to just the final term). This "
40 "is useful for special studies. A container can appear both here and "
41 "in containers (with different prefixes).")
42 self.addOption ('containersOnlyForMC', {}, type=None,
43 info="same as containers, but for MC-only containers so as to avoid "
44 "a crash when running on data.")
45 self.addOption ('containersOnlyForDSIDs', {}, type=None,
46 info="specify which DSIDs are allowed to produce a given container. "
47 "This works like 'onlyForDSIDs': pass a list of DSIDs or regexps.")
48 self.addOption ('treeName', 'analysis', type=str,
49 info="name of the output TTree to save. The default is analysis.")
50 self.addOption ('streamName', 'ANALYSIS', type=str,
51 info="name of the output stream to save the tree in. "
52 "The default is ANALYSIS.")
53 self.addOption ('metTermName', 'Final', type=str,
54 info="the name (string) of the MET term to save, turning the MET "
55 "container into a single object. The default is 'Final'.")
56 self.addOption ('truthMetTermName', 'NonInt', type=str,
57 info="the name (string) of the truth MET term to save, turning the MET "
58 "container into a single object. The default is 'NonInt'.")
59 # TODO: add info strng
60 self.addOption ('storeSelectionFlags', True, type=bool,
61 info="")
62 # TODO: add info strng
63 self.addOption ('selectionFlagPrefix', 'select', type=str,
64 info="")
65 self.addOption ('commands', [], type=None,
66 info="a list of strings containing commands (regexp strings "
67 "prefaced by the keywords enable or disable) to turn on/off the "
68 "writing of branches to the output ntuple. The default is None "
69 "(no modification to the scheduled output branches).")
70 self.addOption ('commandsOnlyForDSIDs', {}, type=None,
71 info="a dictionary with individual DSIDs as keys, and a list of strings "
72 "like for the 'commands' option as items. These 'commands' will only be run "
73 "for the corresponding DSID.")
74 self.addOption ('alwaysAddNosys', False, type=bool,
75 info="If set to True, all branches will be given a systematics suffix, "
76 "even if they have no systematics (beyond the nominal).")
77 self.addOption ('skipRedundantSelectionFlags', True, type=bool,
78 info="remove the redundant 'outputSelect' branches created by the Thinning step. "
79 "These could however be used to simplify downstream workflows, as in Easyjet. "
80 "The default is True.")
81 # helper to protect for second pass
82 self.validated = False
83

Member Function Documentation

◆ branchSortOrder()

python.OutputAnalysisConfig.OutputAnalysisConfig.branchSortOrder ( rule)
static

Definition at line 91 of file OutputAnalysisConfig.py.

91 def branchSortOrder (rule):
92 return rule.split('->')[1].strip()
93

◆ createOutputAlgs()

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

Definition at line 94 of file OutputAnalysisConfig.py.

94 def createOutputAlgs (self, config, name, vars, isMet=False):
95 """A helper function to create output algorithm"""
96 alg = config.createAlgorithm('CP::AsgxAODMetNTupleMakerAlg' if isMet else 'CP::AsgxAODNTupleMakerAlg', name)
97 alg.TreeName = self.treeName
98 alg.RootStreamName = self.streamName
99 branchList = list(vars)
100 branchList.sort(key=self.branchSortOrder)
101 branchList_nosys = [branch for branch in branchList if "%SYS%" not in branch]
102 branchList_sys = [branch for branch in branchList if "%SYS%" in branch]
103 alg.Branches = branchList_nosys + branchList_sys
104 return alg
105

◆ 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 284 of file OutputAnalysisConfig.py.

284 def createSelectionFlagBranches(self, config):
285 """
286 For each container and for each selection, create a single pass variable in output NTuple,
287 which aggregates all the selections flag of the given selection. For example, this can include
288 pT, eta selections, some object ID selection, overlap removal, etc.
289 The goal is to have only one flag per object and working point in the output NTuple.
290 """
291 originalContainersSeen = []
292 for prefix in self.containers.keys() :
293 outputContainerName = self.containers[prefix]
294 containerName = config.getOutputContainerOrigin(outputContainerName)
295 if containerName in originalContainersSeen:
296 continue
297 else:
298 originalContainersSeen.append(containerName)
299
300 # EventInfo is one obvious example of a container that has no object selections
301 if containerName == 'EventInfo':
302 continue
303
304 selectionNames = config.getSelectionNames(containerName)
305 for selectionName in selectionNames:
306 # skip default selection
307 if selectionName == '':
308 continue
309 # skip selection coming from the Thinning block
310 if self.skipRedundantSelectionFlags and "outputSelect" in selectionName:
311 continue
312 self.makeSelectionSummaryAlg(config, containerName, selectionName)
313

◆ instanceName()

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

Definition at line 84 of file OutputAnalysisConfig.py.

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

◆ makeAlgs()

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

Definition at line 106 of file OutputAnalysisConfig.py.

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

◆ 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 314 of file OutputAnalysisConfig.py.

314 def makeSelectionSummaryAlg(self, config, containerName, selectionName):
315 """
316 Schedule an algorithm to pick up all cut flags for a given selectionName.
317 The summary selection flag is written to output as selectionFlagPrefix_selectionName.
318 """
319 alg = config.createAlgorithm( 'CP::AsgSelectionAlg',
320 f'ObjectSelectionSummary_{containerName}_{selectionName}')
321 selectionDecoration = f'baselineSelection_{selectionName}_%SYS%'
322 alg.selectionDecoration = f'{selectionDecoration},as_char'
323 alg.particles = config.readName (containerName)
324 alg.preselection = config.getFullSelection (containerName, selectionName)
325 config.addOutputVar (containerName, selectionDecoration, self.selectionFlagPrefix + '_' + selectionName)

Member Data Documentation

◆ alwaysAddNosys

python.OutputAnalysisConfig.OutputAnalysisConfig.alwaysAddNosys

Definition at line 254 of file OutputAnalysisConfig.py.

◆ commands

python.OutputAnalysisConfig.OutputAnalysisConfig.commands

Definition at line 194 of file OutputAnalysisConfig.py.

◆ containers

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

Definition at line 113 of file OutputAnalysisConfig.py.

◆ containersFullMET

python.OutputAnalysisConfig.OutputAnalysisConfig.containersFullMET

Definition at line 126 of file OutputAnalysisConfig.py.

◆ containersOnlyForDSIDs

python.OutputAnalysisConfig.OutputAnalysisConfig.containersOnlyForDSIDs

Definition at line 146 of file OutputAnalysisConfig.py.

◆ containersOnlyForMC

python.OutputAnalysisConfig.OutputAnalysisConfig.containersOnlyForMC

Definition at line 141 of file OutputAnalysisConfig.py.

◆ metVars

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

Definition at line 116 of file OutputAnalysisConfig.py.

◆ storeSelectionFlags

python.OutputAnalysisConfig.OutputAnalysisConfig.storeSelectionFlags

Definition at line 168 of file OutputAnalysisConfig.py.

◆ truthMetVars

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

Definition at line 117 of file OutputAnalysisConfig.py.

◆ validated

bool python.OutputAnalysisConfig.OutputAnalysisConfig.validated = False

Definition at line 82 of file OutputAnalysisConfig.py.

◆ vars

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

Definition at line 114 of file OutputAnalysisConfig.py.

◆ varsOnlyForMC

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

Definition at line 115 of file OutputAnalysisConfig.py.


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