From e6b9583cfb299bc68045741aa02e3760222b39af Mon Sep 17 00:00:00 2001
From: Goetz Gaycken <goetz.gaycken@cern.ch>
Date: Fri, 11 Sep 2020 19:17:28 +0200
Subject: [PATCH] Renounce recursively the newly created cluster splitting
 probability map from all child tools.

- Use new Gaudi helper class to iterate recursively through all child tools and using the new
  Gaudi visitor which renounces certain inputs from a tool, to renounce the output cluster splitting
  probability map from all child tools. The map is recorded to StoreGate before any of the child tools
  are called. Thus, the map, although not final yet, can already be used through read handles. Without
  renouncing the inputs, Gaudi would issue a circular dependency warning.
- Remove the previously introduced property which allowed to renounce manually the input cluster
  splitting probability map from the PixelClusterOnTrackTool.
---
 .../python/InDetRecExampleConfig.py           | 16 ++--
 .../InDetRecExample/python/TrackingCommon.py  | 16 ++--
 .../share/ConfiguredNewTrackingSiPattern.py   |  6 +-
 .../InDetTrackSummaryHelperTool.h             |  3 -
 .../src/InDetTrackSummaryHelperTool.cxx       | 19 -----
 .../PixelClusterOnTrackTool.h                 |  2 -
 .../src/PixelClusterOnTrackTool.cxx           | 19 -----
 .../src/AmbiguityProcessorBase.cxx            | 74 ++++++++++++++++++-
 .../src/AmbiguityProcessorBase.h              | 32 +++++++-
 ...enseEnvironmentsAmbiguityProcessorTool.cxx | 30 +-------
 .../DenseEnvironmentsAmbiguityProcessorTool.h |  9 +--
 .../src/SimpleAmbiguityProcessorTool.cxx      | 32 ++------
 .../src/SimpleAmbiguityProcessorTool.h        |  5 --
 13 files changed, 130 insertions(+), 133 deletions(-)

diff --git a/InnerDetector/InDetExample/InDetRecExample/python/InDetRecExampleConfig.py b/InnerDetector/InDetExample/InDetRecExample/python/InDetRecExampleConfig.py
index 8f2b310003e..d4968cf69d3 100644
--- a/InnerDetector/InDetExample/InDetRecExample/python/InDetRecExampleConfig.py
+++ b/InnerDetector/InDetExample/InDetRecExample/python/InDetRecExampleConfig.py
@@ -110,7 +110,7 @@ def InDetKOL(name='InDetKOL',**kwargs) :
 def InDetMeasRecalibST(name='InDetMeasRecalibST',**kwargs) :
     from TrkKalmanFitter.TrkKalmanFitterConf import Trk__MeasRecalibSteeringTool
 
-    pix_cluster_on_track_args = stripArgs(kwargs,['SplitClusterMapExtension','ClusterSplitProbabilityName','RenounceInputHandles','nameSuffix'])
+    pix_cluster_on_track_args = stripArgs(kwargs,['SplitClusterMapExtension','ClusterSplitProbabilityName','nameSuffix'])
 
     from InDetRecExample import TrackingCommon as TrackingCommon
     if 'BroadPixelClusterOnTrackTool' not in kwargs :
@@ -132,7 +132,7 @@ def InDetKalmanTrackFitterBase(name='InDetKalmanTrackFitterBase',**kwargs) :
     from AthenaCommon.AppMgr import ToolSvc
 
     nameSuffix=kwargs.pop('nameSuffix','')
-    pix_cluster_on_track_args = stripArgs(kwargs,['SplitClusterMapExtension','ClusterSplitProbabilityName','RenounceInputHandles'])
+    pix_cluster_on_track_args = stripArgs(kwargs,['SplitClusterMapExtension','ClusterSplitProbabilityName'])
     if len(pix_cluster_on_track_args)>0 and len(nameSuffix)>0 :
         pix_cluster_on_track_args['nameSuffix']=nameSuffix
 
@@ -194,7 +194,7 @@ def KalmanDNAFitter(name='KalmanDNAFitter',**kwargs) :
     return InDetKalmanTrackFitterBase(name,**kwargs)
 
 def DistributedKalmanFilter(name="DistributedKalmanFilter", **kwargs) :
-    pix_cluster_on_track_args = stripArgs(kwargs,['SplitClusterMapExtension','ClusterSplitProbabilityName','RenounceInputHandles','nameSuffix'])
+    pix_cluster_on_track_args = stripArgs(kwargs,['SplitClusterMapExtension','ClusterSplitProbabilityName','nameSuffix'])
 
     from InDetRecExample.TrackingCommon          import setDefaults
     if 'ExtrapolatorTool' not in kwargs :
@@ -241,7 +241,7 @@ def InDetGlobalChi2FitterBase(name='GlobalChi2FitterBase', **kwargs) :
     return Trk__GlobalChi2Fitter(name, **kwargs)
 
 def InDetGlobalChi2Fitter(name='InDetGlobalChi2Fitter', **kwargs) :
-    pix_cluster_on_track_args = stripArgs(kwargs,['SplitClusterMapExtension','ClusterSplitProbabilityName','RenounceInputHandles','nameSuffix'])
+    pix_cluster_on_track_args = stripArgs(kwargs,['SplitClusterMapExtension','ClusterSplitProbabilityName','nameSuffix'])
 
     from InDetRecExample import TrackingCommon as TrackingCommon
 
@@ -305,7 +305,7 @@ def InDetGlobalChi2FitterBT(name='InDetGlobalChi2FitterBT', **kwargs):
 def InDetGlobalChi2FitterLowPt(name='InDetGlobalChi2FitterLowPt', **kwargs) :
     # @TODO TrackingGeometrySvc was not set but is set now
     #       RotCreatorTool and BroadRotCreatorTool not set
