From 7236ac7aee669043c004cba70dcadeec1294ffa7 Mon Sep 17 00:00:00 2001
From: Krzysztof Jamrog <krzysztof.piotr.jamrog@cern.ch>
Date: Thu, 21 Mar 2019 19:35:39 +0100
Subject: [PATCH] Flat algorithms structure in CA

---
 Control/AthenaCommon/python/CFElements.py     | 23 +++--
 Control/AthenaCommon/python/Configurable.py   |  3 +
 .../python/ComponentAccumulator.py            | 92 ++++++++++++-------
 .../python/ComponentAccumulatorTest.py        |  9 +-
 .../python/Deduplication.py                   | 13 ---
 .../TrigUpgradeTest/share/EmuNewJOTest.py     |  7 +-
 .../Electron/generateElectron.py              | 30 ++++--
 .../Menu/GenerateMenuMT_newJO.py              |  2 -
 .../HLTMenuConfig/Menu/HLTCFConfig_newJO.py   | 14 +--
 .../HLTMenuConfig/Menu/MenuComponents.py      | 20 +++-
 .../Menu/MenuComponentsNaming.py              |  8 ++
 .../python/HLTMenuConfig/Muon/generateMuon.py | 15 ++-
 .../HLTMenuConfig/Photon/generatePhoton.py    | 29 ++++--
 13 files changed, 172 insertions(+), 93 deletions(-)

diff --git a/Control/AthenaCommon/python/CFElements.py b/Control/AthenaCommon/python/CFElements.py
index ba88b5a750e..5a325c8dfb5 100755
--- a/Control/AthenaCommon/python/CFElements.py
+++ b/Control/AthenaCommon/python/CFElements.py
@@ -1,4 +1,5 @@
 from AthenaCommon.AlgSequence import AthSequencer
+from TriggerMenuMT.HLTMenuConfig.Menu.MenuComponentsNaming import CFNaming
 import collections
 
 def parOR(name, subs=[]):
@@ -71,6 +72,11 @@ def stepSeq(name, filterAlg, rest):
     stepAnd = seqAND(name, [ filterAlg, stepReco ])
     return stepAnd
 
+def createStepView(stepName):
+    stepReco = parOR(CFNaming.stepRecoName(stepName))
+    stepView = seqAND(CFNaming.stepViewName(stepName), [stepReco])
+    return stepReco, stepView
+
 def isSequence( obj ):
     return 'AthSequence' in type( obj ).__name__
     
@@ -130,6 +136,7 @@ def findAllAlgorithms(sequence, nameToLookFor=None):
 
 
 def findAllAlgorithmsByName(sequence, namesToLookFor=None):
+    """Finds all algorithms in sequence and groups them by name"""
     algorithms = collections.defaultdict(list)
     for idx, child in enumerate(sequence.getChildren()):
         if isSequence(child):
@@ -138,7 +145,7 @@ def findAllAlgorithmsByName(sequence, namesToLookFor=None):
                 algorithms[algName] += childAlgs[algName]
         else:
             if namesToLookFor is None or child.name() in namesToLookFor:
-                algorithms[child.name()].append(child)
+                algorithms[child.name()].append( (child, sequence, idx) )
     return algorithms
 
 
@@ -157,19 +164,21 @@ def flatAlgorithmSequences( start ):
     __inner(start, c)
     return c
 
-def flatSequencers( start ):
+def flatSequencers( start, algsCollection=None ):
     """ Flattens sequences """
     
     def __inner( seq, collector ):
         if seq.name() not in collector:
             collector[seq.name()] = []
         for c in seq.getChildren():
+            isSeq = isSequence(c)
+            if not isSeq and algsCollection is not None and c.name() in algsCollection:
+                collector[seq.name()].append( algsCollection[c.name()] )
+                continue
             collector[seq.name()].append( c )
-            if isSequence( c ):            
-                if c.name() in collector: # already visited
-                    pass
-                else:       
-                    __inner( c, collector )
+            if isSeq and c.name() not in collector:
+                __inner( c, collector )
+
 
     from collections import defaultdict
     c = defaultdict(list)
diff --git a/Control/AthenaCommon/python/Configurable.py b/Control/AthenaCommon/python/Configurable.py
index aef02ffea9c..8e2c3d01102 100755
--- a/Control/AthenaCommon/python/Configurable.py
+++ b/Control/AthenaCommon/python/Configurable.py
@@ -402,6 +402,9 @@ class Configurable( object ):
    def getChildren( self ):
       return self.__children[:]    # read only
 
+   def overwriteChild( self, idx, newChild ):
+      self.__children[idx] = newChild
+
    def getAllChildren( self ):
       """Get all (private) configurable children, both explicit ones (added with +=)
       and the ones in the private GaudiHandle properties"""
