From 91a9b3b85d52532fcdcab1b0cc02375f9b3d8b28 Mon Sep 17 00:00:00 2001
From: Nils Krumnack <krumnack@iastate.edu>
Date: Fri, 3 Apr 2020 13:37:27 -0500
Subject: [PATCH 1/5] update to use the algorithm meta-configuration for jet
 selection

Not sure I got it completely correct, there was some more extensive
logic in here, but at least the tests work out.
---
 .../python/JetAnalysisSequence.py             | 45 ++++++++-----------
 .../python/JetJvtAnalysisSequence.py          | 33 +++++++-------
 2 files changed, 34 insertions(+), 44 deletions(-)

diff --git a/PhysicsAnalysis/Algorithms/JetAnalysisAlgorithms/python/JetAnalysisSequence.py b/PhysicsAnalysis/Algorithms/JetAnalysisAlgorithms/python/JetAnalysisSequence.py
index 454aed27c2c0..a0f35f04f039 100644
--- a/PhysicsAnalysis/Algorithms/JetAnalysisAlgorithms/python/JetAnalysisSequence.py
+++ b/PhysicsAnalysis/Algorithms/JetAnalysisAlgorithms/python/JetAnalysisSequence.py
@@ -85,45 +85,45 @@ def makeJetAnalysisSequence( dataType, jetCollection, postfix = '',
         seq.append( alg, inputPropName = 'jets', outputPropName = 'jetsOut', stageName = 'calibration' )
 
     # record all the selections each subfunction makes
-    cutlist = []
-    cutlength = []
+    seq.addMetaConfigDefault ("selectionDecorNames", [])
+    seq.addMetaConfigDefault ("selectionDecorCount", [])
 
     if radius == 4:
-        makeSmallRJetAnalysisSequence(seq, cutlist, cutlength,
+        makeSmallRJetAnalysisSequence(seq,
             dataType, jetCollection, jetInput=jetInput, postfix=postfix, **kwargs)
     elif radius in [2, 6]:
-        makeRScanJetAnalysisSequence(seq, cutlist, cutlength,
+        makeRScanJetAnalysisSequence(seq,
             dataType, jetCollection, jetInput=jetInput, radius=radius, 
             postfix=postfix, **kwargs)
     else:
         trim = match.group(3)
         if trim == "":
             raise ValueError("Untrimmed large-R jets are not supported!")
-        makeLargeRJetAnalysisSequence(seq, cutlist, cutlength,
+        makeLargeRJetAnalysisSequence(seq,
             dataType, jetCollection, jetInput=jetInput, postfix=postfix, **kwargs)
 
     # Set up an algorithm used to create jet selection cutflow:
     if enableCutflow:
         alg = createAlgorithm( 'CP::ObjectCutFlowHistAlg', 'JetCutFlowDumperAlg'+postfix )
         alg.histPattern = 'jet_cflow_%SYS%'+postfix
-        alg.selection = cutlist
-        alg.selectionNCuts = cutlength
-        seq.append( alg, inputPropName = 'input', stageName = 'selection' )
+        seq.append( alg, inputPropName = 'input', stageName = 'selection',
+                    dynConfig = {'selection' : lambda meta : meta["selectionDecorNames"][:],
+                                 'selectionNCuts' : lambda meta : meta["selectionDecorCount"][:]} )
 
     # Set up an algorithm dumping the kinematic properties of the jets:
     if enableKinematicHistograms:
         alg = createAlgorithm( 'CP::KinematicHistAlg', 'JetKinematicDumperAlg'+postfix )
-        alg.preselection = "&&".join (cutlist)
         alg.histPattern = 'jet_%VAR%_%SYS%'+postfix
-        seq.append( alg, inputPropName = 'input', stageName = 'selection' )
+        seq.append( alg, inputPropName = 'input', stageName = 'selection',
+                    dynConfig = {'preselection' : lambda meta : "&&".join (meta["selectionDecorNames"])} )
 
     if shallowViewOutput:
       # Set up an algorithm that makes a view container using the selections
       # performed previously:
       alg = createAlgorithm( 'CP::AsgViewFromSelectionAlg', 'JetViewFromSelectionAlg'+postfix )
-      alg.selection = cutlist
       seq.append( alg, inputPropName = 'input', outputPropName = 'output',
-                  stageName = 'selection' )
+                  stageName = 'selection',
+                  dynConfig = {'selection' : lambda meta : meta["selectionDecorNames"][:]} )
 
     # Set up a final deep copy making algorithm if requested:
     if deepCopyOutput:
@@ -134,7 +134,7 @@ def makeJetAnalysisSequence( dataType, jetCollection, postfix = '',
     
     return seq
 
-def makeSmallRJetAnalysisSequence( seq, cutlist, cutlength, dataType, jetCollection,
+def makeSmallRJetAnalysisSequence( seq, dataType, jetCollection,
                                    jetInput, postfix = '', 
                                    runJvtUpdate = False, runFJvtUpdate = False,
                                    runJvtSelection = True, runFJvtSelection = False,
@@ -144,8 +144,6 @@ def makeSmallRJetAnalysisSequence( seq, cutlist, cutlength, dataType, jetCollect
 
       Keyword arguments
         seq -- The sequence to add the algorithms to
-        cutlist -- Insert any cuts into this
-        cutlength -- Insert the lengths of any cuts into this
         dataType -- The data type to run on ("data", "mc" or "afii")
         jetCollection -- The jet container to run on.
         jetInput -- The type of input used, read from the collection name.
@@ -282,16 +280,14 @@ def makeSmallRJetAnalysisSequence( seq, cutlist, cutlength, dataType, jetCollect
                     stageName = 'selection')
 
     # Return the sequence:
-    return seq, cutlist, cutlength
+    return seq
 
-def makeRScanJetAnalysisSequence( seq, cutlist, cutlength, dataType, jetCollection,
+def makeRScanJetAnalysisSequence( seq, dataType, jetCollection,
                                   jetInput, radius, postfix = '' ):
     """Add algorithms for the R-scan jets.
 
       Keyword arguments
         seq -- The sequence to add the algorithms to
-        cutlist -- Insert any cuts into this
-        cutlength -- Insert the lengths of any cuts into this
         dataType -- The data type to run on ("data", "mc" or "afii")
         jetCollection -- The jet container to run on.
         jetInput -- The type of input used, read from the collection name.
@@ -316,14 +312,12 @@ def makeRScanJetAnalysisSequence( seq, cutlist, cutlength, dataType, jetCollecti
     # Logging would be good
     print("WARNING: uncertainties for R-Scan jets are not yet released!")
 
-def makeLargeRJetAnalysisSequence( seq, cutlist, cutlength, dataType, jetCollection,
+def makeLargeRJetAnalysisSequence( seq, dataType, jetCollection,
                                    jetInput, postfix = '', largeRMass = "Comb"):
     """Add algorithms for the R=1.0 jets.
 
       Keyword arguments
         seq -- The sequence to add the algorithms to
-        cutlist -- Insert any cuts into this
-        cutlength -- Insert the lengths of any cuts into this
         dataType -- The data type to run on ("data", "mc" or "afii")
         jetCollection -- The jet container to run on.
         jetInput -- The type of input used, read from the collection name.
@@ -373,7 +367,6 @@ def makeLargeRJetAnalysisSequence( seq, cutlist, cutlength, dataType, jetCollect
     alg.uncertaintiesTool.MCType = "MC16a"
     alg.uncertaintiesTool.IsData = (dataType == "data")
     seq.append( alg, inputPropName = 'jets', outputPropName = 'jetsOut',
-                stageName = 'calibration' )
-
-    cutlist.append('outOfValidity')
-    cutlength.append(1)
+                stageName = 'calibration',
+                metaConfig = {'selectionDecorNames' : ['outOfValidity'],
+                              'selectionDecorCount' : [1]} )
diff --git a/PhysicsAnalysis/Algorithms/JetAnalysisAlgorithms/python/JetJvtAnalysisSequence.py b/PhysicsAnalysis/Algorithms/JetAnalysisAlgorithms/python/JetJvtAnalysisSequence.py
index 61eb02c74e99..71758fcd513d 100644
--- a/PhysicsAnalysis/Algorithms/JetAnalysisAlgorithms/python/JetJvtAnalysisSequence.py
+++ b/PhysicsAnalysis/Algorithms/JetAnalysisAlgorithms/python/JetJvtAnalysisSequence.py
@@ -5,7 +5,6 @@ from AnaAlgorithm.AnaAlgSequence import AnaAlgSequence
 from AnaAlgorithm.DualUseConfig import createAlgorithm
 
 def makeJetJvtAnalysisSequence( dataType, jetCollection,
-                                preselection = '',
                                 enableFJvt = False,
                                 globalSF = True,
                                 runSelection = True,
@@ -32,52 +31,50 @@ def makeJetJvtAnalysisSequence( dataType, jetCollection,
 
     # Define a list of cuts to apply later on and the
     # number of bits in the corresponding TAccept
-    cutlist = []
-    cutlength = []
+    seq.addMetaConfigDefault ("selectionDecorNames", [])
+    seq.addMetaConfigDefault ("selectionDecorCount", [])
 
     # Set up the per-event jet efficiency scale factor calculation algorithm
     if dataType != 'data' and globalSF:
         alg = createAlgorithm( 'CP::AsgEventScaleFactorAlg', 'JvtEventScaleFactorAlg' )
-        alg.preselection = preselection + '&&no_jvt' if preselection else 'no_jvt'
         alg.scaleFactorInputDecoration = 'jvt_effSF_%SYS%'
         alg.scaleFactorOutputDecoration = 'jvt_effSF_%SYS%'
 
         seq.append( alg,
                     inputPropName = { 'jets' : 'particles',
-                                      'eventInfo' : 'eventInfo' } )
+                                      'eventInfo' : 'eventInfo' },
+                    dynConfig = {'preselection' : lambda meta : "&&".join (meta["selectionDecorNames"])} )
 
         if enableFJvt:
             alg = createAlgorithm( 'CP::AsgEventScaleFactorAlg', 'ForwardJvtEventScaleFactorAlg' )
-            alg.preselection = preselection + '&&no_fjvt' if preselection else 'no_fjvt'
             alg.scaleFactorInputDecoration = 'fjvt_effSF_%SYS%'
             alg.scaleFactorOutputDecoration = 'fjvt_effSF_%SYS%'
 
             seq.append( alg,
                         inputPropName = { 'jets' : 'particles',
-                                          'eventInfo' : 'eventInfo' } )
+                                          'eventInfo' : 'eventInfo' },
+                        metaConfig = {'selectionDecorNames' : ['fjvt_selection'] if runSelection else [],
+                                      'selectionDecorCount' : [1] if runSelection else [] },
+                        dynConfig = {'preselection' : lambda meta : "&&".join (meta["selectionDecorNames"] + ['no_fjvt'])} )
 
     if runSelection:
-        cutlist.append('jvt_selection')
-        cutlength.append(1)
-
-        if enableFJvt:
-            cutlist.append('fjvt_selection')
-            cutlength.append(1)
+        seq.addMetaConfigDefault ("selectionDecorNames", ['jvt_selection'])
+        seq.addMetaConfigDefault ("selectionDecorCount", [1])
 
         # Set up an algorithm used to create jet JVT selection cutflow:
         if enableCutflow:
             alg = createAlgorithm( 'CP::ObjectCutFlowHistAlg', 'JetJvtCutFlowDumperAlg' )
             alg.histPattern = 'jet_cflow_jvt_%SYS%'
-            alg.selection = cutlist
-            alg.selectionNCuts = cutlength
-            seq.append( alg, inputPropName = { 'jets' : 'input' })
+            seq.append( alg, inputPropName = { 'jets' : 'input' },
+                        dynConfig = {'selection' : lambda meta : meta["selectionDecorNames"][:],
+                                     'selectionNCuts' : lambda meta : meta["selectionDecorCount"][:]})
 
         # Set up an algorithm that makes a view container using the selections
         # performed previously:
         alg = createAlgorithm( 'CP::AsgViewFromSelectionAlg', 'JetJvtViewFromSelectionAlg' )
-        alg.selection = cutlist
         seq.append( alg, inputPropName = { 'jets' : 'input' },
-                    outputPropName = { 'jets' : 'output' } )
+                    outputPropName = { 'jets' : 'output' },
+                    dynConfig = {'selection' : lambda meta : meta["selectionDecorNames"][:]} )
 
     # Return the sequence:
     return seq
-- 
GitLab


From 22bbaaf609f1eed4fe2d227100fbe1be55ae7c18 Mon Sep 17 00:00:00 2001
From: Nils Krumnack <krumnack@iastate.edu>
Date: Fri, 3 Apr 2020 12:19:53 -0500
Subject: [PATCH 2/5] make copies of python lists from meta-configuration

Just for safety, since the lists may be subsequently updated.
---
 .../python/MuonAnalysisSequence.py                     | 10 +++++-----
 1 file changed, 5 insertions(+), 5 deletions(-)

diff --git a/PhysicsAnalysis/Algorithms/MuonAnalysisAlgorithms/python/MuonAnalysisSequence.py b/PhysicsAnalysis/Algorithms/MuonAnalysisAlgorithms/python/MuonAnalysisSequence.py
index 1464a60cc58b..2b79d744c5e5 100644
--- a/PhysicsAnalysis/Algorithms/MuonAnalysisAlgorithms/python/MuonAnalysisSequence.py
+++ b/PhysicsAnalysis/Algorithms/MuonAnalysisAlgorithms/python/MuonAnalysisSequence.py
@@ -167,15 +167,15 @@ def makeMuonAnalysisSequence( dataType, workingPoint,
     alg.selectionDecoration = 'baselineSelection' + postfix + ',as_char'
     seq.append( alg, inputPropName = 'particles',
                 stageName = 'selection',
-                dynConfig = {'selectionTool.selectionFlags' : lambda meta : meta["selectionDecorNames"]})
+                dynConfig = {'selectionTool.selectionFlags' : lambda meta : meta["selectionDecorNames"][:]})
 
     # Set up an algorithm used to create muon selection cutflow:
     if enableCutflow:
         alg = createAlgorithm( 'CP::ObjectCutFlowHistAlg', 'MuonCutFlowDumperAlg' + postfix )
         alg.histPattern = 'muon' + postfix + '_cflow_%SYS%'
         seq.append( alg, inputPropName = 'input', stageName = 'selection',
-                    dynConfig = {'selection' : lambda meta : meta["selectionDecorNames"],
-                                 'selectionNCuts' : lambda meta : meta["selectionDecorCount"]} )
+                    dynConfig = {'selection' : lambda meta : meta["selectionDecorNames"][:],
+                                 'selectionNCuts' : lambda meta : meta["selectionDecorCount"][:]} )
 
     # Set up an algorithm that makes a view container using the selections
     # performed previously:
@@ -184,7 +184,7 @@ def makeMuonAnalysisSequence( dataType, workingPoint,
                             'MuonViewFromSelectionAlg' + postfix )
         seq.append( alg, inputPropName = 'input', outputPropName = 'output',
                     stageName = 'selection',
-                    dynConfig = {'selection' : lambda meta : meta["selectionDecorNamesOutput"]} )
+                    dynConfig = {'selection' : lambda meta : meta["selectionDecorNamesOutput"][:]} )
 
     # Set up the efficiency scale factor calculation algorithm:
     alg = createAlgorithm( 'CP::MuonEfficiencyScaleFactorAlg',
@@ -214,7 +214,7 @@ def makeMuonAnalysisSequence( dataType, workingPoint,
         alg.deepCopy = True
         seq.append( alg, inputPropName = 'input', outputPropName = 'output',
                     stageName = 'selection',
-                    dynConfig = {'selection' : lambda meta : meta["selectionDecorNamesOutput"]} )
+                    dynConfig = {'selection' : lambda meta : meta["selectionDecorNamesOutput"][:]} )
         pass
 
     # Return the sequence:
-- 
GitLab


From fadc54b64e680ce2b089fb464da3aa13f485df1c Mon Sep 17 00:00:00 2001
From: Nils Krumnack <krumnack@iastate.edu>
Date: Fri, 3 Apr 2020 12:20:35 -0500
Subject: [PATCH 3/5] switch selection accounting to use algorithm
 meta-configuration

Just to allow easier sequence modification.
---
 .../python/ElectronAnalysisSequence.py        | 121 +++++++++---------
 .../python/PhotonAnalysisSequence.py          |  49 +++----
 2 files changed, 84 insertions(+), 86 deletions(-)

diff --git a/PhysicsAnalysis/Algorithms/EgammaAnalysisAlgorithms/python/ElectronAnalysisSequence.py b/PhysicsAnalysis/Algorithms/EgammaAnalysisAlgorithms/python/ElectronAnalysisSequence.py
index 185c986e6e6d..468ffc3f37ab 100644
--- a/PhysicsAnalysis/Algorithms/EgammaAnalysisAlgorithms/python/ElectronAnalysisSequence.py
+++ b/PhysicsAnalysis/Algorithms/EgammaAnalysisAlgorithms/python/ElectronAnalysisSequence.py
@@ -66,12 +66,12 @@ def makeElectronAnalysisSequence( dataType, workingPoint,
     seq = AnaAlgSequence( "ElectronAnalysisSequence" + postfix )
 
     # Variables keeping track of the selections being applied.
-    selectionDecorNames = []
-    selectionDecorCount = []
+    seq.addMetaConfigDefault ("selectionDecorNames", [])
+    seq.addMetaConfigDefault ("selectionDecorNamesOutput", [])
+    seq.addMetaConfigDefault ("selectionDecorCount", [])
 
     # Set up the eta-cut on all electrons prior to everything else
     alg = createAlgorithm( 'CP::AsgSelectionAlg', 'ElectronEtaCutAlg' + postfix )
-    alg.preselection = "&&".join (selectionDecorNames)
     alg.selectionDecoration = 'selectEta' + postfix + ',as_bits'
     addPrivateTool( alg, 'selectionTool', 'CP::AsgPtEtaSelectionTool' )
     alg.selectionTool.maxEta = 2.47
@@ -81,76 +81,76 @@ def makeElectronAnalysisSequence( dataType, workingPoint,
     alg.selectionTool.useClusterEta = True
     seq.append( alg, inputPropName = 'particles',
                 outputPropName = 'particlesOut',
-                stageName = 'calibration' )
-    selectionDecorNames.append( alg.selectionDecoration )
-    if crackVeto :
-        selectionDecorCount.append( 5 )
-    else :
-        selectionDecorCount.append( 4 )
+                stageName = 'calibration',
+                metaConfig = {'selectionDecorNames' : [alg.selectionDecoration],
+                              'selectionDecorNamesOutput' : [alg.selectionDecoration],
+                              'selectionDecorCount' : [5 if crackVeto else 4]},
+                dynConfig = {'preselection' : lambda meta : "&&".join (meta["selectionDecorNames"])} )
 
     # Set up the track selection algorithm:
     alg = createAlgorithm( 'CP::AsgLeptonTrackSelectionAlg',
                            'ElectronTrackSelectionAlg' + postfix )
-    alg.preselection = "&&".join (selectionDecorNames)
     alg.selectionDecoration = 'trackSelection' + postfix + ',as_bits'
     alg.maxD0Significance = 5
     alg.maxDeltaZ0SinTheta = 0.5
     seq.append( alg, inputPropName = 'particles',
-                stageName = 'selection' )
-    selectionDecorNames.append( alg.selectionDecoration )
-    selectionDecorCount.append( 3 )
+                stageName = 'selection',
+                metaConfig = {'selectionDecorNames' : [alg.selectionDecoration],
+                              'selectionDecorNamesOutput' : [alg.selectionDecoration],
+                              'selectionDecorCount' : [3]},
+                dynConfig = {'preselection' : lambda meta : "&&".join (meta["selectionDecorNames"])} )
 
     if 'LH' in likelihoodWP:
         # Set up the likelihood ID selection algorithm
         # It is safe to do this before calibration, as the cluster E is used
         alg = createAlgorithm( 'CP::AsgSelectionAlg', 'ElectronLikelihoodAlg' + postfix )
-        alg.preselection = "&&".join (selectionDecorNames)
         alg.selectionDecoration = 'selectLikelihood' + postfix + ',as_bits'
-        selectionDecorNames.append( alg.selectionDecoration )
         if recomputeLikelihood:
             # Rerun the likelihood ID
             addPrivateTool( alg, 'selectionTool', 'AsgElectronLikelihoodTool' )
             alg.selectionTool.primaryVertexContainer = 'PrimaryVertices'
             alg.selectionTool.WorkingPoint = likelihoodWP
-            selectionDecorCount.append( 7 )
+            algDecorCount = 7
         else:
             # Select from Derivation Framework flags
             addPrivateTool( alg, 'selectionTool', 'CP::AsgFlagSelectionTool' )
             dfFlag = "DFCommonElectronsLH" + likelihoodWP.split('LH')[0]
             alg.selectionTool.selectionFlags = [dfFlag]
-            selectionDecorCount.append( 1 )
+            algDecorCount = 1
     else:
         # Set up the DNN ID selection algorithm
         alg = createAlgorithm( 'CP::AsgSelectionAlg', 'ElectronDNNAlg' + postfix )
-        alg.preselection = "&&".join (selectionDecorNames)
         alg.selectionDecoration = 'selectDNN' + postfix + ',as_bits'
-        selectionDecorNames.append( alg.selectionDecoration )
         if recomputeLikelihood:
             # Rerun the DNN ID
             addPrivateTool( alg, 'selectionTool', 'AsgElectronSelectorTool' )
             alg.selectionTool.WorkingPoint = likelihoodWP
-            selectionDecorCount.append( 6 )
+            algDecorCount = 6
         else:
             # Select from Derivation Framework flags
             raise ValueError ( "DNN working points are not available in derivations yet.")
     seq.append( alg, inputPropName = 'particles',
-                stageName = 'selection' )
+                stageName = 'selection',
+                metaConfig = {'selectionDecorNames' : [alg.selectionDecoration],
+                              'selectionDecorNamesOutput' : [alg.selectionDecoration],
+                              'selectionDecorCount' : [algDecorCount]},
+                dynConfig = {'preselection' : lambda meta : "&&".join (meta["selectionDecorNames"])} )
 
     # Select electrons only with good object quality.
     alg = createAlgorithm( 'CP::AsgSelectionAlg', 'ElectronObjectQualityAlg' + postfix )
-    alg.preselection = "&&".join (selectionDecorNames)
     alg.selectionDecoration = 'goodOQ' + postfix + ',as_bits'
     addPrivateTool( alg, 'selectionTool', 'CP::EgammaIsGoodOQSelectionTool' )
     alg.selectionTool.Mask = xAOD.EgammaParameters.BADCLUSELECTRON
     seq.append( alg, inputPropName = 'particles',
-                stageName = 'calibration' )
-    selectionDecorNames.append( alg.selectionDecoration )
-    selectionDecorCount.append( 1 )
+                stageName = 'calibration',
+                metaConfig = {'selectionDecorNames' : [alg.selectionDecoration],
+                              'selectionDecorNamesOutput' : [alg.selectionDecoration],
+                              'selectionDecorCount' : [1]},
+                dynConfig = {'preselection' : lambda meta : "&&".join (meta["selectionDecorNames"])} )
 
     # Set up the calibration and smearing algorithm:
     alg = createAlgorithm( 'CP::EgammaCalibrationAndSmearingAlg',
                            'ElectronCalibrationAndSmearingAlg' + postfix )
-    alg.preselection = "&&".join (selectionDecorNames)
     addPrivateTool( alg, 'calibrationAndSmearingTool',
                     'CP::EgammaCalibrationAndSmearingTool' )
     alg.calibrationAndSmearingTool.ESModel = 'es2018_R21_v0'
@@ -161,25 +161,25 @@ def makeElectronAnalysisSequence( dataType, workingPoint,
         alg.calibrationAndSmearingTool.useAFII = 0
         pass
     seq.append( alg, inputPropName = 'egammas', outputPropName = 'egammasOut',
-                stageName = 'calibration' )
+                stageName = 'calibration',
+                dynConfig = {'preselection' : lambda meta : "&&".join (meta["selectionDecorNames"])} )
 
     # Set up the the pt selection
-    ptSelectionDecoration = 'selectPt' + postfix + ',as_bits'
     alg = createAlgorithm( 'CP::AsgSelectionAlg', 'ElectronPtCutAlg' + postfix )
-    alg.preselection = "&&".join (selectionDecorNames)
-    alg.selectionDecoration = ptSelectionDecoration
+    alg.selectionDecoration = 'selectPt' + postfix + ',as_bits'
     addPrivateTool( alg, 'selectionTool', 'CP::AsgPtEtaSelectionTool' )
     alg.selectionTool.minPt = 4.5e3
     seq.append( alg, inputPropName = 'particles',
-                stageName = 'selection' )
-    selectionDecorNames.append( alg.selectionDecoration )
-    selectionDecorCount.append( 2 )
+                stageName = 'selection',
+                metaConfig = {'selectionDecorNames' : [alg.selectionDecoration],
+                              'selectionDecorNamesOutput' : [alg.selectionDecoration] if ptSelectionOutput else [],
+                              'selectionDecorCount' : [2]},
+                dynConfig = {'preselection' : lambda meta : "&&".join (meta["selectionDecorNames"])} )
 
     # Set up the isolation correction algorithm:
     if isolationCorrection:
         alg = createAlgorithm( 'CP::EgammaIsolationCorrectionAlg',
                                'ElectronIsolationCorrectionAlg' + postfix )
-        alg.preselection = "&&".join (selectionDecorNames)
         addPrivateTool( alg, 'isolationCorrectionTool',
                         'CP::IsolationCorrectionTool' )
         if dataType == 'data':
@@ -188,26 +188,27 @@ def makeElectronAnalysisSequence( dataType, workingPoint,
             alg.isolationCorrectionTool.IsMC = 1
             pass
         seq.append( alg, inputPropName = 'egammas', outputPropName = 'egammasOut',
-                    stageName = 'calibration' )
+                    stageName = 'calibration',
+                    dynConfig = {'preselection' : lambda meta : "&&".join (meta["selectionDecorNames"])} )
 
     # Set up the isolation selection algorithm:
     if isolationWP != 'NonIso' :
         alg = createAlgorithm( 'CP::EgammaIsolationSelectionAlg',
                                'ElectronIsolationSelectionAlg' + postfix )
-        alg.preselection = "&&".join (selectionDecorNames)
         alg.selectionDecoration = 'isolated' + postfix + ',as_bits'
         addPrivateTool( alg, 'selectionTool', 'CP::IsolationSelectionTool' )
         alg.selectionTool.ElectronWP = isolationWP
         seq.append( alg, inputPropName = 'egammas',
-                    stageName = 'selection' )
-        selectionDecorNames.append( alg.selectionDecoration )
-        selectionDecorCount.append( 1 )
+                    stageName = 'selection',
+                    metaConfig = {'selectionDecorNames' : [alg.selectionDecoration],
+                                  'selectionDecorNamesOutput' : [alg.selectionDecoration],
+                                  'selectionDecorCount' : [1]},
+                    dynConfig = {'preselection' : lambda meta : "&&".join (meta["selectionDecorNames"])} )
 
     # Select electrons only if they don't appear to have flipped their charge.
     if chargeIDSelection:
         alg = createAlgorithm( 'CP::AsgSelectionAlg',
                                'ElectronChargeIDSelectionAlg' + postfix )
