From 77d2bba6cc18d3ca449c8d29baebb408efe1d3eb Mon Sep 17 00:00:00 2001
From: Scott Snyder <scott.snyder@cern.ch>
Date: Fri, 21 Mar 2025 08:36:33 +0000
Subject: [PATCH] IsolationSelection: Remove isAssociatedToEG decoration.

IsolationSelection: Remove isAssociatedToEG decoration.

IsolationCloseByCorrection was using the decoration isAssociatedToEG to tell
if a cluster was matched to an EM object.  This decoration was left unlocked,
resulting in warnings further on.  But that decoration is used only within
this tool, so this information would be better maintained locally.
Add it to the internal cache used by the tool rather than having it
as a decoration.
---
 .../IsolationSelection/Defs.h                 |  5 +++-
 .../IsolationCloseByCorrectionTool.h          | 10 +++++---
 .../Root/IsolationCloseByCorrectionTool.cxx   | 25 +++++++++----------
 3 files changed, 22 insertions(+), 18 deletions(-)

diff --git a/PhysicsAnalysis/AnalysisCommon/IsolationSelection/IsolationSelection/Defs.h b/PhysicsAnalysis/AnalysisCommon/IsolationSelection/IsolationSelection/Defs.h
index db4e1d81907..160f6ce2dd8 100644
--- a/PhysicsAnalysis/AnalysisCommon/IsolationSelection/IsolationSelection/Defs.h
+++ b/PhysicsAnalysis/AnalysisCommon/IsolationSelection/IsolationSelection/Defs.h
@@ -1,5 +1,5 @@
 /*
- Copyright (C) 2002-2022 CERN for the benefit of the ATLAS collaboration
+ Copyright (C) 2002-2025 CERN for the benefit of the ATLAS collaboration
  */
 
 #ifndef ISOLATIONSELECTION_DEFS_H
@@ -13,6 +13,7 @@
 #include <xAODTracking/TrackParticle.h>
 
 #include <set>
