From f9ac7b07bca0f5836798ce8ef93a505ba052ee6f Mon Sep 17 00:00:00 2001
From: Mark Hodgkinson <m.hodgkinson@sheffield.ac.uk>
Date: Thu, 22 Sep 2022 17:03:00 +0200
Subject: [PATCH] Add new links between global FE and CP Objects (Second
 Attempt)

Add new global linking to CA reco.
Bug fix CA based link exclusion.
Add link exclusion to old style reco.
---
 .../python/AthenaMonitoringCfg.py             |  7 +-
 .../python/PhysCommon.py                      | 10 +++
 .../python/PhysCommonConfig.py                |  7 ++
 .../METReconstruction/Root/METAssociator.cxx  |  4 +-
 .../MuonCombinedReconstructionConfig.py       |  8 +-
 .../share/MuonCombined_OutputItemsAOD.py      |  5 +-
 .../RecExCommon/share/CombinedRec_config.py   |  9 +-
 .../RecJobTransforms/python/RecoSteering.py   |  4 +
 Reconstruction/eflowRec/python/PFCfg.py       | 82 +++++++++++++++++--
 .../eflowRec/src/PFMuonFlowElementAssoc.cxx   | 41 ++++++----
 .../eflowRec/src/PFTauFlowElementAssoc.cxx    |  9 +-
 .../egammaConfig/python/egammaConfigFlags.py  |  6 +-
 .../egamma/egammaRec/python/egammaKeys.py     | 11 ++-
 Reconstruction/tauRec/python/TauConfig.py     |  6 +-
 Reconstruction/tauRec/share/TauAODList.py     |  3 +-
 Reconstruction/tauRec/share/TauESDList.py     |  3 +-
 Tools/WorkflowTestRunner/python/References.py |  6 +-
 17 files changed, 175 insertions(+), 46 deletions(-)

diff --git a/Control/AthenaMonitoring/python/AthenaMonitoringCfg.py b/Control/AthenaMonitoring/python/AthenaMonitoringCfg.py
index 847c4c80b85d..048cc1561fcb 100644
--- a/Control/AthenaMonitoring/python/AthenaMonitoringCfg.py
+++ b/Control/AthenaMonitoring/python/AthenaMonitoringCfg.py
@@ -79,6 +79,11 @@ def AthenaMonitoringCfg(flags):
         info('Set up Jet monitoring')
         from JetMonitoring.JetMonitoringStandard import standardJetMonitoring
         result.merge(standardJetMonitoring(flags))
+        #Need to create links between global FE, created in jet finding, and other objects
+        #MET monitoring will need these in some workflows (but not in tier0ESD)
+        if flags.DQ.Environment != 'tier0ESD':
+            from eflowRec.PFCfg import PFGlobalFlowElementLinkingCfg
+            result.merge(PFGlobalFlowElementLinkingCfg(flags))
         
     if flags.DQ.Steering.doJetInputsMon:
         info('Set up Jet Inputs monitoring')
@@ -158,4 +163,4 @@ def AthenaMonitoringPostprocessingCfg(flags):
         ppa.FileKey = ((flags.DQ.FileKey + '/') if not flags.DQ.FileKey.endswith('/')
                     else flags.DQ.FileKey)
     result.addEventAlgo(ppa, "AthEndSeq")