-        alg.preselection = "&&".join (selectionDecorNames)
         alg.selectionDecoration = 'chargeID' + postfix + ',as_bits'
         addPrivateTool( alg, 'selectionTool',
                         'AsgElectronChargeIDSelectorTool' )
@@ -216,55 +217,50 @@ def makeElectronAnalysisSequence( dataType, workingPoint,
         alg.selectionTool.WorkingPoint = 'Loose'
         alg.selectionTool.CutOnBDT = -0.337671 # Loose 97%
         seq.append( alg, inputPropName = 'particles',
-                    stageName = 'selection' )
-        selectionDecorNames.append( alg.selectionDecoration )
-        selectionDecorCount.append( 1 )
+                    stageName = 'selection',
+                    metaConfig = {'selectionDecorNames' : [alg.selectionDecoration],
+                                  'selectionDecorNamesOutput' : [alg.selectionDecoration],
+                                  'selectionDecorCount' : [1]},
+                    dynConfig = {'preselection' : lambda meta : "&&".join (meta["selectionDecorNames"])} )
         pass
 
     # Set up an algorithm used for decorating baseline electron selection:
     alg = createAlgorithm( 'CP::AsgSelectionAlg',
                            'ElectronSelectionSummary' + postfix )
     addPrivateTool( alg, 'selectionTool', 'CP::AsgFlagSelectionTool' )
