From 0d694c61f6dee493bdf3774149e7c0637487be95 Mon Sep 17 00:00:00 2001
From: Joseph Earl Lambert <joseph.earl.lambert@cern.ch>
Date: Fri, 3 May 2024 11:38:56 +0200
Subject: [PATCH] Add unit test for the text configuration

update FullCPAlgorithmsTest so that the order matches the text config and is identical to the yaml config
---
 .../AnalysisAlgorithmsConfig/CMakeLists.txt   |  15 +-
 .../data/for_compare.yaml                     |  30 +++-
 .../python/ConfigText_unitTest.py             | 161 ++++++++++++++----
 .../python/FullCPAlgorithmsTest.py            | 147 ++++++++--------
 4 files changed, 239 insertions(+), 114 deletions(-)

diff --git a/PhysicsAnalysis/Algorithms/AnalysisAlgorithmsConfig/CMakeLists.txt b/PhysicsAnalysis/Algorithms/AnalysisAlgorithmsConfig/CMakeLists.txt
index a669f73dc73c..bcfda4923cca 100644
--- a/PhysicsAnalysis/Algorithms/AnalysisAlgorithmsConfig/CMakeLists.txt
+++ b/PhysicsAnalysis/Algorithms/AnalysisAlgorithmsConfig/CMakeLists.txt
@@ -56,11 +56,6 @@ else()
 
 endif()
 
-atlas_add_test( ConfigTextUnitTest
-   SCRIPT python/ConfigText_unitTest.py --text-config ${CONFIG_PATH}
-   POST_EXEC_SCRIPT nopost.sh
-   PROPERTIES TIMEOUT 30 )
-
 # This runs test jobs for both sequences and block configs.  Currently
 # (26 Apr 24) we are running both, but the tests that compare their
 # output are disabled (i.e. commented out).  The comparisons had
