diff --git a/Tracking/TrkAlgorithms/TrkAmbiguitySolver/TrkAmbiguitySolver/TrkAmbiguityScore.h b/Tracking/TrkAlgorithms/TrkAmbiguitySolver/TrkAmbiguitySolver/TrkAmbiguityScore.h
index e112ca6e98f251c12c2a9d27e3b46cab471586e6..dfc97b79118651caba40aef777ab125ae0224c93 100644
--- a/Tracking/TrkAlgorithms/TrkAmbiguitySolver/TrkAmbiguitySolver/TrkAmbiguityScore.h
+++ b/Tracking/TrkAlgorithms/TrkAmbiguitySolver/TrkAmbiguitySolver/TrkAmbiguityScore.h
@@ -1,5 +1,5 @@
 /*
-  Copyright (C) 2002-2019 CERN for the benefit of the ATLAS collaboration
+  Copyright (C) 2002-2020 CERN for the benefit of the ATLAS collaboration
 */
 
 
diff --git a/Tracking/TrkAlgorithms/TrkAmbiguitySolver/TrkAmbiguitySolver/TrkAmbiguitySolver.h b/Tracking/TrkAlgorithms/TrkAmbiguitySolver/TrkAmbiguitySolver/TrkAmbiguitySolver.h
index 600744a934b4775cb3d5cbe2e699c63a00d8c468..37ebe6c7f566dd8c6c48b34bafa1f70ac591dfb4 100644
--- a/Tracking/TrkAlgorithms/TrkAmbiguitySolver/TrkAmbiguitySolver/TrkAmbiguitySolver.h
+++ b/Tracking/TrkAlgorithms/TrkAmbiguitySolver/TrkAmbiguitySolver/TrkAmbiguitySolver.h
@@ -1,5 +1,5 @@
 /*
-  Copyright (C) 2002-2019 CERN for the benefit of the ATLAS collaboration
+  Copyright (C) 2002-2020 CERN for the benefit of the ATLAS collaboration
 */
 
 
diff --git a/Tracking/TrkAlgorithms/TrkAmbiguitySolver/src/TrkAmbiguityScore.cxx b/Tracking/TrkAlgorithms/TrkAmbiguitySolver/src/TrkAmbiguityScore.cxx
index a6e67930c9bfdbfde4d29e3f6313a305716fe8ff..f3dce3e541842313ca533b4d4d27117acb70cc5c 100644
--- a/Tracking/TrkAlgorithms/TrkAmbiguitySolver/src/TrkAmbiguityScore.cxx
+++ b/Tracking/TrkAlgorithms/TrkAmbiguitySolver/src/TrkAmbiguityScore.cxx
@@ -1,5 +1,5 @@
 /*
-  Copyright (C) 2002-2019 CERN for the benefit of the ATLAS collaboration
+  Copyright (C) 2002-2020 CERN for the benefit of the ATLAS collaboration
 */
 
 #include "TrkAmbiguitySolver/TrkAmbiguityScore.h"
@@ -22,47 +22,34 @@ Trk::TrkAmbiguityScore::~TrkAmbiguityScore(void)
 
 //-----------------------------------------------------------------------
 StatusCode