-    alg.selectionTool.selectionFlags = selectionDecorNames[ : ]
     alg.selectionDecoration = 'baselineSelection' + postfix + ',as_char'
     seq.append( alg, inputPropName = 'particles',
-                stageName = 'selection' )
+                stageName = 'selection',
+                dynConfig = {'selectionTool.selectionFlags' : lambda meta : meta["selectionDecorNames"] [ : ]} )
 
     # Set up an algorithm used to create electron selection cutflow:
     if enableCutflow:
         alg = createAlgorithm( 'CP::ObjectCutFlowHistAlg', 'ElectronCutFlowDumperAlg' + postfix )
         alg.histPattern = 'electron_cflow_%SYS%' + postfix
-        alg.selection = selectionDecorNames[ : ]
-        alg.selectionNCuts = selectionDecorCount[ : ]
-        seq.append( alg, inputPropName = 'input', stageName = 'selection' )
+        seq.append( alg, inputPropName = 'input', stageName = 'selection',
+                    dynConfig = {'selection' : lambda meta : meta["selectionDecorNames"][:],
+                                 'selectionNCuts' : lambda meta : meta["selectionDecorCount"][:]} )
 
     # Set up an algorithm dumping the kinematic properties of the electrons:
     if enableKinematicHistograms:
         alg = createAlgorithm( 'CP::KinematicHistAlg', 'ElectronKinematicDumperAlg' + postfix )