-    return result
\ No newline at end of file
+    return result
diff --git a/PhysicsAnalysis/DerivationFramework/DerivationFrameworkPhys/python/PhysCommon.py b/PhysicsAnalysis/DerivationFramework/DerivationFrameworkPhys/python/PhysCommon.py
index e9668e3a513d..0fb4146a3110 100644
--- a/PhysicsAnalysis/DerivationFramework/DerivationFrameworkPhys/python/PhysCommon.py
+++ b/PhysicsAnalysis/DerivationFramework/DerivationFrameworkPhys/python/PhysCommon.py
@@ -76,6 +76,16 @@ jetList = [AntiKt4EMTopo_deriv,
 
 addDAODJets(jetList,DerivationFrameworkJob)
 
+#We also need to build links between the newly created jet constituents (GlobalFE)
+#and electrons,photons,muons and taus
+from AthenaConfiguration.AllConfigFlags import ConfigFlags
+from AthenaConfiguration.ComponentAccumulator import CAtoGlobalWrapper
+from eflowRec.PFCfg import PFGlobalFlowElementLinkingCfg
+CAtoGlobalWrapper(PFGlobalFlowElementLinkingCfg,ConfigFlags)
+#AOD do not have calorimeter cells for CaloCalTopoCluster, so we have to use 
+#this special setting for the muon-FE links.
+DerivationFrameworkJob.PFMuonGlobalFlowElementAssoc.m_UseMuonTopoClusters=True
+
 # Special rho definition for PFlow jets
 addSidebandEventShape(sequence=DerivationFrameworkJob)
 # Event cleaning flags
diff --git a/PhysicsAnalysis/DerivationFramework/DerivationFrameworkPhys/python/PhysCommonConfig.py b/PhysicsAnalysis/DerivationFramework/DerivationFrameworkPhys/python/PhysCommonConfig.py
index 146cd9e8d944..b12368ff50b1 100644
--- a/PhysicsAnalysis/DerivationFramework/DerivationFrameworkPhys/python/PhysCommonConfig.py
+++ b/PhysicsAnalysis/DerivationFramework/DerivationFrameworkPhys/python/PhysCommonConfig.py
@@ -71,6 +71,13 @@ def PhysCommonAugmentationsCfg(ConfigFlags,**kwargs):
     from DerivationFrameworkTau.TauCommonConfig import AddTauWPDecorationCfg
     from DerivationFrameworkJetEtMiss.METCommonConfig import METCommonCfg 
     acc.merge(JetCommonCfg(ConfigFlags))
+    #We also need to build links between the newly created jet constituents (GlobalFE)
+    #and electrons,photons,muons and taus
+    from eflowRec.PFCfg import PFGlobalFlowElementLinkingCfg
+    acc.merge(PFGlobalFlowElementLinkingCfg(ConfigFlags))
+    #AOD do not have calorimeter cells for CaloCalTopoCluster, so we have to use 
+    #this special setting for the muon-FE links.
+    acc.getEventAlgo("PFMuonGlobalFlowElementAssoc").m_UseMuonTopoClusters=True
     acc.merge(AddDiTauLowPtCfg(ConfigFlags, prefix = 'PhysCommon'))
     acc.merge(AddTauWPDecorationCfg(ConfigFlags, prefix = 'PhysCommon', evetoFixTag="v1"))
     FTagJetColl = ['AntiKt4EMPFlowJets','AntiKtVR30Rmax4Rmin02TrackJets']
diff --git a/Reconstruction/MET/METReconstruction/Root/METAssociator.cxx b/Reconstruction/MET/METReconstruction/Root/METAssociator.cxx
index 5c7e7d8e2d20..5ce9904a8aaf 100755
--- a/Reconstruction/MET/METReconstruction/Root/METAssociator.cxx
+++ b/Reconstruction/MET/METReconstruction/Root/METAssociator.cxx
@@ -71,8 +71,8 @@ namespace met {
     declareProperty( "UseFELinks",         m_useFELinks = false                  ); 
     declareProperty( "NeutralPFOLinksKey", m_neutralPFOLinksKey = "neutralpfoLinks"); 
     declareProperty( "ChargedPFOLinksKey", m_chargedPFOLinksKey = "chargedpfoLinks"); 
-    declareProperty( "NeutralFELinksKey",  m_neutralFELinksKey  = "neutralFELinks"); 
-    declareProperty( "ChargedFELinksKey",  m_chargedFELinksKey  = "chargedFELinks"); 
+    declareProperty( "NeutralFELinksKey",  m_neutralFELinksKey  = "neutralGlobalFELinks"); 
+    declareProperty( "ChargedFELinksKey",  m_chargedFELinksKey  = "chargedGlobalFELinks"); 
   }
 
   // Destructor
diff --git a/Reconstruction/MuonIdentification/MuonCombinedConfig/python/MuonCombinedReconstructionConfig.py b/Reconstruction/MuonIdentification/MuonCombinedConfig/python/MuonCombinedReconstructionConfig.py
index 28ca04c5eb13..02f0eea3ddee 100644
--- a/Reconstruction/MuonIdentification/MuonCombinedConfig/python/MuonCombinedReconstructionConfig.py
+++ b/Reconstruction/MuonIdentification/MuonCombinedConfig/python/MuonCombinedReconstructionConfig.py
@@ -513,8 +513,12 @@ def CombinedMuonOutputCfg(flags):
 
     # FIXME! Next two lines are hack to remove derivation framework variables that are added by DRAW building and are supposed to be transient
     wp_decors = ["DFCommonMuonsTight", "DFCommonGoodMuon", "DFCommonMuonsMedium",
-                 "DFCommonMuonsLoose", "InnerDetectorPt", "MuonSpectrometerPt"]
-    excludedMuonAuxData = ".-"+".-".join(iso_vars+wp_decors)
+                 "DFCommonMuonsLoose", "InnerDetectorPt", "MuonSpectrometerPt"]    
+    #Remove GlobalFELinks and related variables - these are links between FlowElement (FE) containers created in jet finding and muons. 
+    #Since these transient FE containers are not in the ESD/AOD, we should not write out these links.
+    gpf_vars=[ "chargedGlobalFELinks", "neutralGlobalFELinks", "muon_efrac_matched_GlobalFE", "deltaR_muon_clus_GlobalFEalg"]
+    excludedMuonAuxData = ".-"+".-".join(iso_vars+wp_decors+gpf_vars)
+
     aod_items += ["xAOD::MuonAuxContainer#MuonsAux" + excludedMuonAuxData]
     aod_items += ["xAOD::MuonAuxContainer#MuonsLRTAux" + excludedMuonAuxData]
 
diff --git a/Reconstruction/MuonIdentification/MuonCombinedRecExample/share/MuonCombined_OutputItemsAOD.py b/Reconstruction/MuonIdentification/MuonCombinedRecExample/share/MuonCombined_OutputItemsAOD.py
index 419087096bf2..98ac8e064ede 100644
--- a/Reconstruction/MuonIdentification/MuonCombinedRecExample/share/MuonCombined_OutputItemsAOD.py
+++ b/Reconstruction/MuonIdentification/MuonCombinedRecExample/share/MuonCombined_OutputItemsAOD.py
@@ -30,7 +30,10 @@ if DetFlags.detdescr.Calo_on(): # FIXME - check if the objects below still make
 if DetFlags.detdescr.Muon_on():
    excludedAuxData = '-clusterAssociation'
    common_flags = [ "DFCommonMuonsTight", "DFCommonGoodMuon","DFCommonMuonsMedium", "DFCommonMuonsLoose", "InnerDetectorPt", "MuonSpectrometerPt" ]