-Trk::TrkAmbiguityScore::initialize()
-{
-  ATH_MSG_INFO( "TrkAmbiguityScore::initialize(). " );
-
+Trk::TrkAmbiguityScore::initialize(){
+  ATH_MSG_VERBOSE( "TrkAmbiguityScore::initialize(). " );
   ATH_CHECK(m_scoreTool.retrieve( DisableTool{m_scoreTool.empty()} ));
-
   ATH_CHECK(m_scoredTracksKey.initialize());
   ATH_CHECK(m_originTracksKey.initialize());
-
   return StatusCode::SUCCESS;
 }
 
 //-------------------------------------------------------------------------
 StatusCode
-Trk::TrkAmbiguityScore::execute(const EventContext& ctx) const
-{
+Trk::TrkAmbiguityScore::execute(const EventContext& ctx) const{
   std::vector<SG::ReadHandle<TrackCollection>> handles = m_originTracksKey.makeHandles(ctx);
-  size_t totalsize = 0;
-  for (SG::ReadHandle<TrackCollection>& trackColHandle : handles) {
-     if (!trackColHandle.isValid())
-       msg(MSG::WARNING) << "Could not retrieve tracks from "<< trackColHandle.key() << endmsg;
-     totalsize += trackColHandle->size();
+  ATH_MSG_DEBUG(handles.size() << " handles are requested");
+  if (handles.size() > 1){
+    ATH_MSG_WARNING("More than one collection has been requested. Only the first collection is taken");
   }
-
-  std::vector<const Track*> originTracks;
-  originTracks.reserve(totalsize);
-  for (SG::ReadHandle<TrackCollection>& trackColHandle : handles) {
-    for(const Track* trk: *trackColHandle ) {
-       if (std::find(originTracks.begin(), originTracks.end(),trk) == originTracks.end()) {
-          originTracks.push_back(trk);
-       }
-    }
+  auto & theTrackCollectionHandle = handles.at(0);
+  if (not theTrackCollectionHandle.isValid()){
+    ATH_MSG_FATAL( "Could not retrieve tracks from "<< theTrackCollectionHandle.key() );
+    return StatusCode::FAILURE;
   }
-
+  const auto & theTrackCollection = *theTrackCollectionHandle;
   std::unique_ptr<TracksScores> scoredTracks(new TracksScores);
   if (m_scoreTool.isEnabled()){
-    m_scoreTool->process(&originTracks, scoredTracks.get());
-  }
-  else{
-    scoredTracks->reserve(originTracks.size());
-    for(const Track* trk: originTracks ){
+    m_scoreTool->process(theTrackCollection, scoredTracks.get());
+  } else {
+    scoredTracks->reserve(theTrackCollection.size());
+    for(const Track* trk: theTrackCollection ){
       scoredTracks->push_back( std::pair<const Track*, float>(trk, 0));//TODO: logpT
     }
   }
diff --git a/Tracking/TrkAlgorithms/TrkAmbiguitySolver/src/TrkAmbiguitySolver.cxx b/Tracking/TrkAlgorithms/TrkAmbiguitySolver/src/TrkAmbiguitySolver.cxx
index d5acba4f127a3a02102ab530be1a776428ef7701..fd3a6a9c0836bca564f59d2d382c10304ed0a745 100644
--- a/Tracking/TrkAlgorithms/TrkAmbiguitySolver/src/TrkAmbiguitySolver.cxx
+++ b/Tracking/TrkAlgorithms/TrkAmbiguitySolver/src/TrkAmbiguitySolver.cxx
@@ -1,5 +1,5 @@
 /*
-  Copyright (C) 2002-2019 CERN for the benefit of the ATLAS collaboration
+  Copyright (C) 2002-2020 CERN for the benefit of the ATLAS collaboration
 */
 
 #include "TrkAmbiguitySolver/TrkAmbiguitySolver.h"
@@ -58,8 +58,7 @@ Trk::TrkAmbiguitySolver::execute(const EventContext& ctx) const
 //---------------------------------------------------------------------------
 
 StatusCode
-Trk::TrkAmbiguitySolver::finalize()
-{
+Trk::TrkAmbiguitySolver::finalize(){
   if (m_ambiTool.isEnabled()) {
       m_ambiTool->statistics();
   }
diff --git a/Tracking/TrkTools/TrkAmbiguityProcessor/CMakeLists.txt b/Tracking/TrkTools/TrkAmbiguityProcessor/CMakeLists.txt
index ce2b1e29d05078478d1ec7d085c06127e6d9513a..5e9256a66bdfab56679670c2a0ef61362b46737e 100644
--- a/Tracking/TrkTools/TrkAmbiguityProcessor/CMakeLists.txt
+++ b/Tracking/TrkTools/TrkAmbiguityProcessor/CMakeLists.txt
@@ -35,13 +35,14 @@ find_package( HepPDT )
 atlas_add_library(   TrkAmbiguityProcessorLib
                      src/DenseEnvironmentsAmbiguityProcessorTool.cxx
                      src/DenseEnvironmentsAmbiguityScoreProcessorTool.cxx
-                   
+                     src/AmbiguityProcessorUtility.cxx
+                     src/AmbiguityProcessorBase.cxx
                      PUBLIC_HEADERS TrkAmbiguityProcessor
                      PRIVATE_INCLUDE_DIRS ${ROOT_INCLUDE_DIRS}
                      LINK_LIBRARIES ${ROOT_LIBRARIES} AthenaKernel AthenaBaseComps AtlasDetDescr GaudiKernel InDetPrepRawData InDetRecToolInterfaces TrkDetElementBase TrkEventPrimitives TrkParameters TrkRIO_OnTrack TrkTrack TrkTrackSummary TrkTruthData TrkFitterInterfaces TrkToolInterfaces TrkValInterfaces TrkExInterfaces TrkCaloClusterROI)
 
 atlas_add_component( TrkAmbiguityProcessor
-                     src/SimpleAmbiguityProcessorTool.cxx  src/TrackScoringTool.cxx  src/TrackSelectionProcessorTool.cxx
+                     src/SimpleAmbiguityProcessorTool.cxx  src/TrackScoringTool.cxx  src/TrackSelectionProcessorTool.cxx src/AmbiguityProcessorUtility.cxx src/AmbiguityProcessorBase.cxx
                      src/components/*.cxx 
                      INCLUDE_DIRS ${CLHEP_INCLUDE_DIRS} ${HEPPDT_INCLUDE_DIRS}
                      LINK_LIBRARIES ${CLHEP_LIBRARIES} ${HEPPDT_LIBRARIES} TrkAmbiguityProcessorLib )
diff --git a/Tracking/TrkTools/TrkAmbiguityProcessor/src/AmbiguityProcessorBase.cxx b/Tracking/TrkTools/TrkAmbiguityProcessor/src/AmbiguityProcessorBase.cxx
new file mode 100644
index 0000000000000000000000000000000000000000..a29225e6e389d3364906aceb719f374af6f8eca1
--- /dev/null
+++ b/Tracking/TrkTools/TrkAmbiguityProcessor/src/AmbiguityProcessorBase.cxx
@@ -0,0 +1,170 @@
+/*
+  Copyright (C) 2002-2020 CERN for the benefit of the ATLAS collaboration
+*/
+
+#include "AmbiguityProcessorBase.h"
+#include "TrackScoringTool.h"
+#include "AmbiguityProcessorUtility.h"
+
+
+
+namespace Trk {
+  AmbiguityProcessorBase::AmbiguityProcessorBase(const std::string& t, const std::string& n, const IInterface*  p ):
+    AthAlgTool(t,n,p), 
+    m_etaBounds{0.8, 1.6, 2.5, 4.0}, 
+    m_stat(m_etaBounds),
+    m_scoringTool("Trk::TrackScoringTool/TrackScoringTool"){
+  }
+  //
+  bool
+  AmbiguityProcessorBase::shouldTryBremRecovery(const Trk::Track & track) const{
+    return m_tryBremFit and 
+      not (track.info().trackProperties(Trk::TrackInfo::BremFit)) and
+      (track.trackParameters()->front()->pT() > m_pTminBrem) and 
+      ((not m_caloSeededBrem) or track.info().patternRecoInfo(Trk::TrackInfo::TrackInCaloROI));
+  }
+  
+  bool
+  AmbiguityProcessorBase::shouldTryBremRecovery(const Trk::Track & track, const TrackParameters * pPar) const{
+    return m_tryBremFit and
+      (pPar->pT() > m_pTminBrem) and 
+      ((not m_caloSeededBrem)  or  track.info().patternRecoInfo(Trk::TrackInfo::TrackInCaloROI));
+  }
+  //
+  Track * 
+  AmbiguityProcessorBase::refitTrack( const Trk::Track* track,Trk::PRDtoTrackMap &prdToTrackMap, Counter &stat) const{
+    std::unique_ptr<Trk::Track> newTrack;
+    if (!m_suppressTrackFit){
+      if (m_refitPrds) {
+        // simple case, fit PRD directly
+        ATH_MSG_VERBOSE ("Refit track "<<track<<" from PRDs");
+        newTrack.reset(refitPrds (track,prdToTrackMap, stat));
+      }else {
+        // ok, we fit ROTs
+        ATH_MSG_VERBOSE ("Refit track "<<track<<" from ROTs");
+        newTrack.reset(refitRots (track,stat));
+      }
+    } else {
+      newTrack = AmbiguityProcessor::createNewFitQualityTrack(*track);
+    }
+    if (newTrack) {
+      ATH_MSG_DEBUG ("New track "<<newTrack.get()<<" successfully fitted from "<<track);
+    } else { 
+      ATH_MSG_DEBUG ("Fit failed !");
+    }  
+    return newTrack.release();
+  }
+  //
+  void
+  AmbiguityProcessorBase::addTrack(Trk::Track* in_track,const bool fitted,
+                                                 TrackScoreMap &trackScoreTrackMap,
+                                                 Trk::PRDtoTrackMap &prdToTrackMap,
+                                                 std::vector<std::unique_ptr<const Trk::Track> >& trackDustbin,
+                                                 Counter &stat) const {
+    std::unique_ptr<Trk::Track> atrack(in_track);
+    // compute score
+    TrackScore score;
+    bool suppressHoleSearch = fitted ? m_suppressHoleSearch : true;
+    if (m_trackSummaryTool.isEnabled()) {
+       m_trackSummaryTool->computeAndReplaceTrackSummary(*atrack,&prdToTrackMap,suppressHoleSearch);
+    }
+    score = m_scoringTool->score( *atrack, suppressHoleSearch );
+    // do we accept the track ?
+    if (score!=0){
+      ATH_MSG_DEBUG ("Track  ("<< atrack.get() <<") has score "<<score);
+      // statistic
+      stat.incrementCounterByRegion(CounterIndex::kNscoreOk,atrack.get());
+      // add track to map, map is sorted small to big !
+      trackScoreTrackMap.emplace(-score, TrackPtr(atrack.release(), fitted));
+      return;
+    }
+    // do we try to recover the track ?
+    if (fitted and shouldTryBremRecovery(*atrack)){
+      ATH_MSG_DEBUG ("Track score is zero, try to recover it via brem fit");
+      // run track fit using electron hypothesis
+      auto bremTrack(doBremRefit(*atrack));
+      if (!bremTrack){
+        ATH_MSG_DEBUG ("Brem refit failed, drop track");
+        // statistic
+        stat.incrementCounterByRegion(CounterIndex::kNscoreZeroBremRefitFailed,atrack.get());
+        stat.incrementCounterByRegion(CounterIndex::kNfailedFits,atrack.get());
+        // clean up
+        trackDustbin.push_back(std::move(atrack));
+      } else {
+        // statistic
+        stat.incrementCounterByRegion(CounterIndex::kNgoodFits,bremTrack.get());
+        // rerun score
+        if (m_trackSummaryTool.isEnabled()) {
+          m_trackSummaryTool->computeAndReplaceTrackSummary(*bremTrack, &prdToTrackMap,suppressHoleSearch);
+        }
+        score = m_scoringTool->score( *bremTrack, suppressHoleSearch );
+        //put original track in the bin, ready to preserve a new Brem track
+        trackDustbin.push_back(std::move(atrack) );
+        // do we accept the track ?
+        if (score!=0){
+          ATH_MSG_DEBUG ("Brem refit successful, recovered track  ("<< bremTrack.get() <<") has score "<<score);
+          // statistics
+          stat.incrementCounterByRegion(CounterIndex::kNscoreZeroBremRefit,bremTrack.get());
+          // add track to map, map is sorted small to big !
+          trackScoreTrackMap.emplace(-score, TrackPtr(bremTrack.release(), fitted) );
+          return;
+        } else {
+          ATH_MSG_DEBUG ("Brem refit gave still track score zero, reject it");
+          // statistic
+          stat.incrementCounterByRegion(CounterIndex::kNscoreZeroBremRefitScoreZero,bremTrack.get());
+        }
+      }
+    } else {
+      ATH_MSG_DEBUG ("Track score is zero, reject it");
+      // statistic
+      stat.incrementCounterByRegion(CounterIndex::kNscoreZero,atrack.get());
+      trackDustbin.push_back(std::move(atrack));
+    }
+  }
+
+  const TrackParameters *
+  AmbiguityProcessorBase::getTrackParameters(const Trk::Track* track) const{
+    const TrackParameters* par = track->perigeeParameters();
+    if (not par) {
+      ATH_MSG_DEBUG ("Track ("<<track<<") has no perigee! Try any other ?");
+      par = track->trackParameters()->front();
+    }
+    if (not par) ATH_MSG_DEBUG ("Track ("<<track<<") has no Track Parameters ! No refit !");
+    return par;
+  }
+  
+  //==================================================================================================
+
+  Trk::Track* 
+  AmbiguityProcessorBase::refitRots(const Trk::Track* track,Counter &stat) const{
+    ATH_MSG_VERBOSE ("Refit track "<<track);
+    // refit using first parameter, do outliers
+    std::unique_ptr<Trk::Track> newTrack{};
+    if (m_tryBremFit and track->info().trackProperties(Trk::TrackInfo::BremFit)){
+      stat.incrementCounterByRegion(CounterIndex::kNbremFits,track);
+      ATH_MSG_VERBOSE ("Brem track, refit with electron brem fit");
+      newTrack = doBremRefit(*track);
+    } else {
+      stat.incrementCounterByRegion(CounterIndex::kNfits,track);
+      ATH_MSG_VERBOSE ("Normal track, refit");
+      newTrack = fit(*track, true, m_particleHypothesis);
+      if ( (not newTrack) and shouldTryBremRecovery(*track)){
+        stat.incrementCounterByRegion(CounterIndex::kNrecoveryBremFits,track);
+        ATH_MSG_VERBOSE ("Normal fit failed, try brem recovery");
+        newTrack = doBremRefit(*track);
+      }
+    }
+
+    if(newTrack){
+      stat.incrementCounterByRegion(CounterIndex::kNgoodFits,newTrack.get());
+      //keeping the track of previously accumulated TrackInfo
+      const Trk::TrackInfo& originalInfo = track->info();
+      newTrack->info().addPatternReco(originalInfo);
+    } else {
+      stat.incrementCounterByRegion(CounterIndex::kNfailedFits,track);
+    }
+    return newTrack.release();
+  }
+  
+
+}
\ No newline at end of file
diff --git a/Tracking/TrkTools/TrkAmbiguityProcessor/src/AmbiguityProcessorBase.h b/Tracking/TrkTools/TrkAmbiguityProcessor/src/AmbiguityProcessorBase.h
new file mode 100644
index 0000000000000000000000000000000000000000..4c9fec21d7c9ec61a44ee170b1a1bef2ac46fdcc
--- /dev/null
+++ b/Tracking/TrkTools/TrkAmbiguityProcessor/src/AmbiguityProcessorBase.h
@@ -0,0 +1,126 @@
+/*
+  Copyright (C) 2002-2020 CERN for the benefit of the ATLAS collaboration
+*/
+
+#ifndef AmbiguityProcessorBase_h
+#define AmbiguityProcessorBase_h
+
+#include "AthenaBaseComps/AthAlgTool.h"
+#include "TrkToolInterfaces/ITrackAmbiguityProcessorTool.h"
+#include "TrkToolInterfaces/IExtendedTrackSummaryTool.h"
+#include "AmbiCounter.icc"
+#include "GaudiKernel/ToolHandle.h"
+
+#include "TrackPtr.h"
+#include "TrkEventPrimitives/TrackScore.h"
+
+#include <vector>
+#include <map> //multimap
+#include <memory> //unique_ptr
+#include <mutex>  //mutex
+
+
+
+namespace Trk {
+  //fwd declare
+  class ITrackScoringTool;
+  class Track;
+  class PRDtoTrackMap;
+
+  //base class for SimpleAmbiguityProcessorTool and DenseEnvironmentsAmbiguityProcessorTool
+  class AmbiguityProcessorBase : public AthAlgTool, virtual public ITrackAmbiguityProcessorTool {
+  public:
+    enum class CounterIndex {
+      kNcandidates,
+      kNcandScoreZero,
+      kNcandDouble,
+      kNscoreOk,
+      kNscoreZeroBremRefit,
+      kNscoreZeroBremRefitFailed,
+      kNscoreZeroBremRefitScoreZero,
+      kNscoreZero,
+      kNaccepted,
+      kNsubTrack,
+      kNnoSubTrack,
+      kNacceptedBrem,
+      kNbremFits,
+      kNfits,
+      kNrecoveryBremFits,
+      kNgoodFits,
+      kNfailedFits,
+      kNCounter
+    };
+    using Counter = AmbiCounter<CounterIndex>;
+    using TrackScoreMap = std::multimap< TrackScore, TrackPtr > ;
+
+    // default methods
+    AmbiguityProcessorBase(const std::string&,const std::string&,const IInterface*);
+    virtual ~AmbiguityProcessorBase () = default;
+  protected:
+    // methods
+    // should try a Brem refit? based on track properties
+    bool
+    shouldTryBremRecovery(const Trk::Track & track) const;
+    
+    // should try a Brem refit? based on track properties and previously obtained track parameters
+    bool
+    shouldTryBremRecovery(const Trk::Track & track, const TrackParameters * pPar) const;
+    
+    // do a brem refit; implemented in the derived classes
+    virtual std::unique_ptr<Trk::Track>
+    doBremRefit(const Trk::Track & track) const = 0;
+    
+    /** refit track */
+    Track * 
+    refitTrack( const Trk::Track* track,Trk::PRDtoTrackMap &prdToTrackMap, Counter &stat) const;
+                       
+    //refit PRD
+    virtual Trk::Track* 
+    refitPrds( const Trk::Track* track, Trk::PRDtoTrackMap &prdToTrackMap,Counter &stat) const = 0;
+    
+    //refit ROTs
+    virtual Trk::Track* 
+    refitRots( const Trk::Track* track, Counter &stat) const;
+    
+    //generic normal fit
+    virtual std::unique_ptr<Trk::Track>
+    fit(const Track &track, bool flag, Trk::ParticleHypothesis hypo) const = 0;
+    
+    void
+    addTrack(Trk::Track* in_track, const bool fitted,
+             TrackScoreMap &trackScoreTrackMap,
+             Trk::PRDtoTrackMap &prdToTrackMap,
+             std::vector<std::unique_ptr<const Trk::Track> >& trackDustbin,
+             Counter &stat) const;
+                                                 
+    const TrackParameters *
+    getTrackParameters(const Trk::Track* track) const;
+    
+    //variables accessible to derived classes
+    std::vector<float>     m_etaBounds;           //!< eta intervals for internal monitoring
+    mutable std::mutex m_statMutex;
+    mutable Counter  m_stat ATLAS_THREAD_SAFE;
+    /**Scoring tool
+       This tool is used to 'score' the tracks, i.e. to quantify what a good track is.
+       @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"};
+     /** brem recovery mode with brem fit ? */
+    bool  m_tryBremFit{};
+    bool  m_caloSeededBrem{};
+    float m_pTminBrem{1000.};
+    bool m_suppressHoleSearch{};
+    // for track refit
+    bool m_suppressTrackFit{};
+    bool m_refitPrds{};
+    /** by default tracks at input get refitted */
+    bool m_forceRefit{true};
+    
+    /** read in as an integer and convert to particle hypothesis */
+    /** reference: /TrkEventPrimitives/ParticleHypothesis.h **/
+    int m_matEffects{3};//pion
+    Trk::ParticleHypothesis m_particleHypothesis{undefined};   
+  };
+}//namespace
+#endif
+
diff --git a/Tracking/TrkTools/TrkAmbiguityProcessor/src/AmbiguityProcessorUtility.cxx b/Tracking/TrkTools/TrkAmbiguityProcessor/src/AmbiguityProcessorUtility.cxx
new file mode 100644
index 0000000000000000000000000000000000000000..0ab7ba28597ff53cbd37898bd598b21f0ff5eaa9
--- /dev/null
+++ b/Tracking/TrkTools/TrkAmbiguityProcessor/src/AmbiguityProcessorUtility.cxx
@@ -0,0 +1,60 @@
+/*
+  Copyright (C) 2002-2020 CERN for the benefit of the ATLAS collaboration
+*/
+
+#include "AmbiguityProcessorUtility.h"
+#include "AthContainers/DataVector.h"
+#include "TrkTrack/TrackStateOnSurface.h"
+#include "TrkEventPrimitives/FitQuality.h"
+#include "TrkTrack/TrackInfo.h"
+#include "TrkTrack/Track.h"
+
+
+namespace AmbiguityProcessor{
+  TrackFilterCategory
+  categoriseTrack(const Trk::Track & track, const Trk::TrackScore & score, const bool dropDuplicates, const AssociationTool & associate, AssociationMap & map, DuplicationCheckSet & set){
+    if (score == 0) return  TrackFilterCategory::ScoreIsZero;
+    if (dropDuplicates){
+      if(const auto & [p, uniqueTrack] = set.insert(associate->getPrdsOnTrack( map, track)); not uniqueTrack) return TrackFilterCategory::TrackIsDuplicate;
+    }
+    return TrackFilterCategory::TrackAccepted;
+  }
+  //
+  float 
+  calculateFitQuality(const Trk::Track & track){
+    float result{0.0};
+    if  (const auto quality=track.fitQuality(); quality and quality->numberDoF()>0 ){ 
+      result = quality->chiSquared()/quality->numberDoF();
+    }
+    return result; 
+  }
+  //
+  std::unique_ptr<Trk::Track>
+  createNewFitQualityTrack(const Trk::Track & track){
+    double reXi2 = 0.; 
+    int nDF = 0;
+    const DataVector<const Trk::TrackStateOnSurface>* tsos = track.trackStateOnSurfaces();
+    DataVector<const Trk::TrackStateOnSurface>* vecTsos = new DataVector<const Trk::TrackStateOnSurface>();
+    // loop over TSOS, copy TSOS and push into vector
+    DataVector<const Trk::TrackStateOnSurface>::const_iterator iTsos    = tsos->begin();
+    DataVector<const Trk::TrackStateOnSurface>::const_iterator iTsosEnd = tsos->end(); 
+    for ( ; iTsos != iTsosEnd ; ++iTsos) {
+      const Trk::TrackStateOnSurface* newTsos = new Trk::TrackStateOnSurface(**iTsos);
+      vecTsos->push_back(newTsos);
+      if((*iTsos)->type(Trk::TrackStateOnSurface::Measurement)){  //Get the chi2 and number of hits
+        if ((*iTsos)->fitQualityOnSurface()) {
+          reXi2 += (*iTsos)->fitQualityOnSurface()->chiSquared();
+          nDF   += (*iTsos)->fitQualityOnSurface()->numberDoF();
+        }
+      }
+    }
+    Trk::FitQuality* fq = new Trk::FitQuality(reXi2,nDF-5);
+    Trk::TrackInfo info;
+    info.addPatternRecoAndProperties(track.info());
+    Trk::TrackInfo newInfo;
+    newInfo.setPatternRecognitionInfo(Trk::TrackInfo::SimpleAmbiguityProcessorTool);
+    info.addPatternReco(newInfo); 
+    return std::make_unique<Trk::Track>(info, vecTsos, fq);
+  }
+
+}
diff --git a/Tracking/TrkTools/TrkAmbiguityProcessor/src/AmbiguityProcessorUtility.h b/Tracking/TrkTools/TrkAmbiguityProcessor/src/AmbiguityProcessorUtility.h
new file mode 100644
index 0000000000000000000000000000000000000000..94bec981350da102901b6fe724fdbecbb82add14
--- /dev/null
+++ b/Tracking/TrkTools/TrkAmbiguityProcessor/src/AmbiguityProcessorUtility.h
@@ -0,0 +1,41 @@
+/*
+  Copyright (C) 2002-2020 CERN for the benefit of the ATLAS collaboration
+*/
+#ifndef AmbiguityProcessorUtility_h
+#define AmbiguityProcessorUtility_h
+
+#include "GaudiKernel/ToolHandle.h"
+#include "TrkToolInterfaces/IPRDtoTrackMapTool.h"
+#include "TrkEventUtils/PRDtoTrackMap.h"
+#include "TrkEventPrimitives/TrackScore.h"
+#include <vector>
+#include <set>
+#include <array>
+#include <string>
+#include <memory> //unique_ptr
+
+namespace Trk{
+  class Track;
+  class PrepRawData;
+}
+
+
+namespace AmbiguityProcessor{
+  enum TrackFilterCategory{ ScoreIsZero, TrackIsDuplicate, TrackAccepted, nCategories};
+  using AssociationTool = ToolHandle<Trk::IPRDtoTrackMapTool>;
+  using AssociationMap = Trk::PRDtoTrackMap;
+  using DuplicationCheckSet = std::set<std::vector<const Trk::PrepRawData*>> ;
+  //
+  //categorise the track as zero-score, duplicate or 'accepted'
+  TrackFilterCategory
+  categoriseTrack(const Trk::Track & track, const Trk::TrackScore & score, const bool dropDuplicates, const AssociationTool &, AssociationMap &, DuplicationCheckSet &);
+  //
+  //give appropriate text for each category
+  const static std::array<std::string , nCategories> debugMessage {"Score is zero, reject.", "Track is duplicate, reject.", "Track is accepted."};
+  //calculate a simple chi^2/ndof
+  float calculateFitQuality(const Trk::Track & track);
+  //create a track from a new FitQuality object looping over track-state-on-surfaces to calculate
+  std::unique_ptr<Trk::Track> createNewFitQualityTrack(const Trk::Track & track);
+}//namespace
+
+#endif
diff --git a/Tracking/TrkTools/TrkAmbiguityProcessor/src/DenseEnvironmentsAmbiguityProcessorTool.cxx b/Tracking/TrkTools/TrkAmbiguityProcessor/src/DenseEnvironmentsAmbiguityProcessorTool.cxx
index 0be1d65fef6fd94b47965be988d78ac8dd64479d..e6224bce632a627f675b38501de1df7c260f4bbd 100644
--- a/Tracking/TrkTools/TrkAmbiguityProcessor/src/DenseEnvironmentsAmbiguityProcessorTool.cxx
+++ b/Tracking/TrkTools/TrkAmbiguityProcessor/src/DenseEnvironmentsAmbiguityProcessorTool.cxx
@@ -17,6 +17,7 @@
 #include "InDetPrepRawData/PixelCluster.h"
 #include "InDetPrepRawData/SCT_Cluster.h"
 #include "InDetIdentifier/PixelID.h"
+#include "AmbiguityProcessorUtility.h"
 #include <cmath>
 #include <iterator>
 
@@ -48,20 +49,15 @@ Trk::DenseEnvironmentsAmbiguityProcessorTool::DenseEnvironmentsAmbiguityProcesso
                                 const std::string& n,
                                 const IInterface*  p )
   :
-  AthAlgTool(t,n,p),
-  m_particleHypothesis{undefined},
-  m_scoringTool("Trk::TrackScoringTool/TrackScoringTool"),
+  AmbiguityProcessorBase(t,n,p),
   m_extrapolatorTool("Trk::Extrapolator/AtlasExtrapolator"),
-  m_selectionTool("InDet::InDetDenseEnvAmbiTrackSelectionTool/InDetAmbiTrackSelectionTool"),
-  m_etaBounds{0.8, 1.6, 2.5, 4.0},
-  m_stat(m_etaBounds){
+  m_selectionTool("InDet::InDetDenseEnvAmbiTrackSelectionTool/InDetAmbiTrackSelectionTool"){
   // statitics stuff
 
   m_fitterTool.push_back("Trk::KalmanFitter/InDetTrackFitter");
 
   declareInterface<ITrackAmbiguityProcessorTool>(this);
   declareProperty("RefitPrds"            , m_refitPrds          = true); //  True to allow for updated NN information to be taken into account
-  declareProperty("applydRcorrection"    , m_applydRcorrection  = false);
   declareProperty("MatEffects"           , m_matEffects         = 3); // pion
   declareProperty("ScoringTool"          , m_scoringTool);
   declareProperty("SelectionTool"        , m_selectionTool);
@@ -123,11 +119,15 @@ Trk::DenseEnvironmentsAmbiguityProcessorTool::initialize(){
      ATH_CHECK(m_dRMap.initialize() );
   }
 
-  if (m_etaBounds.size() != TrackStat::nRegions) {
-     ATH_MSG_FATAL("There must be exactly " << (TrackStat::nRegions) << " eta bounds but "
+  if (m_etaBounds.size() != Counter::nRegions) {
+     ATH_MSG_FATAL("There must be exactly " << (Counter::nRegions) << " eta bounds but "
                    << m_etaBounds.size() << " are set." );
      return StatusCode::FAILURE;
   }
+  ATH_MSG_INFO(m_fitterTool.size()<<" fitters was/were input");
+  for(const auto & i:m_fitterTool){
+    ATH_MSG_INFO(i.name());
+  }
   return sc;
 }
 //==================================================================================================
@@ -164,7 +164,7 @@ Trk::DenseEnvironmentsAmbiguityProcessorTool::process(const TracksScores *trackS
         ATH_MSG_ERROR("Failed to retrieve prd to track map " << m_assoMapName.key() );
      }
   }
-  std::vector<std::unique_ptr<const Trk::Track> > cleanup_tracks;
+  std::vector<std::unique_ptr<const Trk::Track> > trackDustbin;
   reloadHadROIs();
   // going to do simple algorithm for now:
   // - take track with highest score
@@ -173,112 +173,35 @@ Trk::DenseEnvironmentsAmbiguityProcessorTool::process(const TracksScores *trackS
   ATH_MSG_DEBUG ("Solving Tracks");
   TrackCollection* finalTracks = new TrackCollection;
   {
-     TrackStat stat(m_etaBounds);
+     Counter stat(m_etaBounds);
      stat.newEvent();
-     solveTracks(*trackScoreTrackMap, *prdToTrackMap, *finalTracks, cleanup_tracks,stat);
+     solveTracks(*trackScoreTrackMap, *prdToTrackMap, *finalTracks, trackDustbin,stat);
      {
         std::lock_guard<std::mutex> lock(m_statMutex);
         m_stat += stat;
      }
   }
-  if(m_applydRcorrection){
-    ATH_MSG_ERROR("applydRcorrection is going to be removed.");
-  }
   return finalTracks;
 }
 
 
-//==================================================================================================
-// taking ownership of input track
-void 
-Trk::DenseEnvironmentsAmbiguityProcessorTool::addTrack(Trk::Track* track, const bool fitted,
-                                                            std::multimap<float, TrackPtr > &scoreTrackFitflagMap,
-                                                            const Trk::PRDtoTrackMap &prdToTrackMap,
-                                                            std::vector<std::unique_ptr<const Trk::Track> >& cleanup_tracks,
-                                                            TrackStat &stat) const{
-  // compute score
-  TrackScore score;
-  bool suppressHoleSearch = fitted ? m_suppressHoleSearch : true;
-  ATH_MSG_DEBUG ("addTrack()::Fitted             "<< fitted);
-  if (m_trackSummaryTool.isEnabled()) {
-    m_trackSummaryTool->computeAndReplaceTrackSummary(*track,
-                                                       &prdToTrackMap,
-                                                       suppressHoleSearch);
-  }
-  // @TODO create track summary for track
-  score = m_scoringTool->score( *track, suppressHoleSearch );
-  // do we accept the track ?
-  if (score!=0){
-    ATH_MSG_DEBUG ("Track  ("<< track <<") has score "<<score);
-    // add track to map, map is sorted small to big !
-    scoreTrackFitflagMap.emplace(-score, TrackPtr(track, fitted) );
-    return;
-  }
-  // do we try to recover the track ?
-  if ( fitted && m_tryBremFit &&
-    !track->info().trackProperties(Trk::TrackInfo::BremFit) &&
-    track->trackParameters()->front()->pT() > m_pTminBrem &&
-    (!m_caloSeededBrem || track->info().patternRecoInfo(Trk::TrackInfo::TrackInCaloROI))){
-    //
-    ATH_MSG_DEBUG ("Track score is zero, try to recover it via brem fit");
-    // run track fit using electron hypothesis
-    Trk::Track* bremTrack = fit(*track,true,Trk::electron);
-    if (!bremTrack){
-      ATH_MSG_DEBUG ("Brem refit failed, drop track");
-      stat.incrementCounterByRegion(EStatType::kNscoreZeroBremRefitFailed,track);
-      stat.incrementCounterByRegion(EStatType::kNfailedFits,track);
-      // clean up
-      cleanup_tracks.push_back(std::unique_ptr<const Trk::Track>(track) );
-      track=nullptr;
-    } else {
-      if (m_trackSummaryTool.isEnabled()) {
-         m_trackSummaryTool->computeAndReplaceTrackSummary(*bremTrack,&prdToTrackMap,m_suppressHoleSearch);
-      }
-      stat.incrementCounterByRegion(EStatType::kNgoodFits,bremTrack);
-      // rerun score
-      score = m_scoringTool->score( *bremTrack, suppressHoleSearch );
-      cleanup_tracks.push_back(std::unique_ptr<const Trk::Track>(track) );
-      track=nullptr;
-      // do we accept the track ?
-      if (score!=0){
-        ATH_MSG_DEBUG ("Brem refit successful, recovered track  ("<< track <<") has score "<<score);
-        stat.incrementCounterByRegion(EStatType::kNscoreZeroBremRefit,bremTrack);
-        // add track to map, map is sorted small to big !
-        scoreTrackFitflagMap.emplace( -score, TrackPtr(bremTrack, true) );
-        return;
-      } 
-        ATH_MSG_DEBUG ("Brem refit gave still track score zero, reject it");
-        stat.incrementCounterByRegion(EStatType::kNscoreZeroBremRefitScoreZero,bremTrack);
-        // clean up
-        cleanup_tracks.push_back(std::unique_ptr<const Trk::Track>(bremTrack) );
-      
-    }
-  } else {
-    ATH_MSG_DEBUG ("Track score is zero, reject it");
-    stat.incrementCounterByRegion(EStatType::kNscoreZero,track);
-    // @TODO can delete this track ?
-    cleanup_tracks.push_back(std::unique_ptr<const Trk::Track>(track) );
-  }
-}
-//==================================================================================================
-
 
 void 
 Trk::DenseEnvironmentsAmbiguityProcessorTool::solveTracks(const TracksScores &trackScoreTrackMap,
                                                                Trk::PRDtoTrackMap &prdToTrackMap,
                                                                TrackCollection &finalTracks,
-                                                               std::vector<std::unique_ptr<const Trk::Track> > &cleanup_tracks,
-                                                               TrackStat &stat) const{
-  std::multimap<float, TrackPtr  > scoreTrackFitflagMap;
+                                                               std::vector<std::unique_ptr<const Trk::Track> > &trackDustbin,
+                                                               Counter &stat) const{
+  TrackScoreMap scoreTrackFitflagMap;
   for(const std::pair< const Trk::Track *, float> &scoreTrack: trackScoreTrackMap){
      scoreTrackFitflagMap.emplace(scoreTrack.second, TrackPtr(scoreTrack.first) );
-     stat.incrementCounterByRegion(EStatType::kNcandidates,scoreTrack.first);
+     stat.incrementCounterByRegion(CounterIndex::kNcandidates,scoreTrack.first);
   }
   ATH_MSG_DEBUG ("Starting to solve tracks");
   // now loop as long as map is not empty
   while ( !scoreTrackFitflagMap.empty() ){
     // get current best candidate 
-    std::multimap<float, TrackPtr >::iterator itnext = scoreTrackFitflagMap.begin();
+    TrackScoreMap::iterator itnext = scoreTrackFitflagMap.begin();
     TrackPtr atrack( std::move(itnext->second) );
     float ascore =  itnext->first;
     scoreTrackFitflagMap.erase(itnext);
@@ -292,15 +215,12 @@ Trk::DenseEnvironmentsAmbiguityProcessorTool::solveTracks(const TracksScores &tr
     if (keepOriginal && atrack.fitted()){
       // track can be kept as is and is already fitted
       ATH_MSG_DEBUG ("Accepted track "<<atrack.track()<<"\t has score "<<-ascore);
-      stat.incrementCounterByRegion(EStatType::kNaccepted, atrack.track() );
+      stat.incrementCounterByRegion(CounterIndex::kNaccepted, atrack.track() );
       if (m_tryBremFit && atrack.track()->info().trackProperties(Trk::TrackInfo::BremFit)) {
-        stat.incrementCounterByRegion(EStatType::kNacceptedBrem,atrack.track());
+        stat.incrementCounterByRegion(CounterIndex::kNacceptedBrem,atrack.track());
       }
       //Compute the fitQuality
-      double fitQual = 0;
-      if  (atrack->fitQuality() && atrack->fitQuality()->numberDoF()>0 ){ 
-         fitQual = atrack->fitQuality()->chiSquared()/atrack->fitQuality()->numberDoF();
-      }
+      const float fitQual = AmbiguityProcessor::calculateFitQuality(*atrack);
       if(fitQual > 1.3 && decideIfInHighPtBROI(atrack.track())){
         std::unique_ptr<Trk::Track> refittedTrack( refitTracksFromB(atrack.track(), fitQual)); //Q: Is there the case  atrack == refittedTrack ?
         if(refittedTrack){
@@ -311,7 +231,7 @@ Trk::DenseEnvironmentsAmbiguityProcessorTool::solveTracks(const TracksScores &tr
           // add to output list
           finalTracks.push_back( refittedTrack.release() );
           if (atrack.newTrack()) {
-             cleanup_tracks.push_back(std::unique_ptr<const Trk::Track>(atrack.release()) );
+             trackDustbin.emplace_back(atrack.release());
           }
         } else {
           // add track to PRD_AssociationTool
@@ -333,30 +253,30 @@ Trk::DenseEnvironmentsAmbiguityProcessorTool::solveTracks(const TracksScores &tr
     } else if ( keepOriginal){
       // track can be kept as is, but is not yet fitted
       ATH_MSG_DEBUG ("Good track("<< atrack.track() << ") but need to fit this track first, score, add it into map again and retry ! ");
-      Trk::Track *refittedTrack = refitTrack(atrack.track(),prdToTrackMap, stat);
-      if(refittedTrack) {
-         addTrack( refittedTrack, true , scoreTrackFitflagMap, prdToTrackMap, cleanup_tracks, stat);
+      Trk::Track * pRefittedTrack = refitTrack(atrack.track(),prdToTrackMap, stat);
+      if(pRefittedTrack) {
+         addTrack( pRefittedTrack, true , scoreTrackFitflagMap, prdToTrackMap, trackDustbin, stat);
       }
       // remove original copy, but delay removal since some pointer to it or its constituents may still be in used
       if (atrack.newTrack()) {
-         cleanup_tracks.push_back(std::unique_ptr<const Trk::Track>(atrack.release()) );
+         trackDustbin.emplace_back(atrack.release());
       }
     } else if ( cleanedTrack ) {//cleanedTrack != atrack
       ATH_MSG_DEBUG ("Candidate excluded, add subtrack to map. Track "<<cleanedTrack.get());
-      stat.incrementCounterByRegion(EStatType::kNsubTrack,cleanedTrack.get());
+      stat.incrementCounterByRegion(CounterIndex::kNsubTrack,cleanedTrack.get());
       // for this case clenedTrack is a new created object.
-      addTrack(cleanedTrack.release(), false, scoreTrackFitflagMap, prdToTrackMap, cleanup_tracks, stat);
+      addTrack(cleanedTrack.release(), false, scoreTrackFitflagMap, prdToTrackMap, trackDustbin, stat);
       // remove original copy, but delay removal since some pointer to it or its constituents may still be in used
       if (atrack.newTrack()) {
-         cleanup_tracks.push_back(std::unique_ptr<const Trk::Track>(atrack.release()) );
+         trackDustbin.emplace_back(atrack.release() );
       }
     } else {
       // track should be discarded
       ATH_MSG_DEBUG ("Track "<< atrack.track() << " is excluded, no subtrack, reject");
-      stat.incrementCounterByRegion(EStatType::kNnoSubTrack,atrack.track());
+      stat.incrementCounterByRegion(CounterIndex::kNnoSubTrack,atrack.track());
       // remove original copy, but delay removal since some pointer to it or its constituents may still be in used
       if (atrack.newTrack()) {
-        cleanup_tracks.push_back(std::unique_ptr<const Trk::Track>(atrack.release()) );
+        trackDustbin.emplace_back(atrack.release());
       }
     }
   }
@@ -365,62 +285,12 @@ Trk::DenseEnvironmentsAmbiguityProcessorTool::solveTracks(const TracksScores &tr
 
 
 
-//==================================================================================================
-Trk::Track* Trk::DenseEnvironmentsAmbiguityProcessorTool::refitTrack( const Trk::Track* track,
-                                                                      Trk::PRDtoTrackMap &prdToTrackMap,
-                                                  TrackStat &stat) const{
-  Trk::Track* newTrack = nullptr;
-  if (!m_suppressTrackFit){
-    if (m_refitPrds) {
-      // simple case, fit PRD directly
-      ATH_MSG_VERBOSE ("Refit track "<<track<<" from PRDs");
-      newTrack = refitPrds (track,prdToTrackMap, stat);
-    }else {
-      // ok, we fit ROTs
-      ATH_MSG_VERBOSE ("Refit track "<<track<<" from ROTs");
-      newTrack = refitRots (track,stat);
-    }
-  } else {
-    double reXi2 = 0.; 
-    int nDF = 0;
-    const DataVector<const TrackStateOnSurface>* tsos = track->trackStateOnSurfaces();
-    DataVector<const TrackStateOnSurface>* vecTsos = new DataVector<const TrackStateOnSurface>();
-    // loop over TSOS, copy TSOS and push into vector
-    DataVector<const TrackStateOnSurface>::const_iterator iTsos    = tsos->begin();
-    DataVector<const TrackStateOnSurface>::const_iterator iTsosEnd = tsos->end(); 
-    for ( ; iTsos != iTsosEnd ; ++iTsos) {
-      const TrackStateOnSurface* newTsos = new TrackStateOnSurface(**iTsos);
-      vecTsos->push_back(newTsos);
-      if((*iTsos)->type(Trk::TrackStateOnSurface::Measurement)){  //Get the chi2 and number of hits
-        if ((*iTsos)->fitQualityOnSurface()) {
-          reXi2 += (*iTsos)->fitQualityOnSurface()->chiSquared();
-          nDF   += (*iTsos)->fitQualityOnSurface()->numberDoF();
-        }
-      }
-    }
-    Trk::FitQuality* fq = new Trk::FitQuality(reXi2,nDF-5);
-    Trk::TrackInfo info;
-    info.addPatternRecoAndProperties(track->info());
-    Trk::TrackInfo newInfo;
-    newInfo.setPatternRecognitionInfo(Trk::TrackInfo::SimpleAmbiguityProcessorTool);
-    info.addPatternReco(newInfo); 
-    newTrack = new Trk::Track(info, vecTsos, fq);  
-  }
-  
-  if (newTrack!=nullptr) {
-    ATH_MSG_DEBUG ("New track "<<newTrack<<" successfully fitted from "<<track);
-  } else { 
-    ATH_MSG_DEBUG ("Fit failed !");
-  }  
-  return newTrack;
-}
-
 //==================================================================================================
 
 Trk::Track* 
 Trk::DenseEnvironmentsAmbiguityProcessorTool::refitPrds( const Trk::Track* track,
                                                  Trk::PRDtoTrackMap &prdToTrackMap,
-                                                 TrackStat &stat) const{
+                                                 Counter &stat) const{
   // get vector of PRDs
   // @TODO ensured that prds on track are registered for this track ?
   const auto & prds = m_assoTool->getPrdsOnTrack(prdToTrackMap,*track);
@@ -429,86 +299,38 @@ Trk::DenseEnvironmentsAmbiguityProcessorTool::refitPrds( const Trk::Track* track
     return nullptr;
   }
   ATH_MSG_VERBOSE ("Track "<<track<<"\t has "<<prds.size()<<"\t PRDs");
-  const TrackParameters* par = track->perigeeParameters();
-  if (par==nullptr) {
-    ATH_MSG_DEBUG ("Track ("<<track<<") has no perigee! Try any other ?");
-    par = track->trackParameters()->front();
-    if (par==nullptr) {
-      ATH_MSG_DEBUG ("Track ("<<track<<") has no Track Parameters ! No refit !");
-      return nullptr;
-    }
-  }
+  const TrackParameters* par = getTrackParameters(track);
+  if (not par) return nullptr;
+  //
   // refit using first parameter, do outliers
-  Trk::Track* newTrack = nullptr;
-  if (m_tryBremFit && track->info().trackProperties(Trk::TrackInfo::BremFit)){
-    stat.incrementCounterByRegion(EStatType::kNbremFits,track);
+  std::unique_ptr<Trk::Track> newTrack;
+  if (m_tryBremFit and track->info().trackProperties(Trk::TrackInfo::BremFit)){
+    stat.incrementCounterByRegion(CounterIndex::kNbremFits,track);
     ATH_MSG_VERBOSE ("Brem track, refit with electron brem fit");
-    // TODO revert once GlobalChi2Fitter properly handles brem fits when 
-    //      starting from prds
+    //revert once GlobalChi2Fitter properly handles brem fits when starting from prds
     // newTrack = fit(prds, *par, true, Trk::electron);
-    newTrack = fit(*track, true, Trk::electron);
+    newTrack = doBremRefit(*track);
   } else {
-    stat.incrementCounterByRegion(EStatType::kNfits,track);
+    stat.incrementCounterByRegion(CounterIndex::kNfits,track);
     ATH_MSG_VERBOSE ("Normal track, refit");
     newTrack = fit(prds, *par, true, m_particleHypothesis);
-    if (!newTrack && m_tryBremFit && par->pT() > m_pTminBrem &&
-  (!m_caloSeededBrem || track->info().patternRecoInfo(Trk::TrackInfo::TrackInCaloROI)))
-    {
-      stat.incrementCounterByRegion(EStatType::kNrecoveryBremFits,track);
+    if ((not newTrack) and shouldTryBremRecovery(*track, par)){
+      stat.incrementCounterByRegion(CounterIndex::kNrecoveryBremFits,track);
       ATH_MSG_VERBOSE ("Normal fit failed, try brem recovery");
-      // TODO revert once GlobalChi2Fitter properly handles brem fits when 
-      //      starting from prds
-      // newTrack = fit(prds, *par, true, Trk::electron);
-      newTrack = fit(*track, true, Trk::electron);
+      //revert once GlobalChi2Fitter properly handles brem fits when starting from prds
+      //newTrack = fit(prds, *par, true, Trk::electron);
+      newTrack = doBremRefit(*track);
     }
   }
   if(newTrack) {
-    stat.incrementCounterByRegion(EStatType::kNgoodFits,newTrack);
+    stat.incrementCounterByRegion(CounterIndex::kNgoodFits,newTrack.get());
     //keeping the track of previously accumulated TrackInfo
     const Trk::TrackInfo& originalInfo = track->info();
     newTrack->info().addPatternReco(originalInfo);
   } else {
-     stat.incrementCounterByRegion(EStatType::kNfailedFits,track);
+     stat.incrementCounterByRegion(CounterIndex::kNfailedFits,track);
   }
-  return newTrack;
-}
-
-//==================================================================================================
-
-Trk::Track* 
-Trk::DenseEnvironmentsAmbiguityProcessorTool::refitRots(const Trk::Track* track,
-                                                TrackStat &stat) const{
-  ATH_MSG_VERBOSE ("Refit track "<<track);
-  // refit using first parameter, do outliers
-  Trk::Track* newTrack = nullptr;
-  if (m_tryBremFit &&
-      track->info().trackProperties(Trk::TrackInfo::BremFit)){
-    stat.incrementCounterByRegion(EStatType::kNbremFits,track);
-    ATH_MSG_VERBOSE ("Brem track, refit with electron brem fit");
-    newTrack = fit(*track, true, Trk::electron);
-  } else {
-    stat.incrementCounterByRegion(EStatType::kNfits,track);
-    ATH_MSG_VERBOSE ("Normal track, refit");
-    newTrack = fit(*track, true, m_particleHypothesis);
-    if (!newTrack && m_tryBremFit &&
-        track->trackParameters()->front()->pT() > m_pTminBrem &&
-        (!m_caloSeededBrem || track->info().patternRecoInfo(Trk::TrackInfo::TrackInCaloROI)))
-    {
-      stat.incrementCounterByRegion(EStatType::kNrecoveryBremFits,track);
-      ATH_MSG_VERBOSE ("Normal fit failed, try brem recovery");
-      newTrack = fit(*track, true, Trk::electron);
-    }
-  }
-
-  if(newTrack){
-    stat.incrementCounterByRegion(EStatType::kNgoodFits,newTrack);
-    //keeping the track of previously accumulated TrackInfo
-    const Trk::TrackInfo& originalInfo = track->info();
-    newTrack->info().addPatternReco(originalInfo);
-  } else {
-    stat.incrementCounterByRegion(EStatType::kNfailedFits,track);
-  }
-  return newTrack;
+  return newTrack.release();
 }
 
 
@@ -602,9 +424,10 @@ Trk::DenseEnvironmentsAmbiguityProcessorTool::storeTrkDistanceMapdR( TrackCollec
          // if we already have a dR for this prd, we update it, if current value is smaller
          if (!ret.second) {
             InDet::DRMap::iterator it{dRMapHandle->find(pixel)};
-            if(std::sqrt(std::pow((*it).second.first,2)+std::pow((*it).second.second,2)) > (float)mindR) {
-                (*it).second.first  = (float)mindX;
-                (*it).second.second = (float)mindZ;
+            auto &[x, z] = it->second;
+            if(std::sqrt(x * x + z * z) > (float)mindR) {
+                x = (float) mindX;
+                z = (float) mindZ;
 	        }
          }
       }
@@ -717,19 +540,19 @@ Trk::DenseEnvironmentsAmbiguityProcessorTool::refitTracksFromB(const Trk::Track*
   }  
   std::vector<const Trk::MeasurementBase*> measurementSet{};
   //store all silicon measurements into the measurementset
-  DataVector<const Trk::TrackStateOnSurface>::const_iterator trackStateOnSurface = track->trackStateOnSurfaces()->begin();
-  for ( ; trackStateOnSurface != track->trackStateOnSurfaces()->end(); ++trackStateOnSurface ) {
-    if ( !(*trackStateOnSurface) ){
+  DataVector<const Trk::TrackStateOnSurface>::const_iterator TrackStateOnSurface = track->trackStateOnSurfaces()->begin();
+  for ( ; TrackStateOnSurface != track->trackStateOnSurfaces()->end(); ++TrackStateOnSurface ) {
+    if ( !(*TrackStateOnSurface) ){
       ATH_MSG_WARNING( "This track contains an empty MeasurementBase object that won't be included in the fit" );
       continue;
     }
-    if ( (*trackStateOnSurface)->measurementOnTrack() ){
-      if ( (*trackStateOnSurface)->type( Trk::TrackStateOnSurface::Measurement) ){
-        const Trk::RIO_OnTrack* rio = dynamic_cast <const Trk::RIO_OnTrack*>( (*trackStateOnSurface)->measurementOnTrack() );
+    if ( (*TrackStateOnSurface)->measurementOnTrack() ){
+      if ( (*TrackStateOnSurface)->type( Trk::TrackStateOnSurface::Measurement) ){
+        const Trk::RIO_OnTrack* rio = dynamic_cast <const Trk::RIO_OnTrack*>( (*TrackStateOnSurface)->measurementOnTrack() );
         if (rio != nullptr) {
           const Identifier& surfaceID = (rio->identify()) ;                            
           if(m_idHelper->is_pixel(surfaceID)|| m_idHelper->is_sct(surfaceID)) {
-            measurementSet.push_back( (*trackStateOnSurface)->measurementOnTrack() );
+            measurementSet.push_back( (*TrackStateOnSurface)->measurementOnTrack() );
           }
         }
       }
@@ -740,13 +563,13 @@ Trk::DenseEnvironmentsAmbiguityProcessorTool::refitTracksFromB(const Trk::Track*
   while (true){
     removeInnerHits(measurementSet); 
     if(measurementSet.size()>4){
-      Trk::Track* refittedTrack = fit(measurementSet,*par,true,Trk::pion);
+      auto pRefittedTrack{fit(measurementSet,*par,true,Trk::pion)};
       double fitQualPostRefit = 10;
-      if  (refittedTrack && refittedTrack->fitQuality() && refittedTrack->fitQuality()->numberDoF()!=0 ) 
-        fitQualPostRefit = refittedTrack->fitQuality()->chiSquared()/refittedTrack->fitQuality()->numberDoF(); 
+      if  (pRefittedTrack && pRefittedTrack->fitQuality() && pRefittedTrack->fitQuality()->numberDoF()!=0 ) 
+        fitQualPostRefit = pRefittedTrack->fitQuality()->chiSquared()/pRefittedTrack->fitQuality()->numberDoF(); 
       if (fitQualityOriginal/fitQualPostRefit > 1){
         if ( fitQualityOriginal/fitQualPostRefit > 1.2){
-          return refittedTrack;
+          return pRefittedTrack.release();
         }
       }
       if (previousMeasSize == measurementSet.size()){
@@ -777,48 +600,53 @@ Trk::DenseEnvironmentsAmbiguityProcessorTool::dumpStat(MsgStream &out) const{
    out << __func__;
    out << "\n";
    out << "------------------------------------------------------------------------------------" << "\n";
-   out << "  Number of events processed      :   "<< m_stat.globalCount(TrackStat::nEvents) << "\n";
-   if (const auto nInvalid = m_stat.globalCount(TrackStat::nInvalidTracks); nInvalid>0) {
+   out << "  Number of events processed      :   "<< m_stat.globalCount(Counter::nEvents) << "\n";
+   if (const auto nInvalid = m_stat.globalCount(Counter::nInvalidTracks); nInvalid>0) {
       out << "  Number of invalid tracks        :   "<< nInvalid<< "\n";
    }
-   if (const auto nNoParams = m_stat.globalCount(TrackStat::nTracksWithoutParam); nNoParams>0) {
+   if (const auto nNoParams = m_stat.globalCount(Counter::nTracksWithoutParam); nNoParams>0) {
       out << "  Tracks without parameters       :   "<< nNoParams << "\n";
    }
    out << "  statistics by eta range          ------All---Barrel---Trans.-- Endcap-- Forwrd-- " << "\n";
    out << "------------------------------------------------------------------------------------" << "\n";
-   out << m_stat.dumpRegions( "  Number of candidates at input   :",    EStatType::kNcandidates,iw);
+   out << m_stat.dumpRegions( "  Number of candidates at input   :",    CounterIndex::kNcandidates,iw);
    out << "------------------------------------------------------------------------------------" << "\n";
-   out << m_stat.dumpRegions( "  candidates with good score      :",    EStatType::kNscoreOk,iw);
+   out << m_stat.dumpRegions( "  candidates with good score      :",    CounterIndex::kNscoreOk,iw);
    if (m_tryBremFit) {
-      out << m_stat.dumpRegions( "  + recovered after brem refit    :", EStatType::kNscoreZeroBremRefit,iw);
+      out << m_stat.dumpRegions( "  + recovered after brem refit    :", CounterIndex::kNscoreZeroBremRefit,iw);
    }
-   out << m_stat.dumpRegions( "  candidates rejected score 0     :",    EStatType::kNscoreZero,iw);
+   out << m_stat.dumpRegions( "  candidates rejected score 0     :",    CounterIndex::kNscoreZero,iw);
    if (m_tryBremFit) {
-      out << m_stat.dumpRegions( "  + m refit                       :", EStatType::kNscoreZeroBremRefitFailed,iw);
-      out << m_stat.dumpRegions( "  + rejected brem refit score 0   :", EStatType::kNscoreZeroBremRefitScoreZero,iw);
+      out << m_stat.dumpRegions( "  + m refit                       :", CounterIndex::kNscoreZeroBremRefitFailed,iw);
+      out << m_stat.dumpRegions( "  + rejected brem refit score 0   :", CounterIndex::kNscoreZeroBremRefitScoreZero,iw);
    }
    out << "------------------------------------------------------------------------------------" << "\n";
-   out << m_stat.dumpRegions( "  number of normal fits           :" ,   EStatType::kNfits,iw);
+   out << m_stat.dumpRegions( "  number of normal fits           :" ,   CounterIndex::kNfits,iw);
    if (m_tryBremFit) {
-      out << m_stat.dumpRegions( "  + 2nd brem fit for failed fit   :", EStatType::kNrecoveryBremFits,iw);
-      out << m_stat.dumpRegions( "  normal brem fits for electrons  :", EStatType::kNbremFits,iw);
+      out << m_stat.dumpRegions( "  + 2nd brem fit for failed fit   :", CounterIndex::kNrecoveryBremFits,iw);
+      out << m_stat.dumpRegions( "  normal brem fits for electrons  :", CounterIndex::kNbremFits,iw);
    }
    out << "------------------------------------------------------------------------------------" << "\n";
-   out << m_stat.dumpRegions( "  sum of succesful fits           :",    EStatType::kNgoodFits,iw);
-   out << m_stat.dumpRegions( "  sum of failed fits              :",    EStatType::kNfailedFits,iw);
+   out << m_stat.dumpRegions( "  sum of succesful fits           :",    CounterIndex::kNgoodFits,iw);
+   out << m_stat.dumpRegions( "  sum of failed fits              :",    CounterIndex::kNfailedFits,iw);
    out << "------------------------------------------------------------------------------------" << "\n";
-   out << m_stat.dumpRegions( "  Number of subtracks created     :",    EStatType::kNsubTrack,iw);
-   out << m_stat.dumpRegions( "  Number of candidates excluded   :",    EStatType::kNnoSubTrack,iw);
+   out << m_stat.dumpRegions( "  Number of subtracks created     :",    CounterIndex::kNsubTrack,iw);
+   out << m_stat.dumpRegions( "  Number of candidates excluded   :",    CounterIndex::kNnoSubTrack,iw);
    out << "------------------------------------------------------------------------------------" << "\n";
-   out << m_stat.dumpRegions( "  Number of tracks accepted       :",    EStatType::kNaccepted,iw);
+   out << m_stat.dumpRegions( "  Number of tracks accepted       :",    CounterIndex::kNaccepted,iw);
    if (m_tryBremFit) {
-      out << m_stat.dumpRegions( "  including number of brem fits   :", EStatType::kNacceptedBrem,iw);
+      out << m_stat.dumpRegions( "  including number of brem fits   :", CounterIndex::kNacceptedBrem,iw);
    }
    out << "------------------------------------------------------------------------------------" << "\n";
    out << std::setiosflags(std::ios::fixed | std::ios::showpoint) << std::setprecision(2)
-       << "    definition: ( 0.0 < Barrel < " << m_etaBounds[TrackStat::iBarrel] << " < Transition < " << m_etaBounds[TrackStat::iTransi]
-       << " < Endcap < " << m_etaBounds[TrackStat::iEndcap] << " < Forward < " << m_etaBounds[TrackStat::iForwrd] << " )" << "\n";
+       << "    definition: ( 0.0 < Barrel < " << m_etaBounds[Counter::iBarrel] << " < Transition < " << m_etaBounds[Counter::iTransi]
+       << " < Endcap < " << m_etaBounds[Counter::iEndcap] << " < Forward < " << m_etaBounds[Counter::iForwrd] << " )" << "\n";
    out << "------------------------------------------------------------------------------------" << "\n";
    out << std::setprecision(ss);
-  }
+}
+  
+std::unique_ptr<Trk::Track>
+Trk::DenseEnvironmentsAmbiguityProcessorTool::doBremRefit(const Trk::Track & track) const{
+  return std::unique_ptr<Trk::Track>(fit(track,true,Trk::electron));
+}
 
diff --git a/Tracking/TrkTools/TrkAmbiguityProcessor/src/DenseEnvironmentsAmbiguityProcessorTool.h b/Tracking/TrkTools/TrkAmbiguityProcessor/src/DenseEnvironmentsAmbiguityProcessorTool.h
index 178af39e0e4d5fca62a75a4bd2fd3643870dae13..2acd36c3019b2f897fbd238bb1045c0165ef67c3 100644
--- a/Tracking/TrkTools/TrkAmbiguityProcessor/src/DenseEnvironmentsAmbiguityProcessorTool.h
+++ b/Tracking/TrkTools/TrkAmbiguityProcessor/src/DenseEnvironmentsAmbiguityProcessorTool.h
@@ -5,11 +5,7 @@
 #ifndef DenseEnvironmentsAmbiguityProcessorTool_H
 #define DenseEnvironmentsAmbiguityProcessorTool_H
 
-#include "AthenaBaseComps/AthAlgTool.h"
-#include "GaudiKernel/ToolHandle.h"
-
-#include "TrkToolInterfaces/ITrackAmbiguityProcessorTool.h"
-#include "TrkEventPrimitives/TrackScore.h"
+#include "AmbiguityProcessorBase.h"
 #include "TrkFitterInterfaces/ITrackFitter.h"
 #include "TrkToolInterfaces/IAmbiTrackSelectionTool.h"
 #include "InDetPrepRawData/PixelGangedClusterAmbiguities.h"
@@ -18,7 +14,6 @@
 
 #include "TrkToolInterfaces/IPRDtoTrackMapTool.h"
 #include "TrkEventUtils/PRDtoTrackMap.h"
-#include "TrkToolInterfaces/IExtendedTrackSummaryTool.h"
 
 //need to include the following, since its a typedef and can't be forward declared.
 #include "TrkTrack/TrackCollection.h"
@@ -30,7 +25,7 @@
 #include <map>
 #include <vector>
 
-#include "TrackPtr.h"
+
 
 
 class AtlasDetectorID;
@@ -43,34 +38,11 @@ namespace InDet{
 }
 
 namespace Trk {
-  class ITrackScoringTool;
   class ITruthToTrack;
   class IExtrapolator;
   //
-  class DenseEnvironmentsAmbiguityProcessorTool : public AthAlgTool, 
-        virtual public ITrackAmbiguityProcessorTool{
+  class DenseEnvironmentsAmbiguityProcessorTool : public AmbiguityProcessorBase{
   public:
-    enum class EStatType {
-      kNtracks,
-      kNinvalid,
-      kNcandidates,
-      kNscoreOk,
-      kNscoreZeroBremRefit,
-      kNscoreZeroBremRefitFailed,
-      kNscoreZeroBremRefitScoreZero,
-      kNscoreZero,
-      kNaccepted,
-      kNsubTrack,
-      kNnoSubTrack,
-      kNacceptedBrem,
-      kNbremFits,
-      kNfits,
-      kNrecoveryBremFits,
-      kNgoodFits,
-      kNfailedFits,
-      kNCounter
-    };
-  using TrackStat = AmbiCounter<EStatType>;
   // default methods
   DenseEnvironmentsAmbiguityProcessorTool(const std::string&,const std::string&,const IInterface*);
   virtual ~DenseEnvironmentsAmbiguityProcessorTool ();
@@ -93,81 +65,64 @@ namespace Trk {
   virtual void statistics() override;
   
   private:
-    //transfer ownership
-    void addTrack(Track* track, const bool fitted,
-                  std::multimap<float, TrackPtr > &scoreTrackFitflagMap,
-                  const Trk::PRDtoTrackMap &prd_to_track_map,
-                  std::vector<std::unique_ptr<const Trk::Track> >& cleanup_tracks,
-                  TrackStat &stat) const;
-
     void solveTracks(const TracksScores& trackScoreTrackMap,
                      Trk::PRDtoTrackMap &prd_to_track_map,
                      TrackCollection &finalTracks,
-                     std::vector<std::unique_ptr<const Trk::Track> >& cleanup_tracks,
-                     TrackStat &stat) const;
+                     std::vector<std::unique_ptr<const Trk::Track> >& trackDustbin,
+                     Counter &stat) const;
 
-    /** refit track */
-    Track* refitTrack( const Trk::Track* track, Trk::PRDtoTrackMap &prd_to_track_map,
-    TrackStat &stat) const;
 
     /** refit PRDs */
-    Track* refitPrds( const Track* track, Trk::PRDtoTrackMap &prd_to_track_map,
-    TrackStat &stat) const;
+    Track* 
+    refitPrds( const Track* track, Trk::PRDtoTrackMap &prd_to_track_map,
+    Counter &stat) const override final;
 
     /** refit ROTs corresponding to PRDs*/
     //TODO or Q: new created track, why const
-    Track* refitRots( const Track* track, TrackStat &stat) const;
+    /**Track* 
+    refitRots( const Track* track, Counter &stat) const override final;**/
 
     /** stores the minimal dist(trk,trk) for covariance correction*/
-    void storeTrkDistanceMapdR(TrackCollection& tracks, std::vector<Trk::Track*> &refit_tracks_out );
+    void 
+    storeTrkDistanceMapdR(TrackCollection& tracks, std::vector<Trk::Track*> &refit_tracks_out );
     
     /** refit Tracks that are in the region of interest and removes inner hits that are wrongly assigned*/
-    void removeInnerHits(std::vector<const Trk::MeasurementBase*>& measurements) const;
+    void 
+    removeInnerHits(std::vector<const Trk::MeasurementBase*>& measurements) const;
     
-    Trk::Track* refitTracksFromB(const Trk::Track* track,double fitQualityOriginal) const;
+    Trk::Track* 
+    refitTracksFromB(const Trk::Track* track,double fitQualityOriginal) const;
    
     /** see if we are in the region of interest for B tracks*/
-    bool decideIfInHighPtBROI(const Trk::Track*) const;
+    bool 
+    decideIfInHighPtBROI(const Trk::Track*) const;
 
     /** Check if the cluster is compatible with a hadronic cluster*/
-    bool isHadCaloCompatible(const Trk::TrackParameters& Tp) const;
+    bool 
+    isHadCaloCompatible(const Trk::TrackParameters& Tp) const;
 
     /** Load the clusters to see if they are compatibles with ROI*/
-    void reloadHadROIs() const;
+    void 
+    reloadHadROIs() const;
+    
+    virtual std::unique_ptr<Trk::Track>
+    doBremRefit(const Trk::Track & track) const override final;
          
 
-    Trk::Track *fit(const std::vector<const Trk::PrepRawData*> &raw,
+    std::unique_ptr<Trk::Track>
+    fit(const std::vector<const Trk::PrepRawData*> &raw,
           const TrackParameters &param, bool flag, Trk::ParticleHypothesis hypo) const;
           
-    Trk::Track *fit(const std::vector<const Trk::MeasurementBase*> &measurements,
+    std::unique_ptr<Trk::Track>
+    fit(const std::vector<const Trk::MeasurementBase*> &measurements,
           const TrackParameters &param, bool flag, Trk::ParticleHypothesis hypo) const;
           
-    template<typename... Args>
-    Trk::Track *fit(const Track &track, Args... args) const;
     
-    bool checkTrack(const Trk::Track *) const;
-  
-    // private data members
-
-    /** brem recovery mode with brem fit ? */
-    bool  m_tryBremFit;
-    bool  m_caloSeededBrem;
-    float m_pTminBrem;
-
-    /** by default refit tracks from PRD */
-    bool m_refitPrds;
+    std::unique_ptr<Trk::Track>
+    fit(const Track &track, bool flag, Trk::ParticleHypothesis hypo) const override final;
     
-    /** rescale pixel PRD covariances */
-    bool m_applydRcorrection;
-
-    /** suppress Hole Search */ 
-    bool m_suppressHoleSearch;
-
-    /** suppress Track Fit */ 
-    bool m_suppressTrackFit;
-
-    /** by default tracks at input get refitted */
-    bool m_forceRefit;
+    bool 
+    checkTrack(const Trk::Track *) const;
 
     /** variables to decide if we are in a ROI */
     bool m_useHClusSeed;
@@ -180,16 +135,6 @@ namespace Trk {
     mutable std::vector<double>   m_hadE;
     mutable std::vector<double>   m_hadR;
     mutable std::vector<double>   m_hadZ;
-
-    /** control material effects (0=non-interacting, 1=pion, 2=electron, 3=muon, 4=pion) read in as an integer 
-    read in as an integer and convert to particle hypothesis */
-    int m_matEffects;
-    Trk::ParticleHypothesis m_particleHypothesis;   
-    
-    /**Scoring tool
-       This tool is used to 'score' the tracks, i.e. to quantify what a good track is.
-       @todo The actual tool that is used should be configured through job options*/
-    ToolHandle<ITrackScoringTool> m_scoringTool;
     
     /** refitting tool - used to refit tracks once shared hits are removed. 
         Refitting tool used is configured via jobOptions.*/
@@ -201,9 +146,6 @@ namespace Trk {
     ToolHandle<Trk::IPRDtoTrackMapTool>         m_assoTool
        {this, "AssociationTool", "InDet::InDetPRDtoTrackMapToolGangedPixels" };
 
-    ToolHandle<Trk::IExtendedTrackSummaryTool> m_trackSummaryTool
-      {this, "TrackSummaryTool", "InDetTrackSummaryToolNoHoleSearch"};
-
     /** key for the PRDtoTrackMap to filled by the ambiguity score processor.**/
     SG::ReadHandleKey<Trk::PRDtoTrackMap>  m_assoMapName
        {this,"AssociationMapName",""};  ///< the key given to the newly created association map
@@ -215,70 +157,57 @@ namespace Trk {
     /**These allow us to retrieve the helpers*/
     const PixelID* m_pixelId;
     const AtlasDetectorID* m_idHelper;
-    std::vector<float>     m_etaBounds;           //!< eta intervals for internal monitoring
 
     SG::WriteHandleKey<InDet::DRMap>                    m_dRMap;      //!< the actual dR map         
 
-    mutable std::mutex m_statMutex;
-    mutable TrackStat  m_stat ATLAS_THREAD_SAFE;
-
     bool m_rejectInvalidTracks;
   };
   
-  inline Trk::Track *
+  inline std::unique_ptr<Trk::Track>
   DenseEnvironmentsAmbiguityProcessorTool::fit(const std::vector<const Trk::PrepRawData*> &raw,
                                                            const TrackParameters &param, bool flag,
                                                            Trk::ParticleHypothesis hypo) const {
-     Trk::Track *newTrack=nullptr;
+     std::unique_ptr<Trk::Track> newTrack;
      for ( const ToolHandle<ITrackFitter> &thisFitter : m_fitterTool) {
-          delete newTrack;
-          newTrack=nullptr;
-          newTrack =  thisFitter->fit(raw, param, flag,hypo);
-          if (Trk::DenseEnvironmentsAmbiguityProcessorTool::checkTrack(newTrack)) {
+          newTrack.reset(thisFitter->fit(raw, param, flag,hypo));
+          if (Trk::DenseEnvironmentsAmbiguityProcessorTool::checkTrack(newTrack.get())) {
                       return newTrack;
           }
           ATH_MSG_WARNING( "The track fitter, " <<  thisFitter->name() << ", produced a track with an invalid covariance matrix." );
      }
      ATH_MSG_WARNING( "None of the " <<  m_fitterTool.size() << " track fitter(s) produced a track with a valid covariance matrix." );
      if (m_rejectInvalidTracks) {
-         delete newTrack;
-         newTrack=nullptr;
+         newTrack.reset(nullptr);
      }
      return newTrack;
   }
 
-  inline Trk::Track *
+  inline std::unique_ptr<Trk::Track>
   DenseEnvironmentsAmbiguityProcessorTool::fit(const std::vector<const Trk::MeasurementBase*> &measurements,
                                                            const TrackParameters &param,
                                                            bool flag,
                                                            Trk::ParticleHypothesis hypo) const{
-    Trk::Track *newTrack=nullptr;
+    std::unique_ptr<Trk::Track> newTrack;
     for ( const ToolHandle<ITrackFitter> &thisFitter : m_fitterTool) {
-      delete newTrack;
-      newTrack = nullptr;
-      newTrack = thisFitter->fit(measurements, param, flag, hypo);
-      if (Trk::DenseEnvironmentsAmbiguityProcessorTool::checkTrack(newTrack)) {
+      newTrack.reset(thisFitter->fit(measurements, param, flag, hypo));
+      if (Trk::DenseEnvironmentsAmbiguityProcessorTool::checkTrack(newTrack.get())) {
         return newTrack;
       }
       ATH_MSG_WARNING( "The track fitter, " <<  thisFitter->name() << ", produced a track with an invalid covariance matrix." );
     }
     ATH_MSG_WARNING( "None of the " <<  m_fitterTool.size() << " track fitter(s) produced a track with a valid covariance matrix." );
     if (m_rejectInvalidTracks) {
-      delete newTrack;
-      newTrack = nullptr;
+      newTrack.reset(nullptr);
     }
     return newTrack;
   }
 
-  template<typename... Args>
-  inline Trk::Track *
-  DenseEnvironmentsAmbiguityProcessorTool::fit(const Track &track, Args... args) const{
-    Trk::Track *newTrack=nullptr;
-    for ( const ToolHandle<ITrackFitter> &thisFitter : m_fitterTool) {
-      delete newTrack;
-      newTrack=nullptr;
-      newTrack =  thisFitter->fit(track,args...);
-      if (Trk::DenseEnvironmentsAmbiguityProcessorTool::checkTrack(newTrack)) {
+  inline std::unique_ptr<Trk::Track>
+  DenseEnvironmentsAmbiguityProcessorTool::fit(const Track &track, bool flag, Trk::ParticleHypothesis hypo) const{
+    std::unique_ptr<Trk::Track> newTrack;
+    for ( const ToolHandle<ITrackFitter> &thisFitter : m_fitterTool) { //note: there is only ever one fitter anyway
+      newTrack.reset(thisFitter->fit(track,flag, hypo));
+      if (Trk::DenseEnvironmentsAmbiguityProcessorTool::checkTrack(newTrack.get())) {
          return newTrack;
       }
       ATH_MSG_WARNING( "The track fitter, " <<  thisFitter->name() << ", produced a track with an invalid covariance matrix." );
@@ -286,8 +215,7 @@ namespace Trk {
     }
     ATH_MSG_WARNING( "None of the " <<  m_fitterTool.size() << " track fitter(s) produced a track with a valid covariance matrix." );
     if (m_rejectInvalidTracks) {
-      delete newTrack;
-      newTrack=nullptr;
+      newTrack.reset(nullptr);
     }
     return newTrack;
   }
diff --git a/Tracking/TrkTools/TrkAmbiguityProcessor/src/DenseEnvironmentsAmbiguityScoreProcessorTool.cxx b/Tracking/TrkTools/TrkAmbiguityProcessor/src/DenseEnvironmentsAmbiguityScoreProcessorTool.cxx
index c1d0d4c6a8a5e6a41454ad54cf53c4608f69e824..90aac7985425c99954df631e8a4c7c71686bbfe1 100644
--- a/Tracking/TrkTools/TrkAmbiguityProcessor/src/DenseEnvironmentsAmbiguityScoreProcessorTool.cxx
+++ b/Tracking/TrkTools/TrkAmbiguityProcessor/src/DenseEnvironmentsAmbiguityScoreProcessorTool.cxx
@@ -19,6 +19,7 @@
 #include "InDetPrepRawData/PixelCluster.h"
 #include "InDetPrepRawData/SCT_Cluster.h"
 #include "InDetIdentifier/PixelID.h"
+#include "AmbiguityProcessorUtility.h"
 
 //==================================================================================================
 Trk::DenseEnvironmentsAmbiguityScoreProcessorTool::DenseEnvironmentsAmbiguityScoreProcessorTool(const std::string& t, 
@@ -65,8 +66,8 @@ Trk::DenseEnvironmentsAmbiguityScoreProcessorTool::initialize(){
   ATH_CHECK( m_splitClusterMapKey_last.initialize(!m_splitClusterMapKey_last.key().empty()) );
   ATH_CHECK( m_splitClusterMapKey.initialize(!m_splitClusterMapKey.key().empty()) );
 
-  if (m_etaBounds.size() != TrackStat3::nRegions) {
-     ATH_MSG_FATAL("There must be exactly " << (TrackStat3::nRegions) << " eta bounds but "
+  if (m_etaBounds.size() != Counter::nRegions) {
+     ATH_MSG_FATAL("There must be exactly " << (Counter::nRegions) << " eta bounds but "
                    << m_etaBounds.size() << " are set." );
      return StatusCode::FAILURE;
   }
@@ -98,7 +99,7 @@ Trk::DenseEnvironmentsAmbiguityScoreProcessorTool::statistics() {
     and then returns the tracks which have been selected*/
 
 void 
-Trk::DenseEnvironmentsAmbiguityScoreProcessorTool::process(std::vector<const Track*>* tracks,
+Trk::DenseEnvironmentsAmbiguityScoreProcessorTool::process(const TrackCollection & tracks,
                                                     Trk::TracksScores* trackScoreTrackMap) const{
   InDet::PixelGangedClusterAmbiguities *splitClusterMap = nullptr;
   if(!m_splitClusterMapKey.key().empty()){
@@ -138,43 +139,27 @@ Trk::DenseEnvironmentsAmbiguityScoreProcessorTool::process(std::vector<const Tra
 
 //==================================================================================================
 void 
-Trk::DenseEnvironmentsAmbiguityScoreProcessorTool::addNewTracks(std::vector<const Track*>* tracks,
+Trk::DenseEnvironmentsAmbiguityScoreProcessorTool::addNewTracks(const TrackCollection & tracks,
                                                           Trk::TracksScores* trackScoreTrackMap) const{
-  TrackStat3 stat(m_etaBounds);
+  Counter stat(m_etaBounds);
   stat.newEvent();
   std::unique_ptr<Trk::PRDtoTrackMap> prdToTrackMap( m_assoTool->createPRDtoTrackMap() );
-  PrdSignatureSet prdSigSet;  
-  ATH_MSG_DEBUG ("Number of tracks at Input: "<<tracks->size());
-  for(const Track* a_track : *tracks) {
-    ATH_MSG_DEBUG ("Processing track candidate "<<a_track);
-    stat.incrementCounterByRegion(EStatType::kNcandidates,a_track); // @TODO should go to the score processor
-    // only fitted tracks get hole search, input is not fitted
-    float score = m_scoringTool->score( *a_track, true);
-    ATH_MSG_DEBUG ("Track Score is "<< score);
-    // veto tracks with score 0
-    bool reject = (score==0);      
-    if (reject){
-      stat.incrementCounterByRegion(EStatType::kNcandScoreZero,a_track);
-    } else {// double track rejection
-      const std::vector<const Trk::PrepRawData*> & prds = m_assoTool->getPrdsOnTrack(*prdToTrackMap, *a_track);
-      // convert to set
-      //PrdSignature prdSig( prds.begin(),prds.end() );
-      // we try to insert it into the set, if we fail (pair.second), it then exits already
-      if ( !(prdSigSet.insert(prds)).second ) {
-        ATH_MSG_DEBUG ("Double track, reject it !");
-        stat.incrementCounterByRegion(EStatType::kNcandDouble,a_track);
-        reject = true;
-      } else {
-        ATH_MSG_DEBUG ("Insert new track in PrdSignatureSet");
-      }
-    }
-    if (!reject) {
-      // add track to map, map is sorted small to big ! set if fitted
-      ATH_MSG_VERBOSE ("Track ("<< a_track <<" --> "<< *a_track << ") has score "<<score);
-      trackScoreTrackMap->push_back( std::make_pair(a_track, -score));
+  PrdSignatureSet prdSigSet; 
+  ATH_MSG_DEBUG ("Number of tracks at Input: "<<tracks.size());
+  const std::array<ScoreCategory, 3> categoryMapping {ScoreCategory::kNcandScoreZero, ScoreCategory::kNcandDouble, ScoreCategory::kNaccept};
+  constexpr bool dropDuplicateTracks{true};
+  for(const Track* pThisTrack : tracks) {
+    ATH_MSG_VERBOSE ("Processing track candidate "<<pThisTrack);
+    stat.incrementCounterByRegion(ScoreCategory::kNcandidates,pThisTrack); // @TODO should go to the score processor
+    TrackScore score = m_scoringTool->score( *pThisTrack, true);
+    const auto category = AmbiguityProcessor::categoriseTrack(*pThisTrack, score, dropDuplicateTracks, m_assoTool, *prdToTrackMap, prdSigSet);
+    if (category<categoryMapping.size()) stat.incrementCounterByRegion(categoryMapping[category],pThisTrack);
+    ATH_MSG_DEBUG(AmbiguityProcessor::debugMessage[category]);
+    if (category == AmbiguityProcessor::TrackAccepted){
+      ATH_MSG_VERBOSE ("Track  ("<< pThisTrack <<") has score "<<score);
+      trackScoreTrackMap->push_back(std::make_pair(pThisTrack, -score));
     }
   }
-  ATH_MSG_DEBUG ("Number of tracks in map:"<<trackScoreTrackMap->size());
   {
      std::lock_guard<std::mutex> lock(m_statMutex);
      m_stat += stat;
@@ -325,22 +310,22 @@ Trk::DenseEnvironmentsAmbiguityScoreProcessorTool::dumpStat(MsgStream &out) cons
    out << __func__;
    out << "\n";
    out << "------------------------------------------------------------------------------------" << "\n";
-   out << "  Number of events processed      :   "<< m_stat.globalCount(TrackStat3::nEvents) << "\n";
-   if (m_stat.globalCount(TrackStat3::nInvalidTracks)>0) {
-      out << "  Number of invalid tracks        :   "<< m_stat.globalCount(TrackStat3::nInvalidTracks) << "\n";
+   out << "  Number of events processed      :   "<< m_stat.globalCount(Counter::nEvents) << "\n";
+   if (m_stat.globalCount(Counter::nInvalidTracks)>0) {
+      out << "  Number of invalid tracks        :   "<< m_stat.globalCount(Counter::nInvalidTracks) << "\n";
    }
-   if (m_stat.globalCount(TrackStat3::nTracksWithoutParam)>0) {
-      out << "  Tracks without parameters       :   "<< m_stat.globalCount(TrackStat3::nTracksWithoutParam) << "\n";
+   if (m_stat.globalCount(Counter::nTracksWithoutParam)>0) {
+      out << "  Tracks without parameters       :   "<< m_stat.globalCount(Counter::nTracksWithoutParam) << "\n";
    }
    out << "  statistics by eta range          ------All---Barrel---Trans.-- Endcap-- Forwrd-- " << "\n";
    out << "------------------------------------------------------------------------------------" << "\n";
-   out << m_stat.dumpRegions("  Number of candidates at input   :",    EStatType::kNcandidates,iw);
-   out << m_stat.dumpRegions("  - candidates rejected score 0   :",    EStatType::kNcandScoreZero,iw);
-   out << m_stat.dumpRegions("  - candidates rejected as double :",    EStatType::kNcandDouble,iw);
+   out << m_stat.dumpRegions("  Number of candidates at input   :",    ScoreCategory::kNcandidates,iw);
+   out << m_stat.dumpRegions("  - candidates rejected score 0   :",    ScoreCategory::kNcandScoreZero,iw);
+   out << m_stat.dumpRegions("  - candidates rejected as double :",    ScoreCategory::kNcandDouble,iw);
    out << "------------------------------------------------------------------------------------" << "\n";
    out << std::setiosflags(std::ios::fixed | std::ios::showpoint) << std::setprecision(2)
-       << "    definition: ( 0.0 < Barrel < " << m_etaBounds[TrackStat3::iBarrel] << " < Transition < " << m_etaBounds[TrackStat3::iTransi]
-       << " < Endcap < " << m_etaBounds[TrackStat3::iEndcap] << " < Forward < " << m_etaBounds[TrackStat3::iForwrd] << " )" << "\n";
+       << "    definition: ( 0.0 < Barrel < " << m_etaBounds[Counter::iBarrel] << " < Transition < " << m_etaBounds[Counter::iTransi]
+       << " < Endcap < " << m_etaBounds[Counter::iEndcap] << " < Forward < " << m_etaBounds[Counter::iForwrd] << " )" << "\n";
    out << "------------------------------------------------------------------------------------" << "\n";
    out << std::setprecision(ss);
 }
diff --git a/Tracking/TrkTools/TrkAmbiguityProcessor/src/DenseEnvironmentsAmbiguityScoreProcessorTool.h b/Tracking/TrkTools/TrkAmbiguityProcessor/src/DenseEnvironmentsAmbiguityScoreProcessorTool.h
index 69cfa2e5ae91ef14b0974fc35fcfe09778d57acc..df34c8de899c134d58f27ab3971afd7820fe9985 100644
--- a/Tracking/TrkTools/TrkAmbiguityProcessor/src/DenseEnvironmentsAmbiguityScoreProcessorTool.h
+++ b/Tracking/TrkTools/TrkAmbiguityProcessor/src/DenseEnvironmentsAmbiguityScoreProcessorTool.h
@@ -40,14 +40,15 @@ namespace Trk {
                                                       virtual public ITrackAmbiguityScoreProcessorTool
   {
   public:
-    enum class EStatType {
+    enum class ScoreCategory {
       kNtracks,
       kNcandidates,
       kNcandScoreZero,
       kNcandDouble,
+      kNaccept,
       kNCounter
     };
-    using TrackStat3 = AmbiCounter<EStatType>;
+    using Counter = AmbiCounter<ScoreCategory>;
       // public types
       typedef std::multimap< TrackScore, const Track* > TrackScoreMap;
       typedef std::vector<const PrepRawData*> PrdSignature;
@@ -56,11 +57,10 @@ namespace Trk {
       // default methods
       DenseEnvironmentsAmbiguityScoreProcessorTool(const std::string&,const std::string&,const IInterface*);
       virtual ~DenseEnvironmentsAmbiguityScoreProcessorTool();
-      virtual StatusCode initialize() override;
-      virtual StatusCode finalize  () override;
+      virtual StatusCode initialize() override final;
+      virtual StatusCode finalize  () override final;
 
-      virtual void process(std::vector<const Track*>* tracks,
-                           TracksScores* trackScoreTrackMap) const override;
+      virtual void process(const TrackCollection & tracks, TracksScores* trackScoreTrackMap) const override final;
 
       /** statistics output to be called by algorithm during finalize. */
       void statistics() override;
@@ -72,7 +72,7 @@ namespace Trk {
          @param tracks the TrackCollection is looped over, 
          and each Trk::Track is added to the various caches. 
          The Trk::PrepRawData from each Trk::Track are added to the IPRD_AssociationTool*/
-      void addNewTracks(std::vector<const Track*>* tracks,
+      void addNewTracks(const TrackCollection & tracks,
                         TracksScores* trackScoreTrackMap) const;
 
       /**  Find SiS Tracks that share hits in the track score map*/
@@ -122,7 +122,7 @@ namespace Trk {
 
       std::vector<float>     m_etaBounds;           //!< eta intervals for internal monitoring
       mutable std::mutex m_statMutex;
-      mutable TrackStat3  m_stat ATLAS_THREAD_SAFE;
+      mutable Counter  m_stat ATLAS_THREAD_SAFE;
   };
 } //end ns
 
diff --git a/Tracking/TrkTools/TrkAmbiguityProcessor/src/SimpleAmbiguityProcessorTool.cxx b/Tracking/TrkTools/TrkAmbiguityProcessor/src/SimpleAmbiguityProcessorTool.cxx
index 7328fd37a19030ce14d6509e6c16dc48498e56e5..70da48d5cb0c448a5e0692c52f0365cf7a7eb17b 100644
--- a/Tracking/TrkTools/TrkAmbiguityProcessor/src/SimpleAmbiguityProcessorTool.cxx
+++ b/Tracking/TrkTools/TrkAmbiguityProcessor/src/SimpleAmbiguityProcessorTool.cxx
@@ -12,21 +12,18 @@
 #include "TrkTrack/TrackInfo.h"
 #include <map>
 #include <memory>
+#include "AmbiguityProcessorUtility.h"
+
 
 //==================================================================================================
 Trk::SimpleAmbiguityProcessorTool::SimpleAmbiguityProcessorTool(const std::string& t, 
                 const std::string& n,
                 const IInterface*  p )
   :
-  AthAlgTool(t,n,p),
-  m_particleHypothesis{undefined},
-  m_scoringTool("Trk::TrackScoringTool/TrackScoringTool"), 
+  AmbiguityProcessorBase(t,n,p),
   m_fitterTool ("Trk::KalmanFitter/InDetTrackFitter"), 
-  m_selectionTool("InDet::InDetAmbiTrackSelectionTool/InDetAmbiTrackSelectionTool"),
-  m_etabounds( {0.8,1.6,2.5,10.0} ),
-  m_stat(m_etabounds)
-{
-  // statitics stuff
+  m_selectionTool("InDet::InDetAmbiTrackSelectionTool/InDetAmbiTrackSelectionTool"){
+  // statistics stuff
 
   declareInterface<ITrackAmbiguityProcessorTool>(this);
   declareProperty("DropDouble"           , m_dropDouble         = true);
@@ -41,7 +38,7 @@ Trk::SimpleAmbiguityProcessorTool::SimpleAmbiguityProcessorTool(const std::strin
   declareProperty("tryBremFit"           , m_tryBremFit         = false);
   declareProperty("caloSeededBrem"       , m_caloSeededBrem     = false);
   declareProperty("pTminBrem"            , m_pTminBrem          = 1000.);
-  declareProperty("etaBounds"            , m_etabounds,"eta intervals for internal monitoring");
+  declareProperty("etaBounds"            , m_etaBounds,"eta intervals for internal monitoring");
 
 }
 //==================================================================================================
@@ -65,7 +62,7 @@ StatusCode Trk::SimpleAmbiguityProcessorTool::initialize(){
   ATH_CHECK( m_fitterTool.retrieve());
   // suppress refit overwrites force refit
   if (m_forceRefit && m_suppressTrackFit ) {
-    ATH_MSG_WARNING( "Inconsistent parameter settings, forced refit is true, but fitting suppressed, resetingt force refit !" );
+    ATH_MSG_WARNING( "Inconsistent parameter settings, forced refit is true, but fitting suppressed, resetting force refit !" );
     m_forceRefit = false;
   }
   // Print out memo that tracks have to be fitted
@@ -81,7 +78,7 @@ StatusCode Trk::SimpleAmbiguityProcessorTool::initialize(){
      ATH_MSG_INFO( "Try brem fit and recovery for electron like tracks.");
   }
   // statistics
-  if (m_etabounds.size() != Counter::nRegions) {
+  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;
@@ -139,19 +136,15 @@ Trk::SimpleAmbiguityProcessorTool::processVector(const TrackCollection &tracks,
   }
   //put tracks into maps etc
   ATH_MSG_DEBUG ("Adding input track candidates to list");
-  Counter stat(m_etabounds);
-  addNewTracks(tracks, trackScoreTrackMap, *prdToTrackMap, stat);
-  {
-    std::lock_guard<std::mutex> lock(m_statMutex);
-    stat.newEvent();
-  }
+  Counter stat(m_etaBounds);
+  addNewTracks(tracks, trackScoreTrackMap, *prdToTrackMap);
   // going to do simple algorithm for now:
   // - take track with highest score
   // - remove shared hits from all other tracks
   // - take next highest scoring tracks, and repeat
   ATH_MSG_DEBUG ("Solving Tracks");
-  std::vector<std::unique_ptr<const Trk::Track> > cleanupTracks;
-  TrackCollection* finalTracks = solveTracks(trackScoreTrackMap, *prdToTrackMap,cleanupTracks, stat);
+  std::vector<std::unique_ptr<const Trk::Track> > trackDustbin;
+  TrackCollection* finalTracks = solveTracks(trackScoreTrackMap, *prdToTrackMap,trackDustbin, stat);
   {
      std::lock_guard<std::mutex> lock(m_statMutex);
      m_stat += stat;
@@ -163,45 +156,22 @@ Trk::SimpleAmbiguityProcessorTool::processVector(const TrackCollection &tracks,
 //==================================================================================================
 void Trk::SimpleAmbiguityProcessorTool::addNewTracks(const TrackCollection &tracks,
                                                      TrackScoreMap& trackScoreTrackMap,
-                                                     Trk::PRDtoTrackMap &prdToTrackMap,
-                                                     Counter &stat) const {
+                                                     Trk::PRDtoTrackMap &prdToTrackMap) const {
+  Counter stat(m_etaBounds);
+  stat.newEvent();
+  //                              
   ATH_MSG_DEBUG ("Number of tracks at Input: "<<tracks.size());
-  /** signature map to drop double track. */
+  /** signature set to drop double track. */
   PrdSignatureSet prdSigSet;
+  //map the two lowest categories (zero score, duplicate track) onto the counter categories
+  const std::array<CounterIndex, 2> categoryMapping {CounterIndex::kNcandScoreZero, CounterIndex::kNcandDouble};
   for(const Track *pTrack : tracks) {
-    ATH_MSG_DEBUG ("Processing track candidate "<<pTrack);
-    // statistics
-    stat.incrementCounterByRegion(ECounter::kNcandidates,pTrack);
-    bool reject = false;
-    // only fitted tracks get hole search, input is not fitted
+    stat.incrementCounterByRegion(CounterIndex::kNcandidates,pTrack);
     TrackScore score = m_scoringTool->score( *pTrack, true);
-    // veto tracks with score 0
-    if (score==0) { 
-      ATH_MSG_DEBUG ("Candidate score is zero, reject it");
-      // statistic
-      stat.incrementCounterByRegion(ECounter::kNcandScoreZero,pTrack);
-      reject = true;
-    } else {
-      ATH_MSG_DEBUG ("Track Score is "<< score);
-      // double track rejection
-      if (m_dropDouble) {
-        const auto & prds = m_assoTool->getPrdsOnTrack(prdToTrackMap, *pTrack);
-        // unfortunately PrepRawDataSet is not a set !
-        PrdSignature prdSig;
-        prdSig.insert( prds.begin(),prds.end() );
-        // we try to insert it into the set, if we fail (pair.second), it then exists already
-        if ( !(prdSigSet.insert(prdSig)).second ) {
-          ATH_MSG_DEBUG ("Double track, reject it !");
-          // statistic
-          stat.incrementCounterByRegion(ECounter::kNcandDouble,pTrack);
-          reject = true;
-        } else {
-          ATH_MSG_DEBUG ("Insert new track in PrdSignatureSet");
-        }
-      }
-    }
-    if (!reject) {
-      // add track to map, map is sorted small to big ! set if fitted
+    const auto category = AmbiguityProcessor::categoriseTrack(*pTrack, score, m_dropDouble, m_assoTool, prdToTrackMap, prdSigSet);
+    if (category < categoryMapping.size()) stat.incrementCounterByRegion(categoryMapping[category],pTrack);
+    ATH_MSG_DEBUG(AmbiguityProcessor::debugMessage[category]);
+    if (category == AmbiguityProcessor::TrackAccepted){
       ATH_MSG_VERBOSE ("Track  ("<< pTrack <<") has score "<<score);
       TrackPtr ptr(pTrack);
       if (!m_forceRefit) ptr.forceFitted();
@@ -209,83 +179,20 @@ void Trk::SimpleAmbiguityProcessorTool::addNewTracks(const TrackCollection &trac
     }
   }
   ATH_MSG_DEBUG ("Number of tracks in map:"<<trackScoreTrackMap.size());
+  {
+     std::lock_guard<std::mutex> lock(m_statMutex);
+     m_stat += stat;
+  }
 }
 
-//==================================================================================================
 
-void Trk::SimpleAmbiguityProcessorTool::addTrack(Trk::Track* in_track,
-                                                 const bool fitted,
-                                                 TrackScoreMap &trackScoreTrackMap,
-                                                 Trk::PRDtoTrackMap &prdToTrackMap,
-                                                 std::vector<std::unique_ptr<const Trk::Track> >& cleanupTracks,
-                                                 Counter &stat) const {
-  std::unique_ptr<Trk::Track> atrack(in_track);
-  // compute score
-  TrackScore score;
-  bool suppressHoleSearch = fitted ? m_suppressHoleSearch : true;
-  if (m_trackSummaryTool.isEnabled()) {
-     m_trackSummaryTool->computeAndReplaceTrackSummary(*atrack,&prdToTrackMap,suppressHoleSearch);
-  }
-  score = m_scoringTool->score( *atrack, suppressHoleSearch );
-  // do we accept the track ?
-  if (score!=0){
-    ATH_MSG_DEBUG ("Track  ("<< atrack.get() <<") has score "<<score);
-    // statistic
-    stat.incrementCounterByRegion(ECounter::kNscoreOk,atrack.get());
-    // add track to map, map is sorted small to big !
-    trackScoreTrackMap.insert( std::make_pair(-score, TrackPtr(atrack.release(), fitted)) );
-    return;
-  }
-  // do we try to recover the track ?
-  if (score==0 && fitted && m_tryBremFit &&
-    !atrack->info().trackProperties(Trk::TrackInfo::BremFit) &&
-    atrack->trackParameters()->front()->pT() > m_pTminBrem &&
-    (!m_caloSeededBrem || atrack->info().patternRecoInfo(Trk::TrackInfo::TrackInCaloROI))){
-    ATH_MSG_DEBUG ("Track score is zero, try to recover it via brem fit");
-    // run track fit using electron hypothesis
-    std::unique_ptr<Trk::Track> bremTrack( m_fitterTool->fit(*atrack,true,Trk::electron) );
-    if (!bremTrack){
-      ATH_MSG_DEBUG ("Brem refit failed, drop track");
-      // statistic
-      stat.incrementCounterByRegion(ECounter::kNscoreZeroBremRefitFailed,atrack.get());
-      stat.incrementCounterByRegion(ECounter::kNfailedFits,atrack.get());
-      // clean up
-      cleanupTracks.push_back(std::move(atrack));
-    } else {
-      // statistic
-      stat.incrementCounterByRegion(ECounter::kNgoodFits,bremTrack.get());
-      // rerun score
-      if (m_trackSummaryTool.isEnabled()) {
-        m_trackSummaryTool->computeAndReplaceTrackSummary(*bremTrack, &prdToTrackMap,suppressHoleSearch);
-      }
-      score = m_scoringTool->score( *bremTrack, suppressHoleSearch );
-      // do we accept the track ?
-      if (score!=0){
-        ATH_MSG_DEBUG ("Brem refit successful, recovered track  ("<< atrack.get() <<") has score "<<score);
-        // statistics
-        stat.incrementCounterByRegion(ECounter::kNscoreZeroBremRefit,bremTrack.get());
-        // add track to map, map is sorted small to big !
-        trackScoreTrackMap.insert( std::make_pair(-score, TrackPtr(bremTrack.release(), fitted)) );
-        return;
-      } else {
-        ATH_MSG_DEBUG ("Brem refit gave still track score zero, reject it");
-        // statistic
-        stat.incrementCounterByRegion(ECounter::kNscoreZeroBremRefitScoreZero,bremTrack.get());
-      }
-      cleanupTracks.push_back(std::move(atrack));
-    }
-  } else {
-    ATH_MSG_DEBUG ("Track score is zero, reject it");
-    // statistic
-    stat.incrementCounterByRegion(ECounter::kNscoreZero,atrack.get());
-    cleanupTracks.push_back(std::move(atrack));
-  }
-}
+
 //==================================================================================================
 
-TrackCollection *Trk::SimpleAmbiguityProcessorTool::solveTracks(TrackScoreMap& trackScoreTrackMap,
+TrackCollection *
+Trk::SimpleAmbiguityProcessorTool::solveTracks(TrackScoreMap& trackScoreTrackMap,
                                                                 Trk::PRDtoTrackMap &prdToTrackMap,
-                                                                std::vector<std::unique_ptr<const Trk::Track> >& cleanupTracks,
+                                                                std::vector<std::unique_ptr<const Trk::Track> >& trackDustbin,
                                                                 Counter &stat) const{
   std::unique_ptr<TrackCollection> finalTracks(std::make_unique<TrackCollection>());
   ATH_MSG_DEBUG ("Starting to solve tracks");
@@ -306,8 +213,8 @@ TrackCollection *Trk::SimpleAmbiguityProcessorTool::solveTracks(TrackScoreMap& t
       // track can be kept as is and is already fitted
       ATH_MSG_DEBUG ("Accepted track "<<atrack.track()<<"\t has score "<<-(ascore));
       // statistic
-      stat.incrementCounterByRegion(ECounter::kNaccepted,atrack.track());
-      if (m_tryBremFit && atrack->info().trackProperties(Trk::TrackInfo::BremFit)) stat.incrementCounterByRegion(ECounter::kNacceptedBrem,atrack.track());
+      stat.incrementCounterByRegion(CounterIndex::kNaccepted,atrack.track());
+      if (m_tryBremFit && atrack->info().trackProperties(Trk::TrackInfo::BremFit)) stat.incrementCounterByRegion(CounterIndex::kNacceptedBrem,atrack.track());
       // add track to PRD_AssociationTool
       if (m_assoTool->addPRDs(prdToTrackMap, *atrack.track()).isFailure()) ATH_MSG_ERROR("addPRDs() failed" );
       // add to output list 
@@ -316,30 +223,33 @@ TrackCollection *Trk::SimpleAmbiguityProcessorTool::solveTracks(TrackScoreMap& t
       // don't forget to drop track from map
       // track can be kept as is, but is not yet fitted
       ATH_MSG_DEBUG ("Good track, but need to fit this track first, score, add it into map again and retry !");
-      refitTrack(atrack.track(),trackScoreTrackMap, prdToTrackMap, cleanupTracks, stat);
+      auto pRefittedTrack = refitTrack(atrack.track(), prdToTrackMap, stat);
+      if(pRefittedTrack) {
+         addTrack( pRefittedTrack, true , trackScoreTrackMap, prdToTrackMap, trackDustbin, stat);
+      }
       if (atrack.newTrack()) {
-        cleanupTracks.push_back( std::unique_ptr<Trk::Track>(atrack.release()) );
+        trackDustbin.emplace_back(atrack.release());
       }
     // delete original copy
     } else if ( cleanedTrack ) {
       // now delete original track
       if (atrack.newTrack()) {
-        cleanupTracks.push_back( std::unique_ptr<Trk::Track>(atrack.release()));
+        trackDustbin.emplace_back(atrack.release());
       }
       // don't forget to drop track from map
       // stripped down version should be reconsidered
       ATH_MSG_DEBUG ("Candidate excluded, add subtrack to map. Track "<<cleanedTrack.get());
       // statistic
-      stat.incrementCounterByRegion(ECounter::kNsubTrack,cleanedTrack.get());
+      stat.incrementCounterByRegion(CounterIndex::kNsubTrack,cleanedTrack.get());
       // track needs fitting !
-      addTrack( cleanedTrack.release(), false, trackScoreTrackMap, prdToTrackMap, cleanupTracks, stat);
+      addTrack( cleanedTrack.release(), false, trackScoreTrackMap, prdToTrackMap, trackDustbin, stat);
     } else {
       // track should be discarded
       ATH_MSG_DEBUG ("Track "<< atrack.track() << " is excluded, no subtrack, reject");
       // statistic
-      stat.incrementCounterByRegion(ECounter::kNnoSubTrack,atrack.track());
+      stat.incrementCounterByRegion(CounterIndex::kNnoSubTrack,atrack.track());
       if (atrack.newTrack()) {
-        cleanupTracks.push_back(  std::unique_ptr<Trk::Track>(atrack.release()) );
+        trackDustbin.emplace_back(atrack.release());
       }
     // don't forget to drop track from map
     }
@@ -348,58 +258,6 @@ TrackCollection *Trk::SimpleAmbiguityProcessorTool::solveTracks(TrackScoreMap& t
   return finalTracks.release();
 }
 
-//==================================================================================================
-
-void 
-Trk::SimpleAmbiguityProcessorTool::refitTrack( const Trk::Track* track,
-                                                    TrackScoreMap& trackScoreTrackMap,
-                                                    Trk::PRDtoTrackMap &prdToTrackMap,
-                                                    std::vector<std::unique_ptr<const Trk::Track> >& cleanupTracks,
-                                                    Counter &stat) const{
-  std::unique_ptr<Trk::Track> newTrack;
-  if (!m_suppressTrackFit) {
-    if (m_refitPrds) {
-      // simple case, fit PRD directly
-      ATH_MSG_VERBOSE ("Refit track "<<track<<" from PRDs");
-      newTrack.reset( refitPrds (track, prdToTrackMap,stat) );
-    } else {
-      // ok, we fit ROTs
-      ATH_MSG_VERBOSE ("Refit track "<<track<<" from ROTs");
-      newTrack.reset( refitRots (track,stat) );
-    }
-  }else{
-    double reXi2 = 0.; 
-    int nDF = 0;
-    const DataVector<const TrackStateOnSurface>* tsos = track->trackStateOnSurfaces();
-    DataVector<const TrackStateOnSurface>* vecTsos = new DataVector<const TrackStateOnSurface>();
-    // loop over TSOS, copy TSOS and push into vector
-    DataVector<const TrackStateOnSurface>::const_iterator iTsos    = tsos->begin();
-    DataVector<const TrackStateOnSurface>::const_iterator iTsosEnd = tsos->end(); 
-    for ( ; iTsos != iTsosEnd ; ++iTsos)  {
-      const TrackStateOnSurface* newTsos = new TrackStateOnSurface(**iTsos);
-      vecTsos->push_back(newTsos);
-      if((*iTsos)->type(Trk::TrackStateOnSurface::Measurement)){  //Get the chi2 and number of hits
-        if ((*iTsos)->fitQualityOnSurface()) {
-          reXi2 += (*iTsos)->fitQualityOnSurface()->chiSquared();
-          nDF   += (*iTsos)->fitQualityOnSurface()->numberDoF();
-        }
-      }
-    }
-    Trk::FitQuality* fq = new Trk::FitQuality(reXi2,nDF-5);
-    Trk::TrackInfo info;
-    info.addPatternRecoAndProperties(track->info());
-    Trk::TrackInfo newInfo;
-    newInfo.setPatternRecognitionInfo(Trk::TrackInfo::SimpleAmbiguityProcessorTool);
-    info.addPatternReco(newInfo); 
-    newTrack = std::make_unique<Trk::Track>( info, vecTsos, fq );
-  }
-  if (newTrack){
-    ATH_MSG_DEBUG ("New track successfully fitted"<<newTrack.get());
-    addTrack( newTrack.release(), true, trackScoreTrackMap, prdToTrackMap, cleanupTracks, stat);
-  } else {
-   ATH_MSG_DEBUG ("Fit failed !");
-  }  
-}
 
 //==================================================================================================
 
@@ -413,88 +271,35 @@ Trk::SimpleAmbiguityProcessorTool::refitPrds( const Trk::Track* track,
     ATH_MSG_WARNING( "No PRDs on track");
     return nullptr;
   }
-  ATH_MSG_VERBOSE ("Track "<<track<<"\t has "<<prds.size()<<"\t PRDs");
-  const TrackParameters* par = track->perigeeParameters();
-  if (par==nullptr) {
-    ATH_MSG_DEBUG ("Track ("<<track<<") has no perigee! Try any other ?");
-    par = track->trackParameters()->front();
-    if (par==nullptr) {
-      ATH_MSG_DEBUG ("Track ("<<track<<") has no Track Parameters ! No refit !");
-      return nullptr;
-    }
-  }
+  const TrackParameters* par = getTrackParameters(track);
+  if (not par) return nullptr;
   // refit using first parameter, do outliers
   Trk::Track* newTrack = nullptr;
   if (m_tryBremFit && track->info().trackProperties(Trk::TrackInfo::BremFit)){
-    // statistics
-    stat.incrementCounterByRegion(ECounter::kNbremFits,track);
+    stat.incrementCounterByRegion(CounterIndex::kNbremFits,track);
     ATH_MSG_VERBOSE ("Brem track, refit with electron brem fit");
     newTrack = m_fitterTool->fit(prds, *par, true, Trk::electron);
   } else {
-    // statistics
-    stat.incrementCounterByRegion(ECounter::kNfits,track);
+    stat.incrementCounterByRegion(CounterIndex::kNfits,track);
     ATH_MSG_VERBOSE ("Normal track, refit");
     newTrack = m_fitterTool->fit(prds, *par, true, m_particleHypothesis);
-    if (!newTrack && m_tryBremFit && par->pT() > m_pTminBrem &&
-        (!m_caloSeededBrem || track->info().patternRecoInfo(Trk::TrackInfo::TrackInCaloROI))){
-      // statistics
-      stat.incrementCounterByRegion(ECounter::kNrecoveryBremFits,track);
+    if ((not newTrack) and shouldTryBremRecovery(*track, par)){
+      stat.incrementCounterByRegion(CounterIndex::kNrecoveryBremFits,track);
       ATH_MSG_VERBOSE ("Normal fit failed, try brem recovery");
       newTrack = m_fitterTool->fit(prds, *par, true, Trk::electron);
     }
   }
   if(newTrack){
-    // statistic
-    stat.incrementCounterByRegion(ECounter::kNgoodFits,newTrack);
+    stat.incrementCounterByRegion(CounterIndex::kNgoodFits,newTrack);
     //keeping the track of previously accumulated TrackInfo
     const Trk::TrackInfo& originalInfo = track->info();
     newTrack->info().addPatternReco(originalInfo);
   } else {
-    // statistic
-    stat.incrementCounterByRegion(ECounter::kNfailedFits,track);
+    stat.incrementCounterByRegion(CounterIndex::kNfailedFits,track);
   }
   return newTrack;
 }
 
-//==================================================================================================
-
-Trk::Track* Trk::SimpleAmbiguityProcessorTool::refitRots( const Trk::Track* track,
-                                                          Counter &stat) const {
-  ATH_MSG_VERBOSE ("Refit track "<<track);
-  // refit using first parameter, do outliers
-  Trk::Track* newTrack = nullptr;
-  if (m_tryBremFit && track->info().trackProperties(Trk::TrackInfo::BremFit)) {
-    // statistics
-    stat.incrementCounterByRegion(ECounter::kNbremFits,track);
-    ATH_MSG_VERBOSE ("Brem track, refit with electron brem fit");
-    newTrack = m_fitterTool->fit(*track, true, Trk::electron);
-  } else {
-    // statistics
-    stat.incrementCounterByRegion(ECounter::kNfits,track);
-    ATH_MSG_VERBOSE ("Normal track, refit");
-    newTrack = m_fitterTool->fit(*track, true, m_particleHypothesis);
-    if (!newTrack && m_tryBremFit &&
-      track->trackParameters()->front()->pT() > m_pTminBrem &&
-      (!m_caloSeededBrem || track->info().patternRecoInfo(Trk::TrackInfo::TrackInCaloROI))){
-      // statistics
-      stat.incrementCounterByRegion(ECounter::kNrecoveryBremFits,track);
-
-      ATH_MSG_VERBOSE ("Normal fit failed, try brem recovery");
-      newTrack = m_fitterTool->fit(*track, true, Trk::electron);
-    }
-  }
-  if(newTrack){
-      // statistic
-      stat.incrementCounterByRegion(ECounter::kNgoodFits,newTrack);
-      //keeping the track of previously accumulated TrackInfo
-      const Trk::TrackInfo& originalInfo = track->info();
-      newTrack->info().addPatternReco(originalInfo);
-    } else {
-      // statistic
-      stat.incrementCounterByRegion(ECounter::kNfailedFits,track);
-    }
-  return newTrack;
-}
 
 //==================================================================================================
 
@@ -532,44 +337,55 @@ Trk::SimpleAmbiguityProcessorTool::dumpStat(MsgStream &out) const {
   out <<             "  Number of events processed      :   "<< m_stat.numberOfEvents() << "\n";
   out <<             "  statistics by eta range          ------All---Barrel---Trans.--- Endcap---DBM---" << "\n";
   out <<             "---------------------------------------------------------------------------------" << "\n";
-  out << m_stat.dumpRegions(   "  Number of candidates at input   :", ECounter::kNcandidates);
-  out << m_stat.dumpRegions(   "  - candidates rejected score 0   :", ECounter::kNcandScoreZero);
-  out << m_stat.dumpRegions(   "  - candidates rejected as double :", ECounter::kNcandDouble);
+  out << m_stat.dumpRegions(   "  Number of candidates at input   :", CounterIndex::kNcandidates);
+  out << m_stat.dumpRegions(   "  - candidates rejected score 0   :", CounterIndex::kNcandScoreZero);
+  out << m_stat.dumpRegions(   "  - candidates rejected as double :", CounterIndex::kNcandDouble);
   out <<             "---------------------------------------------------------------------------------" << "\n";
-  out << m_stat.dumpRegions(   "  candidates with good score      :", ECounter::kNscoreOk);
+  out << m_stat.dumpRegions(   "  candidates with good score      :", CounterIndex::kNscoreOk);
   if (m_tryBremFit) {
-     out << m_stat.dumpRegions("  + recovered after brem refit    :", ECounter::kNscoreZeroBremRefit);
+     out << m_stat.dumpRegions("  + recovered after brem refit    :", CounterIndex::kNscoreZeroBremRefit);
   }
-  out << m_stat.dumpRegions(   "  candidates rejected score 0     :", ECounter::kNscoreZero);
+  out << m_stat.dumpRegions(   "  candidates rejected score 0     :", CounterIndex::kNscoreZero);
   if (m_tryBremFit) {
-     out << m_stat.dumpRegions("  + rejected failed brem refit    :", ECounter::kNscoreZeroBremRefitFailed);
+     out << m_stat.dumpRegions("  + rejected failed brem refit    :", CounterIndex::kNscoreZeroBremRefitFailed);
   }
   out <<             "---------------------------------------------------------------------------------" << "\n";
-  out << m_stat.dumpRegions(   "  number of normal fits           :", ECounter::kNfits);
+  out << m_stat.dumpRegions(   "  number of normal fits           :", CounterIndex::kNfits);
   if (m_tryBremFit) {
-     out << m_stat.dumpRegions("  + 2nd brem fit for failed fit   :", ECounter::kNrecoveryBremFits);
-     out << m_stat.dumpRegions("  normal brem fits for electrons  :", ECounter::kNbremFits);
+     out << m_stat.dumpRegions("  + 2nd brem fit for failed fit   :", CounterIndex::kNrecoveryBremFits);
+     out << m_stat.dumpRegions("  normal brem fits for electrons  :", CounterIndex::kNbremFits);
   }
   out <<             "---------------------------------------------------------------------------------" << "\n";
-  out << m_stat.dumpRegions(   "  sum of succesful fits           :", ECounter::kNgoodFits);
-  out << m_stat.dumpRegions(   "  sum of failed fits              :", ECounter::kNfailedFits);
+  out << m_stat.dumpRegions(   "  sum of succesful fits           :", CounterIndex::kNgoodFits);
+  out << m_stat.dumpRegions(   "  sum of failed fits              :", CounterIndex::kNfailedFits);
   out <<             "---------------------------------------------------------------------------------" << "\n";
-  out << m_stat.dumpRegions(   "  Number of subtracks created     :", ECounter::kNsubTrack);
-  out << m_stat.dumpRegions(   "  Number of candidates excluded   :", ECounter::kNnoSubTrack);
+  out << m_stat.dumpRegions(   "  Number of subtracks created     :", CounterIndex::kNsubTrack);
+  out << m_stat.dumpRegions(   "  Number of candidates excluded   :", CounterIndex::kNnoSubTrack);
   out <<             "---------------------------------------------------------------------------------" << "\n";
-  out << m_stat.dumpRegions(   "  Number of tracks accepted       :", ECounter::kNaccepted);
+  out << m_stat.dumpRegions(   "  Number of tracks accepted       :", CounterIndex::kNaccepted);
   if (m_tryBremFit) {
-     out << m_stat.dumpRegions("  including number of brem fits   :", ECounter::kNacceptedBrem);
+     out << m_stat.dumpRegions("  including number of brem fits   :", CounterIndex::kNacceptedBrem);
   }
   out <<             "---------------------------------------------------------------------------------" << "\n";
   out << std::setiosflags(std::ios::fixed | std::ios::showpoint) << std::setprecision(2)
-      <<             "    definition: ( 0.0 < Barrel < " << m_etabounds[Counter::iBarrel] << " < Transition < " << m_etabounds[Counter::iTransi]
-      <<             " < Endcap < " << m_etabounds[Counter::iEndcap] << " DBM )" << "\n";
+      <<             "    definition: ( 0.0 < Barrel < " << m_etaBounds[Counter::iBarrel] << " < Transition < " << m_etaBounds[Counter::iTransi]
+      <<             " < Endcap < " << m_etaBounds[Counter::iEndcap] << " DBM )" << "\n";
   out <<             "-------------------------------------------------------------------------------" << "\n";
   out.precision (ss);
 }
 
 
+std::unique_ptr<Trk::Track>
+Trk::SimpleAmbiguityProcessorTool::doBremRefit(const Trk::Track & track) const{
+  return std::unique_ptr<Trk::Track>(m_fitterTool->fit(track,true,Trk::electron));
+}
+
+std::unique_ptr<Trk::Track>
+Trk::SimpleAmbiguityProcessorTool::fit(const Track &track, bool flag, Trk::ParticleHypothesis hypo) const{
+  return std::unique_ptr<Trk::Track>(m_fitterTool->fit(track,flag,hypo));
+}
+
+
 
 
 
diff --git a/Tracking/TrkTools/TrkAmbiguityProcessor/src/SimpleAmbiguityProcessorTool.h b/Tracking/TrkTools/TrkAmbiguityProcessor/src/SimpleAmbiguityProcessorTool.h
index 074760b7f3277676eea39eebd71478dab5ba08ee..532d2f3f1554de573b3a6df12ebf4f5379c6f495 100644
--- a/Tracking/TrkTools/TrkAmbiguityProcessor/src/SimpleAmbiguityProcessorTool.h
+++ b/Tracking/TrkTools/TrkAmbiguityProcessor/src/SimpleAmbiguityProcessorTool.h
@@ -6,8 +6,7 @@
 #define SIMPLEAMBIGUITYPROCESSORTOOL_H
 
 
-#include "AthenaBaseComps/AthAlgTool.h"
-#include "TrkToolInterfaces/ITrackAmbiguityProcessorTool.h"
+#include "AmbiguityProcessorBase.h"
 #include "TrkEventPrimitives/TrackScore.h"
 #include "TrkFitterInterfaces/ITrackFitter.h"
 #include "GaudiKernel/ToolHandle.h"
@@ -25,9 +24,9 @@
 #include <vector>
 #include <mutex>
 #include <array>
-#include "AmbiCounter.icc"
 
-#include "TrackPtr.h"
+
+
 class AtlasDetectorID;
 class PixelID;
 
@@ -37,25 +36,18 @@ namespace Trk {
   class IPRD_AssociationTool;
   class ITruthToTrack;
 
-  class SimpleAmbiguityProcessorTool : public AthAlgTool, virtual public ITrackAmbiguityProcessorTool 
-    {
+  class SimpleAmbiguityProcessorTool : public AmbiguityProcessorBase {
     public:
-      enum class ECounter {kNcandidates, kNcandScoreZero, kNcandDouble,
-                  kNscoreOk,kNscoreZeroBremRefit,kNscoreZeroBremRefitFailed,kNscoreZeroBremRefitScoreZero,kNscoreZero,
-                  kNaccepted,kNsubTrack,kNnoSubTrack,kNacceptedBrem,
-                  kNbremFits,kNfits,kNrecoveryBremFits,kNgoodFits,kNfailedFits, kNCounter};
-      using Counter = AmbiCounter<ECounter>;
       // public types
       typedef std::multimap< TrackScore, TrackPtr > TrackScoreMap;
-    
-      typedef std::set<const PrepRawData*> PrdSignature;
+      typedef std::vector<const PrepRawData*> PrdSignature;
       typedef std::set<PrdSignature> PrdSignatureSet;
 
       // default methods
       SimpleAmbiguityProcessorTool(const std::string&,const std::string&,const IInterface*);
       virtual ~SimpleAmbiguityProcessorTool ();
-      virtual StatusCode initialize() override;
-      virtual StatusCode finalize  () override;
+      virtual StatusCode initialize() override final;
+      virtual StatusCode finalize  () override final;
 
       /**Returns a processed TrackCollection from the passed 'tracks'
       @param tracks collection of tracks which will have ambiguities resolved. Will not be 
@@ -74,106 +66,59 @@ namespace Trk {
       virtual void statistics() override;
     private:
 
-      TrackCollection*  processVector(const TrackCollection &tracks, Trk::PRDtoTrackMap *prdToTrackMap) const;
+      TrackCollection*  
+      processVector(const TrackCollection &tracks, Trk::PRDtoTrackMap *prdToTrackMap) const;
 
       /**Add passed TrackCollection, and Trk::PrepRawData from tracks to caches
       @param tracks the TrackCollection is looped over, 
       and each Trk::Track is added to the various caches. 
       The Trk::PrepRawData from each Trk::Track are added to the IPRD_AssociationTool*/
-      //void addNewTracks(const std::vector<const Track*> &tracks,
-      void addNewTracks(const TrackCollection &tracks,
-                        TrackScoreMap& trackScoreTrackMap,
-                        Trk::PRDtoTrackMap &prdToTrackMap,
-                        Counter &stat) const;
-
-      void addTrack(Track* track, const bool fitted,
-                    TrackScoreMap &trackScoreMap,
-                    Trk::PRDtoTrackMap &prdToTrackMap,
-                    std::vector<std::unique_ptr<const Trk::Track> >& cleanupTracks,
-                    Counter &stat) const;
-
-      TrackCollection *solveTracks(TrackScoreMap &trackScoreTrackMap,
-                                   Trk::PRDtoTrackMap &prdToTrackMap,
-                                   std::vector<std::unique_ptr<const Trk::Track> > &cleanupTracks,
-                                   Counter &stat) const;
+      void 
+      addNewTracks(const TrackCollection &tracks,
+                  TrackScoreMap& trackScoreTrackMap,
+                  Trk::PRDtoTrackMap &prdToTrackMap) const;
+
+      TrackCollection *
+      solveTracks(TrackScoreMap &trackScoreTrackMap,
+                 Trk::PRDtoTrackMap &prdToTrackMap,
+                 std::vector<std::unique_ptr<const Trk::Track> > &trackDustbin,
+                 Counter &stat) const;
 
       /** add subtrack to map */
-      void addSubTrack( const std::vector<const TrackStateOnSurface*>& tsos) const;
+      void 
+      addSubTrack( const std::vector<const TrackStateOnSurface*>& tsos) const;
 
-      /** refit track */
-      void refitTrack( const Trk::Track* track,
-                       TrackScoreMap &trackScoreMap,
-                       Trk::PRDtoTrackMap &prdToTrackMap,
-                       std::vector<std::unique_ptr<const Trk::Track> >& cleanupTracks,
-                       Counter &stat) const;
+      /** do a refit assuming electron hypothesis **/
+      virtual std::unique_ptr<Trk::Track>
+      doBremRefit(const Trk::Track & track) const override final;
 
       /** refit PRDs */
-      Track* refitPrds( const Track* track, Trk::PRDtoTrackMap &prdToTrackMap,
-                        Counter &stat) const;
-
-      /** refit ROTs corresponding to PRDs */
-      Track* refitRots( const Track* track,
-                        Counter &stat) const;
+      Track* 
+      refitPrds( const Track* track, Trk::PRDtoTrackMap &prdToTrackMap, Counter &stat) const override final;
 
       /** print out tracks and their scores for debugging*/
-      void dumpTracks(const TrackCollection& tracks) const;
+      void 
+      dumpTracks(const TrackCollection& tracks) const;
 
       /** dump the accumulated statistics */
-      void dumpStat(MsgStream &out) const;
+      void 
+      dumpStat(MsgStream &out) const;
+      
+      std::unique_ptr<Trk::Track>
+      fit(const Track &track, bool flag, Trk::ParticleHypothesis hypo) const override final;
 
       // private data members
-
-      /** brem recovery mode with brem fit ? */
-      bool  m_tryBremFit;
-      bool  m_caloSeededBrem;
-      float m_pTminBrem;
-
       /** by default drop double tracks before refit*/
       bool m_dropDouble;
-
-      /** by default tracks at input get refitted */
-      bool m_forceRefit;
-
-      /** by default refit tracks from PRD */
-      bool m_refitPrds;
-
-      /** suppress Hole Search */ 
-      bool m_suppressHoleSearch;
-
-      /** suppress Track Fit */ 
-      bool m_suppressTrackFit;
-
-      /** control material effects (0=non-interacting, 1=pion, 2=electron, 3=muon, 4=pion) read in as an integer 
-      read in as an integer and convert to particle hypothesis */
-      int m_matEffects;
-      Trk::ParticleHypothesis m_particleHypothesis;
-   
-      /**Scoring tool
-      This tool is used to 'score' the tracks, i.e. to quantify what a good track is.
-      @todo The actual tool that is used should be configured through job options*/
-      ToolHandle<ITrackScoringTool> m_scoringTool;
-
+  
       /** refitting tool - used to refit tracks once shared hits are removed. 
       Refitting tool used is configured via jobOptions.*/
       ToolHandle<ITrackFitter> m_fitterTool;
-
-      ToolHandle<Trk::IPRDtoTrackMapTool>         m_assoTool
-         {this, "AssociationTool", "Trk::PRDtoTrackMapTool" };
-
-      ToolHandle<Trk::IExtendedTrackSummaryTool> m_trackSummaryTool
-        {this, "TrackSummaryTool", "InDetTrackSummaryToolNoHoleSearch"};
-
-      /** selection tool - here the decision which hits remain on a track and
-       which are removed are made
-      */
+      /** association tool **/
+      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;
 
-      /** monitoring statistics */
-      //enum RegionIndex {iBarrel , iTransi , iEndcap , iDBM = 4, nRegions=4};
-      std::vector<float> m_etabounds;           //!< Four eta intervals for internal monitoring
-      mutable std::mutex m_statMutex;
-      mutable Counter m_stat ATLAS_THREAD_SAFE;
-
     };
 } //end ns
 
diff --git a/Tracking/TrkTools/TrkToolInterfaces/TrkToolInterfaces/ITrackAmbiguityScoreProcessorTool.h b/Tracking/TrkTools/TrkToolInterfaces/TrkToolInterfaces/ITrackAmbiguityScoreProcessorTool.h
index 8217278628edae32df92266838df85024d74a7b8..13600e08b2a953d0619264c92b8a252c2d952ccc 100644
--- a/Tracking/TrkTools/TrkToolInterfaces/TrkToolInterfaces/ITrackAmbiguityScoreProcessorTool.h
+++ b/Tracking/TrkTools/TrkToolInterfaces/TrkToolInterfaces/ITrackAmbiguityScoreProcessorTool.h
@@ -1,5 +1,5 @@
 /*
-  Copyright (C) 2002-2019 CERN for the benefit of the ATLAS collaboration
+  Copyright (C) 2002-2020 CERN for the benefit of the ATLAS collaboration
 */
 
 #ifndef ITRKAMBIGUITYSCOREPROCESSORTOOL_H
@@ -14,7 +14,7 @@ static const InterfaceID IID_ITrackAmbiguityScoreProcessorTool("Trk::ITrackAmbig
 
 namespace Trk {
 
-/** @brief Interface for resolving hit assoication ambiguities in a given track collection.
+/** @brief Interface for resolving hit association ambiguities in a given track collection.
 
 The TrkAmbiguityScoreProcessor attempts to improve the 'score' of an event, where the score of an event is the summed scores of all the tracks it contains. 
 
@@ -28,11 +28,9 @@ class ITrackAmbiguityScoreProcessorTool : virtual public IAlgTool
 	@param tracks collection of tracks which will have ambiguities resolved. Will not be modified.
 	@return  map of score and track. Ownership is passed on 
 	(i.e. client handles deletion)*/
-        virtual void process(std::vector<const Track*>* tracks , TracksScores* scoredTracks) const = 0;
-
-        /** Print statistics at the end of the processing.
-        */
-        virtual void statistics() = 0;
+  virtual void process(const TrackCollection & tracks , TracksScores* scoredTracks) const = 0;
+  //Print statistics at the end of the processing.
+  virtual void statistics() = 0;
 
 };