-    pix_cluster_on_track_args = stripArgs(kwargs,['SplitClusterMapExtension','ClusterSplitProbabilityName','RenounceInputHandles','nameSuffix'])
+    pix_cluster_on_track_args = stripArgs(kwargs,['SplitClusterMapExtension','ClusterSplitProbabilityName','nameSuffix'])
 
     from InDetRecExample import TrackingCommon as TrackingCommon
     if 'RotCreatorTool' not in kwargs :
@@ -329,7 +329,7 @@ def InDetGlobalChi2FitterTRT(name='InDetGlobalChi2FitterTRT', **kwargs) :
     '''
     Global Chi2 Fitter for TRT segments with different settings
     '''
-    pix_cluster_on_track_args = stripArgs(kwargs,['SplitClusterMapExtension','ClusterSplitProbabilityName','RenounceInputHandles','nameSuffix'])
+    pix_cluster_on_track_args = stripArgs(kwargs,['SplitClusterMapExtension','ClusterSplitProbabilityName','nameSuffix'])
 
     if 'RotCreatorTool' not in kwargs :
         from InDetRecExample import TrackingCommon as TrackingCommon
@@ -357,7 +357,7 @@ def InDetGlobalChi2FitterTRT(name='InDetGlobalChi2FitterTRT', **kwargs) :
        ))
 
 def InDetGlobalChi2FitterDBM(name='InDetGlobalChi2FitterDBM', **kwargs) :
-    pix_cluster_on_track_args = stripArgs(kwargs,['SplitClusterMapExtension','ClusterSplitProbabilityName','RenounceInputHandles','nameSuffix'])
+    pix_cluster_on_track_args = stripArgs(kwargs,['SplitClusterMapExtension','ClusterSplitProbabilityName','nameSuffix'])
     if 'RotCreatorTool' not in kwargs :
         from InDetRecExample import TrackingCommon as TrackingCommon
         kwargs=setDefaults(kwargs, RotCreatorTool = TrackingCommon.getInDetRotCreatorDBM(**pix_cluster_on_track_args))
@@ -373,7 +373,7 @@ def InDetGlobalChi2FitterDBM(name='InDetGlobalChi2FitterDBM', **kwargs) :
                                                           Momentum              = 1000.*Units.MeV))
 
 def GaussianSumFitter(name='GaussianSumFitter', **kwargs) :
-    pix_cluster_on_track_args = stripArgs(kwargs,['SplitClusterMapExtension','ClusterSplitProbabilityName','RenounceInputHandles','nameSuffix'])
+    pix_cluster_on_track_args = stripArgs(kwargs,['SplitClusterMapExtension','ClusterSplitProbabilityName','nameSuffix'])
 
     from InDetRecExample import TrackingCommon as TrackingCommon
     if 'ToolForROTCreation' not in kwargs :