-   excludedMuonAuxData = ".-"+".-".join(iso_vars() + common_flags)
+   #Also remove GlobalFELinks and associated variables - these are links between FlowElement (FE) containers created in jet finding and muons. Since these transient FE containers are not in the AOD, 
+   # we should not write out these links or variables
+   gpf_vars = ["chargedGlobalFELinks","neutralGlobalFELinks","deltaR_muon_clus_GlobalFEalg","muon_efrac_matched_GlobalFE"]
+   excludedMuonAuxData = ".-"+".-".join(iso_vars() + common_flags + gpf_vars)
    # Adding the xAOD content by default
    track_particles = GetCombinedTrackParticles()[0]
    for trk_cont in track_particles:
diff --git a/Reconstruction/RecExample/RecExCommon/share/CombinedRec_config.py b/Reconstruction/RecExample/RecExCommon/share/CombinedRec_config.py
index 0eb59a9ef2f1..beff39a2fe05 100755
--- a/Reconstruction/RecExample/RecExCommon/share/CombinedRec_config.py
+++ b/Reconstruction/RecExample/RecExCommon/share/CombinedRec_config.py
@@ -177,8 +177,15 @@ if recAlgs.doEFlow() and jobproperties.eflowRecFlags.usePFFlowElementAssoc:
         from eflowRec.PFCfg import PFTauFlowElementLinkingCfg
         CAtoGlobalWrapper(PFTauFlowElementLinkingCfg,ConfigFlags)        
     except Exception:
-        treatException("Could not set up tau-FE links")
+        treatException("Could not set up tau-FE links")    
 
+#Links to/from global FE containers created during jet finding
+if(jetOK):
+    try:
+        from eflowRec.PFCfg import PFGlobalFlowElementLinkingCfg
+        CAtoGlobalWrapper(PFGlobalFlowElementLinkingCfg,ConfigFlags)
+    except Exception:
+        treatException("Could not setup PFGlobalFlowElementAssoc Algorithms")
 #
 # functionality : Missing Et
 #
diff --git a/Reconstruction/RecJobTransforms/python/RecoSteering.py b/Reconstruction/RecJobTransforms/python/RecoSteering.py
index 0ab8dec4b5b9..c1f9d2f0f21a 100644
--- a/Reconstruction/RecJobTransforms/python/RecoSteering.py
+++ b/Reconstruction/RecJobTransforms/python/RecoSteering.py
@@ -136,6 +136,10 @@ def RecoSteering(flags):
     if flags.Reco.EnableJet:
         from JetRecConfig.JetRecoSteering import JetRecoSteeringCfg
         acc.merge(JetRecoSteeringCfg(flags))
+        #We also need to build links between the newly created jet constituents (GlobalFE)
+        #and electrons,photons,muons and taus
+        from eflowRec.PFCfg import PFGlobalFlowElementLinkingCfg
+        acc.merge(PFGlobalFlowElementLinkingCfg(flags))
         log.info("---------- Configured jets")
 
     # btagging
