diff --git a/Trigger/TrigSteer/DecisionHandling/python/DecisionHandlingConfig.py b/Trigger/TrigSteer/DecisionHandling/python/DecisionHandlingConfig.py index dc8d10cb461cef4e3c7334f6ee9ce2bc3f59a54c..41494be3c87d618e92bcae5299419e6e93416337 100644 --- a/Trigger/TrigSteer/DecisionHandling/python/DecisionHandlingConfig.py +++ b/Trigger/TrigSteer/DecisionHandling/python/DecisionHandlingConfig.py @@ -1,7 +1,7 @@ # # Copyright (C) 2002-2023 CERN for the benefit of the ATLAS collaboration # - +from AthenaConfiguration.ComponentFactory import CompFactory EnableFilterMonitoring = False # Can be changed in a precommand/preExec def setupFilterMonitoring( flags, filterAlg ): @@ -31,7 +31,7 @@ def TriggerSummaryAlg( flags, name ): alg.MonTool = monTool return alg -def ComboHypoCfg( name ): - from DecisionHandling.DecisionHandlingConf import ComboHypo - alg = ComboHypo( name ) +def ComboHypoCfg( name ): + alg = CompFactory.ComboHypo( name ) return alg + diff --git a/Trigger/TriggerCommon/TriggerJobOpts/python/TriggerConfig.py b/Trigger/TriggerCommon/TriggerJobOpts/python/TriggerConfig.py index af6eb9c4cca7e8f7c728351d8068a032db8f195d..e1d41ea18badf22b9c8ff8b51980262f18d988b1 100644 --- a/Trigger/TriggerCommon/TriggerJobOpts/python/TriggerConfig.py +++ b/Trigger/TriggerCommon/TriggerJobOpts/python/TriggerConfig.py @@ -10,6 +10,7 @@ from AthenaCommon.Logging import logging from .TriggerRecoConfig import TriggerMetadataWriterCfg __log = logging.getLogger('TriggerConfig') + def __isCombo(alg): return hasProp( alg, "MultiplicitiesMap" ) @@ -40,7 +41,7 @@ def collectHypos( steps ): __log.debug( "collecting hypos from step %s", stepSeq.getName() ) # start = {} for seq,algs in flatAlgorithmSequences(stepSeq).items(): - for alg in sorted(algs, key=lambda t: str(t.name)): + for alg in sorted(algs, key=lambda t: str(t.getName())): if isSequence( alg ): continue # will replace by function once dependencies are sorted @@ -196,7 +197,7 @@ def triggerSummaryCfg(flags, hypos): hypoChains, hypoOutputKeys = __decisionsFromHypo( hypo ) for chain in hypoChains: if chain not in chainToCollectionInStep: - chainToCollectionInStep[chain] = hypoOutputKeys + chainToCollectionInStep[chain] = hypoOutputKeys chainToLastCollection.update( chainToCollectionInStep ) from TriggerMenuMT.HLT.Config.Utility.HLTMenuConfig import HLTMenuConfig @@ -629,6 +630,10 @@ def triggerRunCfg( flags, menu=None ): acc.addSequence( parOR("HLTEndSeq"), parentName="HLTTop" ) acc.addSequence( seqAND("HLTFinalizeSeq"), parentName="HLTEndSeq" ) + nfilters = sum(len(v) for v in filters.values()) + nhypos = sum(len(v) for v in hypos.values()) + __log.info( "Algorithms counting: Number of Filter algorithms: %d - Number of Hypo algoirthms: %d", nfilters , nhypos) + summaryAcc, summaryAlg = triggerSummaryCfg( flags, hypos ) acc.merge( summaryAcc, sequenceName="HLTFinalizeSeq" ) acc.addEventAlgo( summaryAlg, sequenceName="HLTFinalizeSeq" ) diff --git a/Trigger/TriggerCommon/TriggerJobOpts/python/runHLT_standalone_newJO.py b/Trigger/TriggerCommon/TriggerJobOpts/python/runHLT_standalone_newJO.py index c59fc8d4d933d9fef33e77a423d70627afb7b868..3bcc61ed82dc4616f129d1bb293b58549554a88e 100755 --- a/Trigger/TriggerCommon/TriggerJobOpts/python/runHLT_standalone_newJO.py +++ b/Trigger/TriggerCommon/TriggerJobOpts/python/runHLT_standalone_newJO.py @@ -3,7 +3,6 @@ # # Copyright (C) 2002-2022 CERN for the benefit of the ATLAS collaboration # - from AthenaCommon.Logging import logging log = logging.getLogger('runHLT_standalone_newJO') @@ -55,6 +54,8 @@ flags.addFlag("Trigger.disableChains",[]) flags.Trigger.enabledSignatures = ['Muon', 'Photon','Electron'] +#flags.Trigger.selectChains = ['HLT_mu4_L1MU3V','HLT_mu8_L1MU5VF','HLT_2mu6_L12MU5VF', 'HLT_mu24_mu6_L1MU14FCH','HLT_mu24_mu6_probe_L1MU14FCH'] #, 'HLT_mu4_mu6_L12MU3V'] + #flags.Trigger.disableChains=["HLT_2mu4_l2io_invmDimu_L1BPH-2M9-0DR15-2MU3VF", "HLT_2mu4_l2io_invmDimu_L1BPH-2M9-0DR15-2MU3V", "HLT_2mu6_l2io_invmDimu_L1BPH-2M9-2DR15-2MU5VF"] # exclude jets for now, since their MenuSeuqnece Structure needs more work to migrate @@ -93,10 +94,9 @@ flags.lock() flags.dump() # Enable when debugging deduplication issues # ComponentAccumulator.debugMode = "trackCA trackEventAlog ... and so on" - +log.setLevel(logging.DEBUG) acc = MainServicesCfg(flags) - acc.getService('AvalancheSchedulerSvc').VerboseSubSlots = True # this delcares to the scheduler that EventInfo object comes from the input diff --git a/Trigger/TriggerCommon/TriggerMenuMT/CMakeLists.txt b/Trigger/TriggerCommon/TriggerMenuMT/CMakeLists.txt index 0b94cb99cd71a8e91819138119bd514b6457f242..c448d4d9affed7cacd94183f802f9d1d404c5d7e 100644 --- a/Trigger/TriggerCommon/TriggerMenuMT/CMakeLists.txt +++ b/Trigger/TriggerCommon/TriggerMenuMT/CMakeLists.txt @@ -19,6 +19,7 @@ atlas_install_scripts( scripts/generateL1MenuRun3.py scripts/runTriggerAPIExample.py scripts/generateUnprescaledLists.py scripts/test_menu_dump.py + scripts/test_menu_CA.py POST_BUILD_CMD ${ATLAS_FLAKE8} ) # Shell scripts without flake8 checking: @@ -114,6 +115,14 @@ atlas_add_test(generateMenuMT_newJO PROPERTIES TIMEOUT 500 POST_EXEC_SCRIPT noerror.sh ) +atlas_add_test( test_menu_CA + SCRIPT test_menu_CA.py + PRIVATE_WORKING_DIRECTORY + PROPERTIES TIMEOUT 500 + POST_EXEC_SCRIPT "check_log.py --errors --config checklogTriggerTest.conf ${CMAKE_CURRENT_BINARY_DIR}${CMAKE_FILES_DIRECTORY}/unitTestRun_test_menu_CA/test_menu_CA.log" + ) + + # test for menu name consistency atlas_add_test( test_menu_dump SCRIPT test_menu_dump.py -p diff --git a/Trigger/TriggerCommon/TriggerMenuMT/python/CFtest/test_menu_cf_newJO.py b/Trigger/TriggerCommon/TriggerMenuMT/python/CFtest/test_menu_cf_newJO.py index bc775a776b3c4f75de4697c6a9e88dc272696804..de06371a9726506b4540d87e4eea7a55b6676132 100644 --- a/Trigger/TriggerCommon/TriggerMenuMT/python/CFtest/test_menu_cf_newJO.py +++ b/Trigger/TriggerCommon/TriggerMenuMT/python/CFtest/test_menu_cf_newJO.py @@ -98,7 +98,7 @@ def generateEmuMenu(ConfigFlags): import TriggerMenuMT.HLT.Config.ControlFlow.HLTCFConfig_newJO # set DEBUG flag on the control-flow builder (before building) TriggerMenuMT.HLT.Config.ControlFlow.HLTCFConfig_newJO.log.setLevel(DEBUG) - menuAcc = generateDecisionTree(ConfigFlags, HLTMenuConfig.configsList()) + menuAcc = generateDecisionTree(ConfigFlags, HLTMenuConfig) menuAcc.wasMerged() menuAcc.printConfig() diff --git a/Trigger/TriggerCommon/TriggerMenuMT/python/HLT/CommonSequences/EventBuildingSequences.py b/Trigger/TriggerCommon/TriggerMenuMT/python/HLT/CommonSequences/EventBuildingSequences.py index b35e9bf13ae62c9590790c960425169a2ada7344..a656d74d8ab69f7da96af9c630a648c9969e296e 100644 --- a/Trigger/TriggerCommon/TriggerMenuMT/python/HLT/CommonSequences/EventBuildingSequences.py +++ b/Trigger/TriggerCommon/TriggerMenuMT/python/HLT/CommonSequences/EventBuildingSequences.py @@ -47,7 +47,7 @@ def addEventBuildingSequence(flags, chain, eventBuildType, chainDict): chainDicts=[chainDict]) else: # standard PEB chain - prevStep = chain.steps[-1] + prevStep = chain.steps[-1] step_name = 'Step_merged{:s}_PEBInfoWriter_{:s}'.format(prevStep.name, eventBuildType) step = ChainStep(name=step_name, Sequences=[seq for leg in prevStep.legIds], diff --git a/Trigger/TriggerCommon/TriggerMenuMT/python/HLT/CommonSequences/TLABuildingSequences.py b/Trigger/TriggerCommon/TriggerMenuMT/python/HLT/CommonSequences/TLABuildingSequences.py index 24e70adb9a9dc7ad7a1853905b6a4c212af45e3f..143d45c6000cdc30bdf8d1d99260272eccf54fdd 100644 --- a/Trigger/TriggerCommon/TriggerMenuMT/python/HLT/CommonSequences/TLABuildingSequences.py +++ b/Trigger/TriggerCommon/TriggerMenuMT/python/HLT/CommonSequences/TLABuildingSequences.py @@ -10,7 +10,6 @@ from TriggerMenuMT.HLT.Config.ControlFlow.HLTCFTools import NoCAmigration log = logging.getLogger(__name__) - def addTLAStep(chain, chainDict): ''' Add one extra chain step for TLA Activities @@ -26,7 +25,7 @@ def addTLAStep(chain, chainDict): # call the sequence from their respective signatures tlaSequencesList.append(getTLASignatureSequence(ConfigFlags, chainDict=chainDict, chainPart=cPart)), #signature=cPart['signature'])), - log.debug("addTLAStep: About to add a step with: %d, parallel sequences.", len(tlaSequencesList)) + log.debug("addTLAStep: About to add a step with: %d parallel sequences.", len(tlaSequencesList)) # we add one step per TLA chain, with sequences matching the list of signatures # and multiplicities matching those of the previous step of the chain (already merged if combined) diff --git a/Trigger/TriggerCommon/TriggerMenuMT/python/HLT/Config/ChainConfigurationBase.py b/Trigger/TriggerCommon/TriggerMenuMT/python/HLT/Config/ChainConfigurationBase.py index 13e9f36712cdc8ed4b103ebe13bd2c28ad9603e2..cd5979995abc8aaefd2ab86864de122f868690f6 100644 --- a/Trigger/TriggerCommon/TriggerMenuMT/python/HLT/Config/ChainConfigurationBase.py +++ b/Trigger/TriggerCommon/TriggerMenuMT/python/HLT/Config/ChainConfigurationBase.py @@ -4,7 +4,6 @@ from AthenaCommon.Logging import logging log = logging.getLogger(__name__) - import abc from TriggerMenuMT.HLT.Config.MenuComponents import Chain, ChainStep, RecoFragmentsPool from DecisionHandling.DecisionHandlingConfig import ComboHypoCfg diff --git a/Trigger/TriggerCommon/TriggerMenuMT/python/HLT/Config/ControlFlow/HLTCFComponents.py b/Trigger/TriggerCommon/TriggerMenuMT/python/HLT/Config/ControlFlow/HLTCFComponents.py index 07c62d358778ff252e297e35a807655aa6b2de6e..045b576e0c1157cd2fa7b22a562a2ba3152d5806 100644 --- a/Trigger/TriggerCommon/TriggerMenuMT/python/HLT/Config/ControlFlow/HLTCFComponents.py +++ b/Trigger/TriggerCommon/TriggerMenuMT/python/HLT/Config/ControlFlow/HLTCFComponents.py @@ -2,37 +2,21 @@ from TriggerMenuMT.HLT.Config.MenuComponents import AlgNode from TriggerMenuMT.HLT.Config.ControlFlow.MenuComponentsNaming import CFNaming - -from AthenaCommon.CFElements import compName +from TriggerMenuMT.HLT.Config.Utility.HLTMenuConfig import HLTMenuConfig +from TriggerMenuMT.HLT.Config.ControlFlow.HLTCFTools import isComboHypoAlg +from AthenaConfiguration.ComponentAccumulator import ComponentAccumulator +from AthenaConfiguration.ComponentFactory import CompFactory +from AthenaCommon.CFElements import compName, findAlgorithmByPredicate, parOR, seqAND +from functools import lru_cache from AthenaCommon.Logging import logging log = logging.getLogger( __name__ ) -from AthenaConfiguration.ComponentFactory import CompFactory + RoRSeqFilter = CompFactory.RoRSeqFilter PassFilter = CompFactory.PassFilter -class HypoToolConf(object): - """ Class to group info on hypotools for ChainDict""" - def __init__(self, hypoToolGen): - self.hypoToolGen = hypoToolGen - self.name=hypoToolGen.__name__ - - def setConf( self, chainDict): - if type(chainDict) is not dict: - raise RuntimeError("Configuring hypo with %s, not good anymore, use chainDict" % str(chainDict) ) - self.chainDict = chainDict - - def create(self): - """creates instance of the hypo tool""" - return self.hypoToolGen( self.chainDict ) - - def confAndCreate(self, chainDict): - """sets the configuration and creates instance of the hypo tool""" - self.setConf(chainDict) - return self.create() - class SequenceFilterNode(AlgNode): """Node for any kind of sequence filter""" def __init__(self, Alg, inputProp, outputProp): @@ -50,11 +34,12 @@ class SequenceFilterNode(AlgNode): def __repr__(self): return "SequenceFilter::%s [%s] -> [%s], chains=%s"%(compName(self.Alg),' '.join(map(str, self.getInputList())),' '.join(map(str, self.getOutputList())), self.getChains()) - class RoRSequenceFilterNode(SequenceFilterNode): - def __init__(self, name): - Alg= RoRSeqFilter(name) + def __init__(self, name): + Alg= RoRSeqFilter(name) SequenceFilterNode.__init__(self, Alg, 'Input', 'Output') + self.resetInput() + self.resetOutput() ## why do we need this in CA mode?? def addChain(self, name, input_name): input_index = self.readInputList().index(input_name) @@ -77,13 +62,27 @@ class RoRSequenceFilterNode(SequenceFilterNode): return self.getPar("ChainsPerInput") -from AthenaCommon.AlgSequence import AthSequencer + class PassFilterNode(SequenceFilterNode): """ PassFilter is a Filter node without inputs/outputs, so OutputProp=InputProp=empty""" def __init__(self, name): - Alg=AthSequencer( "PassSequence" ) + Alg=CompFactory.AthSequencer( "PassSequence" ) Alg.IgnoreFilterPassed=True # always pass SequenceFilterNode.__init__(self, Alg, '', '') + + def addOutput(self, name): + self.outputs.append(str(name)) + + def addInput(self, name): + self.inputs.append(str(name)) + + def getOutputList(self): + return self.outputs + + def getInputList(self): + return self.inputs + + ######################################################### @@ -96,19 +95,19 @@ class CFSequence(object): def __init__(self, ChainStep, FilterAlg): self.filter = FilterAlg self.step = ChainStep + self.combo = ChainStep.combo #copy this instance self.connectCombo() - self.setDecisions() + self.setDecisions() log.debug("CFSequence.__init: created %s ",self) def setDecisions(self): """ Set the output decision of this CFSequence as the hypo outputdecision; In case of combo, takes the Combo outputs""" self.decisions=[] # empty steps: - if self.step.combo is None: + if self.combo is None: self.decisions.extend(self.filter.getOutputList()) else: - self.decisions.extend(self.step.combo.getOutputList()) - + self.decisions.extend(self.combo.getOutputList()) log.debug("CFSequence: set out decisions: %s", self.decisions) @@ -141,24 +140,76 @@ class CFSequence(object): def connectCombo(self): """ connect Combo to Hypos""" - if self.step.combo is None: + if self.combo is None: return for seq in self.step.sequences: combo_input=seq.getOutputList()[0] - self.step.combo.addInput(combo_input) - inputs = self.step.combo.readInputList() + self.combo.addInput(combo_input) + inputs = self.combo.readInputList() legindex = inputs.index(combo_input) - log.debug("CFSequence.connectCombo: adding input to %s: %s", self.step.combo.Alg.getName(), combo_input) + log.debug("CFSequence.connectCombo: adding input to %s: %s", self.combo.Alg.getName(), combo_input) # inputs are the output decisions of the hypos of the sequences - combo_output=CFNaming.comboHypoOutputName (self.step.combo.Alg.getName(), legindex) - self.step.combo.addOutput(combo_output) - log.debug("CFSequence.connectCombo: adding output to %s: %s", self.step.combo.Alg.getName(), combo_output) + combo_output=CFNaming.comboHypoOutputName (self.combo.Alg.getName(), legindex) + self.combo.addOutput(combo_output) + log.debug("CFSequence.connectCombo: adding output to %s: %s", self.combo.Alg.getName(), combo_output) + + + def createHypoTools(self, chain, newstep): + """ set and create HypoTools accumulated on the self.step from an input step configuration + """ + if self.step.combo is None: + return + assert len(newstep.sequences) == len(self.step.sequences), f'Trying to add HypoTools from new step {newstep.name}, which differ in number of sequences' + assert len(self.step.sequences) == len(newstep.stepDicts), f'The number of sequences of step {self.step.name} ({len(self.step.sequences)}) differ from the number of dictionaries in the chain {len(newstep.stepDicts)}' + + log.debug("createHypoTools for Step %s", newstep.name) + log.debug('from chain %s with step mult= %d', chain, sum(newstep.multiplicity)) + log.debug("N(seq)=%d, N(chainDicts)=%d", len(newstep.sequences), len(newstep.stepDicts)) + + for seq, myseq, onePartChainDict in zip(newstep.sequences, self.step.sequences, newstep.stepDicts): + log.debug(' seq: %s, onePartChainDict:', seq.name) + log.debug(' %s', onePartChainDict) + hypoToolConf=seq.getHypoToolConf() + if hypoToolConf is not None: # avoid empty sequences + hypoToolConf.setConf( onePartChainDict ) + myseq.hypo.addHypoTool(hypoToolConf) #this creates the HypoTools + chainDict = HLTMenuConfig.getChainDictFromChainName(chain) + self.combo.createComboHypoTools(chainDict, newstep.comboToolConfs) def __repr__(self): return "--- CFSequence ---\n + Filter: %s \n + decisions: %s\n + %s \n"%(\ - self.filter.Alg.getName(), self.decisions, self.step) + compName(self.filter.Alg), self.decisions, self.step) +class CFSequenceCA(CFSequence): + """Class to describe the flow of decisions through ChainStep + filter with their connections (input, output) + A Filter can have more than one input/output if used in different chains, so this class stores and manages all of them (when doing the connect) + """ + def __init__(self, ChainStep, FilterAlg): + log.debug(" *** Create CFSequence %s with Filter %s", ChainStep.name, FilterAlg.Alg.getName()) + self.ca = ComponentAccumulator() + self.empty= ChainStep.isEmpty + #empty step: add the PassSequence, one instance only is appended to the tree + seqAndWithFilter = FilterAlg.Alg if self.empty else seqAND(ChainStep.name) + self.ca.addSequence(seqAndWithFilter) + self.seq = seqAndWithFilter + if not self.empty: + self.ca.addEventAlgo(FilterAlg.Alg, sequenceName=seqAndWithFilter.getName()) + stepReco = parOR(ChainStep.name + CFNaming.RECO_POSTFIX) # all reco algorithms from all the sequences in a parallel sequence + self.ca.addSequence(stepReco, parentName=seqAndWithFilter.getName()) + log.info("created parOR %s inside seqAND %s ", stepReco.getName(), seqAndWithFilter.getName()) + for menuseq in ChainStep.sequences: + self.ca.merge(menuseq.ca, sequenceName=stepReco.getName()) + + CFSequence.__init__(self, ChainStep,FilterAlg) + if self.combo is not None: + self.ca.addEventAlgo(self.step.combo.Alg, sequenceName=seqAndWithFilter.getName()) + + @lru_cache(None) + def findComboHypoAlg(self): + return findAlgorithmByPredicate(self.seq, lambda alg: compName(alg) == self.step.Alg.getName() and isComboHypoAlg(alg)) + + \ No newline at end of file diff --git a/Trigger/TriggerCommon/TriggerMenuMT/python/HLT/Config/ControlFlow/HLTCFConfig.py b/Trigger/TriggerCommon/TriggerMenuMT/python/HLT/Config/ControlFlow/HLTCFConfig.py index 70a6a97726b0c41fdbbfb6838208f0a448b24cd7..17b89515d2d8fce801674844f1795dfcee70758d 100644 --- a/Trigger/TriggerCommon/TriggerMenuMT/python/HLT/Config/ControlFlow/HLTCFConfig.py +++ b/Trigger/TriggerCommon/TriggerMenuMT/python/HLT/Config/ControlFlow/HLTCFConfig.py @@ -23,7 +23,7 @@ """ from TriggerMenuMT.HLT.Config.ControlFlow.HLTCFDot import stepCF_DataFlow_to_dot, stepCF_ControlFlow_to_dot, all_DataFlow_to_dot -from TriggerMenuMT.HLT.Config.ControlFlow.HLTCFComponents import CFSequence, RoRSequenceFilterNode, PassFilterNode +from TriggerMenuMT.HLT.Config.ControlFlow.HLTCFComponents import CFSequence, RoRSequenceFilterNode, PassFilterNode, CFSequenceCA from TriggerMenuMT.HLT.Config.ControlFlow.MenuComponentsNaming import CFNaming from TriggerMenuMT.HLT.Config.Validation.CFValidation import testHLTTree @@ -40,7 +40,8 @@ from TriggerJobOpts.TriggerConfig import collectHypos, collectFilters, collectVi triggerMonitoringCfg, triggerSummaryCfg, triggerMergeViewsAndAddMissingEDMCfg, collectHypoDecisionObjects from TrigNavSlimmingMT.TrigNavSlimmingMTConfig import getTrigNavSlimmingMTOnlineConfig from ViewAlgs.ViewAlgsConf import EventViewCreatorAlgorithm - +from AthenaConfiguration.ComponentFactory import isComponentAccumulatorCfg +from AthenaConfiguration.ComponentAccumulator import ComponentAccumulator from builtins import map, range, str, zip from collections import OrderedDict, defaultdict @@ -48,7 +49,6 @@ import re log = logging.getLogger( __name__ ) - #### Functions to create the CF tree from CF configuration objects def makeSummary(flags, name, flatDecisions): """ Returns a TriggerSummaryAlg connected to given decisions""" @@ -76,10 +76,11 @@ def createStepFilterNode(name, seq_list, dump=False): """ Elementary HLT filter step: OR node containing all Filters of the sequences. The node gates execution of next reco step """ log.debug("Create filter step %s with %d filters", name, len(seq_list)) + stepCF = parOR(name + CFNaming.FILTER_POSTFIX) filter_list=[] for seq in seq_list: filterAlg = seq.filter.Alg - log.debug("createStepFilterNode: Add %s to filter node %s", filterAlg.name(), name) + log.debug("createStepFilterNode: Add %s to filter node %s", filterAlg.getName(), name) if filterAlg not in filter_list: filter_list.append(filterAlg) @@ -108,8 +109,8 @@ def createCFTree(CFseq): for menuseq in CFseq.step.sequences: menuseq.addToSequencer(recoSeqSet,hypoSet) - stepReco += sorted(list(recoSeqSet), key=lambda t: t.name()) - seqAndWithFilter += sorted(list(hypoSet), key=lambda t: t.name()) + stepReco += sorted(list(recoSeqSet), key=lambda t: t.getName()) + seqAndWithFilter += sorted(list(hypoSet), key=lambda t: t.getName()) if CFseq.step.combo is not None: seqAndWithFilter += CFseq.step.combo.Alg @@ -146,7 +147,7 @@ def makeHLTTree(flags, newJO=False, hltMenuConfig = None): log.debug("[makeHLTTree] will now make the DF and CF tree from chains") # make DF and CF tree from chains - finalDecisions = decisionTreeFromChains(flags, steps, hltMenuConfig.configsList(), hltMenuConfig.dictsList(), newJO) + finalDecisions, acc = decisionTreeFromChains(flags, steps, hltMenuConfig.configsList(), hltMenuConfig.dictsList(), newJO) successful_scan = sequenceScanner( steps ) @@ -289,7 +290,7 @@ def matrixDisplay( allCFSeq ): if seq.name == "Empty": mx[stepNumber, "Empty"].extend(chains) else: - mx[stepNumber, seq.sequence.Alg.name()].extend(chains) + mx[stepNumber, seq.sequence.Alg.getName()].extend(chains) # sort dictionary by fist key=step sorted_mx = OrderedDict(sorted( list(mx.items()), key= lambda k: k[0])) @@ -329,7 +330,7 @@ def sequenceScanner( HLTNode ): if isSequence(c): # Detect whether this is the view sequence pointed to # by the EV creator alg, or if it is in such a sequence - inView = c.name()==inViewSequence or childInView + inView = c.getName()==inViewSequence or childInView stepIndex = _mapSequencesInSteps(c, stepIndex, childInView=inView) _seqMapInStep[compName(c)].add((stepIndex,inView)) log.verbose("sequenceScanner: Child %s of sequence %s is in view? %s --> '%s'", compName(c), name, inView, inViewSequence) @@ -365,42 +366,41 @@ def sequenceScanner( HLTNode ): def decisionTreeFromChains(flags, HLTNode, chains, allDicts, newJO): """ Creates the decision tree, given the starting node and the chains containing the sequences """ - log.info("[decisionTreeFromChains] Run decisionTreeFromChains on %s", HLTNode.name()) - HLTNodeName= HLTNode.name() + log.info("[decisionTreeFromChains] Run decisionTreeFromChains on %s", HLTNode.getName()) + HLTNodeName = HLTNode.getName() if len(chains) == 0: log.info("[decisionTreeFromChains] Configuring empty decisionTree") - return [] + acc = ComponentAccumulator() + if isComponentAccumulatorCfg(): + acc.addSequence(HLTNode) + return ([], acc) + (finalDecisions, CFseq_list) = createDataFlow(chains, allDicts) - if not newJO: - createControlFlow(flags, HLTNode, CFseq_list) - else: - raise RuntimeError('createControlFlowNewJO not implemented') - # createControlFlowNewJO(HLTNode, CFseq_list) - + acc = createControlFlow(flags, HLTNode, CFseq_list) - # decode and attach HypoTools: - for chain in chains: - chain.createHypoTools() # create dot graphs log.debug("finalDecisions: %s", finalDecisions) if flags.Trigger.generateMenuDiagnostics: all_DataFlow_to_dot(HLTNodeName, CFseq_list) + + if isComponentAccumulatorCfg(): + acc.printConfig(withDetails = True, summariseProps = True) # matrix display # uncomment for serious debugging # matrixDisplay( CFseq_list ) - return finalDecisions + return (finalDecisions,acc) def createDataFlow(chains, allDicts): """ Creates the filters and connect them to the menu sequences""" # find tot nsteps - chainWithMaxSteps = max(chains, key=lambda chain: len(chain.steps)) + chainWithMaxSteps = max(chains, key = lambda chain: len(chain.steps)) NSTEPS = len(chainWithMaxSteps.steps) log.info("[createDataFlow] creating DF for %d chains and total %d steps", len(chains), NSTEPS) @@ -431,53 +431,59 @@ def createDataFlow(chains, allDicts): log.debug("Set Filter input: %s while setting the chain: %s", filterInput, chain.name) # make one filter per step: - sequenceFilter= None + sequenceFilter = None filterName = CFNaming.filterName(chainStep.name) if chainStep.isEmpty: - filterOutput= filterInput + filterOutput = filterInput else: - filterOutput =[ CFNaming.filterOutName(filterName, inputName) for inputName in filterInput ] - - foundCFSeq = findCFSequences(filterName, CFseqList[nstep]) + filterOutput = [CFNaming.filterOutName(filterName, inputName) for inputName in filterInput ] + + foundCFSeq = [cfseq for cfseq in CFseqList[nstep] if filterName == cfseq.filter.Alg.getName()] log.debug("Found %d CF sequences with filter name %s", len(foundCFSeq), filterName) if not foundCFSeq: sequenceFilter = buildFilter(filterName, filterInput, chainStep.isEmpty) - CFseq = CFSequence( ChainStep=chainStep, FilterAlg=sequenceFilter) + if isComponentAccumulatorCfg(): + CFseq = CFSequenceCA( ChainStep = chainStep, FilterAlg = sequenceFilter) + else: + CFseq = CFSequence( ChainStep = chainStep, FilterAlg = sequenceFilter) CFseq.connect(filterOutput) CFseqList[nstep].append(CFseq) - lastDecisions=CFseq.decisions - lastCFseq=CFseq - else: + lastDecisions = CFseq.decisions + lastCFseq = CFseq + else: if len(foundCFSeq) > 1: - log.error("Found more than one sequence containing filter %s", filterName) - lastCFseq=foundCFSeq[0] - sequenceFilter=lastCFseq.filter - [ sequenceFilter.addInput(inputName) for inputName in filterInput ] - [ sequenceFilter.addOutput(outputName) for outputName in filterOutput ] - lastCFseq.connect(filterOutput) - if chainStep.isEmpty: - lastDecisions=filterOutput - else: - lastDecisions=lastCFseq.decisions - + log.error("Found more than one sequence containing filter %s", filterName) + + lastCFseq = foundCFSeq[0] + sequenceFilter = lastCFseq.filter + if len(list(set(sequenceFilter.getInputList()).intersection(filterInput))) != len(list(set(filterInput))): + [ sequenceFilter.addInput(inputName) for inputName in filterInput ] + [ sequenceFilter.addOutput(outputName) for outputName in filterOutput ] + lastCFseq.connect(filterOutput) + + lastDecisions = filterOutput if chainStep.isEmpty else lastCFseq.decisions + # add chains to the filter: chainLegs = chainStep.getChainLegs() if len(chainLegs) != len(filterInput): - log.error("[createDataFlow] lengths of chainlegs = %s differ from inputs=%s", str(chainLegs), str(filterInput)) + log.error("[createDataFlow] lengths of chainlegs = %s differ from inputs = %s", str(chainLegs), str(filterInput)) raise Exception("[createDataFlow] Cannot proceed, exiting.") for finput, leg in zip(filterInput, chainLegs): + log.debug("Adding chain %s to input %s of %s", leg, finput,compName(sequenceFilter.Alg)) sequenceFilter.addChain(leg, finput) - log.debug("Adding chain %s to input %s of %s", leg, finput,sequenceFilter.Alg.name()) - + log.debug("Now Filter has chains: %s", sequenceFilter.getChains()) log.debug("Now Filter has chains/input: %s", sequenceFilter.getChainsPerInput()) - if chainStep.combo is not None: - chainStep.combo.addChain( [d for d in allDicts if d['chainName'] == chain.name ][0]) - log.debug("Added chains to ComboHypo: %s",chainStep.combo.getChains()) + if lastCFseq.step.combo is not None: + lastCFseq.step.combo.addChain( [d for d in allDicts if d['chainName'] == chain.name ][0]) + log.debug("Added chains to ComboHypo: %s",lastCFseq.step.combo.getChains()) else: log.debug("Combo not implemented if it's empty step") + # add HypoTools to this step (cumulating all same steps) + lastCFseq.createHypoTools(chain.name,chainStep) + if len(chain.steps) == nstep+1: log.debug("Adding finalDecisions for chain %s at step %d:", chain.name, nstep+1) for dec in lastDecisions: @@ -485,10 +491,9 @@ def createDataFlow(chains, allDicts): log.debug(dec) #end of loop over steps - log.debug("\n Built CF for chain %s with %d steps: \n - %s ", chain.name,len(chain.steps),'\n - '.join(map(str, [{step.name:step.multiplicity} for step in chain.steps]))) + log.debug("\n Built CD for chain %s with %d steps: \n - %s ", chain.name,len(chain.steps),'\n - '.join(map(str, [{step.name:step.multiplicity} for step in chain.steps]))) #end of loop over chains - log.debug("End of createDataFlow for %d chains and total %d steps", len(chains), NSTEPS) return (finalDecisions, CFseqList) @@ -496,48 +501,94 @@ def createDataFlow(chains, allDicts): def createControlFlow(flags, HLTNode, CFseqList): """ Creates Control Flow Tree starting from the CFSequences""" - HLTNodeName= HLTNode.name() - log.debug("createControlFlow on node %s",HLTNodeName) - - for nstep in range(len(CFseqList)): + HLTNodeName = HLTNode.getName() + log.debug("[createControlFlow] on node %s",HLTNodeName) + acc = ComponentAccumulator() + if isComponentAccumulatorCfg(): + acc.addSequence(HLTNode) + + for nstep, sequences in enumerate(CFseqList): stepSequenceName = CFNaming.stepName(nstep) log.debug("\n******** Create CF Tree %s with AthSequencers", stepSequenceName) - #first make the filter step - stepFilterNode = createStepFilterNode(stepSequenceName, CFseqList[nstep], dump=False) - HLTNode += stepFilterNode - - # then the reco step - stepRecoNode = createStepRecoNode(stepSequenceName, CFseqList[nstep], dump=False) - HLTNode += stepRecoNode + + # create filter node + log.debug("[createControlFlow] Create filter step %s with %d filters", stepSequenceName, len(CFseqList[nstep])) + stepCFFilter = parOR(stepSequenceName + CFNaming.FILTER_POSTFIX) + if isComponentAccumulatorCfg(): + acc.addSequence(stepCFFilter, parentName=HLTNodeName) + else: + HLTNode += stepCFFilter + + filter_list = [] + # add the filter to the node + for cseq in sequences: + filterAlg = cseq.filter.Alg + if filterAlg.getName() not in filter_list: + log.debug("[createControlFlow] Add %s to filter node %s", filterAlg.getName(), stepSequenceName) + filter_list.append(filterAlg.getName()) + if isComponentAccumulatorCfg(): + stepCFFilter.Members += [filterAlg] + else: + stepCFFilter += filterAlg + + # create reco step node + log.debug("[createControlFlow] Create reco step %s with %d sequences", stepSequenceName, len(CFseqList)) + stepCFReco = parOR(stepSequenceName + CFNaming.RECO_POSTFIX) + if isComponentAccumulatorCfg(): + acc.addSequence(stepCFReco, parentName = HLTNodeName) + else: + HLTNode += stepCFReco + + # add the sequences to the reco node + for cseq in sequences: + log.debug(" *** Create CF Tree for CFSequence %s", cseq.step.name) + if isComponentAccumulatorCfg(): + acc.merge( cseq.ca, sequenceName = stepCFReco.getName()) + else: + filterAlg = cseq.filter.Alg + if len(cseq.step.sequences) == 0: + stepCFReco += filterAlg + else: + seqAndWithFilter = seqAND(cseq.step.name) + stepReco = parOR(cseq.step.name + CFNaming.RECO_POSTFIX) + seqAndWithFilter += [filterAlg, stepReco] + recoSeqSet = set() + hypoSet = set() + for menuseq in cseq.step.sequences: + menuseq.addToSequencer(recoSeqSet, hypoSet) + + stepReco += sorted(list(recoSeqSet), key = lambda t: t.getName()) + seqAndWithFilter += sorted(list(hypoSet), key = lambda t: t.getName()) + if cseq.step.combo is not None: + seqAndWithFilter += cseq.step.combo.Alg + + stepCFReco += seqAndWithFilter - # then the monitor summary + + # add the monitor summary stepDecisions = [] for CFseq in CFseqList[nstep]: stepDecisions.extend(CFseq.decisions) - summary=makeSummary( flags, stepSequenceName, stepDecisions ) - - HLTNode += summary + summary = makeSummary( flags, stepSequenceName, stepDecisions ) + if isComponentAccumulatorCfg(): + acc.addEventAlgo([summary],sequenceName = HLTNode.getName()) + else: + HLTNode += summary if flags.Trigger.generateMenuDiagnostics: - log.debug("Now Draw...") - stepCF_DataFlow_to_dot(stepRecoNode.name(), CFseqList[nstep]) - stepCF_ControlFlow_to_dot(stepRecoNode) - + log.debug("Now Draw Menu Diagnostic dot graphs...") + stepCF_DataFlow_to_dot( stepCFReco.getName(), CFseqList[nstep] ) + stepCF_ControlFlow_to_dot( stepCFReco ) + log.debug("************* End of step %d, %s", nstep+1, stepSequenceName) - return + return acc -def findCFSequences(filter_name, cfseqList): - """ - Searches for a filter, with given name, in the CF sequence list of this step - """ - foundFilters = [cfseq for cfseq in cfseqList if filter_name == cfseq.filter.Alg.name()] - return foundFilters def buildFilter(filter_name, filter_input, empty): @@ -548,18 +599,22 @@ def buildFilter(filter_name, filter_input, empty): one filter per previous sequence: 1 input/previous seq, 1 output/next seq """ if empty: - sfilter = PassFilterNode(name=filter_name) + log.debug("Calling PassFilterNode %s", filter_name) + sfilter = PassFilterNode(name = filter_name) for i in filter_input: sfilter.addInput(i) sfilter.addOutput(i) else: - sfilter = RoRSequenceFilterNode(name=filter_name) + sfilter = RoRSequenceFilterNode(name = filter_name) for i in filter_input: sfilter.addInput(i) sfilter.addOutput(CFNaming.filterOutName(filter_name, i)) log.debug("Added inputs to filter: %s", sfilter.getInputList()) log.debug("Added outputs to filter: %s", sfilter.getOutputList()) - log.debug("Filter Done: %s", sfilter.Alg.name()) + log.debug("Filter Done: %s", compName(sfilter.Alg)) + return (sfilter) + + diff --git a/Trigger/TriggerCommon/TriggerMenuMT/python/HLT/Config/ControlFlow/HLTCFConfig_newJO.py b/Trigger/TriggerCommon/TriggerMenuMT/python/HLT/Config/ControlFlow/HLTCFConfig_newJO.py index 235e1aea55fdd8865b874e12f8d74a05c7bec1d2..ea7b1efed897400cb470293548dd2a16776bdd62 100644 --- a/Trigger/TriggerCommon/TriggerMenuMT/python/HLT/Config/ControlFlow/HLTCFConfig_newJO.py +++ b/Trigger/TriggerCommon/TriggerMenuMT/python/HLT/Config/ControlFlow/HLTCFConfig_newJO.py @@ -143,7 +143,7 @@ def commonWithOtherOutput(acc, newInputColl, filterAlg ): return None -def generateDecisionTree(flags, chains): +def generateDecisionTree(flags, HLTMenuConfig): """Creates CF algorithms The implementation relies of functions that build a small element of it. @@ -152,6 +152,7 @@ def generateDecisionTree(flags, chains): The functions check the global boolean theCFisFixed - and if set to True no CF algorithms are further constructed (assertion error is generated). """ + chains=HLTMenuConfig.configsList() acc = ComponentAccumulator() mainSequence = seqOR('HLTAllSteps') acc.addSequence( mainSequence ) @@ -424,7 +425,6 @@ def generateDecisionTree(flags, chains): needCombo = False for sequenceCounter, sequence in enumerate(step.sequences): if not isinstance(sequence, EmptyMenuSequence): # not an empty sequence - log.debug("Sequence %d: IM=%s, Hypo=%s, comboReco=%s", sequenceCounter, sequence.ca.inputMaker().name, sequence.ca.hypo().name, comboRecoSeq.name) connectIMAndHypo(sequence.ca.inputMaker(), sequence.ca.hypo()) # setup basic CF acc.merge( sequence.ca, sequenceName=comboRecoSeq.name) log.debug("MERGE: sequence %s, sequenceName=%s", sequence, comboRecoSeq.name) diff --git a/Trigger/TriggerCommon/TriggerMenuMT/python/HLT/Config/GenerateMenuMT.py b/Trigger/TriggerCommon/TriggerMenuMT/python/HLT/Config/GenerateMenuMT.py index dfd4cc6e5d69bb864731bfe62715f7e633eb524e..58b2d91382b865de1ded4c9233282a2aca1b1033 100755 --- a/Trigger/TriggerCommon/TriggerMenuMT/python/HLT/Config/GenerateMenuMT.py +++ b/Trigger/TriggerCommon/TriggerMenuMT/python/HLT/Config/GenerateMenuMT.py @@ -10,6 +10,7 @@ from TriggerMenuMT.HLT.Config.ControlFlow.HLTCFTools import NoCAmigration from AthenaCommon.Logging import logging log = logging.getLogger(__name__) + class Singleton(type): _instances = {} def __call__(cls, *args, **kwargs): diff --git a/Trigger/TriggerCommon/TriggerMenuMT/python/HLT/Config/GenerateMenuMT_newJO.py b/Trigger/TriggerCommon/TriggerMenuMT/python/HLT/Config/GenerateMenuMT_newJO.py old mode 100644 new mode 100755 index 5db63b79ea2ded244d9f329046b5d05d770f9b26..934a98ff225625906b2b2af4d98a1e8a2fdb9f63 --- a/Trigger/TriggerCommon/TriggerMenuMT/python/HLT/Config/GenerateMenuMT_newJO.py +++ b/Trigger/TriggerCommon/TriggerMenuMT/python/HLT/Config/GenerateMenuMT_newJO.py @@ -2,7 +2,10 @@ import itertools from TriggerMenuMT.HLT.Config.Utility.DictFromChainName import dictFromChainName -from TriggerMenuMT.HLT.Config.ControlFlow.HLTCFConfig_newJO import generateDecisionTree +from TriggerMenuMT.HLT.Config.ControlFlow.HLTCFConfig import decisionTreeFromChains, sequenceScanner + +from AthenaConfiguration.ComponentAccumulator import ComponentAccumulator +from AthenaCommon.CFElements import seqAND from TriggerMenuMT.HLT.Config.Utility.HLTMenuConfig import HLTMenuConfig from TriggerMenuMT.HLT.Config.Utility.ChainMerging import mergeChainDefs from TriggerMenuMT.HLT.Config.Utility.ChainDictTools import splitInterSignatureChainDict @@ -179,18 +182,16 @@ class FilterChainsToGenerate(object): def generateMenuMT(flags): """ Interface between CA and MenuMT using ChainConfigurationBase - """ - - + """ # Generate the menu, stolen from HLT_standalone from TriggerMenuMT.HLT.Config.GenerateMenuMT import GenerateMenuMT menu = GenerateMenuMT() - - chainsToGenerate = FilterChainsToGenerate(flags) + + chainsToGenerate = FilterChainsToGenerate(flags) + log.debug("Filtering chains ") menu.setChainFilter(chainsToGenerate) finalListOfChainConfigs = menu.generateAllChainConfigs(flags) - log.info("Length of FinalListofChainConfigs %s", len(finalListOfChainConfigs)) # make sure that we didn't generate any steps that are fully empty in all chains @@ -198,9 +199,8 @@ def generateMenuMT(flags): finalListOfChainConfigs = menu.resolveEmptySteps(finalListOfChainConfigs) log.info("finalListOfChainConfig %s", finalListOfChainConfigs) - log.info("Making the HLT configuration tree") - menuAcc=generateMenuAcc(flags) + menuAcc=makeHLTTree(flags) # generate L1 menu # This probably will go to TriggerConfig.triggerRunCfg @@ -214,7 +214,7 @@ def LoadAndGenerateMenu(flags): Load and generate Chain configurations, without ChainConfigurationBase """ loadChains(flags) - menuAcc= generateMenuAcc(flags) + menuAcc= makeHLTTree(flags) # The L1 presacles do not get created in the menu setup from TrigConfigSvc.TrigConfigSvcCfg import generateL1Menu, createL1PrescalesFileFromMenu generateL1Menu(flags) @@ -222,18 +222,29 @@ def LoadAndGenerateMenu(flags): return menuAcc -def generateMenuAcc(flags): +def makeHLTTree(flags): """ Generate appropriate Control Flow Graph wiht all HLT algorithms """ - - menuAcc = generateDecisionTree(flags, HLTMenuConfig.configsList()) + log.info("newJO version of makeHLTTree") + acc = ComponentAccumulator() + + steps = seqAND('HLTAllSteps') + finalDecisions, menuAcc = decisionTreeFromChains(flags, steps, HLTMenuConfig.configsList(), HLTMenuConfig.dictsList(), newJO=False) menuAcc.wasMerged() if log.getEffectiveLevel() <= logging.DEBUG: menuAcc.printConfig() - log.info('CF is built') + acc.merge(menuAcc) + successful_scan = sequenceScanner( steps ) + if not successful_scan: + raise Exception("[makeHLTTree] At least one sequence is expected in more than one step. Check error messages and fix!") + flatDecisions=[] + for step in finalDecisions: + flatDecisions.extend (step) + + # # generate JOSON representation of the config from TriggerMenuMT.HLT.Config.JSON.HLTMenuJSON import generateJSON_newJO generateJSON_newJO(flags, HLTMenuConfig.dictsList(), HLTMenuConfig.configsList(), menuAcc.getSequence("HLTAllSteps")) @@ -241,6 +252,8 @@ def generateMenuAcc(flags): from TriggerMenuMT.HLT.Config.JSON.HLTPrescaleJSON import generateJSON_newJO as generatePrescaleJSON_newJO generatePrescaleJSON_newJO(flags, HLTMenuConfig.dictsList(), HLTMenuConfig.configsList()) + from AthenaCommon.CFElements import checkSequenceConsistency + checkSequenceConsistency(steps) return menuAcc @@ -263,3 +276,5 @@ if __name__ == "__main__": ca.printConfig() ca.wasMerged() log.info("All ok") + + diff --git a/Trigger/TriggerCommon/TriggerMenuMT/python/HLT/Config/MenuComponents.py b/Trigger/TriggerCommon/TriggerMenuMT/python/HLT/Config/MenuComponents.py index 088b700bba114253be388df3f760f494d4fc5247..56969136cff0d92cfd18032192d943d2f263eb93 100644 --- a/Trigger/TriggerCommon/TriggerMenuMT/python/HLT/Config/MenuComponents.py +++ b/Trigger/TriggerCommon/TriggerMenuMT/python/HLT/Config/MenuComponents.py @@ -3,6 +3,7 @@ from TriggerMenuMT.HLT.Config.Utility.HLTMenuConfig import HLTMenuConfig from TriggerMenuMT.HLT.Config.ControlFlow.MenuComponentsNaming import CFNaming from TriggerMenuMT.HLT.Config.ControlFlow.HLTCFTools import (NoHypoToolCreated, + NoCAmigration, algColor, isHypoBase, isComboHypoAlg, @@ -16,12 +17,14 @@ from AthenaConfiguration.ComponentAccumulator import ComponentAccumulator from AthenaConfiguration.ComponentFactory import CompFactory from AthenaConfiguration.AccumulatorCache import AccumulatorCache from DecisionHandling.DecisionHandlingConfig import ComboHypoCfg +import GaudiConfig2 from GaudiKernel.DataHandle import DataHandle from HLTSeeding.HLTSeedingConfig import mapThresholdToL1DecisionCollection from TrigCompositeUtils.TrigCompositeUtils import legName from AthenaCommon.Configurable import ConfigurableCABehavior from AthenaConfiguration.ComponentAccumulator import appendCAtoAthena, conf2toConfigurable from TriggerJobOpts.TriggerConfigFlags import ROBPrefetching +from AthenaConfiguration.ComponentFactory import isComponentAccumulatorCfg from collections.abc import MutableSequence import collections.abc @@ -29,7 +32,6 @@ import re from AthenaCommon.Logging import logging log = logging.getLogger( __name__ ) - # Pool of mutable ComboHypo instances (as opposed to immutable cache of RecoFragmentsPool) _ComboHypoPool = dict() @@ -37,16 +39,16 @@ _ComboHypoPool = dict() class Node(object): """base class representing one Alg + inputs + outputs, to be used to Draw dot diagrams and connect objects""" def __init__(self, Alg): - self.name = ("%sNode")%( Alg.name ) + self.name = ("%sNode")%( Alg.getName() ) self.Alg=Alg self.inputs=[] self.outputs=[] def addOutput(self, name): - self.outputs.append(str(name) if isinstance(name, DataHandle) else name) + self.outputs.append(str(name)) def addInput(self, name): - self.inputs.append(str(name) if isinstance(name, DataHandle) else name) + self.inputs.append(str(name)) def getOutputList(self): return self.outputs @@ -55,16 +57,15 @@ class Node(object): return self.inputs def __repr__(self): - return "Node::%s [%s] -> [%s]"%(self.Alg.name, ' '.join(map(str, self.getInputList())), ' '.join(map(str, self.getOutputList()))) - + return "Node::%s [%s] -> [%s]"%(self.Alg.getName(), ' '.join(map(str, self.getInputList())), ' '.join(map(str, self.getOutputList()))) class AlgNode(Node): """Node class that connects inputs and outputs to basic alg. properties """ def __init__(self, Alg, inputProp, outputProp): Node.__init__(self, Alg) - self.outputProp=outputProp - self.inputProp=inputProp + self.outputProp = outputProp + self.inputProp = inputProp def addDefaultOutput(self): if self.outputProp != '': @@ -88,7 +89,6 @@ class AlgNode(Node): def getPar(self, prop): return getProp(self.Alg, prop) - def resetOutput(self): self.resetPar(self.outputProp) @@ -97,7 +97,6 @@ class AlgNode(Node): def addOutput(self, name): outputs = self.readOutputList() - log.debug("Outputs: %s", outputs) if name in outputs: log.debug("Output DH not added in %s: %s already set!", self.Alg.getName(), name) else: @@ -139,18 +138,15 @@ class HypoToolConf(object): self.hypoToolGen = hypoToolGen self.name=hypoToolGen.__name__ - def setConf( self, chainDict): if type(chainDict) is not dict: raise RuntimeError("Configuring hypo with %s, not good anymore, use chainDict" % str(chainDict) ) self.chainDict = chainDict - def create(self): """creates instance of the hypo tool""" return self.hypoToolGen( self.chainDict ) - def confAndCreate(self, chainDict): """sets the configuration and creates instance of the hypo tool""" self.setConf(chainDict) @@ -177,9 +173,12 @@ class HypoAlgNode(AlgNode): def addHypoTool (self, hypoToolConf): - log.debug("Adding HypoTool %s to %s", hypoToolConf.chainDict['chainName'], compName(self.Alg)) + log.debug("Adding HypoTool %s for chain %s to %s", hypoToolConf.name, hypoToolConf.chainDict['chainName'], self.Alg.getName()) try: self.Alg.HypoTools = self.Alg.HypoTools + [hypoToolConf.create()] # see ATEAM-773 + if isComponentAccumulatorCfg(): + assert isinstance(self.Alg.HypoTools[-1], GaudiConfig2._configurables.Configurable), "The Hypo Tool for {} is not Configurable2".format(hypoToolConf.chainDict['chainName']) + except NoHypoToolCreated as e: log.debug("%s returned empty tool: %s", hypoToolConf.name, e) @@ -204,22 +203,29 @@ class InputMakerNode(AlgNode): def __init__(self, Alg): assert isInputMakerBase(Alg), "Error in creating InputMakerNode from Alg " + compName(Alg) AlgNode.__init__(self, Alg, 'InputMakerInputDecisions', 'InputMakerOutputDecisions') + self.resetInput() + self.resetOutput() ## why do we need this in CA mode?? input_maker_output = CFNaming.inputMakerOutName(compName(self.Alg)) self.addOutput(input_maker_output) class ComboMaker(AlgNode): def __init__(self, name, comboHypoCfg): - self.prop1="MultiplicitiesMap" - self.prop2="LegToInputCollectionMap" + self.prop1 = "MultiplicitiesMap" + self.prop2 = "LegToInputCollectionMap" self.comboHypoCfg = comboHypoCfg Alg = self.create( name ) log.debug("ComboMaker init: Alg %s", name) AlgNode.__init__(self, Alg, 'HypoInputDecisions', 'HypoOutputDecisions') + self.resetInput() + self.resetOutput() ## why do we need this in CA mode?? + # reset the chains, why do we need to do it? + setattr(self.Alg, self.prop1, {}) + setattr(self.Alg, self.prop2, {}) def create (self, name): log.debug("ComboMaker.create %s",name) - return self.comboHypoCfg(name=name) + return self.comboHypoCfg(name=name) """ AlgNode automatically de-duplicates input ReadHandles upon repeated calls to addInput. @@ -241,11 +247,10 @@ class ComboMaker(AlgNode): def addInput(self, name): return AlgNode.addInput(self, name) - def addChain(self, chainDict): + def addChain(self, chainDict): chainName = chainDict['chainName'] - chainMult = chainDict['chainMultiplicities'] - legsToInputCollections = self.mapRawInputsToInputsIndex() - + chainMult = chainDict['chainMultiplicities'] + legsToInputCollections = self.mapRawInputsToInputsIndex() if len(chainMult) != len(legsToInputCollections): log.error("ComboMaker for Alg:{} with addChain for:{} Chain multiplicity:{} Per leg input collection index:{}." .format(compName(self.Alg), chainName, tuple(chainMult), tuple(legsToInputCollections))) @@ -254,24 +259,25 @@ class ComboMaker(AlgNode): log.error("Check why ComboMaker.addInput(...) was not called exactly once per leg.") raise Exception("[createDataFlow] Error in ComboMaker.addChain. Cannot proceed.") - cval1 = self.Alg.getProperties()[self.prop1] # check necessary to see if chain was added already? - cval2 = self.Alg.getProperties()[self.prop2] - if type(cval1) is dict: + cval1 = getProp(self.Alg, self.prop1) # check necessary to see if chain was added already? + cval2 = getProp(self.Alg, self.prop2) + if type(cval1) is dict or isinstance(cval1, GaudiConfig2.semantics._DictHelper): if chainName in cval1.keys(): log.error("ERROR in configuration: ComboAlg %s has already been configured for chain %s", compName(self.Alg), chainName) raise Exception("[createDataFlow] Error in ComboMaker.addChain. Cannot proceed.") else: - cval1[chainName]=chainMult - cval2[chainName]=legsToInputCollections + cval1[chainName] = chainMult + cval2[chainName] = legsToInputCollections else: cval1 = {chainName : chainMult} cval2 = {chainName : legsToInputCollections} setattr(self.Alg, self.prop1, cval1) setattr(self.Alg, self.prop2, cval2) + def getChains(self): - cval = self.Alg.getProperties()[self.prop1] + cval = getProp(self.Alg, self.prop1) return cval.keys() @@ -282,6 +288,7 @@ class ComboMaker(AlgNode): confs = [ HypoToolConf( tool ) for tool in comboToolConfs ] log.debug("ComboMaker.createComboHypoTools for chain %s, Alg %s with %d tools", chainDict["chainName"],self.Alg.getName(), len(comboToolConfs)) for conf in confs: + log.debug("ComboMaker.createComboHypoTools adding %s", conf) tools = self.Alg.ComboHypoTools self.Alg.ComboHypoTools = tools + [ conf.confAndCreate( chainDict ) ] @@ -290,6 +297,8 @@ class ComboMaker(AlgNode): # Now sequences and chains ########################################################## + + class EmptyMenuSequence(object): """ Class to emulate reco sequences with no Hypo""" """ By construction it has no Hypo;""" @@ -302,7 +311,7 @@ class EmptyMenuSequence(object): Maker.isEmptyStep = True Maker.RoIsLink = 'initialRoI' #(this is the default property, just making it explicit) self._maker = InputMakerNode( Alg = Maker ) - self._seed='' + self._seed = '' self._sequence = Node( Alg = seqAND(the_name, [Maker])) log.debug("Made EmptySequence %s",the_name) @@ -326,7 +335,10 @@ class EmptyMenuSequence(object): self._maker.addInput(outfilter) def createHypoTools(self, chainDict): - log.debug("This sequence is empty. No Hypo to conficure") + log.debug("This sequence is empty. No Hypo to configure") + + def getHypoToolConf(self): + return None def addToSequencer(self, recoSeq_list, hypo_list): recoSeq_list.add(self.sequence.Alg) @@ -334,10 +346,8 @@ class EmptyMenuSequence(object): def buildDFDot(self, cfseq_algs, all_hypos, last_step_hypo_nodes, file): cfseq_algs.append(self._maker) cfseq_algs.append(self.sequence ) - file.write(" %s[fillcolor=%s]\n"%(self._maker.Alg.getName(), algColor(self._maker.Alg))) file.write(" %s[fillcolor=%s]\n"%(self.sequence.Alg.getName(), algColor(self.sequence.Alg))) - return cfseq_algs, all_hypos, last_step_hypo_nodes def setSeed( self, seed ): @@ -356,19 +366,25 @@ class MenuSequence(object): # For probe legs we need to substitute the inputmaker and hypo alg # so we will use temp variables for both - if IsProbe: - log.debug("MenuSequence: found a probe leg") - _Hypo = RecoFragmentsPool.retrieve(MenuSequence.getProbeHypo,ConfigFlags,basehypo=Hypo) - # Reset this so that HypoAlgNode.addOutput will actually do something - _Hypo.HypoOutputDecisions = "StoreGateSvc+UNSPECIFIED_OUTPUT" - _Maker = RecoFragmentsPool.retrieve(MenuSequence.getProbeInputMaker,ConfigFlags,baseIM=Maker) + if IsProbe: + from AthenaConfiguration.ComponentFactory import isComponentAccumulatorCfg + if isComponentAccumulatorCfg(): + #_Hypo = Hypo + #_Maker = Maker + #_Sequence = Sequence + log.warning(str(NoCAmigration('[MenuSequence] found a probe leg, dont know how to clone, no sequence {0}_probe created for CA components'.format(compName(Hypo))) )) + else: + _Hypo = RecoFragmentsPool.retrieve(MenuSequence.getProbeHypo,ConfigFlags,basehypo=Hypo) + # Reset this so that HypoAlgNode.addOutput will actually do something + _Hypo.HypoOutputDecisions = "StoreGateSvc+UNSPECIFIED_OUTPUT" + _Maker = RecoFragmentsPool.retrieve(MenuSequence.getProbeInputMaker,ConfigFlags,baseIM=Maker) else: # For regular legs, just use the provided components _Hypo = Hypo _Maker = Maker _Sequence = Sequence - self._maker = InputMakerNode( Alg = _Maker ) - self._seed='' + self._maker = InputMakerNode( Alg = _Maker ) + self._seed ='' input_maker_output= self.maker.readOutputList()[0] # only one since it's merged # Connect InputMaker output to ROBPrefetchingAlg(s) if there are any (except for probe seq which is handled later) @@ -393,29 +409,34 @@ class MenuSequence(object): if IsProbe: def getProbeSequence(baseSeq,probeIM): - # Add IM and sequence contents to duplicated sequence - probeSeq = baseSeq.clone(baseSeq.name()+"_probe") - probeSeq += probeIM - if isinstance(probeIM,CompFactory.EventViewCreatorAlgorithm): - for child in baseSeq.getChildren()[1:]: - probeChild = child.clone(child.name()+"_probe") - if hasProp(child,'ROBPrefetchingInputDecisions') and (ROBPrefetching.StepRoI in ConfigFlags.Trigger.ROBPrefetchingOptions): - # child is a ROB prefetching alg, map the probe IM decisions - probeChild.ROBPrefetchingInputDecisions = [str(probeIM.InputMakerOutputDecisions)] - elif probeIM.ViewNodeName == child.name(): - # child is the view alg sequence, map it to the probe sequence - probeIM.ViewNodeName = probeChild.name() - for viewalg in child.getChildren(): - probeChild += viewalg - probeSeq += probeChild + if isComponentAccumulatorCfg(): + probeSeq = None #baseSeq + #probeSeq.name= baseSeq.getName()+"_probe" + log.warning(str(NoCAmigration('[MenuSequence] found a probe leg, dont know how to clone, no sequence {0}_probe created for CA components'.format(compName(Hypo))) )) + else: + # Add IM and sequence contents to duplicated sequence + probeSeq = baseSeq.clone(baseSeq.getName()+"_probe") + probeSeq += probeIM + if isinstance(probeIM,CompFactory.EventViewCreatorAlgorithm): + for child in baseSeq.getChildren()[1:]: + probeChild = child.clone(child.getName()+"_probe") + if hasProp(child,'ROBPrefetchingInputDecisions') and (ROBPrefetching.StepRoI in ConfigFlags.Trigger.ROBPrefetchingOptions): + # child is a ROB prefetching alg, map the probe IM decisions + probeChild.ROBPrefetchingInputDecisions = [str(probeIM.InputMakerOutputDecisions)] + elif probeIM.ViewNodeName == child.getName(): + # child is the view alg sequence, map it to the probe sequence + probeIM.ViewNodeName = probeChild.getName() + for viewalg in child.getChildren(): + probeChild += viewalg + probeSeq += probeChild return probeSeq # Make sure nothing was lost _Sequence = getProbeSequence(baseSeq=Sequence,probeIM=_Maker) - assert len(_Sequence.getChildren()) == len(Sequence.getChildren()), f'Different number of children in sequence {_Sequence.name()} vs {Sequence.name()} ({len(_Sequence.getChildren())} vs {len(Sequence.getChildren())})' + assert len(_Sequence.getChildren()) == len(Sequence.getChildren()), f'Different number of children in sequence {_Sequence.getName()} vs {Sequence.getName()} ({len(_Sequence.getChildren())} vs {len(Sequence.getChildren())})' self._sequence = Node( Alg=_Sequence) - log.debug("MenuSequence.connect: connecting InputMaker and HypoAlg, adding: \n\ + log.debug("connecting InputMaker and HypoAlg, adding: \n\ InputMaker::%s.output=%s",\ compName(self.maker.Alg), input_maker_output) log.debug("HypoAlg::%s.HypoInputDecisions=%s, \n \ @@ -445,14 +466,14 @@ class MenuSequence(object): @staticmethod def getProbeHypo(flags,basehypo): '''Clone hypo & input maker''' - probehypo = basehypo.clone(basehypo.name()+"_probe") + probehypo = basehypo.clone(basehypo.getName()+"_probe") for p,v in basehypo.getValuedProperties().items(): setattr(probehypo,p,getattr(basehypo,p)) return probehypo @staticmethod def getProbeInputMaker(flags,baseIM): - probeIM = baseIM.clone(baseIM.name()+"_probe") + probeIM = baseIM.clone(baseIM.getName()+"_probe") for p,v in baseIM.getValuedProperties().items(): setattr(probeIM,p,getattr(baseIM,p)) @@ -481,29 +502,13 @@ class MenuSequence(object): outputlist.append(self._hypo.readOutputList()[0]) return outputlist + def connectToFilter(self, outfilter): """ Connect filter to the InputMaker""" - self._maker.addInput(outfilter) - - def connect(self, Hypo, HypoToolGen): - """ Sets the input and output of the hypo, and links to the input maker """ - input_maker_output= self._maker.readOutputList()[0] # only one since it's merged - - #### Add input/output Decision to Hypo - self.name = CFNaming.menuSequenceName(compName(Hypo)) - self.hypoToolConf = HypoToolConf( HypoToolGen ) - self._hypo = HypoAlgNode( Alg = Hypo ) - hypo_output = CFNaming.hypoAlgOutName(compName(Hypo)) - self._hypo.addOutput(hypo_output) - self._hypo.setPreviousDecision( input_maker_output) - - log.debug("MenuSequence.connect: connecting InputMaker and HypoAlg and OverlapRemoverAlg, adding: \n\ - InputMaker::%s.output=%s",\ - compName(self._maker.Alg), input_maker_output) - log.debug("HypoAlg::%s.previousDecision=%s, \n HypoAlg::%s.output=%s",\ - compName(self._hypo.Alg), input_maker_output, compName(self._hypo.Alg), self._hypo.readOutputList()[0]) - - + log.debug("connecting %s to inputs of %s", outfilter,compName(self._maker.Alg)) + self._maker.addInput(outfilter) + + def createHypoTools(self, chainDict): if type(self._hypoToolConf) is list: log.warning ("This sequence %s has %d multiple HypoTools ",self.sequence.name, len(self.hypoToolConf)) @@ -512,28 +517,29 @@ class MenuSequence(object): hypo.addHypoTool(self._hypoToolConf) else: self._hypoToolConf.setConf( chainDict ) - self._hypo.addHypoTool(self._hypoToolConf) #this creates the HypoTools + self._hypo.addHypoTool(self._hypoToolConf) #this creates the HypoTools + + def getHypoToolConf(self) : + return self._hypoToolConf + def getHypoToolMap(self,chainDict) : + self._hypoToolConf.setConf( chainDict ) + return (self._hypo.Alg.getName(), self._hypoToolConf) def addToSequencer(self, recoSeq_list, hypo_list): recoSeq_list.add(self.sequence.Alg) hypo_list.add(self._hypo.Alg) - def buildDFDot(self, cfseq_algs, all_hypos, last_step_hypo_nodes, file): cfseq_algs.append(self._maker) cfseq_algs.append(self.sequence ) - file.write(" %s[fillcolor=%s]\n"%(self._maker.Alg.getName(), algColor(self._maker.Alg))) - file.write(" %s[fillcolor=%s]\n"%(self.sequence.Alg.getName(), algColor(self.sequence.Alg))) - + file.write(" %s[fillcolor=%s]\n"%(self.sequence.Alg.getName(), algColor(self.sequence.Alg))) cfseq_algs.append(self._hypo) file.write(" %s[color=%s]\n"%(self._hypo.Alg.getName(), algColor(self._hypo.Alg))) all_hypos.append(self._hypo) - return cfseq_algs, all_hypos, last_step_hypo_nodes - def setSeed( self, seed ): self._seed = seed @@ -547,36 +553,48 @@ class MenuSequence(object): class MenuSequenceCA(MenuSequence): ''' MenuSequence with Component Accumulator ''' - def __init__(self, selectionCA, HypoToolGen ): + def __init__(self, selectionCA, HypoToolGen, isProbe=False ): self.ca = selectionCA allAlgs = self.ca.getEventAlgos() inputMaker = [ a for a in allAlgs if isInputMakerBase(a)] assert len(inputMaker) == 1, "Wrong number of input makers in the component accumulator {}".format(len(inputMaker)) - inputMaker = inputMaker[0] + inputMaker = inputMaker[0] hypoAlg = [ a for a in allAlgs if isHypoAlg(a)] assert len(hypoAlg) == 1, "Wrong number of hypo algs in the component accumulator {}".format(len(hypoAlg)) - hypoAlg = hypoAlg[0] - MenuSequence.__init__(self, self.ca.getSequence(), inputMaker, hypoAlg, HypoToolGen) + hypoAlg = hypoAlg[0] + MenuSequence.__init__(self, self.ca.topSequence(), inputMaker, hypoAlg, HypoToolGen, IsProbe=isProbe) @property def sequence(self): - makerAlg = self.ca.getEventAlgo(self._maker.Alg.name) + makerAlg = self.ca.getEventAlgo(self._maker.Alg.getName()) self._maker.Alg = makerAlg return self._sequence @property def maker(self): - makerAlg = self.ca.getEventAlgo(self._maker.Alg.name) + makerAlg = self.ca.getEventAlgo(self._maker.Alg.getName()) self._maker.Alg = makerAlg return self._maker @property def hypo(self): - hypoAlg = self.ca.getEventAlgo(self._hypo.Alg.name) + hypoAlg = self.ca.getEventAlgo(self._hypo.Alg.getName()) self._hypo.Alg = hypoAlg return self._hypo +class EmptyMenuSequenceCA(EmptyMenuSequence): + def __init__(self, the_name): + self.ca=ComponentAccumulator() + EmptyMenuSequence.__init__(self,the_name ) + self.ca.addEventAlgo(self._maker.Alg) + + @property + def maker(self): + makerAlg = self.ca.getEventAlgo(self._maker.Alg.getName()) + self._maker.Alg = makerAlg + return self._maker + class Chain(object): """Basic class to define the trigger menu """ @@ -586,11 +604,11 @@ class Chain(object): Construct the Chain from the steps Out of all arguments the ChainSteps & L1Thresholds are most relevant, the chain name is used in debug messages """ - self.name = name - self.steps=ChainSteps + self.name = name + self.steps = ChainSteps self.nSteps = nSteps self.alignmentGroups = alignmentGroups - self.vseeds=L1Thresholds + self.vseeds = L1Thresholds # The chain holds a map of topo ComboHypoTool configurators # This is needed to allow placement of the ComboHypoTool in the right position @@ -737,21 +755,15 @@ class Chain(object): self.name, ' '.join(map(str, self.L1decisions)), '\n '.join(map(str, self.steps))) -class StepComponent(object): - """ Class to build hte ChainStep, for including empty sequences""" - def __init__(self, sequence, multiplicity,empty): - self.sequence=sequence - self.multiplicity=multiplicity - self.empty=empty # next: can we remove multiplicity array, if it can be retrieved from the ChainDict? class ChainStep(object): """Class to describe one step of a chain; if multiplicity is greater than 1, the step is combo/combined. Set one multiplicity value per sequence""" - def __init__(self, name, Sequences=[], multiplicity=[1], chainDicts=[], comboHypoCfg=ComboHypoCfg, comboToolConfs=[], isEmpty = False, createsGhostLegs = False): + def __init__(self, name, Sequences = [], multiplicity = [1], chainDicts = [], comboHypoCfg = ComboHypoCfg, comboToolConfs = [], isEmpty = False, createsGhostLegs = False): # TODO: remove parameter multiplicity, since this must be extracted from the ChainDict ATR-23928 # include cases of empty steps with multiplicity = [] or multiplicity=[0,0,0///] - if sum(multiplicity)==0: - multiplicity=[] + if sum(multiplicity) == 0: + multiplicity = [] else: log.debug("chain %s, step %s: len=%d multiplicty=%d", chainDicts[0]['chainName'], name, len(chainDicts), len(multiplicity)) # sanity check on inputs, excluding empty steps @@ -766,9 +778,9 @@ class ChainStep(object): log.error("[ChainStep] multiplicities: %s",multiplicity) raise RuntimeError("Tried to configure a ChainStep %s with %i Sequences and %i multiplicities. These lists must have the same size" % (name, len(Sequences), len(multiplicity)) ) - self.name = name - self.sequences=Sequences - self.onlyJets = False + self.name = name + self.sequences = Sequences + self.onlyJets = False sig_set = None if len(chainDicts) > 0 and 'signature' in chainDicts[0]: leg_signatures = [step['signature'] for step in chainDicts if step['signature'] != 'Bjet'] @@ -782,10 +794,10 @@ class ChainStep(object): self.onlyJets = True self.multiplicity = multiplicity - self.comboHypoCfg=comboHypoCfg + self.comboHypoCfg = comboHypoCfg self.comboToolConfs = list(comboToolConfs) self.stepDicts = chainDicts # one dict per leg - self.isEmpty=(sum(multiplicity)==0 or isEmpty) + self.isEmpty = (sum(multiplicity) == 0 or isEmpty) if not self.isEmpty: #self.relabelLegIdsForJets() self.setChainPartIndices() @@ -870,22 +882,21 @@ class ChainStep(object): self.comboToolConfs.append(tool) def makeCombo(self): - self.combo=None + self.combo = None if self.isEmpty or self.comboHypoCfg is None: - return + return comboName = CFNaming.comboHypoName(self.name) key = hash((comboName, self.comboHypoCfg)) - if key not in _ComboHypoPool: + if key not in _ComboHypoPool: _ComboHypoPool[key] = createComboAlg(None, name=comboName, comboHypoCfg=self.comboHypoCfg) self.combo = _ComboHypoPool[key] - + def createComboHypoTools(self, chainName): chainDict = HLTMenuConfig.getChainDictFromChainName(chainName) self.combo.createComboHypoTools(chainDict, self.comboToolConfs) def getChainLegs(self): - """ This is extrapolating the chain legs from the step dictionaries""" legs = [part['chainName'] for part in self.stepDicts] return legs @@ -910,9 +921,9 @@ class ChainStep(object): ' '.join(map(str, [dic['chainName'] for dic in self.stepDicts])), ' '.join(map(str, [seq.name for seq in self.sequences]) )) if self.combo is not None: - repr_string += "\n+ ComboHypo = %s, ComboHypoTools = %s" %\ - (self.combo.Alg.name(), - ' '.join(map(str, [tool.__name__ for tool in self.comboToolConfs]))) + repr_string += "\n + ComboHypo = %s" %(compName(self.combo.Alg)) + if len(self.comboToolConfs)>0: + repr_string +=", ComboHypoTools = %s" %(' '.join(map(str, [tool.__name__ for tool in self.comboToolConfs]))) return repr_string @@ -947,19 +958,19 @@ class InEventRecoCA( ComponentAccumulator ): args.update(**inputMakerArgs) self.inputMakerAlg = CompFactory.InputMakerForRoI(**args) - self.addEventAlgo( self.inputMakerAlg, self.mainSeq.name ) - self.recoSeq = parOR( "InputSeq_"+self.inputMakerAlg.name ) #FP: why is this needed? - self.addSequence( self.recoSeq, self.mainSeq.name ) + self.addEventAlgo( self.inputMakerAlg, self.mainSeq.getName() ) + self.recoSeq = parOR( "InputSeq_"+self.inputMakerAlg.getName() ) #FP: why is this needed? + self.addSequence( self.recoSeq, self.mainSeq.getName() ) pass def mergeReco( self, ca ): """ Merged CA moving reconstruction algorithms into the right sequence """ - return self.merge( ca, sequenceName=self.recoSeq.name ) + return self.merge( ca, sequenceName=self.recoSeq.getName() ) def addRecoAlgo( self, algo ): """ Place algorithm in the correct reconstruction sequence """ - return self.addEventAlgo( algo, sequenceName=self.recoSeq.name ) + return self.addEventAlgo( algo, sequenceName=self.recoSeq.getName() ) def inputMaker( self ): return self.inputMakerAlg @@ -968,10 +979,10 @@ class InEventRecoCA( ComponentAccumulator ): class InViewRecoCA(ComponentAccumulator): """ Class to handle in-view reco, sets up the View maker if not provided and exposes InputMaker so that more inputs to it can be added in the process of assembling the menu """ - def __init__(self, name, viewMaker=None, **viewMakerArgs): + def __init__(self, name, viewMaker=None, isProbe=False, **viewMakerArgs): super( InViewRecoCA, self ).__init__() - self.name = name - self.mainSeq = seqAND( name ) + self.name = name +"_probe" if isProbe else name + self.mainSeq = seqAND( self.name ) self.addSequence( self.mainSeq ) if len(viewMakerArgs) != 0: @@ -1013,13 +1024,14 @@ class InViewRecoCA(ComponentAccumulator): class SelectionCA(ComponentAccumulator): """ CA component for MenuSequenceCA sequence """ - def __init__(self, name): - self.name = name - + def __init__(self, name, isProbe=False): + self.name = name+"_probe" if isProbe else name + self.isProbe=isProbe super( SelectionCA, self ).__init__() - self.stepRecoSequence = parOR(CFNaming.stepRecoName(name)) - self.stepViewSequence = seqAND(CFNaming.stepContentName(name), [self.stepRecoSequence]) + # to do: remove content sequence, leave just one for the Hypo? + self.stepRecoSequence = parOR(CFNaming.stepRecoName(self.name)) + self.stepViewSequence = seqAND(CFNaming.stepContentName(self.name), [self.stepRecoSequence]) self.addSequence(self.stepViewSequence) def mergeReco(self, other): @@ -1031,6 +1043,10 @@ class SelectionCA(ComponentAccumulator): def addHypoAlgo(self, algo): """To be used when the hypo alg configuration does not require auxiliary tools/services""" + if self.isProbe: + newname = algo.getName()+'_probe' + algo.name=newname + #algo.name(algo.getName()+'_probe') self.addEventAlgo(algo, sequenceName=self.stepViewSequence.name) def hypo(self): @@ -1045,12 +1061,13 @@ class SelectionCA(ComponentAccumulator): assert im is not None, "No input maker in SeelectionCA {}".format(self.name) return im + def topSequence(self): + return self.stepViewSequence + # mainline/rec-ex-common and CA based JO compatibility layer (basically converters) def algorithmCAToGlobalWrapper(gen, flags, *args, **kwargs): - """Merges CA with athena for all components except the algorithms. Those are converted to Run2 objects and returned. - - If CA contains more than one algorithm, a list is returned, else a single algorithm is returned. - + """ Merges CA with athena for all components except the algorithms. Those are converted to Run2 objects and returned. + If CA contains more than one algorithm, a list is returned, else a single algorithm is returned. """ with ConfigurableCABehavior(): ca = gen(flags, *args, **kwargs) diff --git a/Trigger/TriggerCommon/TriggerMenuMT/python/HLT/Config/Utility/ChainMerging.py b/Trigger/TriggerCommon/TriggerMenuMT/python/HLT/Config/Utility/ChainMerging.py index 5a3205fefb6733823e008a2f3e76efd4f375d1c8..3827d860277acfff4272a42578975429fa9d0593 100644 --- a/Trigger/TriggerCommon/TriggerMenuMT/python/HLT/Config/Utility/ChainMerging.py +++ b/Trigger/TriggerCommon/TriggerMenuMT/python/HLT/Config/Utility/ChainMerging.py @@ -1,7 +1,7 @@ # Copyright (C) 2002-2022 CERN for the benefit of the ATLAS collaboration from TriggerMenuMT.HLT.Config.Utility.MenuAlignmentTools import get_alignment_group_ordering as getAlignmentGroupOrdering -from TriggerMenuMT.HLT.Config.MenuComponents import Chain, ChainStep, EmptyMenuSequence, RecoFragmentsPool +from TriggerMenuMT.HLT.Config.MenuComponents import Chain, ChainStep, EmptyMenuSequence, RecoFragmentsPool, EmptyMenuSequenceCA from AthenaCommon.Logging import logging from AthenaConfiguration.AllConfigFlags import ConfigFlags @@ -155,7 +155,12 @@ def getEmptySeqName(stepName, chain_index, step_number, alignGroup): return seqName def EmptyMenuSequenceCfg(flags, name): - return EmptyMenuSequence(name) + # to clean up + if isComponentAccumulatorCfg(): + return EmptyMenuSequenceCA(name) + else: + return EmptyMenuSequence(name) + def getEmptyMenuSequence(flags, name): if isComponentAccumulatorCfg(): diff --git a/Trigger/TriggerCommon/TriggerMenuMT/python/HLT/Config/Utility/ComboHypoHandling.py b/Trigger/TriggerCommon/TriggerMenuMT/python/HLT/Config/Utility/ComboHypoHandling.py index 2305cebf659b41c083b88c28087bb63832b473e6..d7ec6fec6eed794879eb1defedd023f70f1d8623 100644 --- a/Trigger/TriggerCommon/TriggerMenuMT/python/HLT/Config/Utility/ComboHypoHandling.py +++ b/Trigger/TriggerCommon/TriggerMenuMT/python/HLT/Config/Utility/ComboHypoHandling.py @@ -10,6 +10,7 @@ logging.getLogger().info("Importing %s",__name__) import math import re from TrigConfHLTUtils.HLTUtils import string2hash +from AthenaConfiguration.ComponentFactory import CompFactory topoLegIndices = "ABCDEF" @@ -53,7 +54,6 @@ from TriggerMenuMT.HLT.MinBias.MinBiasChainConfiguration import TrigAFPDijetComb from TriggerMenuMT.HLT.Muon.MuonChainConfiguration import TrigMuonEFIdtpInvMassHypoToolCfg def TrigComboHypoToolFromDict(chainDict): - from TrigHypoCommonTools.TrigHypoCommonToolsConf import TrigComboHypoTool from AthenaMonitoringKernel.GenericMonitoringTool import GenericMonitoringTool chainName = chainDict['chainName'] @@ -195,7 +195,7 @@ def TrigComboHypoToolFromDict(chainDict): # convert list of dicts into dict of lists toolProps = {k:[thedef[k] for thedef in topoDefs] for k in topoDefs[0]} - tool = TrigComboHypoTool(chainName, SkipLegCheck=skipLegCheck, **toolProps) + tool = CompFactory.TrigComboHypoTool(chainName, SkipLegCheck=skipLegCheck, **toolProps) return tool diff --git a/Trigger/TriggerCommon/TriggerMenuMT/python/HLT/Menu/Dev_pp_run3_v1.py b/Trigger/TriggerCommon/TriggerMenuMT/python/HLT/Menu/Dev_pp_run3_v1.py index 574060ac80ecc411f946ec5af737ea8492f108ec..0286305a857cb7840741f10ccc7e5ba6f8d39937 100644 --- a/Trigger/TriggerCommon/TriggerMenuMT/python/HLT/Menu/Dev_pp_run3_v1.py +++ b/Trigger/TriggerCommon/TriggerMenuMT/python/HLT/Menu/Dev_pp_run3_v1.py @@ -73,7 +73,7 @@ def setupMenu(): #ATR-21003 ChainProp(name='HLT_2mu14_l2io_L12MU8F', groups=DevGroup+MultiMuonGroup), ChainProp(name='HLT_2mu6_l2io_L12MU5VF', groups=DevGroup+MultiMuonGroup), - + # Test T&P dimuon ChainProp(name='HLT_mu24_mu6_L1MU14FCH', l1SeedThresholds=['MU14FCH','MU3V'], groups=DevGroup+MultiMuonGroup), ChainProp(name='HLT_mu24_mu6_probe_L1MU14FCH', l1SeedThresholds=['MU14FCH','PROBEMU3V'], groups=DevGroup+MultiMuonGroup), diff --git a/Trigger/TriggerCommon/TriggerMenuMT/python/HLT/Muon/MuonChainConfiguration.py b/Trigger/TriggerCommon/TriggerMenuMT/python/HLT/Muon/MuonChainConfiguration.py index 80afc0921fe03053538aa42b3bed704594bbf087..c809181dc1084dadd73a2625b77f4a1a514baf0b 100755 --- a/Trigger/TriggerCommon/TriggerMenuMT/python/HLT/Muon/MuonChainConfiguration.py +++ b/Trigger/TriggerCommon/TriggerMenuMT/python/HLT/Muon/MuonChainConfiguration.py @@ -13,7 +13,7 @@ from ..Config.ChainConfigurationBase import ChainConfigurationBase from AthenaConfiguration.ComponentFactory import isComponentAccumulatorCfg if isComponentAccumulatorCfg(): - from .generateMuon import muFastSequence, muEFSASequence, muCombSequence, muEFCBSequence + from .generateMuon import muFastSequence, muEFSASequence, muCombSequence, muEFCBSequence, muCombOvlpRmSequence, muFastOvlpRmSequence else: from .MuonMenuSequences import muFastSequence, muFastCalibSequence, muFastOvlpRmSequence, mul2mtSAOvlpRmSequence, muCombSequence, muCombLRTSequence, muCombOvlpRmSequence, mul2mtCBOvlpRmSequence, mul2IOOvlpRmSequence, muEFSASequence, muEFCBSequence, muEFCBIDperfSequence, muEFCBLRTSequence, muEFCBLRTIDperfSequence, muEFSAFSSequence, muEFCBFSSequence, muEFIsoSequence, muEFMSIsoSequence, efLateMuRoISequence, efLateMuSequence, muRoiClusterSequence, muEFIDtpSequence diff --git a/Trigger/TriggerCommon/TriggerMenuMT/python/HLT/Muon/generateMuon.py b/Trigger/TriggerCommon/TriggerMenuMT/python/HLT/Muon/generateMuon.py index 57f722aaf04b0d6708e2df7db0e329a61a2d0971..0417cb482148c240ddd14bf4511a1b1513fcb208 100644 --- a/Trigger/TriggerCommon/TriggerMenuMT/python/HLT/Muon/generateMuon.py +++ b/Trigger/TriggerCommon/TriggerMenuMT/python/HLT/Muon/generateMuon.py @@ -158,11 +158,11 @@ def efMuIsoHypoConf(flags, name="UNSPECIFIED", inputMuons="UNSPECIFIED"): return efHypo @AccumulatorCache -def _muFastStepSeq(flags): +def _muFastStepSeq(flags, is_probe_leg=False): # Step 1 (L2MuonSA) - selAcc = SelectionCA("L2MuFastReco") + selAcc = SelectionCA("L2MuFastReco", is_probe_leg) # Set EventViews for L2MuonSA step - reco = InViewRecoCA("L2MuFastReco") + reco = InViewRecoCA("L2MuFastReco", isProbe=is_probe_leg) #external data loading to view reco.mergeReco( MuFastViewDataVerifier(flags) ) @@ -183,13 +183,13 @@ def _muFastStepSeq(flags): selAcc.addHypoAlgo(l2muFastHypo) l2muFastSequence = MenuSequenceCA(selAcc, - HypoToolGen = TrigMufastHypoToolFromDict ) + HypoToolGen = TrigMufastHypoToolFromDict, isProbe=is_probe_leg ) return (selAcc , l2muFastSequence) def muFastSequence(flags, is_probe_leg=False): muonflags = flags.cloneAndReplace('Muon', 'Trigger.Offline.SA.Muon') - selAcc , l2muFastSequence = _muFastStepSeq(muonflags) + selAcc , l2muFastSequence = _muFastStepSeq(muonflags, is_probe_leg) return l2muFastSequence @@ -199,6 +199,11 @@ def muFastStep(flags, chainDict): return ChainStep( name=selAcc.name, Sequences=[l2muFastSequence], chainDicts=[chainDict] ) +## FP fake, just to test run +def muFastOvlpRmSequence (flags, is_probe_leg=False): + log.warning("FAKE muFastOvlpRmSequence replaced by single muFast") + return muFastSequence(flags, is_probe_leg) + @AccumulatorCache def _muCombStepSeq(flags): ### Set muon step2 - L2muComb ### @@ -236,6 +241,11 @@ def muCombStep(flags, chainDict): return ChainStep( name=selAccL2CB.name, Sequences=[l2muCombSequence], chainDicts=[chainDict] ) +def muCombOvlpRmSequence(flags, is_probe_leg=False): + log.warning("FAKE muCombOvlpRmSequence replaced by single muCombSequence") + return muCombSequence(flags) + + @AccumulatorCache def _muEFSAStepSeq(flags, name='RoI'): #EF MS only diff --git a/Trigger/TriggerCommon/TriggerMenuMT/scripts/test_menu_CA.py b/Trigger/TriggerCommon/TriggerMenuMT/scripts/test_menu_CA.py new file mode 100755 index 0000000000000000000000000000000000000000..f806cb1334a4292beca31c4e1e2bedb50dfbf20c --- /dev/null +++ b/Trigger/TriggerCommon/TriggerMenuMT/scripts/test_menu_CA.py @@ -0,0 +1,46 @@ +#!/usr/bin/env python3 +# Copyright (C) 2002-2023 CERN for the benefit of the ATLAS collaboration + +""" +test of Dev menu with CA migrated menu code, reproducing runHLT_standalone_newJO +""" +from AthenaCommon.Logging import logging +log = logging.getLogger('runHLT_standalone_newJO') + +from AthenaConfiguration.AllConfigFlags import ConfigFlags +from AthenaConfiguration.ComponentAccumulator import ComponentAccumulator +from AthenaConfiguration.AccumulatorCache import AccumulatorDecorator +from AthenaCommon.Configurable import Configurable +Configurable.configurableRun3Behavior = 1 + + +# select chains, as in runHLT_standalone +ConfigFlags.addFlag("Trigger.enabledSignatures",[]) +ConfigFlags.addFlag("Trigger.disabledSignatures",[]) +ConfigFlags.addFlag("Trigger.selectChains",[]) +ConfigFlags.addFlag("Trigger.disableChains",[]) +ConfigFlags.Trigger.enabledSignatures = ['Muon', 'Photon','Electron'] + +from AthenaConfiguration.AllConfigFlags import ConfigFlags +ConfigFlags.Trigger.generateMenuDiagnostics = True + +from AthenaConfiguration.TestDefaults import defaultTestFiles +ConfigFlags.Input.Files = defaultTestFiles.RAW +ConfigFlags.Trigger.triggerMenuSetup="Dev_pp_run3_v1" + +ConfigFlags.Trigger.EDMVersion=3 +ConfigFlags.lock() +ConfigFlags.dump() + + +acc = ComponentAccumulator() +from TrigConfigSvc.TrigConfigSvcCfg import L1ConfigSvcCfg +acc.merge(L1ConfigSvcCfg(ConfigFlags)) + +from TriggerMenuMT.HLT.Config.GenerateMenuMT_newJO import generateMenuMT +menu = generateMenuMT( ConfigFlags) +acc.merge(menu) +acc.printConfig() +AccumulatorDecorator.printStats() + +