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, calibMode = None, isMet = False, noSysSuffix) :
69 raise Exception (
"should not get here, reading container name before created: " + self.
name)
77 """map an internal name to a name for systematics data handles
79 Right now this just means appending a _%SYS% to the name."""
81 return name +
"_%SYS%"
95 """a class that accumulates a configuration from blocks into an
98 This is used as argument to the ConfigurationBlock methods, which
99 need to be called in the correct order. This class will track all
100 meta-information that needs to be communicated between blocks
101 during configuration, and also add the created algorithms to the
104 Use/access of containers in the event store is handled via
105 references that this class hands out. This happens in a separate
106 step before the algorithms are created, as the naming of
107 containers will depend on where in the chain the container is
111 def __init__ (self, algSeq, dataType=None, isPhyslite=False, geometry=None, dsid=0,
112 campaign=None, runNumber=None, autoconfigFromFlags=None, noSysSuffix=False,
113 noSystematics=None, dataYear=0):
115 if autoconfigFromFlags
is not None:
116 if autoconfigFromFlags.Input.isMC:
117 if autoconfigFromFlags.Sim.ISF.Simulator.usesFastCaloSim():
118 dataType = DataType.FastSim
120 dataType = DataType.FullSim
122 dataType = DataType.Data
123 isPhyslite =
'StreamDAOD_PHYSLITE' in autoconfigFromFlags.Input.ProcessingTags
125 geometry = autoconfigFromFlags.GeoModel.Run
126 if dsid == 0
and dataType
is not DataType.Data:
127 dsid = autoconfigFromFlags.Input.MCChannelNumber
129 campaign = autoconfigFromFlags.Input.MCCampaign
130 if runNumber
is None:
131 runNumber =
int(autoconfigFromFlags.Input.RunNumbers[0])
133 dataYear = autoconfigFromFlags.Input.DataYear
134 generatorInfo = autoconfigFromFlags.Input.GeneratorsInfo
135 from TrigDecisionTool.TrigDecisionToolHelpers
import (
136 getRun3NavigationContainerFromInput_forAnalysisBase)
140 if isinstance(dataType, str):
142 dataType = DataType.FullSim
143 elif dataType ==
'afii':
144 dataType = DataType.FastSim
148 hltSummary =
'HLTNav_Summary_DAODSlimmed'
149 if runNumber
is None:
152 geometry = LHCPeriod(geometry)
153 if geometry
is LHCPeriod.Run1:
154 raise ValueError (
"invalid Run geometry: %s" % geometry.value)
181 if DualUseConfig.useComponentAccumulator:
182 from AthenaConfiguration.ComponentAccumulator
import ComponentAccumulator
187 self.
CA.addSequence(algSeq)
191 """noSystematics flag used by CommonServices block"""
195 """auto configuration flags"""
199 """the data type we run on (data, fullsim, fastsim)"""
203 """whether we run on PHYSLITE"""
207 """the LHC Run period we run on"""
211 """the mcChannelNumber or DSID of the sample we run on"""
215 """the MC campaign we run on"""
219 """the MC runNumber"""
223 """for data, the corresponding year; for MC, zero"""
227 """the dictionary of MC generators and their versions for the sample we run on"""
231 """the HLTSummary configuration to be used for the trigger decision tool"""
235 """create a new algorithm and register it as the current algorithm"""
238 raise Exception (
'duplicate algorithms: ' + name)
240 alg = DualUseConfig.createReentrantAlgorithm (type, name)
242 alg = DualUseConfig.createAlgorithm (type, name)
244 if DualUseConfig.useComponentAccumulator:
246 self.
CA.addEventAlgo(alg,self.
_algSeq.name)
248 self.
CA.addEventAlgo(alg)
256 raise Exception (
'unknown algorithm requested: ' + name)
259 raise Exception (
'change to algorithm object: ' + name)
264 '''create a new service and register it as the "current algorithm"'''
267 raise Exception (
'duplicate service: ' + name)
268 service = DualUseConfig.createService (type, name)
271 if DualUseConfig.isAthena:
272 if DualUseConfig.useComponentAccumulator:
273 self.
CA.addService(service)
282 raise Exception (
'unknown service requested: ' + name)
288 '''create a new public tool and register it as the "current algorithm"'''
291 raise Exception (
'duplicate public tool: ' + name)
292 tool = DualUseConfig.createPublicTool (type, name)
295 if DualUseConfig.isAthena:
296 if DualUseConfig.useComponentAccumulator:
297 self.
CA.addPublicTool(tool)
306 raise Exception (
'unknown public tool requested: ' + name)
312 """add a private tool to the current algorithm"""
314 DualUseConfig.addPrivateTool (self.
_currentAlg, propertyName, toolType)
318 *, originalName = None, calibMode = None, isMet = False) :
319 """set the (default) name of the source/original container
321 This is essentially meant to allow using e.g. the muon
322 configuration and the user not having to manually specify that
323 they want to use the Muons/AnalysisMuons container from the
326 In addition it allows to set the original name of the
327 container (which may be different from the source name), which
328 is mostly/exclusively used for jet containers, so that
329 subsequent configurations know which jet container they
332 CalibMode can also be configured to pass it down to some algs which use this
333 information to be configured, like the METSignificance
336 self.
_containerConfig[containerName] = ContainerConfig (containerName, sourceName, noSysSuffix = self.
_noSysSuffix, originalName = originalName, calibMode = calibMode, isMet = isMet)
340 """register that the given container will be made and return
345 raise Exception (
"trying to write container configured for input: " + containerName)
347 raise Exception (
"trying to write container twice: " + containerName)
349 if isMet
is not None :
355 """get the name of the "current copy" of the given container
357 As extra copies get created during processing this will track
358 the correct name of the current copy. Optionally one can pass
359 in the name of the container before the first copy.
362 raise Exception (
"no source container for: " + containerName)
367 """register that a copy of the container will be made and return
370 raise Exception (
"unknown container: " + containerName)
376 """ask whether we want/need a copy of the container
378 This usually only happens if no copy of the container has been
379 made yet and the copy is needed to allow modifications, etc.
382 raise Exception (
"no source container for: " + containerName)
387 """get the "original" name of the given container
389 This is mostly/exclusively used for jet containers, so that
390 subsequent configurations know which jet container they
394 raise Exception (
"container unknown: " + containerName)
397 raise Exception (
"no original name for: " + containerName)
401 """get the calibration mode of the given container
404 raise Exception (
"container unknown: " + containerName)
407 raise Exception (
"no calibration mode for: " + containerName)
411 """whether the given container is registered as a MET container
413 This is mostly/exclusively used for determining whether to
414 write out the whole container or just a single MET term.
417 raise Exception (
"container unknown: " + containerName)
422 """get the name of the "current copy" of the given container, and the
425 This is mostly meant for MET and OR for whom the actual object
426 selection is relevant, and which as such allow to pass in the
427 working point as "ObjectName.WorkingPoint".
429 split = containerName.split (
".")
431 objectName = split[0]
433 elif len(split) == 2 :
434 objectName = split[0]
435 selectionName = split[1]
437 raise Exception (
'invalid object selection name: ' + containerName)
442 """switch to the next configuration pass
444 Configuration happens in two steps, with all the blocks processed
445 twice. This switches from the first to the second pass.
448 raise Exception (
"already performed final pass")
458 """get the preselection string for the given selection on the given
462 raise ValueError (
'invalid selection name: ' + selectionName)
467 for selection
in config.selections :
468 if (selection.name ==
'' or selection.name == selectionName)
and \
469 selection.preselection :
470 decorations += [selection.decoration]
474 return '&&'.join (decorations)
478 *, skipBase = False, excludeFrom = None) :
480 """get the selection string for the given selection on the given
483 This can handle both individual selections or selection
484 expressions (e.g. `loose||tight`) with the later being
485 properly expanded. Either way the base selection (i.e. the
486 selection without a name) will always be applied on top.
488 containerName --- the container the selection is defined on
489 selectionName --- the name of the selection, or a selection
490 expression based on multiple named selections
491 skipBase --- will avoid the base selection, and should normally
492 not be used by the end-user.
493 excludeFrom --- a set of string names of selection sources to exclude
494 e.g. to exclude OR selections from MET
499 if excludeFrom
is None :
501 elif not isinstance(excludeFrom, set) :
502 raise ValueError (
'invalid excludeFrom argument (need set of strings): ' +
str(excludeFrom))
509 if selectionName !=
'' and \
512 while selectionName !=
'' :
515 result += selectionName[0]
516 selectionName = selectionName[1:]
518 subname = match.group(0)
519 subresult = self.
getFullSelection (containerName, subname, skipBase =
True, excludeFrom=excludeFrom)
521 result +=
'(' + subresult +
')'
524 selectionName = selectionName[len(subname):]
525 subresult = self.
getFullSelection (containerName,
'', excludeFrom=excludeFrom)
527 result = subresult +
'&&(' + result +
')'
532 hasSelectionName =
False
533 for selection
in config.selections :
534 if ((selection.name ==
'' and not skipBase)
or selection.name == selectionName)
and (selection.comesFrom
not in excludeFrom) :
535 decorations += [selection.decoration]
536 if selection.name == selectionName :
537 hasSelectionName =
True
538 if not hasSelectionName
and selectionName !=
'' :
539 raise KeyError (
'invalid selection name: ' + containerName +
'.' + selectionName)
540 return '&&'.join (decorations)
545 """get the individual selections as a list for producing the cutflow for
546 the given selection on the given container
548 This can only handle individual selections, not selection
549 expressions (e.g. `loose||tight`).
560 if selectionName !=
'' and \
562 raise ValueError (
'not allowed to do cutflow on selection expression: ' + selectionName)
566 for selection
in config.selections :
567 if (selection.name ==
'' or selection.name == selectionName) :
568 decorations += [selection.decoration]
574 """register a new event cutflow, adding it to the dictionary with key 'selection'
575 and value 'decorations', a list of decorated selections
579 raise ValueError (
'the event cutflow dictionary already contains an entry ' + selection)
586 """get the list of decorated selections for an event cutflow, corresponding to
594 """add another selection decoration to the selection of the given
595 name for the given container"""
597 raise ValueError (
'invalid selection name: ' + selectionName)
601 selection = SelectionConfig (selectionName, decoration, **kwargs)
602 config.selections.append (selection)
606 """register a copy of a container used in outputs"""
608 raise KeyError (
"container unknown: " + containerName)
610 raise KeyError (
"duplicate output container name: " + outputContainerName)
615 """Get the name of the actual container, for which an output is registered"""
622 raise KeyError (
"output container unknown: " + outputContainerName)
626 *, noSys=False, enabled=True) :
627 """add an output variable for the given container to the output
631 raise KeyError (
"container unknown: " + containerName)
633 if outputName
in baseConfig :
634 raise KeyError (
"duplicate output variable name: " + outputName)
635 config = OutputConfig (containerName, variableName, noSys=noSys, enabled=enabled)
636 baseConfig[outputName] = config
640 """get the output variables for the given container"""
644 raise KeyError (
"unknown container for output: " + containerName)
649 """Retrieve set of unique selections defined for a given container"""
652 if excludeFrom
is None:
654 elif not isinstance(excludeFrom, set) :
655 raise ValueError (
'invalid excludeFrom argument (need set of strings): ' +
str(excludeFrom))
660 selectionNames =
set()
661 for selection
in config.selections:
662 if selection.comesFrom
in excludeFrom:
665 if selection.writeToOutput:
666 selectionNames.add(selection.name)
667 return selectionNames