+#include <unordered_set>
 namespace CP {
 
     using CharAccessor = SG::AuxElement::ConstAccessor<char>;
@@ -72,6 +73,8 @@ namespace CP {
     using TrackSet = std::set<TrackPtr>;
     using ClusterSet = std::set<CaloClusterPtr>;
     using PflowSet = std::set<FlowElementPtr>;
+
+    using UnorderedClusterSet = std::unordered_set<const xAOD::CaloCluster*>;
 }  // namespace CP
 
 #endif
diff --git a/PhysicsAnalysis/AnalysisCommon/IsolationSelection/IsolationSelection/IsolationCloseByCorrectionTool.h b/PhysicsAnalysis/AnalysisCommon/IsolationSelection/IsolationSelection/IsolationCloseByCorrectionTool.h
index b190090dfbc..befbf596df8 100644
--- a/PhysicsAnalysis/AnalysisCommon/IsolationSelection/IsolationSelection/IsolationCloseByCorrectionTool.h
+++ b/PhysicsAnalysis/AnalysisCommon/IsolationSelection/IsolationSelection/IsolationCloseByCorrectionTool.h
@@ -1,5 +1,5 @@
 /*
- Copyright (C) 2002-2024 CERN for the benefit of the ATLAS collaboration
+ Copyright (C) 2002-2025 CERN for the benefit of the ATLAS collaboration
  */
 
 #ifndef IsolationSelection_IsolationCloseByCorrectionTool_H
@@ -90,6 +90,7 @@ namespace CP {
             TrackSet tracks{};
             ClusterSet clusters{};
             PflowSet flows{};
+            UnorderedClusterSet eg_associated_clusters{};
         };
 
     private:
@@ -113,13 +114,13 @@ namespace CP {
         const IsoVector& getIsolationTypes(const xAOD::IParticle* particle) const;
 
         // Functions to  perfrom  the isolation correction  directly
-        CorrectionCode subtractCloseByContribution(const EventContext& ctx, const xAOD::IParticle* P, const ObjectCache& cache) const;
+        CorrectionCode subtractCloseByContribution(const EventContext& ctx, const xAOD::IParticle* P, ObjectCache& cache) const;
         // Remove close-by tracks from the track isolation variables
         CorrectionCode getCloseByCorrectionTrackIso(const xAOD::IParticle* primary, const IsoType type, const ObjectCache& cache,
                                                     float& isoValue) const;
         // Remove close-by calo clusters from the topo et isolation variables
         CorrectionCode getCloseByCorrectionTopoIso(const EventContext& ctx, const xAOD::IParticle* primary, const IsoType type,
-                                                   const ObjectCache& cache, float& isoValue) const;
+                                                   ObjectCache& cache, float& isoValue) const;
         // Remove close-by flow elements from the neflow isolation variables
         CorrectionCode getCloseByCorrectionPflowIso(const EventContext& ctx, const xAOD::IParticle* primary, const IsoType type,
                                                     const ObjectCache& cache, float& isoValue) const;
@@ -128,7 +129,8 @@ namespace CP {
 
 
          /// Loads the topo clusters associated with the primary IParticle
-        ClusterSet getAssociatedClusters(const EventContext& ctx, const xAOD::IParticle* particle) const;
+        ClusterSet getAssociatedClusters(const EventContext& ctx, const xAOD::IParticle* particle,
+                                         ObjectCache& cache) const;
         /// Loads the pflow elements associated with the primary IParticle
         PflowSet getAssocFlowElements(const EventContext& ctx, const xAOD::IParticle* particle) const;
 
diff --git a/PhysicsAnalysis/AnalysisCommon/IsolationSelection/Root/IsolationCloseByCorrectionTool.cxx b/PhysicsAnalysis/AnalysisCommon/IsolationSelection/Root/IsolationCloseByCorrectionTool.cxx
index 1d3c77ae84a..cd479af275c 100644
--- a/PhysicsAnalysis/AnalysisCommon/IsolationSelection/Root/IsolationCloseByCorrectionTool.cxx
+++ b/PhysicsAnalysis/AnalysisCommon/IsolationSelection/Root/IsolationCloseByCorrectionTool.cxx
@@ -171,7 +171,7 @@ namespace CP {
                 const TrackSet tracks = getAssociatedTracks(prim, cache.prim_vtx);
                 cache.tracks.insert(tracks.begin(), tracks.end());
             }
-            const ClusterSet clusters = getAssociatedClusters(ctx, prim);
+            const ClusterSet clusters = getAssociatedClusters(ctx, prim, cache);
             cache.clusters.insert(clusters.begin(), clusters.end());
         }
         getAssocFlowElements(ctx, cache);
@@ -330,7 +330,7 @@ namespace CP {
 
     CorrectionCode IsolationCloseByCorrectionTool::subtractCloseByContribution(const EventContext& ctx, 
                                                                                const xAOD::IParticle* par,
-                                                                               const ObjectCache& cache) const {
+                                                                               ObjectCache& cache) const {
         const IsoVector& types = getIsolationTypes(par);
         if (types.empty()) {
             ATH_MSG_WARNING("No isolation types are defiend for " << particleName(par));
@@ -485,10 +485,10 @@ namespace CP {
     //   - for electrons and photons, collect the associated clusters
     //   - for muons, use associated cluster, if it exists, to get topocluster, otherwise, extrapolate the InDet trackParticle to calo 
     //     and look for topoclusters matching in dR the core muon cone
-    ClusterSet IsolationCloseByCorrectionTool::getAssociatedClusters(const EventContext& ctx, const xAOD::IParticle* P) const {
-        // Use accessor to mark topoclusters which are associated to an egamma object, electron or photon
-        // This will be used to avoid associating the same object to a muon during getCloseByCorrectionPflowIso or getCloseByCorrectionTopoIso
-        static const CharDecorator acc_isAssociatedToEG{"isAssociatedToEG"};
+    ClusterSet IsolationCloseByCorrectionTool::getAssociatedClusters(const EventContext& ctx,const xAOD::IParticle* P,
+                                                                     ObjectCache& cache) const {
+        // Remember topoclusters which are associated to an egamma object, electron or photon
+        // This will be used to avoid associating the same object to a muon
         ClusterSet clusters;
         if (isEgamma(P)) {
             const xAOD::Egamma* egamm = static_cast<const xAOD::Egamma*>(P);
@@ -498,11 +498,10 @@ namespace CP {
                 std::vector<const xAOD::CaloCluster*> constituents = xAOD::EgammaHelpers::getAssociatedTopoClusters(clust);
                 for (const xAOD::CaloCluster* cluster : constituents) {
                     if (cluster && std::abs(cluster->eta()) < 7. && cluster->e() > MinClusterEnergy) { 
-                        clusters.emplace(cluster); 
-                        acc_isAssociatedToEG(*cluster) = true; // set flag that this cluster is associate to an electron or photon
+                        clusters.emplace(cluster);
+                        cache.eg_associated_clusters.insert(cluster); // set flag that this cluster is associated to an electron or photon
                         ATH_MSG_VERBOSE("getAssociatedClusters: " << P->type() << " has topo cluster with pt: " << cluster->pt() * MeVtoGeV << " GeV, eta: " 
-                                         << cluster->eta() << ", phi: " << cluster->phi() 
-                                         << ", isAssociatedToEG: " << (int)acc_isAssociatedToEG(*cluster));
+                                         << cluster->eta() << ", phi: " << cluster->phi());
                     }
                 }
             }
@@ -523,7 +522,7 @@ namespace CP {
                 for (const xAOD::CaloCluster* cluster : constituents) {
                     if (cluster && std::abs(cluster->eta()) < 7. && cluster->e() > MinClusterEnergy) {
                         // skip association if this cluster is already associated with an electron or photon - priority is given to egamma reco
-                        if (!acc_isAssociatedToEG.isAvailable(*cluster) || !acc_isAssociatedToEG(*cluster)) {
+                        if (!cache.eg_associated_clusters.contains(cluster)) {
                             clusters.emplace(cluster);
                             foundMuonTopo = true;
                             ATH_MSG_VERBOSE("getAssociatedClusters: muon has topo cluster with pt: " << cluster->pt() * MeVtoGeV << " GeV, eta: " 
@@ -681,7 +680,7 @@ namespace CP {
     }
 
     CorrectionCode IsolationCloseByCorrectionTool::getCloseByCorrectionTopoIso(const EventContext& ctx, const xAOD::IParticle* primary,
-                                                                               const IsoType type, const ObjectCache& cache,
+                                                                               const IsoType type, ObjectCache& cache,
                                                                                float& isoValue) const {
         // check if the isolation can be loaded
         if (!isTopoEtIso(type)) {
@@ -707,7 +706,7 @@ namespace CP {
             ATH_MSG_VERBOSE("getCloseByCorrectionTopoIso: " << toString(type) << " of " << particleName(primary) << " with pt: " 
                             << primary->pt() * MeVtoGeV << " GeV, eta: " << primary->eta()
                             << ", phi: " << primary->phi() << " before correction: " << isoValue * MeVtoGeV << " GeV. ");
-            ClusterSet assoc = getAssociatedClusters(ctx, primary);
+            ClusterSet assoc = getAssociatedClusters(ctx, primary, cache);
             for (const CaloClusterPtr& calo : cache.clusters) {
                 const float dR = xAOD::P4Helpers::deltaR(ref_eta, ref_phi, calo->eta(), calo->phi());
                 ATH_MSG_VERBOSE("getCloseByCorrectionTopoIso: Loop over cluster: " << calo->pt() * MeVtoGeV << " GeV, eta: " << calo->eta() << " phi: " << calo->phi() << " dR: " << dR);
-- 
GitLab