diff --git a/Reconstruction/eflowRec/python/PFCfg.py b/Reconstruction/eflowRec/python/PFCfg.py
index dade392165e9..3d118f422ae4 100644
--- a/Reconstruction/eflowRec/python/PFCfg.py
+++ b/Reconstruction/eflowRec/python/PFCfg.py
@@ -196,10 +196,12 @@ def getLCNeutralFlowElementCreatorAlgorithm(inputFlags,neutralFlowElementOutputN
     
     return LCFlowElementNeutralCreatorAlgorithm 
 
-def getEGamFlowElementAssocAlgorithm(inputFlags,neutral_FE_cont_name="",charged_FE_cont_name="",AODTest=False,doTCC=False):
+def getEGamFlowElementAssocAlgorithm(inputFlags,neutral_FE_cont_name="",charged_FE_cont_name="",AODTest=False,doTCC=False,useGlobal=False,algName=""):
 
     PFEGamFlowElementLinkerAlgorithmFactory=CompFactory.PFEGamFlowElementAssoc
-    PFEGamFlowElementLinkerAlgorithm=PFEGamFlowElementLinkerAlgorithmFactory("PFEGamFlowElementAssoc")
+    if (algName == ""):
+        algName = "PFEGamFlowElementAssoc"
+    PFEGamFlowElementLinkerAlgorithm=PFEGamFlowElementLinkerAlgorithmFactory(algName)
 
     #set an an alternate name if needed
     #this uses some gaudi core magic, namely that you can change the name of the handle as it is a callable attribute, despite the attribute not being explicitly listed in the header
@@ -268,17 +270,44 @@ def getEGamFlowElementAssocAlgorithm(inputFlags,neutral_FE_cont_name="",charged_
         PFEGamFlowElementLinkerAlgorithm.ChargedFEPhotonDecorKey="TrackCaloClustersCharged.TCC_PhotonLinks"
         PFEGamFlowElementLinkerAlgorithm.NeutralFEPhotonDecorKey="TrackCaloClustersNeutral.TCC_PhotonLinks"
         
+    if(useGlobal):
+        # ReadHandles to change
+        PFEGamFlowElementLinkerAlgorithm.JetEtMissNeutralFlowElementContainer="GlobalNeutralParticleFlowObjects"
+        PFEGamFlowElementLinkerAlgorithm.JetEtMissChargedFlowElementContainer="GlobalChargedParticleFlowObjects"
+        
+        #Now to change the writeHandles
+        # first the Electron -> FE links
+        EL_NFE_Link=str(PFEGamFlowElementLinkerAlgorithm.ElectronNeutralFEDecorKey)
+        PFEGamFlowElementLinkerAlgorithm.ElectronNeutralFEDecorKey=EL_NFE_Link.replace("FELinks","GlobalFELinks")
+        EL_CFE_Link=str(PFEGamFlowElementLinkerAlgorithm.ElectronChargedFEDecorKey)
+        PFEGamFlowElementLinkerAlgorithm.ElectronChargedFEDecorKey=EL_CFE_Link.replace("FELinks","GlobalFELinks")
+        #then the converse case (FE -> Electron)
+        
+        PFEGamFlowElementLinkerAlgorithm.ChargedFEElectronDecorKey="GlobalChargedParticleFlowObjects.GlobalFE_ElectronLinks"
+        PFEGamFlowElementLinkerAlgorithm.NeutralFEElectronDecorKey="GlobalNeutralParticleFlowObjects.GLobalFE_ElectronLinks"
+        
+
+        # first the Photon -> FE links
+        PH_NFE_Link=str(PFEGamFlowElementLinkerAlgorithm.PhotonNeutralFEDecorKey)
+        PFEGamFlowElementLinkerAlgorithm.PhotonNeutralFEDecorKey=PH_NFE_Link.replace("FELinks","GlobalFELinks")
+        PH_CFE_Link=str(PFEGamFlowElementLinkerAlgorithm.PhotonChargedFEDecorKey)
+        PFEGamFlowElementLinkerAlgorithm.PhotonChargedFEDecorKey=PH_CFE_Link.replace("FELinks","GlobalFELinks")
+        #then the converse case (FE -> Photons)
         
+        PFEGamFlowElementLinkerAlgorithm.ChargedFEPhotonDecorKey="GlobalChargedParticleFlowObjects.TCC_PhotonLinks"
+        PFEGamFlowElementLinkerAlgorithm.NeutralFEPhotonDecorKey="GlobalNeutralParticleFlowObjects.TCC_PhotonLinks"
         
         
         
     return PFEGamFlowElementLinkerAlgorithm
 
-def getMuonFlowElementAssocAlgorithm(inputFlags,neutral_FE_cont_name="",charged_FE_cont_name="",LinkNeutralFEClusters=True,useMuonTopoClusters=False,AODTest=False,doTCC=False):
+def getMuonFlowElementAssocAlgorithm(inputFlags,neutral_FE_cont_name="",charged_FE_cont_name="",LinkNeutralFEClusters=True,useMuonTopoClusters=False,AODTest=False,doTCC=False,useGlobal=False,algName=""):
     
 
     PFMuonFlowElementLinkerAlgorithmFactory=CompFactory.PFMuonFlowElementAssoc
-    PFMuonFlowElementLinkerAlgorithm=PFMuonFlowElementLinkerAlgorithmFactory("PFMuonFlowElementAssoc")
+    if (algName == ""):
+        algName="PFMuonFlowElementAssoc"
+    PFMuonFlowElementLinkerAlgorithm=PFMuonFlowElementLinkerAlgorithmFactory(algName)
 
     #set an an alternate name if needed
     #this uses some gaudi core magic, namely that you can change the name of the handle as it is a callable attribute, despite the attribute not being explicitly listed in the header as such
@@ -336,6 +365,24 @@ def getMuonFlowElementAssocAlgorithm(inputFlags,neutral_FE_cont_name="",charged_
         PFMuonFlowElementLinkerAlgorithm.MuonContainer_muon_efrac_matched_FE="Muons.muon_efrac_matched_TCC"
         # this is because the algorithm adds this debug container which we don't need 
         PFMuonFlowElementLinkerAlgorithm.MuonContainer_ClusterInfo_deltaR="Muons.deltaR_muon_clus_TCCalg"
+
+    if(useGlobal):
+        PFMuonFlowElementLinkerAlgorithm.JetEtMissChargedFlowElementContainer="GlobalChargedParticleFlowObjects"
+        PFMuonFlowElementLinkerAlgorithm.JetEtMissNeutralFlowElementContainer="GlobalNeutralParticleFlowObjects"
+
+        PFMuonFlowElementLinkerAlgorithm.MuonContainer_chargedFELinks="Muons.chargedGlobalFELinks"
+        PFMuonFlowElementLinkerAlgorithm.MuonContainer_neutralFELinks="Muons.neutralGlobalFELinks"
+
+        PFMuonFlowElementLinkerAlgorithm.JetETMissNeutralFlowElementContainer_FE_MuonLinks="GlobalNeutralParticleFlowObjects.GlobalFE_MuonLinks"
+        PFMuonFlowElementLinkerAlgorithm.JetETMissChargedFlowElements_FE_MuonLinks="GlobalChargedParticleFlowObjects.GlobalFE_MuonLinks"
+
+        PFMuonFlowElementLinkerAlgorithm.FlowElementContainer_nMatchedMuons="GlobalNeutralParticleFlowObjects.GlobalFE_nMatchedMuons"
+        PFMuonFlowElementLinkerAlgorithm.FlowElementContainer_FE_efrac_matched_muon="GlobalNeutralParticleFlowObjects.GlobalFE_efrac_matched_muon"
+
+        PFMuonFlowElementLinkerAlgorithm.MuonContainer_muon_efrac_matched_FE="Muons.muon_efrac_matched_GlobalFE"
+        # this is because the algorithm adds this debug container which we don't need 
+        PFMuonFlowElementLinkerAlgorithm.MuonContainer_ClusterInfo_deltaR="Muons.deltaR_muon_clus_GlobalFEalg"
+
     if(LinkNeutralFEClusters):
         if (doTCC or AODTest):
             # since the cells are deleted on AOD, if you try to run the link between NFE and Muon on AOD, it will crash. Terminate to catch this.
@@ -352,10 +399,13 @@ def getMuonFlowElementAssocAlgorithm(inputFlags,neutral_FE_cont_name="",charged_
 
 
 
-def getTauFlowElementAssocAlgorithm(inputFlags,neutral_FE_cont_name="",charged_FE_cont_name="",AODTest=False,doTCC=False) :
+def getTauFlowElementAssocAlgorithm(inputFlags,neutral_FE_cont_name="",charged_FE_cont_name="",AODTest=False,doTCC=False,useGlobal=False,algName=""):
 
     PFTauFlowElementLinkerAlgorithmFactory=CompFactory.PFTauFlowElementAssoc
-    PFTauFlowElementLinkerAlgorithm=PFTauFlowElementLinkerAlgorithmFactory("PFTauFlowElementAssoc")
+    if(algName == ""):
+        algName = "PFTauFlowElementAssoc"
+
+    PFTauFlowElementLinkerAlgorithm=PFTauFlowElementLinkerAlgorithmFactory(algName)
 
     #set an an alternate name if needed
     #this uses some gaudi core magic, namely that you can change the name of the handle as it is a callable attribute, despite the attribute not being explicitly listed in the header
@@ -390,6 +440,16 @@ def getTauFlowElementAssocAlgorithm(inputFlags,neutral_FE_cont_name="",charged_F
          
          PFTauFlowElementLinkerAlgorithm.NeutralFETauDecorKey="TrackCaloClustersNeutral.TCC_TauLinks"
          PFTauFlowElementLinkerAlgorithm.ChargedFETauDecorKey="TrackCaloClustersCharged.TCC_TauLinks"
+    #This allows to set the links on the global particle flow containers created by JetPFlowSelectionAlg in JetRecTools
+    if(useGlobal):
+        PFTauFlowElementLinkerAlgorithm.JetETMissNeutralFlowElementContainer="GlobalNeutralParticleFlowObjects"
+        PFTauFlowElementLinkerAlgorithm.JetETMissChargedFlowElementContainer="GlobalChargedParticleFlowObjects"
+
+        PFTauFlowElementLinkerAlgorithm.TauNeutralFEDecorKey="TauJets.neutralGlobalFELinks"
+        PFTauFlowElementLinkerAlgorithm.TauChargedFEDecorKey="TauJets.chargedGlobalFELinks"
+
+        PFTauFlowElementLinkerAlgorithm.NeutralFETauDecorKey="GlobalNeutralParticleFlowObjects.GlobalFE_TauLinks"
+        PFTauFlowElementLinkerAlgorithm.ChargedFETauDecorKey="GlobalChargedParticleFlowObjects.GlobalFE_TauLinks"
 
     return PFTauFlowElementLinkerAlgorithm
 
@@ -414,12 +474,18 @@ def getOfflinePFAlgorithm(inputFlags):
     result.addEventAlgo(PFAlgorithm)
     return result
 
-def PFTauFlowElementLinkingCfg(inputFlags,neutral_FE_cont_name="",charged_FE_cont_name="",AODTest=False):
+def PFTauFlowElementLinkingCfg(inputFlags,neutral_FE_cont_name="",charged_FE_cont_name="",AODTest=False,doTCC=False,useGlobal=False,algName=""):
     result=ComponentAccumulator()
     
-    result.addEventAlgo(getTauFlowElementAssocAlgorithm(inputFlags,neutral_FE_cont_name,charged_FE_cont_name,AODTest))
+    result.addEventAlgo(getTauFlowElementAssocAlgorithm(inputFlags,neutral_FE_cont_name,charged_FE_cont_name,AODTest,doTCC,useGlobal,algName))
 
     return result
 
+def PFGlobalFlowElementLinkingCfg(inputFlags):
+    result=ComponentAccumulator()
+    result.addEventAlgo(getTauFlowElementAssocAlgorithm(inputFlags,useGlobal=True,algName="PFTauGlobalFlowElementAssoc"))
+    result.addEventAlgo(getMuonFlowElementAssocAlgorithm(inputFlags,useGlobal=True,algName="PFMuonGlobalFlowElementAssoc"))  
+    result.addEventAlgo(getEGamFlowElementAssocAlgorithm(inputFlags,useGlobal=True,algName="PFEGamGlobalFlowElementAssoc"))
+    return result
 
 
diff --git a/Reconstruction/eflowRec/src/PFMuonFlowElementAssoc.cxx b/Reconstruction/eflowRec/src/PFMuonFlowElementAssoc.cxx
index ce5ea4f9e539..fd2f4cbb0ffc 100644
--- a/Reconstruction/eflowRec/src/PFMuonFlowElementAssoc.cxx
+++ b/Reconstruction/eflowRec/src/PFMuonFlowElementAssoc.cxx
@@ -159,22 +159,21 @@ StatusCode PFMuonFlowElementAssoc::execute(const EventContext& ctx) const {
         for (const xAOD::FlowElement* FE : *NeutralFEmuonWriteDecorHandle) {
             int nMatchedFE = 0;
             // get the index of the cluster corresponding to the Neutral FlowElements
-            size_t FEclusterindex = FE->otherObjects().at(0)->index();
+            ATH_MSG_DEBUG("P1");
+            const xAOD::IParticle* otherObject = FE->otherObjects().at(0);
+            //This is expected to happen for low energy FE - sometimes the linked cluster has E < 0 and 
+            //is thinned away in the AOD
+            if (!otherObject){
+                ATH_MSG_DEBUG("No linked cluster for Neutral FE with E, eta and phi" << FE->e() << ", " << FE->eta() << " and " << FE->phi());
+                continue;
+            }
+            size_t FEclusterindex = otherObject->index();
 
             // FE->otherObjects returns a vector of IParticles. We only want the first one
             const xAOD::IParticle* FE_Iparticle = FE->otherObjects().at(0);
-            // dynamic cast to CaloCluster
-            const xAOD::CaloCluster* FE_cluster = dynamic_cast<const xAOD::CaloCluster*>(FE_Iparticle);  // cast to CaloCluster
 
-            // retrieve the link to cells
-            const CaloClusterCellLink* CellLink = FE_cluster->getCellLinks();
-            // build the iterator(s) for the looping over the elements inside the CellLink
-            if (!CellLink && !m_UseMuonTopoClusters) {  // safety check if no celll link and we're doing the cell based matching only
-                ATH_MSG_WARNING("Flow Element cluster link is nullptr");
-                continue;
-            }
-            CaloClusterCellLink::const_iterator FE_FirstCell = CellLink->begin();
-            CaloClusterCellLink::const_iterator FE_LastCell = CellLink->end();
+            // dynamic cast to CaloCluster
+            const xAOD::CaloCluster* FE_cluster = dynamic_cast<const xAOD::CaloCluster*>(FE_Iparticle);  // cast to CaloCluster            
 
             // debug for Negative energy cluster
 
@@ -198,8 +197,10 @@ StatusCode PFMuonFlowElementAssoc::execute(const EventContext& ctx) const {
                     // get the linker to the topo clusters
                     const std::vector<ElementLink<xAOD::CaloClusterContainer>>& linksToTopoClusters = acc_constClusterLinks(*cluster);
                     for (const ElementLink<xAOD::CaloClusterContainer>& TopoClusterLink : linksToTopoClusters) {
+                         //This is expected to happen for low energy cluster - sometimes the linked cluster has E < 0 and 
+                        //is thinned away in the AOD
                         if (!TopoClusterLink.isValid()) {
-                            ATH_MSG_WARNING("Muon Calo cluster's TopoCluster link not found, skip");
+                            ATH_MSG_DEBUG("Muon Calo cluster's TopoCluster link not found, skip");
                             continue;
                         }
                         const xAOD::CaloCluster* MuonTopoCluster = *TopoClusterLink;  // de-ref the link to get the topo-cluster
@@ -209,7 +210,7 @@ StatusCode PFMuonFlowElementAssoc::execute(const EventContext& ctx) const {
                             // index() is the unique index of the muon in the muon container
                             FEMuonLinks.emplace_back(*muonReadHandle, muon->index());
                             // index() is the unique index of the cFlowElement in the cFlowElementcontaine
-                            muonNeutralFEVec.at(muon->index()).push_back(FlowElementLink_t(*NeutralFEReadHandle, FE->index()));
+                            muonNeutralFEVec.at(muon->index()).push_back(FlowElementLink_t(*NeutralFEReadHandle, FE->index()));            
                             ATH_MSG_VERBOSE("Got a match between NFE and Muon");
                             nMatchedFE++;  // count number of matches between FE and muons
                             if (neg_E_cluster) ATH_MSG_ERROR("Muon cluster matched to negative E topocluster from FE");
@@ -221,6 +222,17 @@ StatusCode PFMuonFlowElementAssoc::execute(const EventContext& ctx) const {
                     // Retrieve cells in both the FE cluster and muon cluster
                     // Define the link as where at least one calo cell is shared between the FE cluster and the Muon Cluster
 
+                    // retrieve the link to cells
+                    const CaloClusterCellLink* CellLink = FE_cluster->getCellLinks();
+                    // build the iterator(s) for the looping over the elements inside the CellLink
+                    if (!CellLink && !m_UseMuonTopoClusters) {  // safety check if no celll link and we're doing the cell based matching only
+                       ATH_MSG_WARNING("Flow Element cluster link is nullptr");
+                        continue;
+                    }
+
+                    CaloClusterCellLink::const_iterator FE_FirstCell = CellLink->begin();
+                    CaloClusterCellLink::const_iterator FE_LastCell = CellLink->end();
+
                     // retrieve cells associated to Muon cluster
                     const CaloClusterCellLink* Muon_Clus_CellLink = cluster->getCellLinks();
                     if (!Muon_Clus_CellLink) {
@@ -283,7 +295,6 @@ StatusCode PFMuonFlowElementAssoc::execute(const EventContext& ctx) const {
                     }
 
                 }  // end of calocluster specific block
-
                 // loop over caloclusters
             }  // loop over muons
             NeutralFEmuon_nMatches_WriteDecorHandle(*FE) = nMatchedFE;
diff --git a/Reconstruction/eflowRec/src/PFTauFlowElementAssoc.cxx b/Reconstruction/eflowRec/src/PFTauFlowElementAssoc.cxx
index 5e678744050b..5cebbca217d1 100644
--- a/Reconstruction/eflowRec/src/PFTauFlowElementAssoc.cxx
+++ b/Reconstruction/eflowRec/src/PFTauFlowElementAssoc.cxx
@@ -77,8 +77,9 @@ StatusCode PFTauFlowElementAssoc::execute(const EventContext &ctx) const {
 
     // Loop over the taus
     for (const xAOD::TauJet* tau : *tauNeutralFEWriteDecorHandle) {
-      // Skip taus that won't be written to AOD
-      if(!acc_passThinning(*tau)) continue;
+      // Skip taus that won't be written to AOD - first check the variable exists
+      // because older ESD and any AOD used as input do not have this variable.
+      if(acc_passThinning.isAvailable(*tau) && !acc_passThinning(*tau)) continue;
       // Get tau vertex
       const xAOD::Vertex* tauVertex = tau->vertex();
       // Get the clusters associated to the tau
@@ -125,7 +126,9 @@ StatusCode PFTauFlowElementAssoc::execute(const EventContext &ctx) const {
 
     // Loop over the taus
     for (const xAOD::TauJet* tau : *tauChargedFEWriteDecorHandle) {
-      if(!acc_passThinning(*tau)) continue;
+      // Skip taus that won't be written to AOD - first check the variable exists                                                                                                                                                                                              
+      // because older ESD and any AOD used as input do not have this variable. 
+      if(acc_passThinning.isAvailable(*tau) && !acc_passThinning(*tau)) continue;
       // Get tau tracks associated to the tau
       std::vector<const xAOD::TauTrack*> tauTracks = tau->tracks();
       for (const auto *tauTrack : tauTracks) {
diff --git a/Reconstruction/egamma/egammaConfig/python/egammaConfigFlags.py b/Reconstruction/egamma/egammaConfig/python/egammaConfigFlags.py
index cef6eb8539bc..e2b35a072792 100644
--- a/Reconstruction/egamma/egammaConfig/python/egammaConfigFlags.py
+++ b/Reconstruction/egamma/egammaConfig/python/egammaConfigFlags.py
@@ -91,7 +91,9 @@ def createEgammaConfigFlags():
                  '-topoetconeCorrBitset')
 
     egcf.addFlag("Egamma.Keys.Output.Electrons", 'Electrons')
-    egcf.addFlag("Egamma.Keys.Output.ElectronsSuppESD", '')
+    #Remove GlobalFELinks - these are links between FlowElement (FE) containers created in jet finding and electrons/photons. Since these transient FE containers are not in the ESD/AOD, we should not write out these links.
+    gpf_vars='-chargedGlobalFELinks.-neutralGlobalFELinks.'
+    egcf.addFlag("Egamma.Keys.Output.ElectronsSuppESD", gpf_vars)
     egcf.addFlag("Egamma.Keys.Output.ElectronsSuppAOD",
                  lambda prevFlags: (
                      prevFlags.Egamma.Keys.Output.ElectronsSuppESD +
@@ -116,7 +118,7 @@ def createEgammaConfigFlags():
                      prevFlags.Egamma.Keys.Output.ForwardClustersSuppESD))
 
     egcf.addFlag("Egamma.Keys.Output.Photons", 'Photons')
-    egcf.addFlag("Egamma.Keys.Output.PhotonsSuppESD", '')
+    egcf.addFlag("Egamma.Keys.Output.PhotonsSuppESD", gpf_vars)
     egcf.addFlag("Egamma.Keys.Output.PhotonsSuppAOD",
                  lambda prevFlags: (
                      prevFlags.Egamma.Keys.Output.PhotonsSuppESD +
diff --git a/Reconstruction/egamma/egammaRec/python/egammaKeys.py b/Reconstruction/egamma/egammaRec/python/egammaKeys.py
index 0231a3ae783a..41cc7e5d3c9f 100644
--- a/Reconstruction/egamma/egammaRec/python/egammaKeys.py
+++ b/Reconstruction/egamma/egammaRec/python/egammaKeys.py
@@ -18,8 +18,11 @@ class egammaKeysDict:
     ShowerShapesSuppress = '.-e033.-e011.-e333.-e335.-e337.-e377'
     PhotonisemSuppress = '.-isEMLoose.-isEMTight'
     ElectronisemSupress = '.-isEMLHLoose.-isEMLHTight.-isEMLHMedium.-isEMLoose.-isEMMultiLepton.-isEMMedium.-isEMTight'
-    ElectronSuppress = ShowerShapesSuppress + ElectronisemSupress + '.-EgammaCovarianceMatrix'
-    PhotonSuppress = ShowerShapesSuppress + PhotonisemSuppress
+    #When we run jet finding we create links between global FE and electrons/photons
+    #Global FE do not go into the ESD/AOD, so we suppress the links to them here
+    GlobalPFlowSuppress = '.-chargedGlobalFELinks.-neutralGlobalFELinks'
+    ElectronSuppress = ShowerShapesSuppress + ElectronisemSupress + '.-EgammaCovarianceMatrix' + GlobalPFlowSuppress
+    PhotonSuppress = ShowerShapesSuppress + PhotonisemSuppress + GlobalPFlowSuppress
     FwdElectronisemSupress = '.-isEMTight.-isEMMedium.-isEMLoose'
     isovar_suppress = "-" + ".-".join(iso_vars())
     egisovar_suppress = isovar_suppress + '.-ptconeCorrBitset.-ptconecoreTrackPtrCorrection.-topoetconeCorrBitset'
@@ -47,7 +50,7 @@ class egammaKeysDict:
         Electron=[
             'xAOD::ElectronContainer',
             'Electrons',
-            egisovar_suppress,
+            egisovar_suppress + GlobalPFlowSuppress,
             ElectronSuppress],
         EgammaRec=['egammaRecContainer',
                    'egammaRecCollection',
@@ -68,7 +71,7 @@ class egammaKeysDict:
                     '-SisterCluster', ''],
         Photon=['xAOD::PhotonContainer',
                 'Photons',
-                phisovar_suppress,
+                phisovar_suppress + GlobalPFlowSuppress,
                 PhotonSuppress],
         TrackParticle=[
             'xAOD::TrackParticleContainer',
diff --git a/Reconstruction/tauRec/python/TauConfig.py b/Reconstruction/tauRec/python/TauConfig.py
index a09c214933cf..5e61c7253bbc 100755
--- a/Reconstruction/tauRec/python/TauConfig.py
+++ b/Reconstruction/tauRec/python/TauConfig.py
@@ -221,10 +221,12 @@ def TauOutputCfg(flags):
     TauESDList = list(TauAODList)
 
     # add AOD specific
-    TauAODList += [ "xAOD::TauJetAuxContainer#TauJetsAux.-VertexedClusters.-mu.-nVtxPU.-ABS_ETA_LEAD_TRACK.-TAU_ABSDELTAPHI.-TAU_ABSDELTAETA.-absipSigLeadTrk.-passThinning" ]
+    #Also remove GlobalFELinks - these are links between FlowElement (FE) containers created in jet finding and taus. Since these transient FE containers are not in the AOD, we should not write out these links.
+    TauAODList += [ "xAOD::TauJetAuxContainer#TauJetsAux.-VertexedClusters.-mu.-nVtxPU.-ABS_ETA_LEAD_TRACK.-TAU_ABSDELTAPHI.-TAU_ABSDELTAETA.-absipSigLeadTrk.-passThinning.-chargedGlobalFELinks.-neutralGlobalFELinks" ]
 
     # addEOD specific
-    TauESDList += [ "xAOD::TauJetAuxContainer#TauJetsAux.-VertexedClusters" ]
+    #Also remove GlobalFELinks - these are links between FlowElement (FE) containers created in jet finding and taus. Since these transient FE containers are not in the AOD, we should not write out these links.
+    TauESDList += [ "xAOD::TauJetAuxContainer#TauJetsAux.-VertexedClusters.-chargedGlobalFELinks.-neutralGlobalFELinks" ]
     TauESDList += [ "xAOD::PFOContainer#TauChargedParticleFlowObjects" ]
     TauESDList += [ "xAOD::PFOAuxContainer#TauChargedParticleFlowObjectsAux." ]
 
diff --git a/Reconstruction/tauRec/share/TauAODList.py b/Reconstruction/tauRec/share/TauAODList.py
index 67e03866f3be..38f07b395373 100644
--- a/Reconstruction/tauRec/share/TauAODList.py
+++ b/Reconstruction/tauRec/share/TauAODList.py
@@ -14,7 +14,8 @@ TauAODList = []
 # Taus
 #------------------------------------------------------------------------------
 TauAODList += [ "xAOD::TauJetContainer#TauJets" ]
-TauAODList += [ "xAOD::TauJetAuxContainer#TauJetsAux.-VertexedClusters.-mu.-nVtxPU.-ABS_ETA_LEAD_TRACK.-TAU_ABSDELTAPHI.-TAU_ABSDELTAETA.-absipSigLeadTrk.-passThinning" ]
+#Also remove GlobalFELinks - these are links between FlowElement (FE) containers created in jet finding and taus. Since these transient FE containers are not in the AOD, we should not write out these links.
+TauAODList += [ "xAOD::TauJetAuxContainer#TauJetsAux.-VertexedClusters.-mu.-nVtxPU.-ABS_ETA_LEAD_TRACK.-TAU_ABSDELTAPHI.-TAU_ABSDELTAETA.-absipSigLeadTrk.-passThinning.-chargedGlobalFELinks.-neutralGlobalFELinks" ]
 
 #------------------------------------------------------------------------------
 # Tau tracks
diff --git a/Reconstruction/tauRec/share/TauESDList.py b/Reconstruction/tauRec/share/TauESDList.py
index 2d04f1c40f04..defe2a52354d 100644
--- a/Reconstruction/tauRec/share/TauESDList.py
+++ b/Reconstruction/tauRec/share/TauESDList.py
@@ -14,7 +14,8 @@ TauESDList = []
 # Taus
 #------------------------------------------------------------------------------
 TauESDList += [ "xAOD::TauJetContainer#TauJets" ]
-TauESDList += [ "xAOD::TauJetAuxContainer#TauJetsAux.-VertexedClusters" ]
+#Also remove GlobalFELinks - these are links between FlowElement (FE) containers created in jet finding and taus. Since these transient FE containers are not in the AOD, we should not write out these links.
+TauESDList += [ "xAOD::TauJetAuxContainer#TauJetsAux.-VertexedClusters.-chargedGlobalFELinks.-neutralGlobalFELinks" ]
 
 #------------------------------------------------------------------------------
 # Tau tracks
diff --git a/Tools/WorkflowTestRunner/python/References.py b/Tools/WorkflowTestRunner/python/References.py
index c58854cbd5e4..c7221506b41f 100644
--- a/Tools/WorkflowTestRunner/python/References.py
+++ b/Tools/WorkflowTestRunner/python/References.py
@@ -19,7 +19,7 @@ references_map = {
     "d1726": "v4",
     "d1759": "v5",
     # Reco
-    "q442": "v7",
-    "q445": "v17",
-    "q449": "v15",
+    "q442": "v9",
+    "q445": "v18",
+    "q449": "v16",
 }
-- 
GitLab