diff --git a/Control/AthenaConfiguration/python/ComponentAccumulator.py b/Control/AthenaConfiguration/python/ComponentAccumulator.py
index b132fb4a963..715dd4841f8 100644
--- a/Control/AthenaConfiguration/python/ComponentAccumulator.py
+++ b/Control/AthenaConfiguration/python/ComponentAccumulator.py
@@ -3,12 +3,12 @@
 from AthenaCommon.Logging import logging
 from AthenaCommon.Configurable import Configurable,ConfigurableService,ConfigurableAlgorithm,ConfigurableAlgTool
 from AthenaCommon.CFElements import isSequence,findSubSequence,findAlgorithm,flatSequencers,findOwningSequence,\
-    checkSequenceConsistency, findAllAlgorithms
+    checkSequenceConsistency, findAllAlgorithmsByName
 from AthenaCommon.AlgSequence import AthSequencer
 
 import GaudiKernel.GaudiHandles as GaudiHandles
 
-from Deduplication import deduplicate, deduplicateWithAll, DeduplicationFailed
+from Deduplication import deduplicate, deduplicateComponent, DeduplicationFailed
 
 import ast
 import collections
@@ -41,6 +41,7 @@ class ComponentAccumulator(object):
         self._wasMerged=False
         self._isMergable=True
 
+        self._algorithms = {}
 
     def empty(self):
         return len(self._sequence)+len(self._conditionsAlgs)+len(self._services)+\
@@ -123,6 +124,9 @@ class ComponentAccumulator(object):
 
     def addSequence(self, newseq, parentName = None ):
         """ Adds new sequence. If second argument is present then it is added under another sequence  """
+        if not isSequence(newseq):
+            raise TypeError('{} is not a sequence'.format(newseq.name()))
+
         if parentName is None:
             parent=self._sequence
         else:
@@ -131,10 +135,19 @@ class ComponentAccumulator(object):
                 raise ConfigurationError("Missing sequence %s to add new sequence to" % parentName )
 
         parent += newseq
-        checkSequenceConsistency(self._sequence)
-        return newseq 
-
+        algsByName = findAllAlgorithmsByName(newseq)
+        for name, existingAlgs in algsByName.iteritems():
+            startingIndex = 0
+            if name not in self._algorithms:
+                firstAlg, parent, idx = existingAlgs[0]
+                self._algorithms[name] = firstAlg
+                startingIndex = 1
+            for alg, parent, idx in existingAlgs[startingIndex:]:
+                deduplicateComponent(self._algorithms[name], alg)
+                parent.overwriteChild(idx, self._algorithms[name])
 
+        checkSequenceConsistency(self._sequence)
+        return newseq
 
     def moveSequence(self, sequence, destination ):
         """ moves sequence from one sub-sequence to another, primary use case HLT Control Flow """
@@ -207,15 +220,19 @@ class ComponentAccumulator(object):
         else:
             seq = findSubSequence(self._sequence, sequenceName )
         if seq is None:
+            self.printConfig()
             raise ConfigurationError("Can not find sequence %s" % sequenceName )
 
         for algo in algorithms:
             if not isinstance(algo, ConfigurableAlgorithm):
                 raise TypeError("Attempt to add wrong type: %s as event algorithm" % type( algo ).__name__)
-            deduplicateWithAll(self.getSequence(), [algo])
-            existingAlgInDest = findAlgorithm(seq, algo.getName())
+            if algo.name() in self._algorithms:
+                deduplicateComponent(self._algorithms[algo.name()], algo)
+            else:
+                self._algorithms[algo.name()] = algo
+            existingAlgInDest = findAlgorithm(seq, algo.name())
             if not existingAlgInDest:
-                seq += algo
+                seq += self._algorithms[algo.name()]
 
         if primary:
             if len(algorithms)>1:
@@ -227,31 +244,17 @@ class ComponentAccumulator(object):
             self._primaryComp=algorithms[0]
         return None
 
-
-    def getEventAlgo(self,name=None,seqName=None):
-        if name is None:
-            algs = self.getEventAlgos(seqName)
-            if len(algs) == 1:
-                return algs[0]
-            raise ConfigurationError("Number of algorithms returned by getEventAlgo %d which is != 1 expected by this API" % len(algs) )
-                
-        if seqName is None:
-            seq=self._sequence
-        else:
-            seq = findSubSequence(self._sequence, seqName )
-        
-
-        algo = findAlgorithm( seq, name )
-        if algo is None:
+    def getEventAlgo(self,name=None):
+        if name not in self._algorithms:
             raise ConfigurationError("Can not find an algorithm of name %s "% name)