-        alg.preselection = "&&".join (selectionDecorNames)
         alg.histPattern = 'electron_%VAR%_%SYS%' + postfix
-        seq.append( alg, inputPropName = 'input', stageName = 'selection' )
-
-    # Set up the output selection
-    if shallowViewOutput or deepCopyOutput:
-        selectionDecorNamesOutput = selectionDecorNames[ : ]
-        if not ptSelectionOutput:
-            selectionDecorNamesOutput.remove(ptSelectionDecoration)
+        seq.append( alg, inputPropName = 'input', stageName = 'selection',
+                    dynConfig = {'preselection' : lambda meta : "&&".join (meta["selectionDecorNames"])} )
 
     # Set up an algorithm that makes a view container using the selections
     # performed previously:
     if shallowViewOutput:
         alg = createAlgorithm( 'CP::AsgViewFromSelectionAlg',
                                'ElectronViewFromSelectionAlg' + postfix )
-        alg.selection = selectionDecorNamesOutput[ : ]
         seq.append( alg, inputPropName = 'input', outputPropName = 'output',
-                    stageName = 'selection' )
+                    stageName = 'selection',
+                    dynConfig = {'selection' : lambda meta : meta["selectionDecorNamesOutput"][:]} )
         pass
 
     # Set up the electron efficiency correction algorithm:
     alg = createAlgorithm( 'CP::ElectronEfficiencyCorrectionAlg',
                            'ElectronEfficiencyCorrectionAlg' + postfix )
