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