-        return algo
+        return self._algorithms[name]
 
     def getEventAlgos(self,seqName=None):
         if seqName is None:
             seq=self._sequence
         else:
             seq = findSubSequence(self._sequence, seqName )
-        return list( set( sum( flatSequencers( seq ).values(), []) ) )
+        return list( set( sum( flatSequencers( seq, algsCollection=self._algorithms ).values(), []) ) )
 
     def addCondAlgo(self,algo,primary=False):
         if not isinstance(algo, ConfigurableAlgorithm):
@@ -389,19 +392,32 @@ class ComponentAccumulator(object):
         #if destSubSeq == None:
         #    raise ConfigurationError( "Nonexistent sequence %s in %s (or its sub-sequences)" % ( sequence, self._sequence.name() ) )          #
         def mergeSequences( dest, src ):
-            for c in src.getChildren():
+            for childIdx, c in enumerate(src.getChildren()):
                 if isSequence( c ):
                     sub = findSubSequence( dest, c.name() ) #depth=1 ???
                     if sub:
                         mergeSequences(sub, c )
                     else:
                         self._msg.debug("  Merging sequence %s to a sequence %s", c.name(), dest.name() )
-                        algorithms = findAllAlgorithms(c)
-                        deduplicateWithAll(self.getSequence(), algorithms)
+                        algorithmsByName = findAllAlgorithmsByName(c)
+                        for name, existingAlgs in algorithmsByName.iteritems():
+                            startingIndex = 0
+                            if name not in self._algorithms:
+                                firstAlg, parent, idx = existingAlgs[0]
+                                self._algorithms[name] = firstAlg
+                                startingIndex = 1
+                            for alg, parent, idx in existingAlgs[startingIndex:]:
+                                deduplicateComponent(self._algorithms[name], alg)
+                                parent.overwriteChild(idx, self._algorithms[name])
                         dest += c
 
                 else: # an algorithm
-                    deduplicateWithAll(self.getSequence(), [c])
+                    if c.name() in self._algorithms:
+                        deduplicateComponent(self._algorithms[c.name()], c)
+                        src.overwriteChild(childIdx, self._algorithms[c.name()])
+                    else:
+                        self._algorithms[c.name()] = c
+
                     existingAlgInDest = findAlgorithm( dest, c.name(), depth=1 )
                     if not existingAlgInDest:
                         self._msg.debug("Adding algorithm %s to a sequence %s", c.name(), dest.name() )
@@ -417,6 +433,12 @@ class ComponentAccumulator(object):
             destSeq=findSubSequence(self._sequence,other._sequence.name()) or self._sequence
         mergeSequences(destSeq,other._sequence)
 
+        # Additional checking and updating other accumulator's algorithms list
+        for name, alg in other._algorithms.iteritems():
+            if name not in self._algorithms:
+                raise ConfigurationError('Error in merging. Algorithm {} missing in destination accumulator'.format(name))
+            other._algorithms[name] = self._algorithms[name]
+
         #self._conditionsAlgs+=other._conditionsAlgs
         for condAlg in other._conditionsAlgs:
             self.addCondAlgo(condAlg) #Profit from deduplicaton here
@@ -573,7 +595,7 @@ class ComponentAccumulator(object):
                                                         'JobOptionsSvc/JobOptionsSvc']"
 
             #Code seems to be wrong here
-            for seqName, algoList in flatSequencers( self._sequence ).iteritems():
+            for seqName, algoList in flatSequencers( self._sequence, algsCollection=self._algorithms ).iteritems():
                 self._jocat[seqName] = {}
                 for alg in algoList:
                   self._jocat[alg.name()] = {}
@@ -581,13 +603,13 @@ class ComponentAccumulator(object):
                 self._jocat[self._sequence.getName()][k]=str(v)
 
         #EventAlgorithms
-        for seqName, algoList  in flatSequencers( self._sequence ).iteritems():
+        for seqName, algoList  in flatSequencers( self._sequence, algsCollection=self._algorithms ).iteritems():
             evtalgseq=[]
             for alg in algoList:
                 self.appendConfigurable( alg )
                 evtalgseq.append( alg.getFullName() )
 
-        for seqName, algoList  in flatSequencers( self._sequence ).iteritems():
+        for seqName, algoList  in flatSequencers( self._sequence, algsCollection=self._algorithms ).iteritems():
             # part of the sequence may come from the bootstrap, we need to retain the content, that is done here
             for prop in self._jocat[seqName]:
                 if prop == "Members":
@@ -702,8 +724,8 @@ class ComponentAccumulator(object):
             pass
 
         #Add tree of algorithm sequences:
-        for seqName, algoList in flatSequencers( self._sequence ).iteritems():
-            self._msg.debug("Members of %s : %s", seqName, str([alg.getFullName() for alg in algoList]))
+        for seqName, algoList in flatSequencers( self._sequence, algsCollection=self._algorithms ).iteritems():
+            self._msg.debug("Members of %s : %s" % (seqName,str([alg.getFullName() for alg in algoList])))
             bsh.addPropertyToCatalogue(jos,seqName,"Members",str( [alg.getFullName() for alg in algoList]))
             for alg in algoList:
                 addCompToJos(alg)
diff --git a/Control/AthenaConfiguration/python/ComponentAccumulatorTest.py b/Control/AthenaConfiguration/python/ComponentAccumulatorTest.py
index 2cdc54e51eb..1b7d5d88910 100644
--- a/Control/AthenaConfiguration/python/ComponentAccumulatorTest.py
+++ b/Control/AthenaConfiguration/python/ComponentAccumulatorTest.py
@@ -292,11 +292,10 @@ class TestComponentAccumulatorAccessors( unittest.TestCase ):
         from AthenaCommon.Configurable import ConfigurablePyAlgorithm,ConfigurableAlgTool
         ca.addEventAlgo(ConfigurablePyAlgorithm("alg1"))
 
-        self.assertIsNotNone( ca.getEventAlgo(), "Found single alg")
-        self.assertEqual( len(ca.getEventAlgos()), 1 , "Found single alg")
-# no idea why this assersts do not recognise exceptions        
-#        self.assertRaises(ConfigurationError, ca.getEventAlgo("alg2")) 
-        
+        self.assertEquals( len(ca.getEventAlgos()), 1 , "Found single alg")
+# no idea why this assersts do not recognise exceptions
+#        self.assertRaises(ConfigurationError, ca.getEventAlgo("alg2"))
+
         ca.addEventAlgo(ConfigurablePyAlgorithm("alg2"))
 
         self.assertIsNotNone( ca.getEventAlgo("alg2"), "Found single alg")
diff --git a/Control/AthenaConfiguration/python/Deduplication.py b/Control/AthenaConfiguration/python/Deduplication.py
index 5fb69e43477..67874d6ec4e 100644
--- a/Control/AthenaConfiguration/python/Deduplication.py
+++ b/Control/AthenaConfiguration/python/Deduplication.py
@@ -129,16 +129,3 @@ def deduplicateComponent(newComp,comp):
             pass
         #end if startswith("_")
     return newComp
-
-
-def deduplicateWithAll(sequence, algorithms):
-    existingAlgsByName = findAllAlgorithmsByName(sequence, namesToLookFor=set(map(lambda alg: alg.name(), algorithms)))
-    for alg in algorithms:
-        existingAlgs = existingAlgsByName[alg.name()]
-        for idx, existingAlg in enumerate(existingAlgs):
-            if alg == existingAlg:
-                continue
-            deduplicateComponent(alg, existingAlg)
-            if idx == len(existingAlgs) - 1:
-                # Merge other way around with last algorithm
-                deduplicateComponent(existingAlg, alg)
diff --git a/Trigger/TrigValidation/TrigUpgradeTest/share/EmuNewJOTest.py b/Trigger/TrigValidation/TrigUpgradeTest/share/EmuNewJOTest.py
index 3d0e4572177..8a5a7571afc 100644
--- a/Trigger/TrigValidation/TrigUpgradeTest/share/EmuNewJOTest.py
+++ b/Trigger/TrigValidation/TrigUpgradeTest/share/EmuNewJOTest.py
@@ -19,6 +19,7 @@ from AthenaCommon.CFElements import seqOR
 from RegionSelector.RegSelConfig import regSelCfg
 from TrigUpgradeTest.InDetConfig import TrigInDetCondConfig
 from TrigUpgradeTest.EmuStepProcessingConfig import generateL1DecoderAndChains
+from AthenaCommon.CFElements import createStepView
 
 log = logging.getLogger('EmuNewJOTest')
 
@@ -56,8 +57,12 @@ for index, chain in enumerate(HLTChains):
             hypoTool = seq.hypoToolConf.hypoToolGen(chainDicts[index])
             hypoAlg.HypoTools = [hypoTool]
 
+            stepReco, stepView = createStepView(step.name)
+
             sequenceAcc = ComponentAccumulator()
-            sequenceAcc.addSequence(seq.sequence.Alg)
+            sequenceAcc.addSequence(stepView)
+            sequenceAcc.addSequence(seq.sequence.Alg, parentName=stepReco.getName())
+            sequenceAcc.addEventAlgo(hypoAlg, sequenceName=stepView.getName())
             seq.ca = sequenceAcc
             sequenceAcc.wasMerged()
 