diff --git a/InnerDetector/InDetExample/InDetRecExample/python/TrackingCommon.py b/InnerDetector/InDetExample/InDetRecExample/python/TrackingCommon.py
index 738553396c4..90142d7220a 100644
--- a/InnerDetector/InDetExample/InDetRecExample/python/TrackingCommon.py
+++ b/InnerDetector/InDetExample/InDetRecExample/python/TrackingCommon.py
@@ -513,7 +513,7 @@ def getInDetTRT_DriftCircleOnTrackUniversalToolCosmics(name='TRT_DriftCircleOnTr
 
 @makePublicTool
 def getInDetRotCreator(name='InDetRotCreator', **kwargs) :
-    strip_args=['SplitClusterMapExtension','ClusterSplitProbabilityName','RenounceInputHandles','nameSuffix']
+    strip_args=['SplitClusterMapExtension','ClusterSplitProbabilityName','nameSuffix']
     pix_cluster_on_track_args = copyArgs(kwargs,strip_args)
     # note nameSuffix is strupped by makeName
     the_name = makeName( name, kwargs)
@@ -548,7 +548,7 @@ def getInDetRotCreator(name='InDetRotCreator', **kwargs) :
 
 def getInDetRotCreatorPattern(name='InDetRotCreatorPattern', **kwargs) :
     if 'ToolPixelCluster' not in kwargs :
-        pix_cluster_on_track_args = copyArgs(kwargs,['SplitClusterMapExtension','ClusterSplitProbabilityName','RenounceInputHandles','nameSuffix'])
+        pix_cluster_on_track_args = copyArgs(kwargs,['SplitClusterMapExtension','ClusterSplitProbabilityName','nameSuffix'])
         kwargs = setDefaults(kwargs,
                              ToolPixelCluster = getInDetPixelClusterOnTrackToolPattern(**pix_cluster_on_track_args))
     return getInDetRotCreator(name=name, **kwargs)
@@ -556,7 +556,7 @@ def getInDetRotCreatorPattern(name='InDetRotCreatorPattern', **kwargs) :
 
 def getInDetRotCreatorDBM(name='InDetRotCreatorDBM', **kwargs) :
     if 'ToolPixelCluster' not in kwargs :
-        pix_cluster_on_track_args = copyArgs(kwargs,['SplitClusterMapExtension','ClusterSplitProbabilityName','RenounceInputHandles','nameSuffix'])
+        pix_cluster_on_track_args = copyArgs(kwargs,['SplitClusterMapExtension','ClusterSplitProbabilityName','nameSuffix'])
         from InDetRecExample.InDetJobProperties import InDetFlags
         from AthenaCommon.DetFlags              import DetFlags
         if InDetFlags.loadRotCreator() and DetFlags.haveRIO.pixel_on():
@@ -569,7 +569,7 @@ def getInDetRotCreatorDBM(name='InDetRotCreatorDBM', **kwargs) :
 
 def getInDetRotCreatorDigital(name='InDetRotCreatorDigital', **kwargs) :
     if 'ToolPixelCluster' not in kwargs :
-        pix_cluster_on_track_args = copyArgs(kwargs,['SplitClusterMapExtension','ClusterSplitProbabilityName','RenounceInputHandles','nameSuffix'])
+        pix_cluster_on_track_args = copyArgs(kwargs,['SplitClusterMapExtension','ClusterSplitProbabilityName','nameSuffix'])
         kwargs = setDefaults(kwargs,
                              ToolPixelCluster = getInDetPixelClusterOnTrackToolDigital(**pix_cluster_on_track_args))
     return getInDetRotCreator(name=name, **kwargs)
@@ -577,7 +577,7 @@ def getInDetRotCreatorDigital(name='InDetRotCreatorDigital', **kwargs) :
 # @TODO rename to InDetBroadRotCreator
 def getInDetBroadRotCreator(name='InDetBroadInDetRotCreator', **kwargs) :
     if 'ToolPixelCluster' not in kwargs :
-        pix_cluster_on_track_args = copyArgs(kwargs,['SplitClusterMapExtension','ClusterSplitProbabilityName','RenounceInputHandles','nameSuffix'])
+        pix_cluster_on_track_args = copyArgs(kwargs,['SplitClusterMapExtension','ClusterSplitProbabilityName','nameSuffix'])
         kwargs = setDefaults(kwargs,
                              ToolPixelCluster    = getInDetBroadPixelClusterOnTrackTool(**pix_cluster_on_track_args))
     if 'ToolSCT_Cluster' not in kwargs :
@@ -1069,9 +1069,8 @@ def getInDetSummaryHelperSharedHits(name='InDetSummaryHelperSharedHits',**kwargs
 def getInDetTrackSummaryTool(name='InDetTrackSummaryTool',**kwargs) :
     # makeName will remove the namePrefix in suffix from kwargs, so copyArgs has to be first
     hlt_args = copyArgs(kwargs,['isHLT','namePrefix'])
-    id_helper_args = copyArgs(kwargs,['ClusterSplitProbabilityName','RenounceInputHandles','namePrefix','nameSuffix']) if 'ClusterSplitProbabilityName' in kwargs else {}
+    id_helper_args = copyArgs(kwargs,['ClusterSplitProbabilityName','namePrefix','nameSuffix']) if 'ClusterSplitProbabilityName' in kwargs else {}
     kwargs.pop('ClusterSplitProbabilityName',None)
-    kwargs.pop('RenounceInputHandles',None)
     kwargs.pop('isHLT',None)
     the_name = makeName( name, kwargs)
     do_holes=kwargs.get("doHolesInDet",True)
@@ -1097,13 +1096,12 @@ def getInDetTrackSummaryToolNoHoleSearch(name='InDetTrackSummaryToolNoHoleSearch
 def getInDetTrackSummaryToolSharedHits(name='InDetTrackSummaryToolSharedHits',**kwargs) :
 
     if 'InDetSummaryHelperTool' not in kwargs :
-        copy_args=['ClusterSplitProbabilityName','RenounceInputHandles','namePrefix','nameSuffix']
+        copy_args=['ClusterSplitProbabilityName','namePrefix','nameSuffix']
         do_holes=kwargs.get("doHolesInDet",True)
         if do_holes :
             copy_args += ['isHLT']
         id_helper_args = copyArgs(kwargs,copy_args) if 'ClusterSplitProbabilityName' in kwargs else {}
         kwargs.pop('ClusterSplitProbabilityName',None)
-        kwargs.pop('RenounceInputHandles',None)
         kwargs = setDefaults( kwargs, InDetSummaryHelperTool = getInDetSummaryHelperSharedHits(**id_helper_args))
 
     if 'TRT_ElectronPidTool' not in kwargs :
diff --git a/InnerDetector/InDetExample/InDetRecExample/share/ConfiguredNewTrackingSiPattern.py b/InnerDetector/InDetExample/InDetRecExample/share/ConfiguredNewTrackingSiPattern.py
index 4f2a7cbdc3c..64b02d8db79 100644
--- a/InnerDetector/InDetExample/InDetRecExample/share/ConfiguredNewTrackingSiPattern.py
+++ b/InnerDetector/InDetExample/InDetRecExample/share/ConfiguredNewTrackingSiPattern.py
@@ -501,8 +501,7 @@ class  ConfiguredNewTrackingSiPattern:
          # @TODO is the cluster split probability container needed here ?
          ambi_track_summary_tool = TrackingCommon.getInDetTrackSummaryTool(namePrefix                 = 'InDetAmbiguityProcessorSplitProb',
                                                                            nameSuffix                 = NewTrackingCuts.extension(),
-                                                                           ClusterSplitProbabilityName= 'InDetAmbiguityProcessorSplitProb'+NewTrackingCuts.extension(),
-                                                                           RenounceInputHandles       = ['InDetAmbiguityProcessorSplitProb'+NewTrackingCuts.extension()])
+                                                                           ClusterSplitProbabilityName= 'InDetAmbiguityProcessorSplitProb'+NewTrackingCuts.extension())
          if InDetFlags.doTIDE_Ambi() and not (NewTrackingCuts.mode() == "ForwardSLHCTracks" or NewTrackingCuts.mode() == "ForwardTracks" or NewTrackingCuts.mode() == "DBM"):
            # DenseEnvironmentsAmbiguityScoreProcessorTool
            from TrkAmbiguityProcessor.TrkAmbiguityProcessorConf import Trk__DenseEnvironmentsAmbiguityScoreProcessorTool as ScoreProcessorTool
@@ -524,8 +523,7 @@ class  ConfiguredNewTrackingSiPattern:
            fitter_args = setDefaults({},
                                      nameSuffix                   = 'Ambi'+NewTrackingCuts.extension(),
                                      SplitClusterMapExtension     = NewTrackingCuts.extension(),
-                                     ClusterSplitProbabilityName  = 'InDetAmbiguityProcessorSplitProb'+NewTrackingCuts.extension(),
-                                     RenounceInputHandles         = ['InDetAmbiguityProcessorSplitProb'+NewTrackingCuts.extension()])
+                                     ClusterSplitProbabilityName  = 'InDetAmbiguityProcessorSplitProb'+NewTrackingCuts.extension())
            if InDetFlags.holeSearchInGX2Fit():
                fitter_args = setDefaults(fitter_args,
                DoHoleSearch                 = True,
diff --git a/InnerDetector/InDetRecTools/InDetTrackSummaryHelperTool/InDetTrackSummaryHelperTool/InDetTrackSummaryHelperTool.h b/InnerDetector/InDetRecTools/InDetTrackSummaryHelperTool/InDetTrackSummaryHelperTool/InDetTrackSummaryHelperTool.h
index 788a389a4bb..5d44f38c256 100755
--- a/InnerDetector/InDetRecTools/InDetTrackSummaryHelperTool/InDetTrackSummaryHelperTool/InDetTrackSummaryHelperTool.h
+++ b/InnerDetector/InDetRecTools/InDetTrackSummaryHelperTool/InDetTrackSummaryHelperTool/InDetTrackSummaryHelperTool.h
@@ -186,9 +186,6 @@ namespace InDet {
     SG::ReadHandleKey<Trk::ClusterSplitProbabilityContainer>   m_clusterSplitProbContainer
        {this, "ClusterSplitProbabilityName", "",""};
 
-    Gaudi::Property<std::vector<std::string> >                 m_renounce
-       {this, "RenounceInputHandles", {},""};
-
     BooleanProperty m_usePixel{this, "usePixel", true};
     BooleanProperty m_useSCT{this, "useSCT", true};
     BooleanProperty m_useTRT{this, "useTRT", true};
diff --git a/InnerDetector/InDetRecTools/InDetTrackSummaryHelperTool/src/InDetTrackSummaryHelperTool.cxx b/InnerDetector/InDetRecTools/InDetTrackSummaryHelperTool/src/InDetTrackSummaryHelperTool.cxx
index c576278b54d..e9482a0348b 100755
--- a/InnerDetector/InDetRecTools/InDetTrackSummaryHelperTool/src/InDetTrackSummaryHelperTool.cxx
+++ b/InnerDetector/InDetRecTools/InDetTrackSummaryHelperTool/src/InDetTrackSummaryHelperTool.cxx
@@ -33,13 +33,6 @@ InDet::InDetTrackSummaryHelperTool::InDetTrackSummaryHelperTool(const std::strin
 }
 
 //==========================================================================
-namespace {
-   std::string_view stripStoreName(const std::string &name) {
-      std::string::size_type pos = name.find("+");
-      pos =  (pos!=std::string::npos ? pos + 1 : 0);
-      return std::string_view( &(name.c_str()[pos]),name.size()-pos);
-   }
-}
 
 StatusCode InDet::InDetTrackSummaryHelperTool::initialize()
 {
@@ -72,18 +65,6 @@ StatusCode InDet::InDetTrackSummaryHelperTool::initialize()
 
   ATH_CHECK(m_clusterSplitProbContainer.initialize( !m_clusterSplitProbContainer.key().empty()));
 
-  if (!m_renounce.empty()) {
-     for (Gaudi::DataHandle* input_handle : inputHandles()) {
-        std::string_view base_name(stripStoreName(input_handle->objKey()));
-        for (const std::string &renounce_input : m_renounce) {
-           if (base_name==renounce_input) {
-              renounce(*input_handle);
-              ATH_MSG_INFO("Renounce : " << name() << " . " << input_handle->objKey() );
-           }
-        }
-     }
-  }
-
   ATH_MSG_INFO("initialize() successful in " << name());
 
   return StatusCode::SUCCESS;
diff --git a/InnerDetector/InDetRecTools/SiClusterOnTrackTool/SiClusterOnTrackTool/PixelClusterOnTrackTool.h b/InnerDetector/InDetRecTools/SiClusterOnTrackTool/SiClusterOnTrackTool/PixelClusterOnTrackTool.h
index b0a7c8cd837..ea222bcf6ec 100755
--- a/InnerDetector/InDetRecTools/SiClusterOnTrackTool/SiClusterOnTrackTool/PixelClusterOnTrackTool.h
+++ b/InnerDetector/InDetRecTools/SiClusterOnTrackTool/SiClusterOnTrackTool/PixelClusterOnTrackTool.h
@@ -175,8 +175,6 @@ private:
 
   SG::ReadHandleKey<Trk::ClusterSplitProbabilityContainer>   m_clusterSplitProbContainer
      {this, "ClusterSplitProbabilityName", "",""};
-  Gaudi::Property<std::vector<std::string> >                 m_renounce
-     {this, "RenounceInputHandles", {},""};
 
   //moved from static to member variable
   static constexpr int s_nbinphi=9;
diff --git a/InnerDetector/InDetRecTools/SiClusterOnTrackTool/src/PixelClusterOnTrackTool.cxx b/InnerDetector/InDetRecTools/SiClusterOnTrackTool/src/PixelClusterOnTrackTool.cxx
index cf4b8c13f70..22b3ef77265 100755
--- a/InnerDetector/InDetRecTools/SiClusterOnTrackTool/src/PixelClusterOnTrackTool.cxx
+++ b/InnerDetector/InDetRecTools/SiClusterOnTrackTool/src/PixelClusterOnTrackTool.cxx
@@ -91,13 +91,6 @@ InDet::PixelClusterOnTrackTool::~PixelClusterOnTrackTool() {
 ///////////////////////////////////////////////////////////////////
 // Initialisation
 ///////////////////////////////////////////////////////////////////
-namespace {
-   std::string_view stripStoreName(const std::string &name) {
-      std::string::size_type pos = name.find("+");
-      pos =  (pos!=std::string::npos ? pos + 1 : 0);
-      return std::string_view( &(name.c_str()[pos]),name.size()-pos);
-   }
-}
 
 StatusCode
 InDet::PixelClusterOnTrackTool::initialize() {
@@ -154,18 +147,6 @@ InDet::PixelClusterOnTrackTool::initialize() {
   ///
 
   ATH_CHECK(m_lorentzAngleTool.retrieve());
-
-  if (!m_renounce.empty()) {
-     for (Gaudi::DataHandle* input_handle : inputHandles()) {
-        std::string_view base_name(stripStoreName(input_handle->objKey()));
-        for (const std::string &renounce_input : m_renounce) {
-           if (base_name==renounce_input) {
-              renounce(*input_handle);
-              ATH_MSG_INFO("Renounce : " << name() << " . " << input_handle->objKey() );
-           }
-        }
-     }
-  }
   return StatusCode::SUCCESS;
 }
 
diff --git a/Tracking/TrkTools/TrkAmbiguityProcessor/src/AmbiguityProcessorBase.cxx b/Tracking/TrkTools/TrkAmbiguityProcessor/src/AmbiguityProcessorBase.cxx
index a29225e6e38..0324fc0095c 100644
--- a/Tracking/TrkTools/TrkAmbiguityProcessor/src/AmbiguityProcessorBase.cxx
+++ b/Tracking/TrkTools/TrkAmbiguityProcessor/src/AmbiguityProcessorBase.cxx
@@ -6,7 +6,8 @@
 #include "TrackScoringTool.h"
 #include "AmbiguityProcessorUtility.h"
 
-
+#include "GaudiKernel/ToolVisitor.h"
+#include "GaudiKernel/RenounceToolInputsVisitor.h"
 
 namespace Trk {
   AmbiguityProcessorBase::AmbiguityProcessorBase(const std::string& t, const std::string& n, const IInterface*  p ):
@@ -23,7 +24,74 @@ namespace Trk {
       (track.trackParameters()->front()->pT() > m_pTminBrem) and 
       ((not m_caloSeededBrem) or track.info().patternRecoInfo(Trk::TrackInfo::TrackInCaloROI));
   }
-  
+
+  StatusCode
+  AmbiguityProcessorBase::initializeClusterSplitProbContainer() {
+    // init ClusterSplitProb input and output container handles and renounce the output handle from its tools.
+    // the latter works because the ClusterSplitProb output container is created and recorded before the tools
+    // are called.
+    ATH_CHECK(m_clusterSplitProbContainerIn.initialize(!m_clusterSplitProbContainerIn.key().empty()));
+    ATH_CHECK(m_clusterSplitProbContainerOut.initialize(!m_clusterSplitProbContainerOut.key().empty()));
+    if (!m_clusterSplitProbContainerOut.key().empty()) {
+      auto visitor=[this](const IAlgTool *tool) {
+         const AlgTool *alg_tool = dynamic_cast<const AlgTool *>(tool);
+         for ( Gaudi::DataHandle* handle : alg_tool->inputHandles() ) {
+            this->msg(MSG::DEBUG)  << " input Handle "
+                                   << tool->name() << " . "
+                                   << handle->objKey() << endmsg;
+         }
+         for (auto elm : alg_tool->inputDataObjs()) {
+            this->msg(MSG::DEBUG) << " input object "
+                                  << tool->name() << " . "
+                                  << elm.key()  << endmsg;
+         }
+      };
+      if (msgLvl(MSG::DEBUG)) {
+         ToolVisitor::visit(tools(), visitor);
+      }
+      /// usage:
+      ATH_MSG_DEBUG(  " Renounce " << m_clusterSplitProbContainerOut.objKey() );
+      auto logger=RenounceToolInputsVisitor::createLogger( [this](const std::string_view& tool_name, const std::string_view& key) {
+         this->msg(MSG::INFO) << " Renounce " << tool_name << " . " << key << endmsg;
+      });
+      RenounceToolInputsVisitor renounce(std::vector<DataObjID>{m_clusterSplitProbContainerOut.fullKey()}, logger);
+      ToolVisitor::visit(tools(), renounce);
+      ATH_MSG_DEBUG(" renounced " << m_clusterSplitProbContainerOut.objKey() );
+      if (msgLvl(MSG::DEBUG)) {
+        ToolVisitor::visit(tools(), visitor);
+     }
+    }
+    return StatusCode::SUCCESS;
+  }
+
+  AmbiguityProcessorBase::UniqueClusterSplitProbabilityContainerPtr
+  AmbiguityProcessorBase::createAndRecordClusterSplitProbContainer(const EventContext& ctx) const {
+    SG::ReadHandle<Trk::ClusterSplitProbabilityContainer> splitProbContainerIn;
+    if (!m_clusterSplitProbContainerIn.key().empty()) {
+      splitProbContainerIn = SG::ReadHandle( m_clusterSplitProbContainerIn, ctx);
+      if (!splitProbContainerIn.isValid()) {
+        ATH_MSG_ERROR( "Failed to get input cluster split probability container "  << m_clusterSplitProbContainerIn.key());
+      }
+    }
+    std::unique_ptr<Trk::ClusterSplitProbabilityContainer>
+       newSplitProbContainer(!m_clusterSplitProbContainerIn.key().empty()
+                             ? std::make_unique<Trk::ClusterSplitProbabilityContainer>(*splitProbContainerIn)
+                             : std::make_unique<Trk::ClusterSplitProbabilityContainer>());
+    SG::WriteHandle<Trk::ClusterSplitProbabilityContainer> splitProbContainerHandle;
+    if (!m_clusterSplitProbContainerOut.key().empty()) {
+      splitProbContainerHandle=SG::WriteHandle<Trk::ClusterSplitProbabilityContainer>( m_clusterSplitProbContainerOut, ctx);
+      if (splitProbContainerHandle.record(std::move(newSplitProbContainer)).isFailure()) {
+        ATH_MSG_FATAL( "Failed to record output cluster split probability container "  << m_clusterSplitProbContainerOut.key());
+      }
+      // newSplitProbContainer owned by storegate -> no cleanup
+      return UniqueClusterSplitProbabilityContainerPtr(splitProbContainerHandle.ptr(), [](Trk::ClusterSplitProbabilityContainer *) {});
+    }
+    else {
+      // when not recording the split prob container in storegate the container must be deleted once going out of scope
+      return UniqueClusterSplitProbabilityContainerPtr(newSplitProbContainer.release(), [](Trk::ClusterSplitProbabilityContainer *ptr) { delete ptr;});
+    }
+  }
+
   bool
   AmbiguityProcessorBase::shouldTryBremRecovery(const Trk::Track & track, const TrackParameters * pPar) const{
     return m_tryBremFit and
@@ -167,4 +235,4 @@ namespace Trk {
   }
   
 
-}
\ No newline at end of file
+}
diff --git a/Tracking/TrkTools/TrkAmbiguityProcessor/src/AmbiguityProcessorBase.h b/Tracking/TrkTools/TrkAmbiguityProcessor/src/AmbiguityProcessorBase.h
index 4c9fec21d7c..9c41f16cb46 100644
--- a/Tracking/TrkTools/TrkAmbiguityProcessor/src/AmbiguityProcessorBase.h
+++ b/Tracking/TrkTools/TrkAmbiguityProcessor/src/AmbiguityProcessorBase.h
@@ -13,6 +13,7 @@
 
 #include "TrackPtr.h"
 #include "TrkEventPrimitives/TrackScore.h"
+#include "TrkEventUtils/ClusterSplitProbabilityContainer.h"
 
 #include <vector>
 #include <map> //multimap
@@ -95,7 +96,26 @@ namespace Trk {
                                                  
     const TrackParameters *
     getTrackParameters(const Trk::Track* track) const;
-    
+
+    /** Initialize read and write handles for ClusterSplitProbabilityContainers.
+     * If a write handle key is specified for the new ClusterSplitProbabilityContainer, read handles
+     * for this key are "renounced" in all child tools.
+     */
+    StatusCode
+    initializeClusterSplitProbContainer();
+
+    // special pointer type for the ClusterSplitProbabilityContainerPtr to allow to use a single "pointer" for
+    // ClusterSplitProbabilityContainer which need to be deleted and those owned by storegate
+    using UniqueClusterSplitProbabilityContainerPtr = std::unique_ptr<Trk::ClusterSplitProbabilityContainer,void(*)(Trk::ClusterSplitProbabilityContainer*) >;
+
+    /** Create a new cluster splitting probability container and (optionally) record it in storegate
+     * The new container may be populated from an already existing container, and might be stored in StoreGate.
+     * The ownersip, which might be either storegate or the calling scope, is taken into account by the
+     * UniqueClusterSplitProbabilityContainerPtr and must not be touched i.e. unique_ptr::release must not be called.
+     */
+    AmbiguityProcessorBase::UniqueClusterSplitProbabilityContainerPtr
+    createAndRecordClusterSplitProbContainer(const EventContext& ctx) const;
+
     //variables accessible to derived classes
     std::vector<float>     m_etaBounds;           //!< eta intervals for internal monitoring
     mutable std::mutex m_statMutex;
@@ -105,6 +125,16 @@ namespace Trk {
        @todo The actual tool that is used should be configured through job options*/
     ToolHandle<ITrackScoringTool> m_scoringTool;
     ToolHandle<Trk::IExtendedTrackSummaryTool> m_trackSummaryTool{this, "TrackSummaryTool", "InDetTrackSummaryToolNoHoleSearch"};
+
+  private:
+    // the handles should not be used directly instead the methods initializeClusterSplitProbContainer
+    // and createAndRecordClusterSplitProbContainer should be used.
+    SG::ReadHandleKey<Trk::ClusterSplitProbabilityContainer> m_clusterSplitProbContainerIn
+        {this, "InputClusterSplitProbabilityName", "",""};
+    SG::WriteHandleKey<Trk::ClusterSplitProbabilityContainer> m_clusterSplitProbContainerOut
+       {this, "OutputClusterSplitProbabilityName", "",""};
+
+  protected:
      /** brem recovery mode with brem fit ? */
     bool  m_tryBremFit{};
     bool  m_caloSeededBrem{};
diff --git a/Tracking/TrkTools/TrkAmbiguityProcessor/src/DenseEnvironmentsAmbiguityProcessorTool.cxx b/Tracking/TrkTools/TrkAmbiguityProcessor/src/DenseEnvironmentsAmbiguityProcessorTool.cxx
index 48891f91622..9982fc9356a 100644
--- a/Tracking/TrkTools/TrkAmbiguityProcessor/src/DenseEnvironmentsAmbiguityProcessorTool.cxx
+++ b/Tracking/TrkTools/TrkAmbiguityProcessor/src/DenseEnvironmentsAmbiguityProcessorTool.cxx
@@ -88,9 +88,9 @@ Trk::DenseEnvironmentsAmbiguityProcessorTool::initialize(){
 
   ATH_CHECK( m_extrapolatorTool.retrieve());
 
-  ATH_CHECK(m_clusterSplitProbContainerIn.initialize(!m_clusterSplitProbContainerIn.key().empty()));
-  ATH_CHECK(m_clusterSplitProbContainerOut.initialize(!m_clusterSplitProbContainerOut.key().empty()));
-
+  if (initializeClusterSplitProbContainer().isFailure()) {
+     sc=StatusCode::FAILURE;
+  }
   // Configuration of the material effects
   Trk::ParticleSwitcher particleSwitch;
   m_particleHypothesis = particleSwitch.particle[m_matEffects];
@@ -110,7 +110,6 @@ Trk::DenseEnvironmentsAmbiguityProcessorTool::initialize(){
   }
   return sc;
 }
-//==================================================================================================
 
 StatusCode 
 Trk::DenseEnvironmentsAmbiguityProcessorTool::finalize(){
@@ -177,28 +176,7 @@ Trk::DenseEnvironmentsAmbiguityProcessorTool::solveTracks(const TracksScores &tr
      stat.incrementCounterByRegion(CounterIndex::kNcandidates,scoreTrack.first);
   }
   const EventContext& ctx = Gaudi::Hive::currentContext();
-  SG::ReadHandle<Trk::ClusterSplitProbabilityContainer> splitProbContainerIn;
-  if (!m_clusterSplitProbContainerIn.key().empty()) {
-     splitProbContainerIn = SG::ReadHandle( m_clusterSplitProbContainerIn, ctx);
-     if (!splitProbContainerIn.isValid()) {
-        ATH_MSG_ERROR( "Failed to get input cluster split probability container "  << m_clusterSplitProbContainerIn.key());
-     }
-  }
-  std::unique_ptr<Trk::ClusterSplitProbabilityContainer> splitProbContainerCleanup(!m_clusterSplitProbContainerIn.key().empty()
-                                                                                      ? std::make_unique<ClusterSplitProbabilityContainer>(*splitProbContainerIn)
-                                                                                      : std::make_unique<ClusterSplitProbabilityContainer>());
-  SG::WriteHandle<Trk::ClusterSplitProbabilityContainer> splitProbContainerHandle;
-  Trk::ClusterSplitProbabilityContainer *splitProbContainer;
-  if (!m_clusterSplitProbContainerOut.key().empty()) {
-     splitProbContainerHandle=SG::WriteHandle<Trk::ClusterSplitProbabilityContainer>( m_clusterSplitProbContainerOut, ctx);
-     if (splitProbContainerHandle.record(std::move(splitProbContainerCleanup)).isFailure()) {
-        ATH_MSG_FATAL( "Failed to record output cluster split probability container "  << m_clusterSplitProbContainerOut.key());
-     }
-     splitProbContainer = splitProbContainerHandle.ptr();
-  }
-  else {
-     splitProbContainer = splitProbContainerCleanup.get();
-  }
+  UniqueClusterSplitProbabilityContainerPtr splitProbContainer(createAndRecordClusterSplitProbContainer(ctx));
   ATH_MSG_DEBUG ("Starting to solve tracks");
   // now loop as long as map is not empty
   while ( !scoreTrackFitflagMap.empty() ){
diff --git a/Tracking/TrkTools/TrkAmbiguityProcessor/src/DenseEnvironmentsAmbiguityProcessorTool.h b/Tracking/TrkTools/TrkAmbiguityProcessor/src/DenseEnvironmentsAmbiguityProcessorTool.h
index 9b51c9f920f..114504e4d09 100644
--- a/Tracking/TrkTools/TrkAmbiguityProcessor/src/DenseEnvironmentsAmbiguityProcessorTool.h
+++ b/Tracking/TrkTools/TrkAmbiguityProcessor/src/DenseEnvironmentsAmbiguityProcessorTool.h
@@ -12,7 +12,6 @@
 
 #include "TrkToolInterfaces/IPRDtoTrackMapTool.h"
 #include "TrkEventUtils/PRDtoTrackMap.h"
-#include "TrkEventUtils/ClusterSplitProbabilityContainer.h"
 
 //need to include the following, since its a typedef and can't be forward declared.
 #include "TrkTrack/TrackCollection.h"
@@ -83,8 +82,7 @@ namespace Trk {
     std::unique_ptr<Trk::Track>
     fit(const std::vector<const Trk::MeasurementBase*> &measurements,
           const TrackParameters &param, bool flag, Trk::ParticleHypothesis hypo) const;
-          
-    
+
     std::unique_ptr<Trk::Track>
     fit(const Track &track, bool flag, Trk::ParticleHypothesis hypo) const override final;
     bool 
@@ -108,11 +106,6 @@ namespace Trk {
         which are removed are made */
     ToolHandle<IAmbiTrackSelectionTool> m_selectionTool;
 
-    SG::ReadHandleKey<Trk::ClusterSplitProbabilityContainer> m_clusterSplitProbContainerIn
-       {this, "InputClusterSplitProbabilityName", "",""};
-    SG::WriteHandleKey<Trk::ClusterSplitProbabilityContainer> m_clusterSplitProbContainerOut
-       {this, "OutputClusterSplitProbabilityName", "",""};
-
     bool m_rejectInvalidTracks;
     /// If enabled, this flag will make the tool restore the hole information from the input track after a refit. 
     /// This is used when we want to use holes from the pattern recognition instead of repeating the hole search
diff --git a/Tracking/TrkTools/TrkAmbiguityProcessor/src/SimpleAmbiguityProcessorTool.cxx b/Tracking/TrkTools/TrkAmbiguityProcessor/src/SimpleAmbiguityProcessorTool.cxx
index cde397de640..acd3a08ba9e 100644
--- a/Tracking/TrkTools/TrkAmbiguityProcessor/src/SimpleAmbiguityProcessorTool.cxx
+++ b/Tracking/TrkTools/TrkAmbiguityProcessor/src/SimpleAmbiguityProcessorTool.cxx
@@ -9,6 +9,7 @@
 #include "TrkToolInterfaces/IPRD_AssociationTool.h"
 #include "TrkTrack/TrackCollection.h"
 #include "TrkTrack/TrackInfo.h"
+
 #include <map>
 #include <memory>
 #include "AmbiguityProcessorUtility.h"
@@ -77,19 +78,19 @@ StatusCode Trk::SimpleAmbiguityProcessorTool::initialize(){
      ATH_MSG_INFO( "Try brem fit and recovery for electron like tracks.");
   }
 
-  ATH_CHECK(m_clusterSplitProbContainerIn.initialize(!m_clusterSplitProbContainerIn.key().empty()));
-  ATH_CHECK(m_clusterSplitProbContainerOut.initialize(!m_clusterSplitProbContainerOut.key().empty()));
   // statistics
   if (m_etaBounds.size() != Counter::nRegions) {
      ATH_MSG_ERROR( "There must be exactly " << Counter::nRegions
                     << " etaBounds: barrel end, transition region end, end-cap end, DBM start, DBM end." );
      return StatusCode::FAILURE;
   }
+  if (initializeClusterSplitProbContainer().isFailure()) {
+     sc=StatusCode::FAILURE;
+  }
   return sc;
 }
-//==================================================================================================
-
 
+//==================================================================================================
 StatusCode Trk::SimpleAmbiguityProcessorTool::finalize(){
   return StatusCode::SUCCESS;
 }
@@ -197,28 +198,7 @@ Trk::SimpleAmbiguityProcessorTool::solveTracks(TrackScoreMap& trackScoreTrackMap
                                                                 std::vector<std::unique_ptr<const Trk::Track> >& trackDustbin,
                                                                 Counter &stat) const{
   const EventContext& ctx = Gaudi::Hive::currentContext();
-  SG::ReadHandle<Trk::ClusterSplitProbabilityContainer> splitProbContainerIn;
-  if (!m_clusterSplitProbContainerIn.key().empty()) {
-     splitProbContainerIn = SG::ReadHandle( m_clusterSplitProbContainerIn, ctx);
-     if (!splitProbContainerIn.isValid()) {
-        ATH_MSG_ERROR( "Failed to get input cluster split probability container "  << m_clusterSplitProbContainerIn.key());
-     }
-  }
-  std::unique_ptr<Trk::ClusterSplitProbabilityContainer> splitProbContainerCleanup(!m_clusterSplitProbContainerIn.key().empty()
-                                                                                      ? std::make_unique<ClusterSplitProbabilityContainer>(*splitProbContainerIn)
-                                                                                      : std::make_unique<ClusterSplitProbabilityContainer>());
-  SG::WriteHandle<Trk::ClusterSplitProbabilityContainer> splitProbContainerHandle;
-  Trk::ClusterSplitProbabilityContainer *splitProbContainer;
-  if (!m_clusterSplitProbContainerOut.key().empty()) {
-     splitProbContainerHandle = SG::WriteHandle<Trk::ClusterSplitProbabilityContainer>( m_clusterSplitProbContainerOut, ctx);
-     if (splitProbContainerHandle.record(std::move(splitProbContainerCleanup)).isFailure()) {
-        ATH_MSG_FATAL( "Failed to record output cluster split probability container "  << m_clusterSplitProbContainerOut.key());
-     }
-     splitProbContainer=splitProbContainerHandle.ptr();
-  }
-  else {
-     splitProbContainer=splitProbContainerCleanup.get();
-  }
+  UniqueClusterSplitProbabilityContainerPtr splitProbContainer(createAndRecordClusterSplitProbContainer(ctx));
 
   std::unique_ptr<TrackCollection> finalTracks(std::make_unique<TrackCollection>());
 
diff --git a/Tracking/TrkTools/TrkAmbiguityProcessor/src/SimpleAmbiguityProcessorTool.h b/Tracking/TrkTools/TrkAmbiguityProcessor/src/SimpleAmbiguityProcessorTool.h
index 958b33bb4fd..532d2f3f155 100644
--- a/Tracking/TrkTools/TrkAmbiguityProcessor/src/SimpleAmbiguityProcessorTool.h
+++ b/Tracking/TrkTools/TrkAmbiguityProcessor/src/SimpleAmbiguityProcessorTool.h
@@ -14,7 +14,6 @@
 
 #include "TrkToolInterfaces/IPRDtoTrackMapTool.h"
 #include "TrkEventUtils/PRDtoTrackMap.h"
-#include "TrkEventUtils/ClusterSplitProbabilityContainer.h"
 #include "TrkToolInterfaces/IExtendedTrackSummaryTool.h"
 
 //need to include the following, since its a typedef and can't be forward declared.
@@ -119,10 +118,6 @@ namespace Trk {
       ToolHandle<Trk::IPRDtoTrackMapTool>         m_assoTool{this, "AssociationTool", "Trk::PRDtoTrackMapTool" };
       /** selection tool - here the decision which hits remain on a track and which are removed are made */
       ToolHandle<IAmbiTrackSelectionTool> m_selectionTool;
-      SG::ReadHandleKey<Trk::ClusterSplitProbabilityContainer> m_clusterSplitProbContainerIn
-         {this, "InputClusterSplitProbabilityName", "",""};
-      SG::WriteHandleKey<Trk::ClusterSplitProbabilityContainer> m_clusterSplitProbContainerOut
-         {this, "OutputClusterSplitProbabilityName", "",""};
 
     };
 } //end ns
-- 
GitLab