@@ -71,6 +66,16 @@ atlas_add_test( ConfigTextUnitTest
 # out comparison tests.
 
 
+atlas_add_test( ConfigTextCompareBuilder
+   SCRIPT python/ConfigText_unitTest.py --text-config ${CONFIG_PATH} --compare-builder --check-order
+   POST_EXEC_SCRIPT nopost.sh
+   PROPERTIES TIMEOUT 30 )
+
+atlas_add_test( ConfigTextCompareBlock
+   SCRIPT python/ConfigText_unitTest.py --text-config ${CONFIG_PATH} --compare-block --check-order
+   POST_EXEC_SCRIPT nopost.sh
+   PROPERTIES TIMEOUT 30 )
+
 add_test_job( TestJobDataSequence data --for-compare --no-systematics )
 add_test_job( TestJobDataConfig data --for-compare --block-config --no-systematics )
 add_test_job( TestJobDataTextConfig data --for-compare --text-config ${CONFIG_PATH} --no-systematics )
diff --git a/PhysicsAnalysis/Algorithms/AnalysisAlgorithmsConfig/data/for_compare.yaml b/PhysicsAnalysis/Algorithms/AnalysisAlgorithmsConfig/data/for_compare.yaml
index 6cbbab165e36..44d4ac7e83bb 100644
--- a/PhysicsAnalysis/Algorithms/AnalysisAlgorithmsConfig/data/for_compare.yaml
+++ b/PhysicsAnalysis/Algorithms/AnalysisAlgorithmsConfig/data/for_compare.yaml
@@ -63,7 +63,29 @@ TauJets:
         quality: 'Tight'
     PtEtaSelection: {}
 
-GeneratorLevelAnalysis: {}
+SystObjectLink:
+  - containerName: 'AnaJets'
+  - containerName: 'AnaElectrons'
+  - containerName: 'AnaPhotons'
+  - containerName: 'AnaMuons'
+  - containerName: 'AnaTauJets'
+
+ObjectCutFlow:
+  - containerName: 'AnaJets'
+    selectionName: 'jvt'
+  - containerName: 'AnaElectrons'
+    selectionName: 'loose'
+  - containerName: 'AnaPhotons'
+    selectionName: 'tight'
+  - containerName: 'AnaMuons'
+    selectionName: 'medium'
+  - containerName: 'AnaTauJets'
+    selectionName: 'tight'
+
+GeneratorLevelAnalysis:
+  - saveCutBookkeepers: True
+    runNumber: 284500
+    cutBookkeepersSystematics: True
 
 # containerName and selectionName must be defined in their respective blocks
 MissingET:
@@ -87,8 +109,6 @@ OverlapRemoval:
     muons: 'AnaMuons.medium'
 
 Thinning:
-  - containerName: 'AnaJets'
-    outputName: 'OutJets'
   - containerName: 'AnaElectrons'
     outputName: 'OutElectrons'
     selectionName: 'loose'
@@ -101,6 +121,8 @@ Thinning:
   - containerName: 'AnaTauJets'
     outputName: 'OutTauJets'
     selectionName: 'tight'
+  - containerName: 'AnaJets'
+    outputName: 'OutJets'
 
 # After configuring each container, many variables will be saved automatically.
 Output:
@@ -118,7 +140,7 @@ Output:
         '': 'EventInfo'
     commands:
       - 'disable jet_select_baselineJvt.*'
-      - 'disable el_select_loose.*'
       - 'disable mu_select_medium.*'
       - 'disable ph_select_tight.*'
       - 'disable tau_select_tight.*'
+      - 'disable el_select_loose.*'
diff --git a/PhysicsAnalysis/Algorithms/AnalysisAlgorithmsConfig/python/ConfigText_unitTest.py b/PhysicsAnalysis/Algorithms/AnalysisAlgorithmsConfig/python/ConfigText_unitTest.py
index 82dddaa25895..5c18b175f475 100755
--- a/PhysicsAnalysis/Algorithms/AnalysisAlgorithmsConfig/python/ConfigText_unitTest.py
+++ b/PhysicsAnalysis/Algorithms/AnalysisAlgorithmsConfig/python/ConfigText_unitTest.py
@@ -4,10 +4,51 @@
 #
 # @author Joseph Lambert
 
-def compareTextBuilder(yamlPath='') :
+def compareConfigSeq(seq1, seq2, *, checkOrder=False):
+    """Compares two ConfigSequences"""
+    blocks1 = seq1._blocks
+    blocks2 = seq2._blocks
+    print("Block order for each config sequence")
+    print("\033[4m{0:<30} {1:<30}\033[0m".format("Sequence1", "Sequence2"))
+    for i in range(max(len(blocks1), len(blocks2))):
+        name1, name2 = '', ''
+        if i < len(blocks1):
+            name1 = blocks1[i].__class__.__name__
+        if i < len(blocks2):
+            name2 = blocks2[i].__class__.__name__
+        print(f"{name1:<30} {name2}")
+    if not checkOrder:
+        print("Sorting blocks by name (will not sort blocks with same name)")
+        blocks1.sort(key=lambda x: x.__class__.__name__)
+        blocks2.sort(key=lambda x: x.__class__.__name__)
+    if len(blocks1) != len(blocks2):
+        raise Exception("Number of blocks are different")
+    for i in range(len(blocks1)):
+        block1 = blocks1[i]
+        block2 = blocks2[i]
+        name1 = block1.__class__.__name__
+        name2 = block2.__class__.__name__
+        if name1 != name2:
+            raise Exception(f"In position {i} "
+                f"the first sequence results in {name1} "
+                f"and the second sequence results in {name2}")
+        for name in block1.getOptions():
+            if name == 'groupName':
+                continue
+            value1 = block1.getOptionValue(name)
+            value2 = block2.getOptionValue(name)
+            if value1 != value2:
+                raise Exception(f"For block {name1}, the block "
+                    f"option {name} the first sequence results in {value1} "
+                    f"and the second sequence results in {value2}")
+
+
+def compareTextBuilder(yamlPath='', *, checkOrder=False) :
     """
-    Return result of comparing a ConfigSequence produced using the provided
-    YAML file and the one produced by the Builder sequence below.
+    Create a configSequence using provided YAML file and a
+    configSequence using ConfigText python commands and compare.
+
+    Will raise an exception if configSequences differ
     """
     # create text config object to build text configurations
     from AnalysisAlgorithmsConfig.ConfigText import TextConfig
@@ -109,8 +150,38 @@ def compareTextBuilder(yamlPath='') :
     config.setOptions (containerName='AnaTauJets')
     config.setOptions (selectionDecoration='selectPtEta')
 
+    config.addBlock ('SystObjectLink')
+    config.setOptions (containerName='AnaJets')
+    config.addBlock ('SystObjectLink')
+    config.setOptions (containerName='AnaElectrons')
+    config.addBlock ('SystObjectLink')
+    config.setOptions (containerName='AnaPhotons')
+    config.addBlock ('SystObjectLink')
+    config.setOptions (containerName='AnaMuons')
+    config.addBlock ('SystObjectLink')
+    config.setOptions (containerName='AnaTauJets')
+
+    config.addBlock ('ObjectCutFlow')
+    config.setOptions (containerName='AnaJets')
+    config.setOptions (selectionName='jvt')
+    config.addBlock ('ObjectCutFlow')
+    config.setOptions (containerName='AnaElectrons')
+    config.setOptions (selectionName='loose')
+    config.addBlock ('ObjectCutFlow')
+    config.setOptions (containerName='AnaPhotons')
+    config.setOptions (selectionName='tight')
+    config.addBlock ('ObjectCutFlow')
+    config.setOptions (containerName='AnaMuons')
+    config.setOptions (selectionName='medium')
+    config.addBlock ('ObjectCutFlow')
+    config.setOptions (containerName='AnaTauJets')
+    config.setOptions (selectionName='tight')
+
     # GeneratorLevelAnalysis
     config.addBlock( 'GeneratorLevelAnalysis')
+    config.setOptions (saveCutBookkeepers=True)
+    config.setOptions (runNumber=284500)
+    config.setOptions (cutBookkeepersSystematics=True)
 
     # MissingET
     config.addBlock ('MissingET')
@@ -133,9 +204,6 @@ def compareTextBuilder(yamlPath='') :
 
     # Thinning
     config.addBlock ('Thinning')
-    config.setOptions (containerName='AnaJets')
-    config.setOptions (outputName='OutJets')
-    config.addBlock ('Thinning')
     config.setOptions (containerName='AnaElectrons')
     config.setOptions (selectionName='loose')
     config.setOptions (outputName='OutElectrons')
@@ -151,6 +219,9 @@ def compareTextBuilder(yamlPath='') :
     config.setOptions (containerName='AnaTauJets')
     config.setOptions (selectionName='tight')
     config.setOptions (outputName='OutTauJets')
+    config.addBlock ('Thinning')
+    config.setOptions (containerName='AnaJets')
+    config.setOptions (outputName='OutJets')
 
     config.addBlock ('Output')
     config.setOptions (treeName='analysis')
@@ -167,45 +238,45 @@ def compareTextBuilder(yamlPath='') :
     config.setOptions (containers=outputContainers)
     disable_commands = [
         'disable jet_select_baselineJvt.*',
-        'disable el_select_loose.*',
         'disable mu_select_medium.*',
         'disable ph_select_tight.*',
         'disable tau_select_tight.*',
+        'disable el_select_loose.*',
     ]
     config.setOptions (commands=disable_commands)
 
     # configure ConfigSequence
     configSeq = config.configure()
 
+    # create text config object to build text configurations
+    textConfig = TextConfig(yamlPath)
+    textConfigSeq = textConfig.configure()
+
+    # compare - will raise error if False
+    compareConfigSeq(configSeq, textConfigSeq, checkOrder=checkOrder)
+
 
-    ## produce ConfigSequecne with yaml file
+def compareBlockConfig(yamlPath='', *, checkOrder=False) :
+    """
+    Create a configSequence using provided YAML file and a
+    configSequence using the block configuration and compare.
+
+    Will raise an exception if configSequences differ
+    """
+    # create configSeq for block configuration
+    from AnalysisAlgorithmsConfig.FullCPAlgorithmsTest import makeSequenceBlocks
+    configSeq = makeSequenceBlocks(dataType='fullsim', algSeq=None,
+            forCompare=True, isPhyslite=False, forceEGammaFullSimConfig=True,
+            returnConfigSeq=True)
+
+    # create text config object to build text configurations
+    from AnalysisAlgorithmsConfig.ConfigText import TextConfig
     textConfig = TextConfig(yamlPath)
     textConfigSeq = textConfig.configure()
 
-    ## Compare
-    buildBlocks = configSeq._blocks
-    textBlocks = textConfigSeq._blocks 
-    if len(buildBlocks) != len(textBlocks):
-        raise Exception("Number of blocks are different")
-    for i in range(len(buildBlocks)):
-        buildBlock = buildBlocks[i]
-        textBlock = textBlocks[i]
-        buildName = buildBlock.__class__.__name__
-        textName = textBlock.__class__.__name__
-        if buildName != textName:
-            raise Exception(f"In position {i} "
-                f"the yaml file results in {textName} "
-                f"and the builder results in {buildName}")
-        for name in buildBlock.getOptions():
-            if name == 'groupName':
-                continue
-            build = buildBlock.getOptionValue(name)
-            text = textBlock.getOptionValue(name)
-            if build != text:
-                raise Exception(f"For block {buildName}, the block "
-                    f"option {name} the yaml file results in {text} "
-                    f"and the builder results in {build}")
-            
+    # compare - will raise error if False
+    compareConfigSeq(configSeq, textConfigSeq, checkOrder=checkOrder)
+
 
 if __name__ == '__main__':
     import os
@@ -213,12 +284,32 @@ if __name__ == '__main__':
     parser = optparse.OptionParser()
     parser.add_option('--text-config', dest='text_config',
             default='', action='store',
-            help='Perform unit tests using the provided yaml file')
+            help='YAML file used in unit test')
+    parser.add_option('--compare-block', dest='compare_block',
+            default=False, action='store_true',
+            help='Compare config sequence from YAML and block configuration')
+    parser.add_option('--compare-builder', dest='compare_builder',
+            default=False, action='store_true',
+            help='Compare config sequence from YAML and python configuration')
+    parser.add_option('--check-order', dest='check_order',
+            default=False, action='store_true',
+            help='Require blocks to be in the same order')
     (options, args) = parser.parse_args()
     textConfig = options.text_config