diff --git a/Trigger/TriggerCommon/TriggerMenuMT/python/HLTMenuConfig/Electron/generateElectron.py b/Trigger/TriggerCommon/TriggerMenuMT/python/HLTMenuConfig/Electron/generateElectron.py
index b095360f295..676b94563b8 100644
--- a/Trigger/TriggerCommon/TriggerMenuMT/python/HLTMenuConfig/Electron/generateElectron.py
+++ b/Trigger/TriggerCommon/TriggerMenuMT/python/HLTMenuConfig/Electron/generateElectron.py
@@ -6,6 +6,8 @@ from TriggerMenuMT.HLTMenuConfig.Menu.MenuComponents import MenuSequence, \
 
 from TrigEgammaHypo.TrigL2CaloHypoTool import TrigL2CaloHypoToolFromDict
 from AthenaConfiguration.ComponentAccumulator import ComponentAccumulator
+from AthenaCommon.CFElements import createStepView
+
 
 # TODO remove once full tracking is in place
 def fakeHypoAlgCfg(flags, name="FakeHypoForElectron"):
@@ -17,17 +19,20 @@ def generateChains( flags,  chainDict ):
     import pprint
     pprint.pprint( chainDict )
 
+    firstStepName = getChainStepName('Electron', 1)
+    stepReco, stepView = createStepView(firstStepName)
+
     accCalo = ComponentAccumulator()
+    accCalo.addSequence(stepView)
+
+    l2CaloReco = l2CaloRecoCfg(flags)
+    accCalo.merge(l2CaloReco, sequenceName=stepReco.getName())
 
     l2CaloHypo =  l2CaloHypoCfg( flags, name = 'L2ElectronCaloHypo',
                                  CaloClusters = 'L2CaloEMClusters')
     l2CaloHypo.HypoTools=[ TrigL2CaloHypoToolFromDict( chainDict ) ]
 
-    l2CaloReco = l2CaloRecoCfg(flags)
-    accCalo.merge(l2CaloReco)
-    #l2CaloReco = l2CaloRecoCfg( flags ) 
-    #accCalo.merge( l2CaloReco )
-
+    accCalo.addEventAlgo(l2CaloHypo, sequenceName=stepView.getName())
 
     fastCaloSequence = MenuSequence( Sequence    = l2CaloReco.sequence(),
                                      Maker       = l2CaloReco.inputMaker(),
@@ -35,14 +40,21 @@ def generateChains( flags,  chainDict ):
                                      HypoToolGen = None, 
                                      CA = accCalo)
 
-    fastCaloStep = ChainStep(getChainStepName('Electron', 1), [fastCaloSequence])
+    accCalo.printConfig()
+
+    fastCaloStep = ChainStep(firstStepName, [fastCaloSequence])
+
+
+    secondStepName = getChainStepName('Electron', 2)
+    stepReco, stepView = createStepView(secondStepName)
 
     accTrk = ComponentAccumulator()
+    accTrk.addSequence(stepView)
 
     # # # fast ID
     from TrigUpgradeTest.InDetConfig import indetInViewRecoCfg
     fastInDetReco = indetInViewRecoCfg(flags, viewMakerName='ElectronInDet')
-    accTrk.merge( fastInDetReco )
+    accTrk.merge( fastInDetReco, sequenceName=stepReco.getName() )
     # TODO once tracking fully works remove fake hypos
 
     from TrigUpgradeTest.TrigUpgradeTestConf import HLTTest__TestHypoTool
@@ -56,13 +68,15 @@ def generateChains( flags,  chainDict ):
 
     fakeHypoAlg.HypoTools = [ makeFakeHypoTool(chainDict['chainName'], None) ]
 
+    accTrk.addEventAlgo(fakeHypoAlg, sequenceName=stepView.getName())
+
     fastInDetSequence = MenuSequence( Sequence    = fastInDetReco.sequence(),
                                       Maker       = fastInDetReco.inputMaker(),
                                       Hypo        = fakeHypoAlg,
                                       HypoToolGen = None,
                                       CA = accTrk)
 
-    fastInDetStep = ChainStep( getChainStepName( "Electron", 2 ), [fastInDetSequence] )
+    fastInDetStep = ChainStep( secondStepName, [fastInDetSequence] )
     
     # # # EF calo
 