-    alg.preselection = "&&".join (selectionDecorNames)
     addPrivateTool( alg, 'efficiencyCorrectionTool',
                     'AsgElectronEfficiencyCorrectionTool' )
     alg.scaleFactorDecoration = 'effSF' + postfix + '_%SYS%'
@@ -281,17 +277,18 @@ def makeElectronAnalysisSequence( dataType, workingPoint,
     alg.outOfValidityDeco = 'bad_eff' + postfix
     if dataType != 'data':
         seq.append( alg, inputPropName = 'electrons',
-                    stageName = 'efficiency' )
+                    stageName = 'efficiency',
+                    dynConfig = {'preselection' : lambda meta : "&&".join (meta["selectionDecorNames"])} )
         pass
 
     # Set up a final deep copy making algorithm if requested:
     if deepCopyOutput:
         alg = createAlgorithm( 'CP::AsgViewFromSelectionAlg',
                                'ElectronDeepCopyMaker' + postfix )
-        alg.selection = selectionDecorNamesOutput[:]
         alg.deepCopy = True
         seq.append( alg, inputPropName = 'input', outputPropName = 'output',
-                    stageName = 'selection' )
+                    stageName = 'selection',
+                    dynConfig = {'selection' : lambda meta : meta["selectionDecorNamesOutput"][:]} )
         pass
 
     # Return the sequence:
diff --git a/PhysicsAnalysis/Algorithms/EgammaAnalysisAlgorithms/python/PhotonAnalysisSequence.py b/PhysicsAnalysis/Algorithms/EgammaAnalysisAlgorithms/python/PhotonAnalysisSequence.py
index 0e1325e6c63c..7ba200c2d023 100644
--- a/PhysicsAnalysis/Algorithms/EgammaAnalysisAlgorithms/python/PhotonAnalysisSequence.py
+++ b/PhysicsAnalysis/Algorithms/EgammaAnalysisAlgorithms/python/PhotonAnalysisSequence.py
@@ -63,30 +63,30 @@ def makePhotonAnalysisSequence( dataType, workingPoint,
     seq = AnaAlgSequence( "PhotonAnalysisSequence" + postfix )
 
     # Variables keeping track of the selections being applied.
-    selectionDecorNames = []
-    selectionDecorCount = []
+    seq.addMetaConfigDefault ("selectionDecorNames", [])
+    seq.addMetaConfigDefault ("selectionDecorCount", [])
 
     # Set up the photon selection algorithm:
     alg = createAlgorithm( 'CP::AsgSelectionAlg', 'PhotonIsEMSelectorAlg' + postfix )
     alg.selectionDecoration = 'selectEM'
-    selectionDecorNames.append( alg.selectionDecoration )
     if recomputeIsEM:
         # Rerun the cut-based ID
         addPrivateTool( alg, 'selectionTool', 'AsgPhotonIsEMSelector' )
         alg.selectionTool.isEMMask = quality
         alg.selectionTool.ConfigFile = \
           'ElectronPhotonSelectorTools/offline/20180116/PhotonIsEMTightSelectorCutDefs.conf'
-        selectionDecorCount.append( 32 )
     else:
         # Select from Derivation Framework flags
         addPrivateTool( alg, 'selectionTool', 'CP::AsgFlagSelectionTool' )
         dfFlag = 'DFCommonPhotonsIsEM' + qualityWP
         alg.selectionTool.selectionFlags = [ dfFlag ]
-        selectionDecorCount.append( 1 )
         pass
     seq.append( alg, inputPropName = 'particles',
                 outputPropName = 'particlesOut',
-                stageName = 'calibration' )
+                stageName = 'calibration',
+                metaConfig = {'selectionDecorNames' : [alg.selectionDecoration],
+                              'selectionDecorCount' : [32 if recomputeIsEM else 1]},
+                dynConfig = {'preselection' : lambda meta : "&&".join (meta["selectionDecorNames"])} )
 
     # Select electrons only with good object quality.
     alg = createAlgorithm( 'CP::AsgSelectionAlg', 'PhotonObjectQualityAlg' + postfix )
@@ -95,18 +95,19 @@ def makePhotonAnalysisSequence( dataType, workingPoint,
     alg.selectionTool.Mask = xAOD.EgammaParameters.BADCLUSPHOTON
     seq.append( alg, inputPropName = 'particles',
                 outputPropName = 'particlesOut',
-                stageName = 'calibration' )
-    selectionDecorNames.append( alg.selectionDecoration )
-    selectionDecorCount.append( 1 )
+                stageName = 'calibration',
+                metaConfig = {'selectionDecorNames' : [alg.selectionDecoration],
+                              'selectionDecorCount' : [1]},
+                dynConfig = {'preselection' : lambda meta : "&&".join (meta["selectionDecorNames"])} )
 
     # Only run subsequent processing on the objects passing all of these cuts.
     # Since these are independent of the photon calibration, and this speeds
     # up the job.
     alg = createAlgorithm( 'CP::AsgViewFromSelectionAlg',
                            'PhotonPreSelViewFromSelectionAlg' + postfix )
-    alg.selection = selectionDecorNames[ : ]
     seq.append( alg, inputPropName = 'input', outputPropName = 'output',
-                stageName = 'calibration' )
+                stageName = 'calibration',
+                dynConfig = {'selection' : lambda meta : meta["selectionDecorNames"] [:]} )
 
     # Set up the calibration ans smearing algorithm.
     alg = createAlgorithm( 'CP::EgammaCalibrationAndSmearingAlg',
@@ -154,9 +155,9 @@ def makePhotonAnalysisSequence( dataType, workingPoint,
     addPrivateTool( alg, 'selectionTool', 'CP::IsolationSelectionTool' )
     alg.selectionTool.PhotonWP = isolationWP
     seq.append( alg, inputPropName = 'egammas', outputPropName = 'egammasOut',
-                stageName = 'selection' )
-    selectionDecorNames.append( alg.selectionDecoration )
-    selectionDecorCount.append( 1 )
+                stageName = 'selection',
+                metaConfig = {'selectionDecorNames' : [alg.selectionDecoration],
+                              'selectionDecorCount' : [1]} )
 
     # Set up the photon efficiency correction algorithm.
     alg = createAlgorithm( 'CP::PhotonEfficiencyCorrectionAlg',
@@ -176,9 +177,9 @@ def makePhotonAnalysisSequence( dataType, workingPoint,
     if dataType != 'data':
         seq.append( alg, inputPropName = 'photons',
                     outputPropName = 'photonsOut',
-                    stageName = 'efficiency' )
-        selectionDecorNames.append( alg.outOfValidityDeco )
-        selectionDecorCount.append( 1 )
+                    stageName = 'efficiency',
+                    metaConfig = {'selectionDecorNames' : [alg.outOfValidityDeco],
+                                  'selectionDecorCount' : [1]} )
         pass
 
     # Set up an algorithm used to create photon selection cutflow:
@@ -186,26 +187,26 @@ def makePhotonAnalysisSequence( dataType, workingPoint,
         alg = createAlgorithm( 'CP::ObjectCutFlowHistAlg',
                             'PhotonCutFlowDumperAlg' + postfix )
         alg.histPattern = 'photon_cflow_%SYS%' + postfix
-        alg.selection = selectionDecorNames[ : ]
-        alg.selectionNCuts = selectionDecorCount[ : ]
         seq.append( alg, inputPropName = 'input',
-                    stageName = 'selection' )
+                    stageName = 'selection',
+                    dynConfig = {'selection' : lambda meta : meta["selectionDecorNames"][:],
+                                 'selectionNCuts' : lambda meta : meta["selectionDecorCount"][:]} )
 
     # Set up an algorithm that makes a view container using the selections
     # performed previously:
     alg = createAlgorithm( 'CP::AsgViewFromSelectionAlg',
                            'PhotonViewFromSelectionAlg' + postfix )
-    alg.selection = selectionDecorNames[ : ]
     seq.append( alg, inputPropName = 'input', outputPropName = 'output',
-                stageName = 'selection' )
+                stageName = 'selection',
+                dynConfig = {'selection' : lambda meta : meta["selectionDecorNames"] [:]} )
 
     # Set up an algorithm dumping the kinematic properties of the photons:
     if enableKinematicHistograms:
         alg = createAlgorithm( 'CP::KinematicHistAlg', 'PhotonKinematicDumperAlg' + postfix )
-        alg.preselection = "&&".join (selectionDecorNames)
         alg.histPattern = 'photon_%VAR%_%SYS%' + postfix
         seq.append( alg, inputPropName = 'input',
-                    stageName = 'selection' )
+                    stageName = 'selection',
+                    dynConfig = {'preselection' : lambda meta : "&&".join (meta["selectionDecorNames"])} )
 
     # Set up a final deep copy making algorithm if requested:
     if deepCopyOutput:
-- 
GitLab


From 01f2eae9c4a2ff679d871c9caf5cb98169b28874 Mon Sep 17 00:00:00 2001
From: Nils Krumnack <krumnack@iastate.edu>
Date: Fri, 3 Apr 2020 12:22:15 -0500
Subject: [PATCH 4/5] switch to using meta-configuration for selection
 accounting

Just to make modifications to analysis sequences more easy to do for
the user.
---
 .../python/TauAnalysisSequence.py             | 32 +++++++++----------
 1 file changed, 16 insertions(+), 16 deletions(-)

diff --git a/PhysicsAnalysis/Algorithms/TauAnalysisAlgorithms/python/TauAnalysisSequence.py b/PhysicsAnalysis/Algorithms/TauAnalysisAlgorithms/python/TauAnalysisSequence.py
index c3860c70cd49..29817be83509 100644
--- a/PhysicsAnalysis/Algorithms/TauAnalysisAlgorithms/python/TauAnalysisSequence.py
+++ b/PhysicsAnalysis/Algorithms/TauAnalysisAlgorithms/python/TauAnalysisSequence.py
@@ -59,8 +59,8 @@ def makeTauAnalysisSequence( dataType, workingPoint, postfix = '',
     seq = AnaAlgSequence( "TauAnalysisSequence" + postfix )
 
     # Variables keeping track of the selections being applied.
-    selectionDecorNames = []
-    selectionDecorCount = []
+    seq.addMetaConfigDefault ("selectionDecorNames", [])
+    seq.addMetaConfigDefault ("selectionDecorCount", [])
 
     # Setup the tau selection tool
     selectionTool = createPublicTool( 'TauAnalysisTools::TauSelectionTool',
@@ -91,9 +91,9 @@ def makeTauAnalysisSequence( dataType, workingPoint, postfix = '',
     alg.selectionTool.ConfigPath = inputfile
     alg.selectionDecoration = 'selected_tau' + postfix + ',as_bits'
     seq.append( alg, inputPropName = 'particles',
-                stageName = 'selection' )
-    selectionDecorNames.append( alg.selectionDecoration )
-    selectionDecorCount.append( 6 )
+                stageName = 'selection',
+                metaConfig = {'selectionDecorNames' : [alg.selectionDecoration],
+                              'selectionDecorCount' : [6]} )
 
     # Set up the algorithm calculating the efficiency scale factors for the
     # taus:
@@ -114,43 +114,43 @@ def makeTauAnalysisSequence( dataType, workingPoint, postfix = '',
     if enableCutflow:
         alg = createAlgorithm( 'CP::ObjectCutFlowHistAlg', 'TauCutFlowDumperAlg' + postfix )
         alg.histPattern = 'tau_cflow_%SYS%'
-        alg.selection = selectionDecorNames[ : ]
-        alg.selectionNCuts = selectionDecorCount[ : ]
-        seq.append( alg, inputPropName = 'input', stageName = 'selection' )
+        seq.append( alg, inputPropName = 'input', stageName = 'selection',
+                    dynConfig = {'selection' : lambda meta : meta["selectionDecorNames"][:],
+                                 'selectionNCuts' : lambda meta : meta["selectionDecorCount"][:]} )
 
     # Set up an algorithm used for decorating baseline tau selection:
     alg = createAlgorithm( 'CP::AsgSelectionAlg',
                            'TauSelectionSummary' + postfix )
     addPrivateTool( alg, 'selectionTool', 'CP::AsgFlagSelectionTool' )
-    alg.selectionTool.selectionFlags = selectionDecorNames[ : ]
     alg.selectionDecoration = 'baselineSelection' + postfix + ',as_char'
     seq.append( alg, inputPropName = 'particles',
-                stageName = 'selection' )
+                stageName = 'selection',
+                dynConfig = {'selectionTool.selectionFlags' : lambda meta : meta["selectionDecorNames"][:]} )
 
     # Set up an algorithm that makes a view container using the selections
     # performed previously:
     if shallowViewOutput:
         alg = createAlgorithm( 'CP::AsgViewFromSelectionAlg',
                             'TauViewFromSelectionAlg' + postfix )
-        alg.selection = selectionDecorNames[ : ]
         seq.append( alg, inputPropName = 'input', outputPropName = 'output',
-                    stageName = 'selection' )
+                    stageName = 'selection',
+                    dynConfig = {'selection' : lambda meta : meta["selectionDecorNames"][:]} )
 
     # Set up an algorithm dumping the kinematic properties of the taus:
     if enableKinematicHistograms:
         alg = createAlgorithm( 'CP::KinematicHistAlg', 'TauKinematicDumperAlg' + postfix )
-        alg.preselection = '&&'.join (selectionDecorNames)
         alg.histPattern = 'tau_%VAR%_%SYS%'
-        seq.append( alg, inputPropName = 'input', stageName = 'selection' )
+        seq.append( alg, inputPropName = 'input', stageName = 'selection',
+                    dynConfig = {'preselection' : lambda meta : "&&".join (meta["selectionDecorNames"])} )
 
     # Set up a final deep copy making algorithm if requested:
     if deepCopyOutput:
         alg = createAlgorithm( 'CP::AsgViewFromSelectionAlg',
                                'TauDeepCopyMaker' + postfix )
         alg.deepCopy = True
-        alg.selection = selectionDecorNames[ : ]
         seq.append( alg, inputPropName = 'input', outputPropName = 'output',
-                    stageName = 'selection' )
+                    stageName = 'selection',
+                    dynConfig = {'selection' : lambda meta : meta["selectionDecorNames"] [:]} )
         pass
 
     # Return the sequence:
-- 
GitLab


From 450ddb46daae9c4b8527f4b2977a455c1a001611 Mon Sep 17 00:00:00 2001
From: Nils Krumnack <krumnack@iastate.edu>
Date: Wed, 30 Sep 2020 15:23:23 -0500
Subject: [PATCH 5/5] move call to xAOD::LoadDictionaries() earlier

It needs to happen as early as possible in the job, so I added a
separate point in the setup to call it.  This may still not fully work
for the legacy EL::Algorithm, just due to the fact that it gets
instantiated too early.
---
 .../D3PDTools/EventLoop/EventLoop/Module.h    | 20 ++++++++++++++-----
 .../EventLoop/EventLoop/StopwatchModule.h     |  2 +-
 .../D3PDTools/EventLoop/Root/Module.cxx       |  8 +++++++-
 .../EventLoop/Root/StopwatchModule.cxx        |  2 +-
 .../D3PDTools/EventLoop/Root/Worker.cxx       |  8 ++++++--
 5 files changed, 30 insertions(+), 10 deletions(-)

diff --git a/PhysicsAnalysis/D3PDTools/EventLoop/EventLoop/Module.h b/PhysicsAnalysis/D3PDTools/EventLoop/EventLoop/Module.h
index 47ee245888bf..96e09b45ca77 100644
--- a/PhysicsAnalysis/D3PDTools/EventLoop/EventLoop/Module.h
+++ b/PhysicsAnalysis/D3PDTools/EventLoop/EventLoop/Module.h
@@ -43,14 +43,24 @@ namespace EL
       virtual ~Module () noexcept = default;
 
 
-      /// \brief action at the beginning of worker job
+      /// \brief action at the the very beginning of the worker job
       ///
       /// This gets called as early as possible in the worker
-      /// initialization.  The main purpose is to start any benchmarks
-      /// that are meant to capture the initialization process as
-      /// well.
+      /// initialization.  Essentially all that should happen before
+      /// this is to load all the modules.  The main purpose is to
+      /// start any benchmarks that are meant to capture the
+      /// initialization process as well.
     public:
-      virtual ::StatusCode preInitialize (ModuleData& data);
+      virtual ::StatusCode firstInitialize (ModuleData& data);
+
+
+      /// \brief action before opening the first file in the worker
+      /// job
+      ///
+      /// This is mostly meant to allow loading the dictionaries
+      /// before any files and associated information is loaded.
+    public:
+      virtual ::StatusCode preFileInitialize (ModuleData& data);
 
 
       /// \brief action just before algorithms are initialized
diff --git a/PhysicsAnalysis/D3PDTools/EventLoop/EventLoop/StopwatchModule.h b/PhysicsAnalysis/D3PDTools/EventLoop/EventLoop/StopwatchModule.h
index ff51b0a35933..830d87d36841 100644
--- a/PhysicsAnalysis/D3PDTools/EventLoop/EventLoop/StopwatchModule.h
+++ b/PhysicsAnalysis/D3PDTools/EventLoop/EventLoop/StopwatchModule.h
@@ -28,7 +28,7 @@ namespace EL
       //
 
     public:
-      virtual ::StatusCode preInitialize (ModuleData& data) override;
+      virtual ::StatusCode firstInitialize (ModuleData& data) override;
 
     public:
       virtual ::StatusCode onFileExecute (ModuleData& data) override;
diff --git a/PhysicsAnalysis/D3PDTools/EventLoop/Root/Module.cxx b/PhysicsAnalysis/D3PDTools/EventLoop/Root/Module.cxx
index 12d6011d0e10..89aa5b70c327 100644
--- a/PhysicsAnalysis/D3PDTools/EventLoop/Root/Module.cxx
+++ b/PhysicsAnalysis/D3PDTools/EventLoop/Root/Module.cxx
@@ -23,7 +23,13 @@ namespace EL
   namespace Detail
   {
     ::StatusCode Module ::
-    preInitialize (ModuleData& /*data*/)
+    firstInitialize (ModuleData& /*data*/)
+    {
+      return ::StatusCode::SUCCESS;
+    }
+
+    ::StatusCode Module ::
+    preFileInitialize (ModuleData& /*data*/)
     {
       return ::StatusCode::SUCCESS;
     }
diff --git a/PhysicsAnalysis/D3PDTools/EventLoop/Root/StopwatchModule.cxx b/PhysicsAnalysis/D3PDTools/EventLoop/Root/StopwatchModule.cxx
index 471460d36bfe..f12dc3a9a50d 100644
--- a/PhysicsAnalysis/D3PDTools/EventLoop/Root/StopwatchModule.cxx
+++ b/PhysicsAnalysis/D3PDTools/EventLoop/Root/StopwatchModule.cxx
@@ -26,7 +26,7 @@ namespace EL
   namespace Detail
   {
     ::StatusCode StopwatchModule ::
-    preInitialize (ModuleData& /*data*/)
+    firstInitialize (ModuleData& /*data*/)
     {
       m_stopwatch = std::make_unique<TStopwatch> ();
 
diff --git a/PhysicsAnalysis/D3PDTools/EventLoop/Root/Worker.cxx b/PhysicsAnalysis/D3PDTools/EventLoop/Root/Worker.cxx
index b5226174b7d0..21da6aa14aec 100644
--- a/PhysicsAnalysis/D3PDTools/EventLoop/Root/Worker.cxx
+++ b/PhysicsAnalysis/D3PDTools/EventLoop/Root/Worker.cxx
@@ -400,9 +400,13 @@ namespace EL
       ("EventLoop_JobStats", "EventLoop job statistics");
     m_jobStats->SetDirectory (nullptr);
 
+    ANA_MSG_INFO ("calling firstInitialize on all modules");
     for (auto& module : m_modules)
-      ANA_CHECK (module->preInitialize (*this));
-
+      ANA_CHECK (module->firstInitialize (*this));
+    ANA_MSG_INFO ("calling preFileInitialize on all modules");
+    for (auto& module : m_modules)
+      ANA_CHECK (module->preFileInitialize (*this));
+    
     return ::StatusCode::SUCCESS;
   }
 
-- 
GitLab