+    compareBlock = options.compare_block
+    compareBuilder = options.compare_builder
+    checkOrder = options.check_order
 
     if not os.path.isfile(textConfig):
         raise FileNotFoundError(f"{textConfig} is not a file")
 
-    # compare text and builder
-    compareTextBuilder(textConfig)
+    # compare YAML and builder
+    if compareBuilder:
+        print("Comparing config sequences from the block and text"
+            "configuration methods")
+        compareTextBuilder(textConfig, checkOrder=checkOrder)
+    # compare YAML and block config
+    if compareBlock:
+        print("Comparing config sequences from the block and block"
+            "configuration methods")
+        compareBlockConfig(textConfig, checkOrder=checkOrder)
diff --git a/PhysicsAnalysis/Algorithms/AnalysisAlgorithmsConfig/python/FullCPAlgorithmsTest.py b/PhysicsAnalysis/Algorithms/AnalysisAlgorithmsConfig/python/FullCPAlgorithmsTest.py
index 22a579ecb40b..3a2a008547d5 100644
--- a/PhysicsAnalysis/Algorithms/AnalysisAlgorithmsConfig/python/FullCPAlgorithmsTest.py
+++ b/PhysicsAnalysis/Algorithms/AnalysisAlgorithmsConfig/python/FullCPAlgorithmsTest.py
@@ -650,7 +650,9 @@ def makeSequenceOld (dataType, algSeq, forCompare, isPhyslite, noSystematics, fo
 
 
 def makeSequenceBlocks (dataType, algSeq, forCompare, isPhyslite,
-                        geometry=None, autoconfigFromFlags=None, noSystematics=None, onlyNominalOR=False,  forceEGammaFullSimConfig=False) :
+                        geometry=None, autoconfigFromFlags=None, noSystematics=None,
+                        onlyNominalOR=False,  forceEGammaFullSimConfig=False,
+                        returnConfigSeq=False) :
 
     vars = []
     metVars = []