diff --git a/Trigger/TriggerCommon/TriggerMenuMT/python/HLTMenuConfig/Menu/GenerateMenuMT_newJO.py b/Trigger/TriggerCommon/TriggerMenuMT/python/HLTMenuConfig/Menu/GenerateMenuMT_newJO.py
index 34364de05b3..f7939bf3afa 100644
--- a/Trigger/TriggerCommon/TriggerMenuMT/python/HLTMenuConfig/Menu/GenerateMenuMT_newJO.py
+++ b/Trigger/TriggerCommon/TriggerMenuMT/python/HLTMenuConfig/Menu/GenerateMenuMT_newJO.py
@@ -92,8 +92,6 @@ def generateMenu( flags ):
 
     menuAcc.printConfig()
 
-    # kaboom
-
     _log.info('CF is built')
 
     return menuAcc
diff --git a/Trigger/TriggerCommon/TriggerMenuMT/python/HLTMenuConfig/Menu/HLTCFConfig_newJO.py b/Trigger/TriggerCommon/TriggerMenuMT/python/HLTMenuConfig/Menu/HLTCFConfig_newJO.py
index cbc71ca92ff..28acc218c07 100644
--- a/Trigger/TriggerCommon/TriggerMenuMT/python/HLTMenuConfig/Menu/HLTCFConfig_newJO.py
+++ b/Trigger/TriggerCommon/TriggerMenuMT/python/HLTMenuConfig/Menu/HLTCFConfig_newJO.py
@@ -7,7 +7,7 @@ from TriggerMenuMT.HLTMenuConfig.Menu.HLTCFConfig import buildFilter, makeSummar
 from TriggerMenuMT.HLTMenuConfig.Menu.HLTCFDot import stepCF_DataFlow_to_dot, \
     stepCF_ControlFlow_to_dot, all_DataFlow_to_dot
 from TriggerMenuMT.HLTMenuConfig.Menu.MenuComponents import CFSequence
-from AthenaCommon.CFElements import parOR, seqAND
+from AthenaCommon.CFElements import parOR, seqAND, createStepView
 from AthenaCommon.Logging import logging
 
 log = logging.getLogger('HLTCFConfig_newJO')
@@ -77,9 +77,10 @@ def generateDecisionTree(chains):
             sfilter = buildFilter(filterName, filter_input)
             filterAcc.addEventAlgo(sfilter.Alg, sequenceName = stepFilterNodeName)
 
-            stepReco = parOR('{}{}'.format(chainStep.name, CFNaming.RECO_POSTFIX))
-            stepView = seqAND('{}{}'.format(chainStep.name, CFNaming.VIEW_POSTFIX), [stepReco])
+            stepReco, stepView = createStepView(chainStep.name)
             viewWithFilter = seqAND(chainStep.name, [sfilter.Alg, stepView])
+            # viewWithFilter = seqAND(chainStep.name, [sfilter.Alg])
+
             recoAcc.addSequence(viewWithFilter, parentName = stepRecoNodeName)
 
             stepsAcc = ComponentAccumulator()
@@ -96,12 +97,11 @@ def generateDecisionTree(chains):
                     if seq.ca is None:
                         raise ValueError('ComponentAccumulator missing in sequence {} in chain {}'.format(seq.name, chain.name))
                     stepsAcc.merge( seq.ca )
-                    recoAcc.addEventAlgo(seq.hypo.Alg, sequenceName = stepView.getName())
                 if step.isCombo:
-                    recoAcc.addEventAlgo(step.combo.Alg, sequenceName = stepView.getName())
+                    stepsAcc.addEventAlgo(step.combo.Alg, sequenceName = stepView.getName())
                 sfilter.setChains(chain.name)
 
-            recoAcc.merge(stepsAcc, sequenceName = stepReco.getName())
+            recoAcc.merge(stepsAcc, sequenceName = viewWithFilter.getName())
 
             for sequence in chainStep.sequences:
                 stepDecisions += sequence.outputs
@@ -110,7 +110,7 @@ def generateDecisionTree(chains):
         acc.merge(recoAcc, sequenceName = mainSequenceName)
 
         summary = makeSummary('TriggerSummary{}'.format(stepName), stepDecisions)
-        acc.addSequence(summary, parentName = mainSequenceName)
+        acc.addEventAlgo(summary, sequenceName = mainSequenceName)
 
         allCFSequences.append(CFSequences)
 
diff --git a/Trigger/TriggerCommon/TriggerMenuMT/python/HLTMenuConfig/Menu/MenuComponents.py b/Trigger/TriggerCommon/TriggerMenuMT/python/HLTMenuConfig/Menu/MenuComponents.py
index 0afa4d7441f..5f84881d928 100644
--- a/Trigger/TriggerCommon/TriggerMenuMT/python/HLTMenuConfig/Menu/MenuComponents.py
+++ b/Trigger/TriggerCommon/TriggerMenuMT/python/HLTMenuConfig/Menu/MenuComponents.py
@@ -255,9 +255,9 @@ class MenuSequence():
     def __init__(self, Sequence, Maker,  Hypo, HypoToolGen, CA=None ):
         self.name = CFNaming.menuSequenceName(Hypo.name())
         self.sequence     = Node( Alg=Sequence)
