3 import AnaAlgorithm.DualUseConfig
as DualUseConfig
4 from AthenaConfiguration.Enums
import LHCPeriod, FlagEnum
8 """holds the various data types as an enum"""
15 """all the data for a given selection that has been registered
17 the bits argument is for backward compatibility, does nothing, and will be
18 removed in the future."""
21 *, bits=0, preselection=None, comesFrom = '',
23 self.
name = selectionName
25 if preselection
is not None :
35 """all the data for a given variables in the output that has been registered"""
37 def __init__ (self, origContainerName, variableName,
48 """all the auto-generated meta-configuration data for a single container
50 This tracks the naming of all temporary containers, as well as all the
51 selection decorations."""
53 def __init__ (self, name, sourceName, *, originalName = None, noSysSuffix) :
68 raise Exception (
"should not get here, reading container name before created: " + self.
name)
76 """map an internal name to a name for systematics data handles
78 Right now this just means appending a _%SYS% to the name."""
80 return name +
"_%SYS%"
94 """a class that accumulates a configuration from blocks into an
97 This is used as argument to the ConfigurationBlock methods, which
98 need to be called in the correct order. This class will track all
99 meta-information that needs to be communicated between blocks
100 during configuration, and also add the created algorithms to the
103 Use/access of containers in the event store is handled via
104 references that this class hands out. This happens in a separate
105 step before the algorithms are created, as the naming of
106 containers will depend on where in the chain the container is
110 def __init__ (self, algSeq, dataType=None, isPhyslite=False, geometry=None, dsid=0,
111 campaign=None, runNumber=None, autoconfigFromFlags=None, noSysSuffix=False,
112 noSystematics=None, dataYear=0):
114 if autoconfigFromFlags
is not None:
115 if autoconfigFromFlags.Input.isMC:
116 if autoconfigFromFlags.Sim.ISF.Simulator.usesFastCaloSim():
117 dataType = DataType.FastSim
119 dataType = DataType.FullSim
121 dataType = DataType.Data
122 isPhyslite =
'StreamDAOD_PHYSLITE' in autoconfigFromFlags.Input.ProcessingTags
124 geometry = autoconfigFromFlags.GeoModel.Run
125 if dsid == 0
and dataType
is not DataType.Data:
126 dsid = autoconfigFromFlags.Input.MCChannelNumber
128 campaign = autoconfigFromFlags.Input.MCCampaign
129 if runNumber
is None:
130 runNumber =
int(autoconfigFromFlags.Input.RunNumbers[0])
132 dataYear = autoconfigFromFlags.Input.DataYear
133 generatorInfo = autoconfigFromFlags.Input.GeneratorsInfo
136 if isinstance(dataType, str):
138 dataType = DataType.FullSim
139 elif dataType ==
'afii':
140 dataType = DataType.FastSim
144 if runNumber
is None:
147 geometry = LHCPeriod(geometry)
148 if geometry
is LHCPeriod.Run1:
149 raise ValueError (
"invalid Run geometry: %s" % geometry.value)
176 if DualUseConfig.useComponentAccumulator:
177 from AthenaConfiguration.ComponentAccumulator
import ComponentAccumulator
182 self.
CA.addSequence(algSeq)
186 """noSystematics flag used by CommonServices block"""
190 """auto configuration flags"""
194 """the data type we run on (data, fullsim, fastsim)"""
198 """whether we run on PHYSLITE"""
202 """the LHC Run period we run on"""
206 """the mcChannelNumber or DSID of the sample we run on"""
210 """the MC campaign we run on"""
214 """the MC runNumber"""
218 """for data, the corresponding year; for MC, zero"""
222 """the dictionary of MC generators and their versions for the sample we run on"""
226 """create a new algorithm and register it as the current algorithm"""
229 raise Exception (
'duplicate algorithms: ' + name)
231 alg = DualUseConfig.createReentrantAlgorithm (type, name)
233 alg = DualUseConfig.createAlgorithm (type, name)
235 if DualUseConfig.useComponentAccumulator:
237 self.
CA.addEventAlgo(alg,self.
_algSeq.name)
239 self.
CA.addEventAlgo(alg)
247 raise Exception (
'unknown algorithm requested: ' + name)
250 raise Exception (
'change to algorithm object: ' + name)
255 '''create a new service and register it as the "current algorithm"'''
258 raise Exception (
'duplicate service: ' + name)
259 service = DualUseConfig.createService (type, name)
262 if DualUseConfig.isAthena:
263 if DualUseConfig.useComponentAccumulator:
264 self.
CA.addService(service)
273 raise Exception (
'unknown service requested: ' + name)
279 '''create a new public tool and register it as the "current algorithm"'''
282 raise Exception (
'duplicate public tool: ' + name)
283 tool = DualUseConfig.createPublicTool (type, name)
286 if DualUseConfig.isAthena:
287 if DualUseConfig.useComponentAccumulator:
288 self.
CA.addPublicTool(tool)
297 raise Exception (
'unknown public tool requested: ' + name)
303 """add a private tool to the current algorithm"""
305 DualUseConfig.addPrivateTool (self.
_currentAlg, propertyName, toolType)
309 *, originalName = None) :
310 """set the (default) name of the source/original container
312 This is essentially meant to allow using e.g. the muon
313 configuration and the user not having to manually specify that
314 they want to use the Muons/AnalysisMuons container from the
317 In addition it allows to set the original name of the
318 container (which may be different from the source name), which
319 is mostly/exclusively used for jet containers, so that
320 subsequent configurations know which jet container they
324 self.
_containerConfig[containerName] = ContainerConfig (containerName, sourceName, noSysSuffix = self.
_noSysSuffix, originalName = originalName)
328 """register that the given container will be made and return
333 raise Exception (
"trying to write container configured for input: " + containerName)
335 raise Exception (
"trying to write container twice: " + containerName)
337 if isMet
is not None :
343 """get the name of the "current copy" of the given container
345 As extra copies get created during processing this will track
346 the correct name of the current copy. Optionally one can pass
347 in the name of the container before the first copy.
350 raise Exception (
"no source container for: " + containerName)
355 """register that a copy of the container will be made and return
358 raise Exception (
"unknown container: " + containerName)
364 """ask whether we want/need a copy of the container
366 This usually only happens if no copy of the container has been
367 made yet and the copy is needed to allow modifications, etc.
370 raise Exception (
"no source container for: " + containerName)
375 """get the "original" name of the given container
377 This is mostly/exclusively used for jet containers, so that
378 subsequent configurations know which jet container they
382 raise Exception (
"container unknown: " + containerName)
385 raise Exception (
"no original name for: " + containerName)
390 """whether the given container is registered as a MET container
392 This is mostly/exclusively used for determining whether to
393 write out the whole container or just a single MET term.
396 raise Exception (
"container unknown: " + containerName)
401 """get the name of the "current copy" of the given container, and the
404 This is mostly meant for MET and OR for whom the actual object
405 selection is relevant, and which as such allow to pass in the
406 working point as "ObjectName.WorkingPoint".
408 split = containerName.split (
".")
410 objectName = split[0]
412 elif len(split) == 2 :
413 objectName = split[0]
414 selectionName = split[1]
416 raise Exception (
'invalid object selection name: ' + containerName)
421 """switch to the next configuration pass
423 Configuration happens in two steps, with all the blocks processed
424 twice. This switches from the first to the second pass.
427 raise Exception (
"already performed final pass")
437 """get the preselection string for the given selection on the given
441 raise ValueError (
'invalid selection name: ' + selectionName)
446 for selection
in config.selections :
447 if (selection.name ==
'' or selection.name == selectionName)
and \
448 selection.preselection :
449 decorations += [selection.decoration]
453 return '&&'.join (decorations)
457 *, skipBase = False, excludeFrom = None) :
459 """get the selection string for the given selection on the given
462 This can handle both individual selections or selection
463 expressions (e.g. `loose||tight`) with the later being
464 properly expanded. Either way the base selection (i.e. the
465 selection without a name) will always be applied on top.
467 containerName --- the container the selection is defined on
468 selectionName --- the name of the selection, or a selection
469 expression based on multiple named selections
470 skipBase --- will avoid the base selection, and should normally
471 not be used by the end-user.
472 excludeFrom --- a set of string names of selection sources to exclude
473 e.g. to exclude OR selections from MET
478 if excludeFrom
is None :
480 elif not isinstance(excludeFrom, set) :
481 raise ValueError (
'invalid excludeFrom argument (need set of strings): ' +
str(excludeFrom))
488 if selectionName !=
'' and \
491 while selectionName !=
'' :
494 result += selectionName[0]
495 selectionName = selectionName[1:]
497 subname = match.group(0)
498 subresult = self.
getFullSelection (containerName, subname, skipBase =
True, excludeFrom=excludeFrom)
500 result +=
'(' + subresult +
')'
503 selectionName = selectionName[len(subname):]
504 subresult = self.
getFullSelection (containerName,
'', excludeFrom=excludeFrom)
506 result = subresult +
'&&(' + result +
')'
511 hasSelectionName =
False
512 for selection
in config.selections :
513 if ((selection.name ==
'' and not skipBase)
or selection.name == selectionName)
and (selection.comesFrom
not in excludeFrom) :
514 decorations += [selection.decoration]
515 if selection.name == selectionName :
516 hasSelectionName =
True
517 if not hasSelectionName
and selectionName !=
'' :
518 raise KeyError (
'invalid selection name: ' + containerName +
'.' + selectionName)
519 return '&&'.join (decorations)
524 """get the individual selections as a list for producing the cutflow for
525 the given selection on the given container
527 This can only handle individual selections, not selection
528 expressions (e.g. `loose||tight`).
539 if selectionName !=
'' and \
541 raise ValueError (
'not allowed to do cutflow on selection expression: ' + selectionName)
545 for selection
in config.selections :
546 if (selection.name ==
'' or selection.name == selectionName) :
547 decorations += [selection.decoration]
553 """register a new event cutflow, adding it to the dictionary with key 'selection'
554 and value 'decorations', a list of decorated selections
558 raise ValueError (
'the event cutflow dictionary already contains an entry ' + selection)
565 """get the list of decorated selections for an event cutflow, corresponding to
573 """add another selection decoration to the selection of the given
574 name for the given container"""
576 raise ValueError (
'invalid selection name: ' + selectionName)
580 selection = SelectionConfig (selectionName, decoration, **kwargs)
581 config.selections.append (selection)
585 """register a copy of a container used in outputs"""
587 raise KeyError (
"container unknown: " + containerName)
589 raise KeyError (
"duplicate output container name: " + outputContainerName)
594 """Get the name of the actual container, for which an output is registered"""
601 raise KeyError (
"output container unknown: " + outputContainerName)
605 *, noSys=False, enabled=True) :
606 """add an output variable for the given container to the output
610 raise KeyError (
"container unknown: " + containerName)
612 if outputName
in baseConfig :
613 raise KeyError (
"duplicate output variable name: " + outputName)
614 config = OutputConfig (containerName, variableName, noSys=noSys, enabled=enabled)
615 baseConfig[outputName] = config
619 """get the output variables for the given container"""
623 raise KeyError (
"unknown container for output: " + containerName)
628 """Retrieve set of unique selections defined for a given container"""
634 selectionNames =
set()
635 for selection
in config.selections:
637 if selection.writeToOutput:
638 selectionNames.add(selection.name)
639 return selectionNames