@@ -715,8 +717,8 @@ def makeSequenceBlocks (dataType, algSeq, forCompare, isPhyslite,
     if not forCompare :
         configSeq.setOptionValue ('.recalibratePhyslite', False)
 
-    # Add systematic object links
-    configSeq += config.makeConfig('SystObjectLink', containerName='AnaJets')
+    configSeq += config.makeConfig( 'Jets.JVT',
+        containerName='AnaJets' )
 
     btagger = "DL1dv01"
     btagWP = "FixedCutBEff_60"
@@ -727,9 +729,6 @@ def makeSequenceBlocks (dataType, algSeq, forCompare, isPhyslite,
     configSeq.setOptionValue ('.btagger', btagger)
     configSeq.setOptionValue ('.btagWP', btagWP)
     
-    configSeq += config.makeConfig( 'Jets.JVT',
-        containerName='AnaJets' )
-
     if not forCompare:
         configSeq += config.makeConfig( 'Jets.FlavourTaggingEventSF',
             containerName='AnaJets.baselineJvt',
@@ -743,9 +742,6 @@ def makeSequenceBlocks (dataType, algSeq, forCompare, isPhyslite,
             jetCollection='AntiKt10UFOCSSKSoftDropBeta100Zcut10Jets' )
         configSeq.setOptionValue ('.postfix', 'largeR_jets' )
         outputContainers['larger_jet_'] = 'OutLargeRJets'
-
-        # Add systematic object links
-        configSeq += config.makeConfig('SystObjectLink', containerName='AnaLargeRJets')
         if not forCompare :
             configSeq.setOptionValue ('.recalibratePhyslite', False)
 
@@ -756,9 +752,26 @@ def makeSequenceBlocks (dataType, algSeq, forCompare, isPhyslite,
         configSeq.setOptionValue ('.postfix', 'track_jets' )
         outputContainers['track_jet_'] = 'OutTrackJets'
 
+    configSeq += config.makeConfig ('Jets.PtEtaSelection',
+        containerName='AnaJets')
+    configSeq.setOptionValue ('.selectionDecoration', 'selectPtEta')
+    configSeq.setOptionValue ('.minPt', jetMinPt)
+    configSeq.setOptionValue ('.maxEta', jetMaxEta)
+    if largeRJets :
+        configSeq += config.makeConfig ('Jets.PtEtaSelection',
+            containerName='AnaLargeRJets')
+        configSeq.setOptionValue ('.selectionDecoration', 'selectPtEta')
+        configSeq.setOptionValue ('.minPt', jetMinPt)
+        configSeq.setOptionValue ('.maxEta', jetMaxEta)
+    if trackJets :
+        configSeq += config.makeConfig ('Jets.PtEtaSelection',
+            containerName='AnaTrackJets')
+        configSeq.setOptionValue ('.selectionDecoration', 'selectPtEta')
+        configSeq.setOptionValue ('.minPt', jetMinPt)
+        configSeq.setOptionValue ('.maxEta', jetMaxEta)
+
 
     # Include, and then set up the electron analysis algorithm sequence:
-
     likelihood = True
     recomputeLikelihood=False
     configSeq += config.makeConfig ('Electrons',
@@ -779,8 +792,12 @@ def makeSequenceBlocks (dataType, algSeq, forCompare, isPhyslite,
     configSeq.setOptionValue ('.isolationWP', 'Loose_VarRad')
     configSeq.setOptionValue ('.recomputeLikelihood', recomputeLikelihood)
 
-    # Add systematic object links
-    configSeq += config.makeConfig('SystObjectLink', containerName='AnaElectrons')
+    configSeq += config.makeConfig ('Electrons.PtEtaSelection',
+        containerName='AnaElectrons')
+    configSeq.setOptionValue ('.selectionDecoration', 'selectPtEta')
+    configSeq.setOptionValue ('.minPt', electronMinPt)
+    configSeq.setOptionValue ('.maxEta', electronMaxEta)
+
 
     # Include, and then set up the photon analysis algorithm sequence:
     configSeq += config.makeConfig ('Photons',
@@ -799,8 +816,11 @@ def makeSequenceBlocks (dataType, algSeq, forCompare, isPhyslite,
     configSeq.setOptionValue ('.isolationWP', 'FixedCutTight')
     configSeq.setOptionValue ('.recomputeIsEM', False)
 
-    # Add systematic object links
-    configSeq += config.makeConfig('SystObjectLink', containerName='AnaPhotons')
+    configSeq += config.makeConfig ('Photons.PtEtaSelection',
+        containerName='AnaPhotons')
+    configSeq.setOptionValue ('.selectionDecoration', 'selectPtEta')
+    configSeq.setOptionValue ('.minPt', photonMinPt)
+    configSeq.setOptionValue ('.maxEta', photonMaxEta)
 
 
     # set up the muon analysis algorithm sequence:
@@ -820,8 +840,11 @@ def makeSequenceBlocks (dataType, algSeq, forCompare, isPhyslite,
     # configSeq.setOptionValue ('.quality', 'Tight')
     # configSeq.setOptionValue ('.isolation', 'Loose_VarRad')
 
-    # Add systematic object links
-    configSeq += config.makeConfig('SystObjectLink', containerName='AnaMuons')
+    configSeq += config.makeConfig ('Muons.PtEtaSelection',
+        containerName='AnaMuons')
+    configSeq.setOptionValue ('.selectionDecoration', 'selectPtEta')
+    configSeq.setOptionValue ('.minPt', muonMinPt)
+    configSeq.setOptionValue ('.maxEta', muonMaxEta)
 
 
     # Include, and then set up the tau analysis algorithm sequence:
@@ -832,7 +855,22 @@ def makeSequenceBlocks (dataType, algSeq, forCompare, isPhyslite,
         selectionName='tight')
     configSeq.setOptionValue ('.quality', 'Tight')
 
+    configSeq += config.makeConfig ('TauJets.PtEtaSelection',
+        containerName='AnaTauJets')
+    configSeq.setOptionValue ('.selectionDecoration', 'selectPtEta')
+    configSeq.setOptionValue ('.minPt', tauMinPt)
+    configSeq.setOptionValue ('.maxEta', tauMaxEta)
+
+
     # Add systematic object links
+    configSeq += config.makeConfig('SystObjectLink', containerName='AnaJets')
+    if largeRJets:
+        configSeq += config.makeConfig('SystObjectLink', containerName='AnaLargeRJets')
+    if trackJets:
+        configSeq += config.makeConfig('SystObjectLink', containerName='AnaTrackJets')
+    configSeq += config.makeConfig('SystObjectLink', containerName='AnaElectrons')
+    configSeq += config.makeConfig('SystObjectLink', containerName='AnaPhotons')
+    configSeq += config.makeConfig('SystObjectLink', containerName='AnaMuons')
     configSeq += config.makeConfig('SystObjectLink', containerName='AnaTauJets')
 
 
@@ -844,60 +882,6 @@ def makeSequenceBlocks (dataType, algSeq, forCompare, isPhyslite,
         configSeq.setOptionValue ('.cutBookkeepersSystematics', True)
 
 
-    configSeq += config.makeConfig ('Electrons.PtEtaSelection',
-        containerName='AnaElectrons')
-    configSeq.setOptionValue ('.selectionDecoration', 'selectPtEta')
-    configSeq.setOptionValue ('.minPt', electronMinPt)
-    configSeq.setOptionValue ('.maxEta', electronMaxEta)
-    configSeq += config.makeConfig ('Photons.PtEtaSelection',
-        containerName='AnaPhotons')
-    configSeq.setOptionValue ('.selectionDecoration', 'selectPtEta')
-    configSeq.setOptionValue ('.minPt', photonMinPt)
-    configSeq.setOptionValue ('.maxEta', photonMaxEta)
-    configSeq += config.makeConfig ('Muons.PtEtaSelection',
-        containerName='AnaMuons')
-    configSeq.setOptionValue ('.selectionDecoration', 'selectPtEta')
-    configSeq.setOptionValue ('.minPt', muonMinPt)
-    configSeq.setOptionValue ('.maxEta', muonMaxEta)
-    configSeq += config.makeConfig ('TauJets.PtEtaSelection',
-        containerName='AnaTauJets')
-    configSeq.setOptionValue ('.selectionDecoration', 'selectPtEta')
-    configSeq.setOptionValue ('.minPt', tauMinPt)
-    configSeq.setOptionValue ('.maxEta', tauMaxEta)
-    configSeq += config.makeConfig ('Jets.PtEtaSelection',
-        containerName='AnaJets')
-    configSeq.setOptionValue ('.selectionDecoration', 'selectPtEta')
-    configSeq.setOptionValue ('.minPt', jetMinPt)
-    configSeq.setOptionValue ('.maxEta', jetMaxEta)
-    if largeRJets :
-        configSeq += config.makeConfig ('Jets.PtEtaSelection',
-            containerName='AnaLargeRJets')
-        configSeq.setOptionValue ('.selectionDecoration', 'selectPtEta')
-        configSeq.setOptionValue ('.minPt', jetMinPt)
-        configSeq.setOptionValue ('.maxEta', jetMaxEta)
-    if trackJets :
-        configSeq += config.makeConfig ('Jets.PtEtaSelection',
-            containerName='AnaTrackJets')
-        configSeq.setOptionValue ('.selectionDecoration', 'selectPtEta')
-        configSeq.setOptionValue ('.minPt', jetMinPt)
-        configSeq.setOptionValue ('.maxEta', jetMaxEta)
-
-    configSeq += config.makeConfig ('ObjectCutFlow',
-        containerName='AnaElectrons',
-        selectionName='loose')
-    configSeq += config.makeConfig ('ObjectCutFlow',
-        containerName='AnaPhotons',
-        selectionName='tight')
-    configSeq += config.makeConfig ('ObjectCutFlow',
-        containerName='AnaMuons',
-        selectionName='medium')
-    configSeq += config.makeConfig ('ObjectCutFlow',
-        containerName='AnaTauJets',
-        selectionName='tight')
-    configSeq += config.makeConfig ('ObjectCutFlow',
-        containerName='AnaJets',
-        selectionName='jvt')
-
     # Include, and then set up the met analysis algorithm config:
     configSeq += config.makeConfig ('MissingET',
         containerName='AnaMET')
@@ -948,6 +932,25 @@ def makeSequenceBlocks (dataType, algSeq, forCompare, isPhyslite,
                                           selectionCutsDict = exampleSelectionCuts, noFilter = True)
 
 
+    # ObjectCutFlow blocks
+    configSeq += config.makeConfig ('ObjectCutFlow',
+        containerName='AnaJets',
+        selectionName='jvt')
+    configSeq += config.makeConfig ('ObjectCutFlow',
+        containerName='AnaElectrons',
+        selectionName='loose')
+    configSeq += config.makeConfig ('ObjectCutFlow',
+        containerName='AnaPhotons',
+        selectionName='tight')
+    configSeq += config.makeConfig ('ObjectCutFlow',
+        containerName='AnaMuons',
+        selectionName='medium')
+    configSeq += config.makeConfig ('ObjectCutFlow',
+        containerName='AnaTauJets',
+        selectionName='tight')
+
+
+    # Thinning blocks
     configSeq += config.makeConfig ('Thinning',
         containerName='AnaElectrons')
     configSeq.setOptionValue ('.selectionName', 'loose')
@@ -1013,6 +1016,10 @@ def makeSequenceBlocks (dataType, algSeq, forCompare, isPhyslite,
             disable_commands.append('disable el_select_loose.*')
     configSeq.setOptionValue ('.commands', disable_commands)
 
+    # return configSeq for unit test
+    if returnConfigSeq:
+        return configSeq
+
     configAccumulator = ConfigAccumulator (algSeq, dataType, isPhyslite, geometry, autoconfigFromFlags=autoconfigFromFlags, noSystematics=noSystematics)
     configSeq.fullConfigure (configAccumulator)
 
-- 
GitLab