-        self.maker        = InputMakerNode( Alg = Maker )
+        self._maker       = InputMakerNode( Alg = Maker )
         self.hypoToolConf = HypoToolConf( HypoToolGen ) if HypoToolGen else None
-        self.hypo         = HypoAlgNode( Alg = Hypo )
+        self._hypo        = HypoAlgNode( Alg = Hypo )
         self.inputs=[]
         self.outputs=[]
         self.seed=''
@@ -268,6 +268,22 @@ class MenuSequence():
         log.debug("set new Hypo %s for combo sequence %s "%(HypoAlg.name(), self.name))
         self.hypo= HypoAlgNode( Alg=HypoAlg )
 
+    @property
+    def maker(self):
+        if self.ca is not None:
+            makerAlg = self.ca.getEventAlgo(self._maker.Alg.name())
+            self._maker.Alg = makerAlg
+            # return InputMakerNode(Alg=makerAlg)
+        return self._maker
+
+    @property
+    def hypo(self):
+        if self.ca is not None:
+            hypoAlg = self.ca.getEventAlgo(self._hypo.Alg.name())
+            self._hypo.Alg = hypoAlg
+            # return HypoAlgNode(Alg=hypoAlg)
+        return self._hypo
+
     def connectToFilter(self, outfilter):
         """ Sets the input and output of the hypo, and links to the input maker """
 
diff --git a/Trigger/TriggerCommon/TriggerMenuMT/python/HLTMenuConfig/Menu/MenuComponentsNaming.py b/Trigger/TriggerCommon/TriggerMenuMT/python/HLTMenuConfig/Menu/MenuComponentsNaming.py
index 93af4058439..708754a5e37 100644
--- a/Trigger/TriggerCommon/TriggerMenuMT/python/HLTMenuConfig/Menu/MenuComponentsNaming.py
+++ b/Trigger/TriggerCommon/TriggerMenuMT/python/HLTMenuConfig/Menu/MenuComponentsNaming.py
@@ -61,3 +61,11 @@ class CFNaming ():
     @staticmethod
     def stepSummaryName(StepCFName):
         return ("TriggerSummary"+ StepCFName)
+
+    @staticmethod
+    def stepRecoName(stepName):
+        return '{}{}'.format(stepName, CFNaming.RECO_POSTFIX)
+
+    @staticmethod
+    def stepViewName(stepName):
+        return '{}{}'.format(stepName, CFNaming.VIEW_POSTFIX)
\ No newline at end of file
diff --git a/Trigger/TriggerCommon/TriggerMenuMT/python/HLTMenuConfig/Muon/generateMuon.py b/Trigger/TriggerCommon/TriggerMenuMT/python/HLTMenuConfig/Muon/generateMuon.py
index 00b0ced4b5b..6f11f083231 100644
--- a/Trigger/TriggerCommon/TriggerMenuMT/python/HLTMenuConfig/Muon/generateMuon.py
+++ b/Trigger/TriggerCommon/TriggerMenuMT/python/HLTMenuConfig/Muon/generateMuon.py
@@ -5,11 +5,19 @@ from AthenaConfiguration.ComponentAccumulator import ComponentAccumulator
 
 from TriggerMenuMT.HLTMenuConfig.Muon.MuonMenuConfig import l2MuFastRecoCfg, l2MuFastHypoCfg
 from TrigMuonHypoMT.TrigMuonHypoMTConfig import TrigMufastHypoToolFromDict
+from AthenaCommon.CFElements import createStepView
 
 
 def generateChains( flags, chainDict ):
 
+    stepName = getChainStepName('Muon', 1)
+    stepReco, stepView = createStepView(stepName)
+
     acc = ComponentAccumulator()
