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