+    acc.addSequence(stepView)
+
+    l2muFastReco = l2MuFastRecoCfg(flags)
+    acc.merge( l2muFastReco, sequenceName=stepReco.getName() )
 
     ### Set muon step1 ###
     l2muFastHypo = l2MuFastHypoCfg( flags,
@@ -18,16 +26,15 @@ def generateChains( flags, chainDict ):
 
     l2muFastHypo.HypoTools = [ TrigMufastHypoToolFromDict(chainDict) ]
 
-    l2muFastReco = l2MuFastRecoCfg(flags)
-    acc.merge( l2muFastReco )
+    acc.addEventAlgo(l2muFastHypo, sequenceName=stepView.getName())
 
     l2muFastSequence = MenuSequence( Sequence = l2muFastReco.sequence(),
                                      Maker = l2muFastReco.inputMaker(),
-                                     Hypo = l2muFastHypo, 
+                                     Hypo = l2muFastHypo,
                                      HypoToolGen = None,
                                      CA = acc )
 
-    l2muFastStep = ChainStep( getChainStepName('Muon', 1), [l2muFastSequence] )
+    l2muFastStep = ChainStep( stepName, [l2muFastSequence] )
 
     ### Set muon step2 ###
     # Please set up L2muComb step here 
diff --git a/Trigger/TriggerCommon/TriggerMenuMT/python/HLTMenuConfig/Photon/generatePhoton.py b/Trigger/TriggerCommon/TriggerMenuMT/python/HLTMenuConfig/Photon/generatePhoton.py
index da9e6ccef25..215ea6656a8 100644
--- a/Trigger/TriggerCommon/TriggerMenuMT/python/HLTMenuConfig/Photon/generatePhoton.py
+++ b/Trigger/TriggerCommon/TriggerMenuMT/python/HLTMenuConfig/Photon/generatePhoton.py
@@ -8,11 +8,19 @@ from AthenaConfiguration.ComponentAccumulator import ComponentAccumulator
 
 from TrigEgammaHypo.TrigL2CaloHypoTool import TrigL2CaloHypoToolFromDict
 from TrigEgammaHypo.TrigL2PhotonHypoTool import TrigL2PhotonHypoToolFromDict
+from AthenaCommon.CFElements import createStepView
 
 
 def generateChains(flags, chainDict):
+
+    firstStepName = getChainStepName('Photon', 1)
+    stepReco, stepView = createStepView(firstStepName)
+
     accCalo = ComponentAccumulator()
+    accCalo.addSequence(stepView)
 
+    l2CaloReco = l2CaloRecoCfg(flags)
+    accCalo.merge(l2CaloReco, sequenceName=stepReco.getName())
 
     l2CaloHypo = l2CaloHypoCfg( flags,
                                 name = 'L2PhotonCaloHypo',
@@ -20,10 +28,7 @@ def generateChains(flags, chainDict):
 
     l2CaloHypo.HypoTools = [ TrigL2CaloHypoToolFromDict(chainDict) ]
 
-    l2CaloReco = l2CaloRecoCfg(flags)
-    accCalo.merge(l2CaloReco)
-    #l2CaloReco = l2CaloRecoCfg( flags ) 
-    #accCalo.merge( l2CaloReco )
+    accCalo.addEventAlgo(l2CaloHypo, sequenceName=stepView.getName())
 
     fastCaloSequence = MenuSequence( Sequence = l2CaloReco.sequence(),
                                      Maker = l2CaloReco.inputMaker(),
@@ -31,9 +36,17 @@ def generateChains(flags, chainDict):
                                      HypoToolGen = None,
                                      CA = accCalo )
 
-    fastCaloStep = ChainStep(getChainStepName('Photon', 1), [fastCaloSequence])
+    fastCaloStep = ChainStep(firstStepName, [fastCaloSequence])
+
+
+    secondStepName = getChainStepName('Photon', 2)
+    stepReco, stepView = createStepView(secondStepName)
 
     accPhoton = ComponentAccumulator()
+    accPhoton.addSequence(stepView)
+
+    l2PhotonReco = l2PhotonRecoCfg(flags)
+    accPhoton.merge(l2PhotonReco, sequenceName=stepReco.getName())
 
     l2PhotonHypo = l2PhotonHypoCfg( flags,
                                     Photons = 'L2Photons',
@@ -41,9 +54,7 @@ def generateChains(flags, chainDict):
 
     l2PhotonHypo.HypoTools = [ TrigL2PhotonHypoToolFromDict(chainDict) ]
 
-    l2PhotonReco = l2PhotonRecoCfg(flags)
-    accPhoton.merge(l2PhotonReco)
-
+    accPhoton.addEventAlgo(l2PhotonHypo, sequenceName=stepView.getName())
 
     l2PhotonSequence = MenuSequence( Sequence = l2PhotonReco.sequence(),
                                      Maker = l2PhotonReco.inputMaker(),
@@ -51,7 +62,7 @@ def generateChains(flags, chainDict):
                                      HypoToolGen = None,
                                      CA = accPhoton )
 
-    l2PhotonStep = ChainStep(getChainStepName('Photon', 2), [l2PhotonSequence])
+    l2PhotonStep = ChainStep(secondStepName, [l2PhotonSequence])
 
     import pprint
     pprint.pprint(chainDict)
-- 
GitLab