diff --git a/Tracking/TrkTools/TrkAmbiguityProcessor/CMakeLists.txt b/Tracking/TrkTools/TrkAmbiguityProcessor/CMakeLists.txt
index a39d791962042c5652221284c731504e4c58630a..b17deee787ed6afc28f2f771a635fbdbc1d4813d 100644
--- a/Tracking/TrkTools/TrkAmbiguityProcessor/CMakeLists.txt
+++ b/Tracking/TrkTools/TrkAmbiguityProcessor/CMakeLists.txt
@@ -35,6 +35,7 @@ find_package( HepPDT )
 atlas_add_library(   TrkAmbiguityProcessorLib
                      src/DenseEnvironmentsAmbiguityProcessorTool.cxx
                      src/DenseEnvironmentsAmbiguityScoreProcessorTool.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)
diff --git a/Tracking/TrkTools/TrkAmbiguityProcessor/src/AmbiCounter.icc b/Tracking/TrkTools/TrkAmbiguityProcessor/src/AmbiCounter.icc
new file mode 100644
index 0000000000000000000000000000000000000000..cc6b2af9c86dd08c54cba26e54b6b70aa3d2838f
--- /dev/null
+++ b/Tracking/TrkTools/TrkAmbiguityProcessor/src/AmbiCounter.icc
@@ -0,0 +1,117 @@
+/*
+  Copyright (C) 2002-2020 CERN for the benefit of the ATLAS collaboration
+*/
+
+#ifndef TrkAmbiguityProcessor_AmbiCounter_icc
+#define TrkAmbiguityProcessor_AmbiCounter_icc
+#include <array>
+#include <vector>
+#include <string>
+#include "TrkTrack/Track.h"
+
+template<class EnumType>
+class AmbiCounter {
+public:
+  using Categories = EnumType;
+  enum RegionIndex {iAll = 0, iBarrel = 1, iTransi = 2, iEndcap = 3, iDBM = 4, nRegions=5, iForwrd = 4};
+  enum GlobalCounterIndices {
+    nEvents,
+    nInvalidTracks,
+    nTracksWithoutParam,
+    nGlobalCounters,
+  };
+  //
+  AmbiCounter(const std::vector<float> &eta_bounds): m_etaBounds(eta_bounds){
+    //nop
+  }
+  
+  //convert Category to array index
+  size_t 
+  idx(const Categories & categoryIndex) const{
+    return static_cast<size_t>(categoryIndex);
+  }
+  
+  //increment event count
+  void 
+  newEvent(){
+    ++m_globalCounter[nEvents];
+  }
+  
+  //return number of events
+  int 
+  numberOfEvents() const{
+    return m_globalCounter[nEvents];
+  }
+  // increment one bin
+  void 
+  increment(Categories regionIdx, unsigned int etaBinIdx) {
+    if (etaBinIdx>=nRegions) return;
+    if (regionIdx<Categories::kNCounter && etaBinIdx < m_counter[idx(regionIdx)].size()) {
+      ++m_counter[idx(regionIdx)][etaBinIdx];
+    } else {  throw std::range_error("out of range"); }
+    
+  }
+  //
+  AmbiCounter<EnumType> & operator +=(const AmbiCounter<EnumType> &a) {
+  for (unsigned int i=0; i<nGlobalCounters; ++i) {
+       m_globalCounter[i]+= a.m_globalCounter[i];
+  }
+  for (size_t regionIdx=0; regionIdx < idx(Categories::kNCounter); ++regionIdx) {
+     for (unsigned int etaBinIdx=0; etaBinIdx < a.m_counter[regionIdx].size(); ++etaBinIdx) {
+        m_counter[regionIdx][etaBinIdx] += a.m_counter[regionIdx][etaBinIdx];
+     }
+  }
+  return *this;
+}
+  //
+  void incrementCounterByRegion(Categories regionIdx,const Trk::Track* track, bool updateAll=true){
+   if (updateAll) increment(regionIdx,iAll);
+   // test
+   if (!track) {
+      ++m_globalCounter[nEvents];
+      return;
+   }
+   // use first parameter
+   if (!track->trackParameters()) {
+      ++m_globalCounter[nTracksWithoutParam];
+   } else {
+      std::array<int, nRegions> &nTracks = m_counter[idx(regionIdx)];
+      // @TODO make sure that list of track parameters is not empty
+      const double absEta = std::abs(track->trackParameters()->front()->eta());
+      ++nTracks[etaBin(absEta)];
+    }
+  }
+  //
+  std::string 
+  dumpRegions(const std::string & head,Categories regionIdx, const int iw =9) const {
+    std::stringstream out;
+    out << head;
+    for (unsigned int etaBinIdx=0; etaBinIdx < nRegions; ++etaBinIdx) {
+       assert( etaBinIdx < m_counter[idx(regionIdx)].size() );
+       out << std::setiosflags(std::ios::dec) << std::setw(iw) << m_counter[idx(regionIdx)][etaBinIdx];
+    }
+    out << "\n";
+    return out.str();
+  }
+  //
+  int 
+  globalCount(GlobalCounterIndices i) const{
+    return m_globalCounter[i]; 
+  }
+  
+private:
+  std::array<std::array<int, nRegions>,static_cast<size_t>(Categories::kNCounter)> m_counter{};
+  std::array<int,nGlobalCounters>                      m_globalCounter{};
+  const std::vector<float>  &m_etaBounds;           //!< eta intervals for internal monitoring
+  size_t 
+  etaBin(const double val){
+    size_t regionIdx=1; 
+    //eta *must be* in ascending order in the m_etaBounds vector
+    for (;regionIdx< nRegions; ++regionIdx){
+      if (val < m_etaBounds[regionIdx-1]) break;
+    }
+    return regionIdx;
+  }
+};
+
+#endif
diff --git a/Tracking/TrkTools/TrkAmbiguityProcessor/src/DenseEnvironmentsAmbiguityProcessorTool.cxx b/Tracking/TrkTools/TrkAmbiguityProcessor/src/DenseEnvironmentsAmbiguityProcessorTool.cxx
index 20b1fa2ed7d90ad4bef01d38bc52752ba4c773a1..38979306628ed799de67657917dd137c922a49d0 100644
--- a/Tracking/TrkTools/TrkAmbiguityProcessor/src/DenseEnvironmentsAmbiguityProcessorTool.cxx
+++ b/Tracking/TrkTools/TrkAmbiguityProcessor/src/DenseEnvironmentsAmbiguityProcessorTool.cxx
@@ -14,14 +14,11 @@
 #include "TrkExInterfaces/IExtrapolator.h"
 #include "TrkTrackSummary/TrackSummary.h"
 #include "TrkCaloClusterROI/CaloClusterROI_Collection.h"
-
-#include <iterator>
-#include "TString.h"
-
 #include "InDetPrepRawData/PixelCluster.h"
 #include "InDetPrepRawData/SCT_Cluster.h"
 #include "InDetIdentifier/PixelID.h"
 #include <cmath>
+#include <iterator>
 
 //TODO: to be improved
 bool Trk::DenseEnvironmentsAmbiguityProcessorTool::checkTrack( const Trk::Track *track) const {
@@ -56,8 +53,8 @@ Trk::DenseEnvironmentsAmbiguityProcessorTool::DenseEnvironmentsAmbiguityProcesso
   m_scoringTool("Trk::TrackScoringTool/TrackScoringTool"),
   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_etaBounds{0.8, 1.6, 2.5, 4.0},
+  m_stat(m_etaBounds)
 {
   // statitics stuff
 
@@ -77,7 +74,7 @@ Trk::DenseEnvironmentsAmbiguityProcessorTool::DenseEnvironmentsAmbiguityProcesso
   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");
 
   //To determine the ROI for high pt Bs
   declareProperty("doHadCaloSeed"        ,m_useHClusSeed = false );
@@ -131,9 +128,9 @@ StatusCode Trk::DenseEnvironmentsAmbiguityProcessorTool::initialize()
      ATH_CHECK(m_dRMap.initialize() );
   }
 
-  if (m_stat.etaBounds().size() != TrackStat::kNStatRegions-1) {
-     ATH_MSG_FATAL("There must be exactly " << (TrackStat::kNStatRegions-1) << " eta bounds but "
-                   << m_stat.etaBounds().size() << " are set." );
+  if (m_etaBounds.size() != TrackStat::nRegions-1) {
+     ATH_MSG_FATAL("There must be exactly " << (TrackStat::nRegions-1) << " eta bounds but "
+                   << m_etaBounds.size() << " are set." );
      return StatusCode::FAILURE;
   }
   return sc;
@@ -151,72 +148,11 @@ void Trk::DenseEnvironmentsAmbiguityProcessorTool::statistics()
      MsgStream &out=msg(MSG::INFO);
      out << " -- statistics \n";
      std::lock_guard<std::mutex> lock( m_statMutex );
-     m_stat.dump(out, m_tryBremFit);
+     dumpStat(out);
      out << endmsg;
   }
 }
 
-void Trk::DenseEnvironmentsAmbiguityProcessorTool::TrackStat::dump(MsgStream &out, bool try_brem_fit) const
-{
-   auto parseFileName=[](const std::string & fullname){
-    auto dotPosition = fullname.rfind('.');
-    auto slashPosition = fullname.rfind('/');
-    auto stringLength = dotPosition - slashPosition;
-    return fullname.substr(slashPosition, stringLength);
-   };
-   // @TODO restore ios
-   std::streamsize ss = out.precision();
-   int iw=9;
-   out << "Output from ";
-   out << parseFileName(__FILE__);
-   out << "::";
-   out << __func__;
-   out << "\n";
-   out << "------------------------------------------------------------------------------------" << "\n";
-   out << "  Number of events processed      :   "<< m_globalCounter[kNevents].value() << "\n";
-   if (m_globalCounter[kNInvalidTracks]>0) {
-      out << "  Number of invalid tracks        :   "<< m_globalCounter[kNInvalidTracks].value() << "\n";
-   }
-   if (m_globalCounter[kNTracksWithoutParam]>0) {
-      out << "  Tracks without parameters       :   "<< m_globalCounter[kNTracksWithoutParam].value() << "\n";
-   }
-   out << "  statistics by eta range          ------All---Barrel---Trans.-- Endcap-- Forwrd-- " << "\n";
-   out << "------------------------------------------------------------------------------------" << "\n";
-   dumpStatType(out, "  Number of candidates at input   :",    kNcandidates,iw);
-   out << "------------------------------------------------------------------------------------" << "\n";
-   dumpStatType(out, "  candidates with good score      :",    kNscoreOk,iw);
-   if (try_brem_fit) {
-      dumpStatType(out, "  + recovered after brem refit    :", kNscoreZeroBremRefit,iw);
-   }
-   dumpStatType(out, "  candidates rejected score 0     :",    kNscoreZero,iw);
-   if (try_brem_fit) {
-      dumpStatType(out, "  + m refit                       :", kNscoreZeroBremRefitFailed,iw);
-      dumpStatType(out, "  + rejected brem refit score 0   :", kNscoreZeroBremRefitScoreZero,iw);
-   }
-   out << "------------------------------------------------------------------------------------" << "\n";
-   dumpStatType(out, "  number of normal fits           :" ,   kNfits,iw);
-   if (try_brem_fit) {
-      dumpStatType(out, "  + 2nd brem fit for failed fit   :", kNrecoveryBremFits,iw);
-      dumpStatType(out, "  normal brem fits for electrons  :", kNbremFits,iw);
-   }
-   out << "------------------------------------------------------------------------------------" << "\n";
-   dumpStatType(out, "  sum of succesful fits           :",    kNgoodFits,iw);
-   dumpStatType(out, "  sum of failed fits              :",    kNfailedFits,iw);
-   out << "------------------------------------------------------------------------------------" << "\n";
-   dumpStatType(out, "  Number of subtracks created     :",    kNsubTrack,iw);
-   dumpStatType(out, "  Number of candidates excluded   :",    kNnoSubTrack,iw);
-   out << "------------------------------------------------------------------------------------" << "\n";
-   dumpStatType(out, "  Number of tracks accepted       :",    kNaccepted,iw);
-   if (try_brem_fit) {
-      dumpStatType(out, "  including number of brem fits   :", kNacceptedBrem,iw);
-   }
-   out << "------------------------------------------------------------------------------------" << "\n";
-   out << std::setiosflags(std::ios::fixed | std::ios::showpoint) << std::setprecision(2)
-       << "    definition: ( 0.0 < Barrel < " << (*m_etabounds)[iBarrel-1] << " < Transition < " << (*m_etabounds)[iTransi-1]
-       << " < Endcap < " << (*m_etabounds)[iEndcap-1] << " < Forward < " << (*m_etabounds)[iForwrd-1] << " )" << "\n";
-   out << "------------------------------------------------------------------------------------" << "\n";
-   out << std::setprecision(ss);
-  }
 
 
 //==================================================================================================
@@ -254,7 +190,7 @@ TrackCollection* Trk::DenseEnvironmentsAmbiguityProcessorTool::process(const Tra
 
   TrackCollection* finalTracks = new TrackCollection;
   {
-     TrackStat stat(m_stat.etaBounds());
+     TrackStat stat(m_etaBounds);
      stat.newEvent();
      solveTracks(*trackScoreTrackMap, *prd_to_track_map, *finalTracks, cleanup_tracks,stat);
      {
@@ -277,7 +213,7 @@ void Trk::DenseEnvironmentsAmbiguityProcessorTool::addTrack(Trk::Track* track, c
                                                             std::multimap<float, TrackPtr > &scoreTrackFitflagMap,
                                                             const Trk::PRDtoTrackMap &prd_to_track_map,
                                                             std::vector<std::unique_ptr<const Trk::Track> >& cleanup_tracks,
-                                                            Trk::DenseEnvironmentsAmbiguityProcessorTool::TrackStat &stat) const
+                                        TrackStat &stat) const
 {
   // compute score
   TrackScore score;
@@ -310,8 +246,8 @@ void Trk::DenseEnvironmentsAmbiguityProcessorTool::addTrack(Trk::Track* track, c
     Trk::Track* bremTrack = fit(*track,true,Trk::electron);
     if (!bremTrack){
       ATH_MSG_DEBUG ("Brem refit failed, drop track");
-      stat.increment_by_eta(TrackStat::kNscoreZeroBremRefitFailed,track);
-      stat.increment_by_eta(TrackStat::kNfailedFits,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;
@@ -319,7 +255,7 @@ void Trk::DenseEnvironmentsAmbiguityProcessorTool::addTrack(Trk::Track* track, c
       if (m_trackSummaryTool.isEnabled()) {
          m_trackSummaryTool->computeAndReplaceTrackSummary(*bremTrack,&prd_to_track_map,m_suppressHoleSearch);
       }
-      stat.increment_by_eta(TrackStat::kNgoodFits,bremTrack);
+      stat.incrementCounterByRegion(EStatType::kNgoodFits,bremTrack);
       // rerun score
       score = m_scoringTool->score( *bremTrack, suppressHoleSearch );
       cleanup_tracks.push_back(std::unique_ptr<const Trk::Track>(track) );
@@ -327,20 +263,20 @@ void Trk::DenseEnvironmentsAmbiguityProcessorTool::addTrack(Trk::Track* track, c
       // do we accept the track ?
       if (score!=0){
         ATH_MSG_DEBUG ("Brem refit successful, recovered track  ("<< track <<") has score "<<score);
-        stat.increment_by_eta(TrackStat::kNscoreZeroBremRefit,bremTrack);
+        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.increment_by_eta(TrackStat::kNscoreZeroBremRefitScoreZero,bremTrack);
+        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.increment_by_eta(TrackStat::kNscoreZero,track);
+    stat.incrementCounterByRegion(EStatType::kNscoreZero,track);
     // @TODO can delete this track ?
     cleanup_tracks.push_back(std::unique_ptr<const Trk::Track>(track) );
   }
@@ -352,13 +288,13 @@ void Trk::DenseEnvironmentsAmbiguityProcessorTool::solveTracks(const TracksScore
                                                                Trk::PRDtoTrackMap &prd_to_track_map,
                                                                TrackCollection &finalTracks,
                                                                std::vector<std::unique_ptr<const Trk::Track> > &cleanup_tracks,
-                                                               Trk::DenseEnvironmentsAmbiguityProcessorTool::TrackStat &stat) const
+                                           TrackStat &stat) const
 {
 
   std::multimap<float, TrackPtr  > scoreTrackFitflagMap;
   for(const std::pair< const Trk::Track *, float> &scoreTrack: trackScoreTrackMap){
      scoreTrackFitflagMap.emplace(scoreTrack.second, TrackPtr(scoreTrack.first) );
-     stat.increment_by_eta(TrackStat::kNcandidates,scoreTrack.first);
+     stat.incrementCounterByRegion(EStatType::kNcandidates,scoreTrack.first);
   }
 
   ATH_MSG_DEBUG ("Starting to solve tracks");
@@ -386,9 +322,9 @@ void Trk::DenseEnvironmentsAmbiguityProcessorTool::solveTracks(const TracksScore
     {
       // track can be kept as is and is already fitted
        ATH_MSG_DEBUG ("Accepted track "<<atrack.track()<<"\t has score "<<-ascore);
-       stat.increment_by_eta(TrackStat::kNaccepted, atrack.track() );
+       stat.incrementCounterByRegion(EStatType::kNaccepted, atrack.track() );
        if (m_tryBremFit && atrack.track()->info().trackProperties(Trk::TrackInfo::BremFit)) {
-          stat.increment_by_eta(TrackStat::kNacceptedBrem,atrack.track());
+          stat.incrementCounterByRegion(EStatType::kNacceptedBrem,atrack.track());
        }
 
       //Compute the fitQuality
@@ -442,7 +378,7 @@ void Trk::DenseEnvironmentsAmbiguityProcessorTool::solveTracks(const TracksScore
     else if ( cleanedTrack ) //cleanedTrack != atrack
     {
       ATH_MSG_DEBUG ("Candidate excluded, add subtrack to map. Track "<<cleanedTrack.get());
-      stat.increment_by_eta(TrackStat::kNsubTrack,cleanedTrack.get());
+      stat.incrementCounterByRegion(EStatType::kNsubTrack,cleanedTrack.get());
 
       // for this case clenedTrack is a new created object.
       addTrack(cleanedTrack.release(), false, scoreTrackFitflagMap, prd_to_track_map, cleanup_tracks, stat);
@@ -456,7 +392,7 @@ void Trk::DenseEnvironmentsAmbiguityProcessorTool::solveTracks(const TracksScore
     {
       // track should be discarded
       ATH_MSG_DEBUG ("Track "<< atrack.track() << " is excluded, no subtrack, reject");
-      stat.increment_by_eta(TrackStat::kNnoSubTrack,atrack.track());
+      stat.incrementCounterByRegion(EStatType::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()) {
@@ -473,7 +409,7 @@ void Trk::DenseEnvironmentsAmbiguityProcessorTool::solveTracks(const TracksScore
 //==================================================================================================
 Trk::Track* Trk::DenseEnvironmentsAmbiguityProcessorTool::refitTrack( const Trk::Track* track,
                                                                       Trk::PRDtoTrackMap &prd_to_track_map,
-                                                                      Trk::DenseEnvironmentsAmbiguityProcessorTool::TrackStat &stat) const
+                                                  TrackStat &stat) const
 {
   Trk::Track* newTrack = nullptr;
   if (!m_suppressTrackFit){
@@ -533,7 +469,7 @@ Trk::Track* Trk::DenseEnvironmentsAmbiguityProcessorTool::refitTrack( const Trk:
 
 Trk::Track* Trk::DenseEnvironmentsAmbiguityProcessorTool::refitPrds( const Trk::Track* track,
                                                                      Trk::PRDtoTrackMap &prd_to_track_map,
-                                                                     Trk::DenseEnvironmentsAmbiguityProcessorTool::TrackStat &stat) const
+                                                 TrackStat &stat) const
 {
 
   // get vector of PRDs
@@ -563,7 +499,7 @@ Trk::Track* Trk::DenseEnvironmentsAmbiguityProcessorTool::refitPrds( const Trk::
   if (m_tryBremFit && track->info().trackProperties(Trk::TrackInfo::BremFit))
   {
 
-    stat.increment_by_eta(TrackStat::kNbremFits,track);
+    stat.incrementCounterByRegion(EStatType::kNbremFits,track);
 
     ATH_MSG_VERBOSE ("Brem track, refit with electron brem fit");
     // TODO revert once GlobalChi2Fitter properly handles brem fits when 
@@ -574,7 +510,7 @@ Trk::Track* Trk::DenseEnvironmentsAmbiguityProcessorTool::refitPrds( const Trk::
   }
   else
   {
-    stat.increment_by_eta(TrackStat::kNfits,track);
+    stat.incrementCounterByRegion(EStatType::kNfits,track);
 
     ATH_MSG_VERBOSE ("Normal track, refit");
     newTrack = fit(prds, *par, true, m_particleHypothesis);
@@ -582,7 +518,7 @@ Trk::Track* Trk::DenseEnvironmentsAmbiguityProcessorTool::refitPrds( const Trk::
     if (!newTrack && m_tryBremFit && par->pT() > m_pTminBrem &&
   (!m_caloSeededBrem || track->info().patternRecoInfo(Trk::TrackInfo::TrackInCaloROI)))
     {
-      stat.increment_by_eta(TrackStat::kNrecoveryBremFits,track);
+      stat.incrementCounterByRegion(EStatType::kNrecoveryBremFits,track);
       ATH_MSG_VERBOSE ("Normal fit failed, try brem recovery");
       // TODO revert once GlobalChi2Fitter properly handles brem fits when 
       //      starting from prds
@@ -593,13 +529,13 @@ Trk::Track* Trk::DenseEnvironmentsAmbiguityProcessorTool::refitPrds( const Trk::
   }
   
   if(newTrack) {
-    stat.increment_by_eta(TrackStat::kNgoodFits,newTrack);
+    stat.incrementCounterByRegion(EStatType::kNgoodFits,newTrack);
     //keeping the track of previously accumulated TrackInfo
     const Trk::TrackInfo& old_info = track->info();
     newTrack->info().addPatternReco(old_info);
   }
   else {
-     stat.increment_by_eta(TrackStat::kNfailedFits,track);
+     stat.incrementCounterByRegion(EStatType::kNfailedFits,track);
   }
   return newTrack;
 }
@@ -607,7 +543,7 @@ Trk::Track* Trk::DenseEnvironmentsAmbiguityProcessorTool::refitPrds( const Trk::
 //==================================================================================================
 
 Trk::Track* Trk::DenseEnvironmentsAmbiguityProcessorTool::refitRots(const Trk::Track* track,
-                                                                    Trk::DenseEnvironmentsAmbiguityProcessorTool::TrackStat &stat) const
+                                                TrackStat &stat) const
 {
 
   ATH_MSG_VERBOSE ("Refit track "<<track);
@@ -618,14 +554,14 @@ Trk::Track* Trk::DenseEnvironmentsAmbiguityProcessorTool::refitRots(const Trk::T
   if (m_tryBremFit &&
       track->info().trackProperties(Trk::TrackInfo::BremFit))
   {
-    stat.increment_by_eta(TrackStat::kNbremFits,track);
+    stat.incrementCounterByRegion(EStatType::kNbremFits,track);
     ATH_MSG_VERBOSE ("Brem track, refit with electron brem fit");
     newTrack = fit(*track, true, Trk::electron);
   }
   else
   {
 
-    stat.increment_by_eta(TrackStat::kNfits,track);
+    stat.incrementCounterByRegion(EStatType::kNfits,track);
     ATH_MSG_VERBOSE ("Normal track, refit");
     newTrack = fit(*track, true, m_particleHypothesis);
 
@@ -633,7 +569,7 @@ Trk::Track* Trk::DenseEnvironmentsAmbiguityProcessorTool::refitRots(const Trk::T
         track->trackParameters()->front()->pT() > m_pTminBrem &&
         (!m_caloSeededBrem || track->info().patternRecoInfo(Trk::TrackInfo::TrackInCaloROI)))
     {
-      stat.increment_by_eta(TrackStat::kNrecoveryBremFits,track);
+      stat.incrementCounterByRegion(EStatType::kNrecoveryBremFits,track);
       ATH_MSG_VERBOSE ("Normal fit failed, try brem recovery");
       newTrack = fit(*track, true, Trk::electron);
     }
@@ -641,13 +577,13 @@ Trk::Track* Trk::DenseEnvironmentsAmbiguityProcessorTool::refitRots(const Trk::T
 
   if(newTrack)
   {
-    stat.increment_by_eta(TrackStat::kNgoodFits,newTrack);
+    stat.incrementCounterByRegion(EStatType::kNgoodFits,newTrack);
     //keeping the track of previously accumulated TrackInfo
     const Trk::TrackInfo& old_info = track->info();
     newTrack->info().addPatternReco(old_info);
   }
   else {
-    stat.increment_by_eta(TrackStat::kNfailedFits,track);
+    stat.incrementCounterByRegion(EStatType::kNfailedFits,track);
   }
   return newTrack;
 }
@@ -909,3 +845,66 @@ Trk::Track* Trk::DenseEnvironmentsAmbiguityProcessorTool::refitTracksFromB(const
     }
   }
 }
+
+void 
+Trk::DenseEnvironmentsAmbiguityProcessorTool::dumpStat(MsgStream &out) const{
+   auto parseFileName=[](const std::string & fullname){
+    auto dotPosition = fullname.rfind(".");
+    auto slashPosition = fullname.rfind("/");
+    auto stringLength = dotPosition - slashPosition;
+    return fullname.substr(slashPosition, stringLength);
+   };
+   // @TODO restore ios
+   std::streamsize ss = out.precision();
+   int iw=9;
+   out << "Output from ";
+   out << parseFileName(__FILE__);
+   out << "::";
+   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 invalid tracks        :   "<< nInvalid<< "\n";
+   }
+   if (const auto nNoParams = m_stat.globalCount(TrackStat::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 << "------------------------------------------------------------------------------------" << "\n";
+   out << m_stat.dumpRegions( "  candidates with good score      :",    EStatType::kNscoreOk,iw);
+   if (m_tryBremFit) {
+      out << m_stat.dumpRegions( "  + recovered after brem refit    :", EStatType::kNscoreZeroBremRefit,iw);
+   }
+   out << m_stat.dumpRegions( "  candidates rejected score 0     :",    EStatType::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 << "------------------------------------------------------------------------------------" << "\n";
+   out << m_stat.dumpRegions( "  number of normal fits           :" ,   EStatType::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 << "------------------------------------------------------------------------------------" << "\n";
+   out << m_stat.dumpRegions( "  sum of succesful fits           :",    EStatType::kNgoodFits,iw);
+   out << m_stat.dumpRegions( "  sum of failed fits              :",    EStatType::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 << "------------------------------------------------------------------------------------" << "\n";
+   out << m_stat.dumpRegions( "  Number of tracks accepted       :",    EStatType::kNaccepted,iw);
+   if (m_tryBremFit) {
+      out << m_stat.dumpRegions( "  including number of brem fits   :", EStatType::kNacceptedBrem,iw);
+   }
+   out << "------------------------------------------------------------------------------------" << "\n";
+   out << std::setiosflags(std::ios::fixed | std::ios::showpoint) << std::setprecision(2)
+       << "    definition: ( 0.0 < Barrel < " << m_etaBounds[TrackStat::iBarrel-1] << " < Transition < " << m_etaBounds[TrackStat::iTransi-1]
+       << " < Endcap < " << m_etaBounds[TrackStat::iEndcap-1] << " < Forward < " << m_etaBounds[TrackStat::iForwrd-1] << " )" << "\n";
+   out << "------------------------------------------------------------------------------------" << "\n";
+   out << std::setprecision(ss);
+  }
+
diff --git a/Tracking/TrkTools/TrkAmbiguityProcessor/src/DenseEnvironmentsAmbiguityProcessorTool.h b/Tracking/TrkTools/TrkAmbiguityProcessor/src/DenseEnvironmentsAmbiguityProcessorTool.h
index 9ea3b8ded714ccaf3ad889dd248499f88c9fa467..ebe80437b0587eb8f44747e8a958cd9a6961486b 100644
--- a/Tracking/TrkTools/TrkAmbiguityProcessor/src/DenseEnvironmentsAmbiguityProcessorTool.h
+++ b/Tracking/TrkTools/TrkAmbiguityProcessor/src/DenseEnvironmentsAmbiguityProcessorTool.h
@@ -24,14 +24,15 @@
 #include "TrkTrack/TrackCollection.h"
 #include "TrkTrack/TrackSeedMap.h"
 #include "TrkParameters/TrackParameters.h"
-
+//
+#include "AmbiCounter.icc"
+//
 #include <map>
-#include <set>
 #include <vector>
-#include <ostream>
 
 #include "TrackPtr.h"
 
+
 class AtlasDetectorID;
 class PixelID;
 
@@ -42,21 +43,41 @@ namespace InDet{
 }
 
 namespace Trk {
-
   class ITrackScoringTool;
   class ITruthToTrack;
   class IExtrapolator;
-
+  //
   class DenseEnvironmentsAmbiguityProcessorTool : public AthAlgTool, 
-                                                  virtual public ITrackAmbiguityProcessorTool
-    {
-    public:
-    
-      // default methods
-      DenseEnvironmentsAmbiguityProcessorTool(const std::string&,const std::string&,const IInterface*);
-      virtual ~DenseEnvironmentsAmbiguityProcessorTool ();
-      virtual StatusCode initialize() override;
-      virtual StatusCode finalize  () override;
+        virtual public ITrackAmbiguityProcessorTool{
+  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 ();
+   virtual StatusCode initialize() override;
+   virtual StatusCode finalize  () override;
+   void dumpStat(MsgStream &out) const;
+
 
       /**Returns a processed TrackCollection from the passed 'tracks'
      @param tracks collection of tracks which will have ambiguities resolved. Will not be 
@@ -71,108 +92,31 @@ namespace Trk {
       /** statistics output to be called by algorithm during finalize. */
       virtual void statistics() override;
     private:
-      class TrackStat {
-      public:
-         TrackStat(const std::vector<float> &eta_bounds) : m_etabounds(&eta_bounds){}
-
-         enum EStatType {
-            kNtracks,
-            kNinvalid,
-            kNcandidates,
-            // kNcandScoreZero,
-            // kNcandDouble,
-            kNscoreOk,
-            kNscoreZeroBremRefit,
-            kNscoreZeroBremRefitFailed,
-            kNscoreZeroBremRefitScoreZero,
-            kNscoreZero,
-            kNaccepted,
-            kNsubTrack,
-            kNnoSubTrack,
-            kNacceptedBrem,
-            kNbremFits,
-            kNfits,
-            kNrecoveryBremFits,
-            kNgoodFits,
-            kNfailedFits,
-            kNStatTypes
-         };
-         enum EGlobalStatType {
-            kNevents,
-            kNInvalidTracks,
-            kNTracksWithoutParam,
-            kNGlobalStatTypes,
-         };
-         /** internal monitoring: categories for counting different types of extension results*/
-         enum StatIndex {iAll = 0, iBarrel = 1, iTransi = 2, iEndcap = 3, iForwrd = 4, kNStatRegions=5};
-
-         class Counter {
-         public:
-            Counter &operator+=(const Counter &a) {
-               m_counter += a.m_counter;
-               return *this;
-            }
-            Counter &operator++()   { ++m_counter; return *this;}
-            operator int() const    { return m_counter; }
-            int value()    const    { return m_counter; }
-         private:
-            unsigned int m_counter=0;
-         };
-
-         void newEvent() {
-            ++m_globalCounter[kNevents];
-         }
-
-         TrackStat &operator+=(const TrackStat &a) {
-            for (unsigned int i=0; i<kNGlobalStatTypes; ++i) {
-               m_globalCounter[i]+= a.m_globalCounter[i];
-            }
-            for (unsigned int i=0; i<kNStatTypes; ++i) {
-               for (unsigned int region_i=0; region_i< kNStatRegions; ++region_i) {
-                  m_counter[i][region_i] += a.m_counter[i][region_i];
-               }
-            }
-            return *this;
-         }
-
-         /** helper for monitoring and validation: does success/failure counting */
-         void increment_by_eta(EStatType type, const Track* track, bool updateAll=true);
-         void dumpStatType(MsgStream &out, const std::string &head, EStatType type, unsigned short iw=9) const;
-         void dump(MsgStream &out, bool try_brem_fit) const;
-
-         const std::vector<float>  &etaBounds() const { return *m_etabounds; }  //!< eta intervals for internal monitoring
-
-      private:
-         std::array<Counter,kNGlobalStatTypes>                      m_globalCounter;
-         std::array<std::array<Counter, kNStatRegions>,kNStatTypes> m_counter;
-
-         const std::vector<float>  *m_etabounds;           //!< eta intervals for internal monitoring
-      };
 
       //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,
-                    Trk::DenseEnvironmentsAmbiguityProcessorTool::TrackStat &stat) const;
+                    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,
-                       Trk::DenseEnvironmentsAmbiguityProcessorTool::TrackStat &stat) const;
+                       TrackStat &stat) const;
 
       /** refit track */
       Track* refitTrack( const Trk::Track* track, Trk::PRDtoTrackMap &prd_to_track_map,
-                         Trk::DenseEnvironmentsAmbiguityProcessorTool::TrackStat &stat) const;
+     TrackStat &stat) const;
 
       /** refit PRDs */
       Track* refitPrds( const Track* track, Trk::PRDtoTrackMap &prd_to_track_map,
-                        Trk::DenseEnvironmentsAmbiguityProcessorTool::TrackStat &stat) const;
+    TrackStat &stat) const;
 
       /** refit ROTs corresponding to PRDs*/
       //TODO or Q: new created track, why const
-      Track* refitRots( const Track* track, Trk::DenseEnvironmentsAmbiguityProcessorTool::TrackStat &stat) const;
+      Track* refitRots( const Track* track, TrackStat &stat) const;
 
       /** stores the minimal dist(trk,trk) for covariance correction*/
       void storeTrkDistanceMapdR(TrackCollection& tracks,
@@ -269,7 +213,7 @@ 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
+      std::vector<float>     m_etaBounds;           //!< eta intervals for internal monitoring
 
       SG::WriteHandleKey<InDet::DRMap>                    m_dRMap;      //!< the actual dR map         
 
@@ -348,41 +292,6 @@ namespace Trk {
       }
 } //end ns
 
-void Trk::DenseEnvironmentsAmbiguityProcessorTool::TrackStat::increment_by_eta(EStatType type,
-                                                                               const Track* track,
-                                                                               bool updateAll) {
-   std::array<Counter,kNStatRegions> &Ntracks = m_counter[type];
-   if (updateAll) ++Ntracks[iAll];
-
-   // test
-   if (!track) {
-      ++m_globalCounter[kNInvalidTracks];
-   }
-   // use first parameter
-   if (!track->trackParameters()) {
-      ++m_globalCounter[kNTracksWithoutParam];
-   }
-   else {
-      double eta = track->trackParameters()->front()->eta();
-      for (unsigned int region_i=1; region_i< kNStatRegions; ++region_i) {
-         if (std::abs(eta)      < (*m_etabounds)[region_i-1]) {
-            ++Ntracks[region_i];
-            break;
-         }
-      }
-   }
-}
-
-void Trk::DenseEnvironmentsAmbiguityProcessorTool::TrackStat::dumpStatType(MsgStream &out,
-                                                                           const std::string &head,
-                                                                           EStatType type,
-                                                                           unsigned short iw) const {
-   out << head << std::setiosflags(std::ios::dec);
-   for (unsigned region_i=0; region_i<kNStatRegions; ++region_i) {
-      out << std::setw(iw) << m_counter[type][region_i].value();
-   }
-   out << "\n";
-}
 
 #endif // TrackAmbiguityProcessorTool_H
 
diff --git a/Tracking/TrkTools/TrkAmbiguityProcessor/src/DenseEnvironmentsAmbiguityScoreProcessorTool.cxx b/Tracking/TrkTools/TrkAmbiguityProcessor/src/DenseEnvironmentsAmbiguityScoreProcessorTool.cxx
index fd5b425131e4134f8495ea93822f88208fc04812..9cca17d85c476a3bc76d7469762d73e786053f19 100644
--- a/Tracking/TrkTools/TrkAmbiguityProcessor/src/DenseEnvironmentsAmbiguityScoreProcessorTool.cxx
+++ b/Tracking/TrkTools/TrkAmbiguityProcessor/src/DenseEnvironmentsAmbiguityScoreProcessorTool.cxx
@@ -29,8 +29,8 @@ Trk::DenseEnvironmentsAmbiguityScoreProcessorTool::DenseEnvironmentsAmbiguitySco
   m_scoringTool("Trk::TrackScoringTool/TrackScoringTool"), 
   m_selectionTool("InDet::InDetDenseEnvAmbiTrackSelectionTool/InDetAmbiTrackSelectionTool"),
   m_splitProbTool("InDet::NnPixelClusterSplitProbTool/NnPixelClusterSplitProbTool"),
-  m_etabounds{0.8, 1.6, 2.5,4.0},
-  m_stat(m_etabounds)
+  m_etaBounds{0.8, 1.6, 2.5,4.0},
+  m_stat(m_etaBounds)
 {
 
   declareInterface<ITrackAmbiguityScoreProcessorTool>(this);
@@ -41,7 +41,7 @@ Trk::DenseEnvironmentsAmbiguityScoreProcessorTool::DenseEnvironmentsAmbiguitySco
   declareProperty("SplitClusterMap_new"  , m_splitClusterMapKey);
   declareProperty("sharedProbCut"        , m_sharedProbCut           = 0.3);
   declareProperty("sharedProbCut2"       , m_sharedProbCut2          = 0.3);
-  declareProperty("etaBounds"            , m_etabounds,"eta intervals for internal monitoring");
+  declareProperty("etaBounds"            , m_etaBounds,"eta intervals for internal monitoring");
 
 }
 //==================================================================================================
@@ -68,9 +68,9 @@ StatusCode 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_stat.etaBounds().size() != TrackStat::kNStatRegions-1) {
-     ATH_MSG_FATAL("There must be exactly " << (TrackStat::kNStatRegions-1) << " eta bounds but "
-                   << m_stat.etaBounds().size() << " are set." );
+  if (m_etaBounds.size() != TrackStat3::nRegions-1) {
+     ATH_MSG_FATAL("There must be exactly " << (TrackStat3::nRegions-1) << " eta bounds but "
+                   << m_etaBounds.size() << " are set." );
      return StatusCode::FAILURE;
   }
 
@@ -88,46 +88,11 @@ void Trk::DenseEnvironmentsAmbiguityScoreProcessorTool::statistics() {
       MsgStream &out=msg(MSG::INFO);
       out << " -- statistics " << "\n";
       std::lock_guard<std::mutex> lock( m_statMutex );
-      m_stat.dump(out);
+      dumpStat(out);
       out << endmsg;
    }
 }
 
-void Trk::DenseEnvironmentsAmbiguityScoreProcessorTool::TrackStat::dump(MsgStream &out) const
-{
-   auto parseFileName=[](const std::string & fullname){
-     auto dotPosition = fullname.rfind('.');
-     auto slashPosition = fullname.rfind('/');
-     auto stringLength = dotPosition - slashPosition;
-     return fullname.substr(slashPosition, stringLength);
-   };
-   std::streamsize ss = out.precision();
-   int iw=9;
-   out << "Output from ";
-   out << parseFileName(__FILE__);
-   out << "::";
-   out << __func__;
-   out << "\n";
-   out << "------------------------------------------------------------------------------------" << "\n";
-   out << "  Number of events processed      :   "<< m_globalCounter[kNevents].value() << "\n";
-   if (m_globalCounter[kNInvalidTracks]>0) {
-      out << "  Number of invalid tracks        :   "<< m_globalCounter[kNInvalidTracks].value() << "\n";
-   }
-   if (m_globalCounter[kNTracksWithoutParam]>0) {
-      out << "  Tracks without parameters       :   "<< m_globalCounter[kNTracksWithoutParam].value() << "\n";
-   }
-   out << "  statistics by eta range          ------All---Barrel---Trans.-- Endcap-- Forwrd-- " << "\n";
-   out << "------------------------------------------------------------------------------------" << "\n";
-   dumpStatType(out, "  Number of candidates at input   :",    kNcandidates,iw);
-   dumpStatType(out, "  - candidates rejected score 0   :",    kNcandScoreZero,iw);
-   dumpStatType(out, "  - candidates rejected as double :",    kNcandDouble,iw);
-   out << "------------------------------------------------------------------------------------" << "\n";
-   out << std::setiosflags(std::ios::fixed | std::ios::showpoint) << std::setprecision(2)
-       << "    definition: ( 0.0 < Barrel < " << (*m_etabounds)[iBarrel-1] << " < Transition < " << (*m_etabounds)[iTransi-1]
-       << " < Endcap < " << (*m_etabounds)[iEndcap-1] << " < Forward < " << (*m_etabounds)[iForwrd-1] << " )" << "\n";
-   out << "------------------------------------------------------------------------------------" << "\n";
-   out << std::setprecision(ss);
-}
 
 //==================================================================================================
 
@@ -181,7 +146,7 @@ void Trk::DenseEnvironmentsAmbiguityScoreProcessorTool::process(std::vector<cons
 void Trk::DenseEnvironmentsAmbiguityScoreProcessorTool::addNewTracks(std::vector<const Track*>* tracks,
                                                                      Trk::TracksScores* trackScoreTrackMap) const
 {
-  TrackStat stat(m_stat.etaBounds());
+  TrackStat3 stat(m_etaBounds);
   stat.newEvent();
 
   std::unique_ptr<Trk::PRDtoTrackMap> prd_to_track_map( m_assoTool->createPRDtoTrackMap() );
@@ -191,7 +156,7 @@ void Trk::DenseEnvironmentsAmbiguityScoreProcessorTool::addNewTracks(std::vector
  
   for(const Track* a_track : *tracks) {
     ATH_MSG_DEBUG ("Processing track candidate "<<a_track);
-    stat.increment_by_eta(TrackStat::kNcandidates,a_track); // @TODO should go to the score processor
+    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);
@@ -199,15 +164,15 @@ void Trk::DenseEnvironmentsAmbiguityScoreProcessorTool::addNewTracks(std::vector
     // veto tracks with score 0
     bool reject = score==0;      
     if (reject){
-      stat.increment_by_eta(TrackStat::kNcandScoreZero,a_track);
+      stat.incrementCounterByRegion(EStatType::kNcandScoreZero,a_track);
     } else {// double track rejection
-      std::vector<const Trk::PrepRawData*> prds = m_assoTool->getPrdsOnTrack(*prd_to_track_map, *a_track);
+      const std::vector<const Trk::PrepRawData*> & prds = m_assoTool->getPrdsOnTrack(*prd_to_track_map, *a_track);
       // convert to set
-      PrdSignature prdSig( prds.begin(),prds.end() );
+      //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(prdSig)).second ) {
+      if ( !(prdSigSet.insert(prds)).second ) {
         ATH_MSG_DEBUG ("Double track, reject it !");
-        stat.increment_by_eta(TrackStat::kNcandDouble,a_track);
+        stat.incrementCounterByRegion(EStatType::kNcandDouble,a_track);
         reject = true;
       } else {
         ATH_MSG_DEBUG ("Insert new track in PrdSignatureSet");
@@ -269,7 +234,8 @@ void Trk::DenseEnvironmentsAmbiguityScoreProcessorTool::updatePixelSplitInformat
 }
 
 //==================================================================================================
-void Trk::DenseEnvironmentsAmbiguityScoreProcessorTool::overlappingTracks(const TracksScores* scoredTracks,
+void 
+Trk::DenseEnvironmentsAmbiguityScoreProcessorTool::overlappingTracks(const TracksScores* scoredTracks,
                                                                           InDet::PixelGangedClusterAmbiguities *splitClusterMap,
                                                                           Trk::PRDtoTrackMap &prd_to_track_map) const
 {
@@ -372,5 +338,43 @@ void Trk::DenseEnvironmentsAmbiguityScoreProcessorTool::overlappingTracks(const
     }
     
   }  
-  }
+}
+
+void
+Trk::DenseEnvironmentsAmbiguityScoreProcessorTool::dumpStat(MsgStream &out) const
+{
+   auto parseFileName=[](const std::string & fullname){
+     auto dotPosition = fullname.rfind(".");
+     auto slashPosition = fullname.rfind("/");
+     auto stringLength = dotPosition - slashPosition;
+     return fullname.substr(slashPosition, stringLength);
+   };
+   std::streamsize ss = out.precision();
+   int iw=9;
+   out << "Output from ";
+   out << parseFileName(__FILE__);
+   out << "::";
+   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";
+   }
+   if (m_stat.globalCount(TrackStat3::nTracksWithoutParam)>0) {
+      out << "  Tracks without parameters       :   "<< m_stat.globalCount(TrackStat3::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 << "------------------------------------------------------------------------------------" << "\n";
+   out << std::setiosflags(std::ios::fixed | std::ios::showpoint) << std::setprecision(2)
+       << "    definition: ( 0.0 < Barrel < " << m_etaBounds[TrackStat3::iBarrel-1] << " < Transition < " << m_etaBounds[TrackStat3::iTransi-1]
+       << " < Endcap < " << m_etaBounds[TrackStat3::iEndcap-1] << " < Forward < " << m_etaBounds[TrackStat3::iForwrd-1] << " )" << "\n";
+   out << "------------------------------------------------------------------------------------" << "\n";
+   out << std::setprecision(ss);
+}
+
 
diff --git a/Tracking/TrkTools/TrkAmbiguityProcessor/src/DenseEnvironmentsAmbiguityScoreProcessorTool.h b/Tracking/TrkTools/TrkAmbiguityProcessor/src/DenseEnvironmentsAmbiguityScoreProcessorTool.h
index a64481f3b548932a01c9304af0723ba7f12ac947..69cfa2e5ae91ef14b0974fc35fcfe09778d57acc 100644
--- a/Tracking/TrkTools/TrkAmbiguityProcessor/src/DenseEnvironmentsAmbiguityScoreProcessorTool.h
+++ b/Tracking/TrkTools/TrkAmbiguityProcessor/src/DenseEnvironmentsAmbiguityScoreProcessorTool.h
@@ -21,12 +21,10 @@
 
 #include "TrkToolInterfaces/IPRDtoTrackMapTool.h"
 #include "TrkEventUtils/PRDtoTrackMap.h"
-
+#include "AmbiCounter.icc"
 #include <map>
 #include <set>
 #include <vector>
-#include <ostream>
-
 
 namespace InDet{
   class IPixelClusterSplitProbTool;
@@ -40,12 +38,19 @@ namespace Trk {
 
   class DenseEnvironmentsAmbiguityScoreProcessorTool: public AthAlgTool, 
                                                       virtual public ITrackAmbiguityScoreProcessorTool
-    {
-    public:
-      
+  {
+  public:
+    enum class EStatType {
+      kNtracks,
+      kNcandidates,
+      kNcandScoreZero,
+      kNcandDouble,
+      kNCounter
+    };
+    using TrackStat3 = AmbiCounter<EStatType>;
       // public types
       typedef std::multimap< TrackScore, const Track* > TrackScoreMap;
-      typedef std::set<const PrepRawData*> PrdSignature;
+      typedef std::vector<const PrepRawData*> PrdSignature;
       typedef std::set<PrdSignature> PrdSignatureSet;
       
       // default methods
@@ -59,69 +64,9 @@ namespace Trk {
 
       /** statistics output to be called by algorithm during finalize. */
       void statistics() override;
+      void dumpStat(MsgStream &out) const;
     private:
-      class TrackStat {
-      public:
-         TrackStat(const std::vector<float> &eta_bounds) : m_etabounds(&eta_bounds){}
-
-         enum EStatType {
-            kNtracks,
-            kNcandidates,
-            kNcandScoreZero,
-            kNcandDouble,
-            kNStatTypes
-         };
-         enum EGlobalStatType {
-            kNevents,
-            kNInvalidTracks,
-            kNTracksWithoutParam,
-            kNGlobalStatTypes,
-         };
-         /** internal monitoring: categories for counting different types of extension results*/
-         enum StatIndex {iAll = 0, iBarrel = 1, iTransi = 2, iEndcap = 3, iForwrd = 4, kNStatRegions=5};
-
-         class Counter {
-         public:
-            Counter &operator+=(const Counter &a) {
-               m_counter += a.m_counter;
-               return *this;
-            }
-            Counter &operator++()   { ++m_counter; return *this;}
-            operator int() const    { return m_counter; }
-            int value()    const    { return m_counter; }
-         private:
-            unsigned int m_counter=0;
-         };
-
-         void newEvent() {
-            ++m_globalCounter[kNevents];
-         }
-
-         TrackStat &operator+=(const TrackStat &a) {
-            for (unsigned int i=0; i<kNGlobalStatTypes; ++i) {
-               m_globalCounter[i]+= a.m_globalCounter[i];
-            }
-            for (unsigned int i=0; i<kNStatTypes; ++i) {
-               for (unsigned int region_i=0; region_i< kNStatRegions; ++region_i) {
-                  m_counter[i][region_i] += a.m_counter[i][region_i];
-               }
-            }
-            return *this;
-         }
-
-         /** helper for monitoring and validation: does success/failure counting */
-         void increment_by_eta(EStatType type, const Track* track, bool updateAll=true);
-         void dumpStatType(MsgStream &out, const std::string &head, EStatType type, unsigned short iw=9) const;
-         void dump(MsgStream &out) const;
-
-         const std::vector<float>  &etaBounds() const { return *m_etabounds; }  //!< eta intervals for internal monitoring
-
-      private:
-         std::array<Counter,kNGlobalStatTypes>                      m_globalCounter;
-         std::array<std::array<Counter, kNStatRegions>,kNStatTypes> m_counter;
-
-         const std::vector<float>  *m_etabounds;           //!< eta intervals for internal monitoring
-      };
+
       
       /**Add passed TrackCollection, and Trk::PrepRawData from tracks to caches
          @param tracks the TrackCollection is looped over, 
@@ -175,46 +120,11 @@ namespace Trk {
       /**NN split sprob cut for 3 particle clusters */      
       float m_sharedProbCut2;
 
-      std::vector<float>     m_etabounds;           //!< eta intervals for internal monitoring
+      std::vector<float>     m_etaBounds;           //!< eta intervals for internal monitoring
       mutable std::mutex m_statMutex;
-      mutable TrackStat  m_stat ATLAS_THREAD_SAFE;
+      mutable TrackStat3  m_stat ATLAS_THREAD_SAFE;
   };
 } //end ns
 
-void Trk::DenseEnvironmentsAmbiguityScoreProcessorTool::TrackStat::increment_by_eta(EStatType type,
-                                                                               const Track* track,
-                                                                               bool updateAll) {
-   std::array<Counter,kNStatRegions> &Ntracks = m_counter[type];
-   if (updateAll) ++Ntracks[iAll];
-
-   // test
-   if (!track) {
-      ++m_globalCounter[kNInvalidTracks];
-   }
-   // use first parameter
-   if (!track->trackParameters()) {
-      ++m_globalCounter[kNTracksWithoutParam];
-   }
-   else {
-      double eta = track->trackParameters()->front()->eta();
-      for (unsigned int region_i=1; region_i< kNStatRegions; ++region_i) {
-         if (std::abs(eta)      < (*m_etabounds)[region_i-1]) {
-            ++Ntracks[region_i];
-            break;
-         }
-      }
-   }
-}
-
-void Trk::DenseEnvironmentsAmbiguityScoreProcessorTool::TrackStat::dumpStatType(MsgStream &out,
-                                                                           const std::string &head,
-                                                                           EStatType type,
-                                                                           unsigned short iw) const {
-   out << head << std::setiosflags(std::ios::dec);
-   for (unsigned region_i=0; region_i<kNStatRegions; ++region_i) {
-      out << std::setw(iw) << m_counter[type][region_i].value();
-   }
-   out << "\n";
-}
 
 #endif // TrackAmbiguityProcessorTool_H
diff --git a/Tracking/TrkTools/TrkAmbiguityProcessor/src/SimpleAmbiguityProcessorTool.cxx b/Tracking/TrkTools/TrkAmbiguityProcessor/src/SimpleAmbiguityProcessorTool.cxx
index a67dd8230344107925d51845e1448db83ed2fca9..732a75b3b66279310040dd962d10c799c37df8c5 100644
--- a/Tracking/TrkTools/TrkAmbiguityProcessor/src/SimpleAmbiguityProcessorTool.cxx
+++ b/Tracking/TrkTools/TrkAmbiguityProcessor/src/SimpleAmbiguityProcessorTool.cxx
@@ -11,8 +11,6 @@
 #include "TrkToolInterfaces/IPRD_AssociationTool.h"
 #include "TrkTrack/TrackCollection.h"
 #include "TrkTrack/TrackInfo.h"
-#include <ext/functional>
-#include <iterator>
 #include <map>
 #include <memory>
 
@@ -31,7 +29,7 @@ Trk::SimpleAmbiguityProcessorTool::SimpleAmbiguityProcessorTool(const std::strin
                 2.5,
                 2.5,
                 10.0} ),
-  m_Nevents(0)
+  m_stat(m_etabounds)
 {
   // statitics stuff
 
@@ -123,101 +121,30 @@ StatusCode Trk::SimpleAmbiguityProcessorTool::initialize()
   }
 
   // statistics
-  if (m_etabounds.size() != kNRegions) {
-     ATH_MSG_ERROR( "There must be exactly " << kNRegions
+  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;
   }
-  m_stat.init();
   return sc;
 }
 //==================================================================================================
 
 
-StatusCode Trk::SimpleAmbiguityProcessorTool::finalize()
-{
+StatusCode Trk::SimpleAmbiguityProcessorTool::finalize(){
   return StatusCode::SUCCESS;
 }
 
-void Trk::SimpleAmbiguityProcessorTool::statistics()
-{
-
+void Trk::SimpleAmbiguityProcessorTool::statistics(){
   if (msgLvl(MSG::INFO)) {
      MsgStream &out=msg(MSG::INFO);
      out << " -- statistics:" << "\n";
+     std::lock_guard<std::mutex> lock( m_statMutex );
      dumpStat(out);
      out << endmsg;
   }
 }
 
-void Trk::SimpleAmbiguityProcessorTool::dumpStat(MsgStream &out) const {
-   std::lock_guard<std::mutex> lock( m_statMutex );
-    auto parseFileName=[](const std::string & fullname){
-      auto dotPosition = fullname.rfind('.');
-      auto slashPosition = fullname.rfind('/');
-      auto stringLength = dotPosition - slashPosition;
-    return fullname.substr(slashPosition, stringLength);
-   };
-   // @TODO restore ios
-    std::streamsize ss = std::cout.precision();
-    out << "Output from ";
-    out << parseFileName(__FILE__);
-    out << "::";
-    out << __func__;
-    out << "\n";
-    out <<             "---------------------------------------------------------------------------------" << "\n";
-    out <<             "  Number of events processed      :   "<< m_Nevents << "\n";
-    out <<             "  statistics by eta range          ------All---Barrel---Trans.--- Endcap---DBM---" << "\n";
-    out <<             "---------------------------------------------------------------------------------" << "\n";
-    dumpRegions(out,   "  Number of candidates at input   :", Trk::SimpleAmbiguityProcessorTool::Counter::kNcandidates);
-    dumpRegions(out,   "  - candidates rejected score 0   :", Trk::SimpleAmbiguityProcessorTool::Counter::kNcandScoreZero);
-    dumpRegions(out,   "  - candidates rejected as double :", Trk::SimpleAmbiguityProcessorTool::Counter::kNcandDouble);
-    out <<             "---------------------------------------------------------------------------------" << "\n";
-    dumpRegions(out,   "  candidates with good score      :", Trk::SimpleAmbiguityProcessorTool::Counter::kNscoreOk);
-    if (m_tryBremFit) {
-       dumpRegions(out,"  + recovered after brem refit    :", Trk::SimpleAmbiguityProcessorTool::Counter::kNscoreZeroBremRefit);
-    }
-    dumpRegions(out,   "  candidates rejected score 0     :", Trk::SimpleAmbiguityProcessorTool::Counter::kNscoreZero);
-    if (m_tryBremFit) {
-       dumpRegions(out,"  + rejected failed brem refit    :", Trk::SimpleAmbiguityProcessorTool::Counter::kNscoreZeroBremRefitFailed);
-    }
-    out <<             "---------------------------------------------------------------------------------" << "\n";
-    dumpRegions(out,   "  number of normal fits           :", Trk::SimpleAmbiguityProcessorTool::Counter::kNfits);
-    if (m_tryBremFit) {
-       dumpRegions(out,"  + 2nd brem fit for failed fit   :", Trk::SimpleAmbiguityProcessorTool::Counter::kNrecoveryBremFits);
-       dumpRegions(out,"  normal brem fits for electrons  :", Trk::SimpleAmbiguityProcessorTool::Counter::kNbremFits);
-    }
-    out <<             "---------------------------------------------------------------------------------" << "\n";
-    dumpRegions(out,   "  sum of succesful fits           :", Trk::SimpleAmbiguityProcessorTool::Counter::kNgoodFits);
-    dumpRegions(out,   "  sum of failed fits              :", Trk::SimpleAmbiguityProcessorTool::Counter::kNfailedFits);
-    out <<             "---------------------------------------------------------------------------------" << "\n";
-    dumpRegions(out,   "  Number of subtracks created     :", Trk::SimpleAmbiguityProcessorTool::Counter::kNsubTrack);
-    dumpRegions(out,   "  Number of candidates excluded   :", Trk::SimpleAmbiguityProcessorTool::Counter::kNnoSubTrack);
-    out <<             "---------------------------------------------------------------------------------" << "\n";
-    dumpRegions(out,   "  Number of tracks accepted       :", Trk::SimpleAmbiguityProcessorTool::Counter::kNaccepted);
-    if (m_tryBremFit) {
-       dumpRegions(out,"  including number of brem fits   :", Trk::SimpleAmbiguityProcessorTool::Counter::kNacceptedBrem);
-    }
-    out <<             "---------------------------------------------------------------------------------" << "\n";
-    out << std::setiosflags(std::ios::fixed | std::ios::showpoint) << std::setprecision(2)
-        <<             "    definition: ( 0.0 < Barrel < " << m_etabounds[iBarrel-1] << " < Transition < " << m_etabounds[iTransi-1]
-        <<             " < Endcap < " << m_etabounds[iEndcap-1] << " DBM )" << "\n";
-    out <<             "-------------------------------------------------------------------------------" << "\n";
-    out.precision (ss);
-}
-
-//==================================================================================================
-
-/** helper function for statistics */
-void Trk::SimpleAmbiguityProcessorTool::missingTrackOrParameters(const Track* track) const {
-  if (!track) {
-     ATH_MSG_ERROR ("track pointer zero, should not happen!");
-     return;
-  }
-  if (!track->trackParameters()) {
-     ATH_MSG_WARNING ("No track parameters, needed for statistics code in Trk::SimpleAmbiguityProcessorTool!");
-  }
-}
 
 //==================================================================================================
 
@@ -225,13 +152,13 @@ void Trk::SimpleAmbiguityProcessorTool::missingTrackOrParameters(const Track* tr
     and then returns the tracks which have been selected*/
 
 
-TrackCollection*  Trk::SimpleAmbiguityProcessorTool::process(const TrackCollection* trackCol, Trk::PRDtoTrackMap *prd_to_track_map) const {
+TrackCollection*  Trk::SimpleAmbiguityProcessorTool::process(const TrackCollection* trackCol, Trk::PRDtoTrackMap *prdToTrackMap) const {
   std::vector<const Track*> tracks;
   tracks.reserve(trackCol->size());
   for(const Track* e: *trackCol){
     tracks.push_back(e);
   }
-  return process_vector(tracks, prd_to_track_map);
+  return process_vector(tracks, prdToTrackMap);
 }
 
 
@@ -246,24 +173,22 @@ TrackCollection*  Trk::SimpleAmbiguityProcessorTool::process(const TracksScores*
   return re_tracks;
 }
 
-TrackCollection*  Trk::SimpleAmbiguityProcessorTool::process_vector(std::vector<const Track*> &tracks, Trk::PRDtoTrackMap *prd_to_track_map) const{
+TrackCollection*  Trk::SimpleAmbiguityProcessorTool::process_vector(std::vector<const Track*> &tracks, Trk::PRDtoTrackMap *prdToTrackMap) const{
   using namespace std;
 
-  DEBUG_CODE( ntupleReset(tracks) );
-  DEBUG_CODE( fillEventData(tracks) );
-  ++m_Nevents; // statistics
+  m_stat.newEvent(); // statistics
 
   TrackScoreMap trackScoreTrackMap;
-  std::unique_ptr<Trk::PRDtoTrackMap> prd_to_track_map_cleanup;
-  if (!prd_to_track_map) {
+  std::unique_ptr<Trk::PRDtoTrackMap> prdToTrackMap_cleanup;
+  if (!prdToTrackMap) {
      // create internal PRD-to-track map
-     prd_to_track_map_cleanup = m_assoTool->createPRDtoTrackMap();
-     prd_to_track_map = prd_to_track_map_cleanup.get();
+     prdToTrackMap_cleanup = m_assoTool->createPRDtoTrackMap();
+     prdToTrackMap = prdToTrackMap_cleanup.get();
   }
   //put tracks into maps etc
   ATH_MSG_DEBUG ("Adding input track candidates to list");
-  Counter stat;
-  addNewTracks(tracks, trackScoreTrackMap, *prd_to_track_map, stat);
+  Counter stat(m_etabounds);
+  addNewTracks(tracks, trackScoreTrackMap, *prdToTrackMap, stat);
 
   // going to do simple algorithm for now:
   // - take track with highest score
@@ -271,73 +196,75 @@ TrackCollection*  Trk::SimpleAmbiguityProcessorTool::process_vector(std::vector<
   // - take next highest scoring tracks, and repeat
 
   ATH_MSG_DEBUG ("Solving Tracks");
-  std::vector<std::unique_ptr<const Trk::Track> > cleanup_tracks;
-  TrackCollection* final_tracks = solveTracks(trackScoreTrackMap, *prd_to_track_map,cleanup_tracks, stat);
+  std::vector<std::unique_ptr<const Trk::Track> > cleanupTracks;
+  TrackCollection* finalTracks = solveTracks(trackScoreTrackMap, *prdToTrackMap,cleanupTracks, stat);
   {
      std::lock_guard<std::mutex> lock(m_statMutex);
      m_stat += stat;
   }
-  if (msgLvl(MSG::DEBUG)) dumpTracks(*final_tracks);
-  return final_tracks;
+  if (msgLvl(MSG::DEBUG)) dumpTracks(*finalTracks);
+  return finalTracks;
 }
 
 //==================================================================================================
 void Trk::SimpleAmbiguityProcessorTool::addNewTracks(const std::vector<const Track*> &tracks,
                                                      TrackScoreMap& trackScoreTrackMap,
-                                                     Trk::PRDtoTrackMap &prd_to_track_map,
-                                                     Trk::SimpleAmbiguityProcessorTool::Counter &stat) const
+                                                     Trk::PRDtoTrackMap &prdToTrackMap,
+                                                     Counter &stat) const
 {
-  using namespace std;
-  DEBUG_CODE( findTrueTracks(&tracks) );
+  using namespace std; 
   ATH_MSG_DEBUG ("Number of tracks at Input: "<<tracks.size());
+
   /** signature map to drop double track. */
   PrdSignatureSet prdSigSet;
-  for(const Track *a_track : tracks) {
-    DEBUG_CODE( resetTrackOutliers() );
-    ATH_MSG_DEBUG ("Processing track candidate "<<a_track);
-    // statistics
-    increment_by_eta(Counter::kNcandidates,stat,a_track);
-    bool reject = false;
-    // only fitted tracks get hole search, input is not fitted
-    TrackScore score = m_scoringTool->score( *a_track, true);
-    DEBUG_CODE( setBarcodeStats(a_track,score) );
-    // veto tracks with score 0
-    if (score==0) { 
-      ATH_MSG_DEBUG ("Candidate score is zero, reject it");
-      // statistic
-      increment_by_eta(Counter::kNcandScoreZero,stat,a_track);
-      reject = true;
-      DEBUG_CODE(fillBadTrack(a_track,prd_to_track_map) );
-    } else {
-      ATH_MSG_DEBUG ("Track Score is "<< score);
-      // double track rejection
-      if (m_dropDouble) {
-        std::vector<const Trk::PrepRawData*> prds = m_assoTool->getPrdsOnTrack(prd_to_track_map, *a_track);
-        // 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 exits already
-        if ( !(prdSigSet.insert(prdSig)).second ) {
-          ATH_MSG_DEBUG ("Double track, reject it !");
-          // statistic
-          increment_by_eta(Counter::kNcandDouble,stat,a_track);
-          reject = true;
-          DEBUG_CODE(fillDuplicateTrack(a_track) );
-        } else {
-          ATH_MSG_DEBUG ("Insert new track in PrdSignatureSet");
-        }
+
+  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
+      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) {
+          std::vector<const Trk::PrepRawData*> 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 exits 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
+        ATH_MSG_VERBOSE ("Track  ("<< pTrack <<") has score "<<score);
+        TrackPtr ptr(pTrack);
+        if (!m_forceRefit) ptr.forceFitted();
+	      trackScoreTrackMap.insert( make_pair(-score,std::move(ptr)) );
       }
     }
-    if (!reject) {
-      // add track to map, map is sorted small to big ! set if fitted
-      ATH_MSG_VERBOSE ("Track  ("<< a_track <<") has score "<<score);
-      TrackPtr ptr(a_track);
-      if (!m_forceRefit) ptr.forceFitted();
-      trackScoreTrackMap.insert( make_pair(-score,std::move(ptr)) );
-    }
-  }
+  
   ATH_MSG_DEBUG ("Number of tracks in map:"<<trackScoreTrackMap.size());
-  DEBUG_CODE( countTrueTracksInMap( trackScoreTrackMap ) );
 }
 
 //==================================================================================================
@@ -345,9 +272,9 @@ void Trk::SimpleAmbiguityProcessorTool::addNewTracks(const std::vector<const Tra
 void Trk::SimpleAmbiguityProcessorTool::addTrack(Trk::Track* in_track,
                                                  const bool fitted,
                                                  TrackScoreMap &trackScoreTrackMap,
-                                                 Trk::PRDtoTrackMap &prd_to_track_map,
-                                                 std::vector<std::unique_ptr<const Trk::Track> >& cleanup_tracks,
-                                                 Trk::SimpleAmbiguityProcessorTool::Counter &stat) const
+                                                 Trk::PRDtoTrackMap &prdToTrackMap,
+                                                 std::vector<std::unique_ptr<const Trk::Track> >& cleanupTracks,
+                                                 Counter &stat) const
 {
   using namespace std;
   std::unique_ptr<Trk::Track> atrack(in_track);
@@ -356,79 +283,96 @@ void Trk::SimpleAmbiguityProcessorTool::addTrack(Trk::Track* in_track,
   bool suppressHoleSearch = fitted ? m_suppressHoleSearch : true;
   if (m_trackSummaryTool.isEnabled()) {
      m_trackSummaryTool->computeAndReplaceTrackSummary(*atrack,
-                                                       &prd_to_track_map,
+                                                       &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
-    increment_by_eta(Counter::kNscoreOk,stat,atrack.get());
-    // add track to map, map is sorted small to big !
-    trackScoreTrackMap.insert( make_pair(-score, TrackPtr(atrack.release(), fitted)) );
-    return;
-  }
-  //track score is zero here...
-  // do we try to recover the track ?
-  if (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");
+  if (score!=0)
+    {
+      ATH_MSG_DEBUG ("Track  ("<< atrack.get() <<") has score "<<score);
       // statistic
-      increment_by_eta(Counter::kNscoreZeroBremRefitFailed,stat,atrack.get());
-      increment_by_eta(Counter::kNfailedFits,stat,atrack.get());
-      // clean up
-      cleanup_tracks.push_back(std::move(atrack));
-	} else {
+      stat.incrementCounterByRegion(ECounter::kNscoreOk,atrack.get());
+
+      // add track to map, map is sorted small to big !
+      trackScoreTrackMap.insert( 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
-    increment_by_eta(Counter::kNgoodFits,stat,bremTrack.get());
+          stat.incrementCounterByRegion(ECounter::kNgoodFits,bremTrack.get());
+
 	  // rerun score
 	  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);
+	  if (score!=0)
+	    {
+              ATH_MSG_DEBUG ("Brem refit successful, recovered track  ("<< atrack.get() <<") has score "<<score);
 	      // statistics
-	      increment_by_eta(Counter::kNscoreZeroBremRefit,stat,bremTrack.get());
+	      stat.incrementCounterByRegion(ECounter::kNscoreZeroBremRefit,bremTrack.get());
+
 	      // add track to map, map is sorted small to big !
 	      trackScoreTrackMap.insert( make_pair(-score, TrackPtr(bremTrack.release(), fitted)) );
 	      return;
-	    } 
+	    }
+	  else
+	    {
 	      ATH_MSG_DEBUG ("Brem refit gave still track score zero, reject it");
 	      // statistic
-	      increment_by_eta(Counter::kNscoreZeroBremRefitScoreZero,stat,bremTrack.get());
-	    
-      cleanup_tracks.push_back(std::move(atrack));
-	  }
-  } else {
-    ATH_MSG_DEBUG ("Track score is zero, reject it");
-    // statistic
-    increment_by_eta(Counter::kNscoreZero,stat,atrack.get());
-    DEBUG_CODE( rejectedTrack(atrack.get(), prd_to_track_map) );
-    cleanup_tracks.push_back(std::move(atrack));
+	      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,
-                                                                Trk::PRDtoTrackMap &prd_to_track_map,
-                                                                std::vector<std::unique_ptr<const Trk::Track> >& cleanup_tracks,
-                                                                Trk::SimpleAmbiguityProcessorTool::Counter &stat) const
+                                                                Trk::PRDtoTrackMap &prdToTrackMap,
+                                                                std::vector<std::unique_ptr<const Trk::Track> >& cleanupTracks,
+                                                                Counter &stat) const
 {
-  std::unique_ptr<TrackCollection> final_tracks(std::make_unique<TrackCollection>());
-  using namespace std;
- 
-  DEBUG_CODE( fitStatReset() );
-
+  std::unique_ptr<TrackCollection> finalTracks(std::make_unique<TrackCollection>());
   ATH_MSG_DEBUG ("Starting to solve tracks");
-
   // now loop as long as map is not empty
   while ( !trackScoreTrackMap.empty() )
     {
@@ -441,93 +385,75 @@ TrackCollection *Trk::SimpleAmbiguityProcessorTool::solveTracks(TrackScoreMap& t
       // clean it out to make sure not to many shared hits
       ATH_MSG_VERBOSE ("--- Trying next track "<<atrack.track()<<"\t with score "<<-ascore);
       std::unique_ptr<Trk::Track> cleanedTrack;
-      auto [cleanedTrack_tmp,keep_orig] = m_selectionTool->getCleanedOutTrack( atrack.track() , -(ascore), prd_to_track_map);
+      auto [cleanedTrack_tmp,keep_orig] = m_selectionTool->getCleanedOutTrack( atrack.track() , -(ascore), prdToTrackMap);
       cleanedTrack.reset( cleanedTrack_tmp);
 
       // cleaned track is input track and fitted
       if (keep_orig && atrack.fitted() )
 	{
 
-          DEBUG_CODE( keepFittedInputTrack(atrack.track(), ascore) );
 	  // track can be kept as is and is already fitted
 	  ATH_MSG_DEBUG ("Accepted track "<<atrack.track()<<"\t has score "<<-(ascore));
 	  // statistic
-	  increment_by_eta(Counter::kNaccepted,stat,atrack.track());
+	  stat.incrementCounterByRegion(ECounter::kNaccepted,atrack.track());
 	  if (m_tryBremFit && atrack->info().trackProperties(Trk::TrackInfo::BremFit))
-             increment_by_eta(Counter::kNacceptedBrem,stat,atrack.track());
+             stat.incrementCounterByRegion(ECounter::kNacceptedBrem,atrack.track());
 
 	  // add track to PRD_AssociationTool
-          StatusCode sc = m_assoTool->addPRDs(prd_to_track_map, *atrack.track());
+          StatusCode sc = m_assoTool->addPRDs(prdToTrackMap, *atrack.track());
 	  if (sc.isFailure()) msg(MSG::ERROR) << "addPRDs() failed" << endmsg;
 	  // add to output list 
-
-          DEBUG_CODE( acceptedTrack(atrack.track()) );
-
-	  final_tracks->push_back( const_cast<Track*>(atrack.release()) );
-
-	}
-      else if ( keep_orig )
-	{
-
-          DEBUG_CODE( memoriseOutliers(itnext->second.frst) );
-
+	  finalTracks->push_back( const_cast<Track*>(atrack.release()) );
+	} else if ( keep_orig ) {
 	  // 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, prd_to_track_map, cleanup_tracks, stat);
+	  refitTrack(atrack.track(),trackScoreTrackMap, prdToTrackMap, cleanupTracks, stat);
           if (atrack.newTrack()) {
-             cleanup_tracks.push_back( std::unique_ptr<Trk::Track>(atrack.release()) );
+             cleanupTracks.push_back( std::unique_ptr<Trk::Track>(atrack.release()) );
           }
 	  // delete original copy
 	 }
       else if ( cleanedTrack )
 	{
-
-           DEBUG_CODE(newCleanedTrack(cleanedTrack.get(), atrack.track()) );
-
 	  // now delete original track
           if (atrack.newTrack()) {
-              cleanup_tracks.push_back( std::unique_ptr<Trk::Track>(atrack.release()));
+              cleanupTracks.push_back( std::unique_ptr<Trk::Track>(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
-	  increment_by_eta(Counter::kNsubTrack,stat,cleanedTrack.get());
+	  stat.incrementCounterByRegion(ECounter::kNsubTrack,cleanedTrack.get());
 
 	  // track needs fitting !
-	  addTrack( cleanedTrack.release(), false, trackScoreTrackMap, prd_to_track_map, cleanup_tracks, stat);
+	  addTrack( cleanedTrack.release(), false, trackScoreTrackMap, prdToTrackMap, cleanupTracks, stat);
 
-	}
-      else
-	{
-
-          DEBUG_CODE( acceptedTrack(atrack.track()));
+	} else {
 
 	  // track should be discarded
 	  ATH_MSG_DEBUG ("Track "<< atrack.track() << " is excluded, no subtrack, reject");
 	  // statistic
-	  increment_by_eta(Counter::kNnoSubTrack,stat,atrack.track());
-    if (atrack.newTrack()) {
-       cleanup_tracks.push_back(  std::unique_ptr<Trk::Track>(atrack.release()) );
-    }
+	  stat.incrementCounterByRegion(ECounter::kNnoSubTrack,atrack.track());
+
+          if (atrack.newTrack()) {
+             cleanupTracks.push_back(  std::unique_ptr<Trk::Track>(atrack.release()) );
+          }
 	  // don't forget to drop track from map
 	}
     }
-  
-  ATH_MSG_DEBUG ("Finished, number of track on output: "<<final_tracks->size());
-  DEBUG_CODE( eventSummary(final_tracks) );
-  return final_tracks.release();
+  ATH_MSG_DEBUG ("Finished, number of track on output: "<<finalTracks->size());
+  return finalTracks.release();
 }
 
 //==================================================================================================
 
 void Trk::SimpleAmbiguityProcessorTool::refitTrack( const Trk::Track* track,
                                                     TrackScoreMap& trackScoreTrackMap,
-                                                    Trk::PRDtoTrackMap &prd_to_track_map,
-                                                    std::vector<std::unique_ptr<const Trk::Track> >& cleanup_tracks,
-                                                    Trk::SimpleAmbiguityProcessorTool::Counter &stat) const
+                                                    Trk::PRDtoTrackMap &prdToTrackMap,
+                                                    std::vector<std::unique_ptr<const Trk::Track> >& cleanupTracks,
+                                                    Counter &stat) const
 {
   using namespace std;
   std::unique_ptr<Trk::Track> newTrack;
@@ -536,7 +462,7 @@ void Trk::SimpleAmbiguityProcessorTool::refitTrack( const Trk::Track* track,
       {
 	// simple case, fit PRD directly
 	ATH_MSG_VERBOSE ("Refit track "<<track<<" from PRDs");
-	newTrack.reset( refitPrds (track, prd_to_track_map,stat) );
+	newTrack.reset( refitPrds (track, prdToTrackMap,stat) );
       }
     else 
       {
@@ -578,12 +504,9 @@ void Trk::SimpleAmbiguityProcessorTool::refitTrack( const Trk::Track* track,
   if (newTrack)
     {
       ATH_MSG_DEBUG ("New track successfully fitted"<<newTrack.get());
-      DEBUG_CODE( newCleanedTrack( newTrack.get(), atrack.get()) );
-
-      addTrack( newTrack.release(), true, trackScoreTrackMap, prd_to_track_map, cleanup_tracks, stat);
+      addTrack( newTrack.release(), true, trackScoreTrackMap, prdToTrackMap, cleanupTracks, stat);
     }
   else {
-     DEBUG_CODE( fillFailedFit(track, prd_to_track_map) );
      ATH_MSG_DEBUG ("Fit failed !");
   }  
   
@@ -592,12 +515,12 @@ void Trk::SimpleAmbiguityProcessorTool::refitTrack( const Trk::Track* track,
 //==================================================================================================
 
 Trk::Track* Trk::SimpleAmbiguityProcessorTool::refitPrds( const Trk::Track* track,
-                                                          Trk::PRDtoTrackMap &prd_to_track_map,
-                                                          Trk::SimpleAmbiguityProcessorTool::Counter &stat) const
+                                                          Trk::PRDtoTrackMap &prdToTrackMap,
+                                                          Counter &stat) const
 {
 
   // get vector of PRDs
-  std::vector<const Trk::PrepRawData*> prds = m_assoTool->getPrdsOnTrack(prd_to_track_map,*track);
+  std::vector<const Trk::PrepRawData*> prds = m_assoTool->getPrdsOnTrack(prdToTrackMap,*track);
 
   if ( prds.empty() ) {
     msg(MSG::WARNING) << "No PRDs on track"<<endmsg;
@@ -622,7 +545,7 @@ Trk::Track* Trk::SimpleAmbiguityProcessorTool::refitPrds( const Trk::Track* trac
   if (m_tryBremFit && track->info().trackProperties(Trk::TrackInfo::BremFit))
     {
       // statistics
-      increment_by_eta(Counter::kNbremFits,stat,track);
+      stat.incrementCounterByRegion(ECounter::kNbremFits,track);
 
       ATH_MSG_VERBOSE ("Brem track, refit with electron brem fit");
       newTrack = m_fitterTool->fit(prds, *par, true, Trk::electron);
@@ -631,7 +554,7 @@ Trk::Track* Trk::SimpleAmbiguityProcessorTool::refitPrds( const Trk::Track* trac
   else
     {
       // statistics
-      increment_by_eta(Counter::kNfits,stat,track);
+      stat.incrementCounterByRegion(ECounter::kNfits,track);
 
       ATH_MSG_VERBOSE ("Normal track, refit");
       newTrack = m_fitterTool->fit(prds, *par, true, m_particleHypothesis);
@@ -640,7 +563,7 @@ Trk::Track* Trk::SimpleAmbiguityProcessorTool::refitPrds( const Trk::Track* trac
 	  (!m_caloSeededBrem || track->info().patternRecoInfo(Trk::TrackInfo::TrackInCaloROI)))
 	{
 	  // statistics
-          increment_by_eta(Counter::kNrecoveryBremFits,stat,track);
+          stat.incrementCounterByRegion(ECounter::kNrecoveryBremFits,track);
 
 	  ATH_MSG_VERBOSE ("Normal fit failed, try brem recovery");
 	  newTrack = m_fitterTool->fit(prds, *par, true, Trk::electron);
@@ -650,7 +573,7 @@ Trk::Track* Trk::SimpleAmbiguityProcessorTool::refitPrds( const Trk::Track* trac
   if(newTrack)
     {
       // statistic
-      increment_by_eta(Counter::kNgoodFits,stat,newTrack);
+      stat.incrementCounterByRegion(ECounter::kNgoodFits,newTrack);
 
       //keeping the track of previously accumulated TrackInfo
       const Trk::TrackInfo& old_info = track->info();
@@ -659,7 +582,7 @@ Trk::Track* Trk::SimpleAmbiguityProcessorTool::refitPrds( const Trk::Track* trac
   else
     {
       // statistic
-      increment_by_eta(Counter::kNfailedFits,stat,track);
+      stat.incrementCounterByRegion(ECounter::kNfailedFits,track);
     }
   return newTrack;
 }
@@ -667,7 +590,7 @@ Trk::Track* Trk::SimpleAmbiguityProcessorTool::refitPrds( const Trk::Track* trac
 //==================================================================================================
 
 Trk::Track* Trk::SimpleAmbiguityProcessorTool::refitRots( const Trk::Track* track,
-                                                          Trk::SimpleAmbiguityProcessorTool::Counter &stat) const
+                                                          Counter &stat) const
 {
 
   ATH_MSG_VERBOSE ("Refit track "<<track);
@@ -679,7 +602,7 @@ Trk::Track* Trk::SimpleAmbiguityProcessorTool::refitRots( const Trk::Track* trac
       track->info().trackProperties(Trk::TrackInfo::BremFit))
     {
       // statistics
-      increment_by_eta(Counter::kNbremFits,stat,track);
+      stat.incrementCounterByRegion(ECounter::kNbremFits,track);
 
       ATH_MSG_VERBOSE ("Brem track, refit with electron brem fit");
       newTrack = m_fitterTool->fit(*track, true, Trk::electron);
@@ -687,7 +610,7 @@ Trk::Track* Trk::SimpleAmbiguityProcessorTool::refitRots( const Trk::Track* trac
   else
     {
       // statistics
-      increment_by_eta(Counter::kNfits,stat,track);
+      stat.incrementCounterByRegion(ECounter::kNfits,track);
 
       ATH_MSG_VERBOSE ("Normal track, refit");
       newTrack = m_fitterTool->fit(*track, true, m_particleHypothesis);
@@ -697,7 +620,7 @@ Trk::Track* Trk::SimpleAmbiguityProcessorTool::refitRots( const Trk::Track* trac
 	  (!m_caloSeededBrem || track->info().patternRecoInfo(Trk::TrackInfo::TrackInCaloROI)))
 	{
 	  // statistics
-          increment_by_eta(Counter::kNrecoveryBremFits,stat,track);
+          stat.incrementCounterByRegion(ECounter::kNrecoveryBremFits,track);
 
 	  ATH_MSG_VERBOSE ("Normal fit failed, try brem recovery");
 	  newTrack = m_fitterTool->fit(*track, true, Trk::electron);
@@ -707,7 +630,7 @@ Trk::Track* Trk::SimpleAmbiguityProcessorTool::refitRots( const Trk::Track* trac
   if(newTrack)
     {
       // statistic
-      increment_by_eta(Counter::kNgoodFits,stat,newTrack);
+      stat.incrementCounterByRegion(ECounter::kNgoodFits,newTrack);
 
       //keeping the track of previously accumulated TrackInfo
       const Trk::TrackInfo& old_info = track->info();
@@ -716,7 +639,7 @@ Trk::Track* Trk::SimpleAmbiguityProcessorTool::refitRots( const Trk::Track* trac
   else
     {
       // statistic
-      increment_by_eta(Counter::kNfailedFits,stat,track);
+      stat.incrementCounterByRegion(ECounter::kNfailedFits,track);
     }
   return newTrack;
 }
@@ -731,14 +654,71 @@ void Trk::SimpleAmbiguityProcessorTool::dumpTracks( const TrackCollection& track
   TrackScore totalScore = 0;
   TrackCollection::const_iterator it    = tracks.begin();
   TrackCollection::const_iterator itEnd = tracks.end();
-  for (; it != itEnd ; ++it)
-    {
+  for (; it != itEnd ; ++it){
       // score track:
       const TrackScore score = m_scoringTool->score( **it, m_suppressHoleSearch );
       ATH_MSG_VERBOSE (num++<<"\tTrack :"<<*it<<"\tScore: "<<score);
       totalScore+=score;
     }
   ATH_MSG_DEBUG ("Total event score : "<<totalScore);
+  
+  
+}
+
+void 
+Trk::SimpleAmbiguityProcessorTool::dumpStat(MsgStream &out) const {
+  auto parseFileName=[](const std::string & fullname){
+    auto dotPosition = fullname.rfind(".");
+    auto slashPosition = fullname.rfind("/");
+    auto stringLength = dotPosition - slashPosition;
+    return fullname.substr(slashPosition, stringLength);
+  };
+  // @TODO restore ios
+  std::streamsize ss = std::cout.precision();
+  out << "Output from ";
+  out << parseFileName(__FILE__);
+  out << "::";
+  out << __func__;
+  out << "\n";
+  out <<             "---------------------------------------------------------------------------------" << "\n";
+  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 <<             "---------------------------------------------------------------------------------" << "\n";
+  out << m_stat.dumpRegions(   "  candidates with good score      :", ECounter::kNscoreOk);
+  if (m_tryBremFit) {
+     out << m_stat.dumpRegions("  + recovered after brem refit    :", ECounter::kNscoreZeroBremRefit);
+  }
+  out << m_stat.dumpRegions(   "  candidates rejected score 0     :", ECounter::kNscoreZero);
+  if (m_tryBremFit) {
+     out << m_stat.dumpRegions("  + rejected failed brem refit    :", ECounter::kNscoreZeroBremRefitFailed);
+  }
+  out <<             "---------------------------------------------------------------------------------" << "\n";
+  out << m_stat.dumpRegions(   "  number of normal fits           :", ECounter::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 <<             "---------------------------------------------------------------------------------" << "\n";
+  out << m_stat.dumpRegions(   "  sum of succesful fits           :", ECounter::kNgoodFits);
+  out << m_stat.dumpRegions(   "  sum of failed fits              :", ECounter::kNfailedFits);
+  out <<             "---------------------------------------------------------------------------------" << "\n";
+  out << m_stat.dumpRegions(   "  Number of subtracks created     :", ECounter::kNsubTrack);
+  out << m_stat.dumpRegions(   "  Number of candidates excluded   :", ECounter::kNnoSubTrack);
+  out <<             "---------------------------------------------------------------------------------" << "\n";
+  out << m_stat.dumpRegions(   "  Number of tracks accepted       :", ECounter::kNaccepted);
+  if (m_tryBremFit) {
+     out << m_stat.dumpRegions("  including number of brem fits   :", ECounter::kNacceptedBrem);
+  }
+  out <<             "---------------------------------------------------------------------------------" << "\n";
+  out << std::setiosflags(std::ios::fixed | std::ios::showpoint) << std::setprecision(2)
+      <<             "    definition: ( 0.0 < Barrel < " << m_etabounds[Counter::iBarrel-1] << " < Transition < " << m_etabounds[Counter::iTransi-1]
+      <<             " < Endcap < " << m_etabounds[Counter::iEndcap-1] << " DBM )" << "\n";
+  out <<             "-------------------------------------------------------------------------------" << "\n";
+  out.precision (ss);
 }
 
 
diff --git a/Tracking/TrkTools/TrkAmbiguityProcessor/src/SimpleAmbiguityProcessorTool.h b/Tracking/TrkTools/TrkAmbiguityProcessor/src/SimpleAmbiguityProcessorTool.h
index deeaa910ead8a4963c6e2786eeca05777f6c8db8..1f7b0f441b4671abc6b27c376f8f5d80d1bb7960 100644
--- a/Tracking/TrkTools/TrkAmbiguityProcessor/src/SimpleAmbiguityProcessorTool.h
+++ b/Tracking/TrkTools/TrkAmbiguityProcessor/src/SimpleAmbiguityProcessorTool.h
@@ -5,8 +5,6 @@
 #ifndef SIMPLEAMBIGUITYPROCESSORTOOL_H
 #define SIMPLEAMBIGUITYPROCESSORTOOL_H
 
-// turn on debugging ? uncomment this
-//#define SIMPLEAMBIGPROCDEBUGCODE
 
 #include "AthenaBaseComps/AthAlgTool.h"
 #include "TrkToolInterfaces/ITrackAmbiguityProcessorTool.h"
@@ -25,20 +23,11 @@
 
 #include <set>
 #include <vector>
-#include <functional>
-#include <atomic>
 #include <mutex>
-#include <algorithm>
 #include <array>
+#include "AmbiCounter.icc"
 
 #include "TrackPtr.h"
-
-#if defined SIMPLEAMBIGPROCNTUPLECODE || defined SIMPLEAMBIGPROCDEBUGCODE
-#define DEBUG_CODE(a) do { a; } while (false)
-#else
-#define DEBUG_CODE(a) do {  } while (false)
-#endif
-
 class AtlasDetectorID;
 class PixelID;
 
@@ -50,8 +39,12 @@ namespace Trk {
 
   class SimpleAmbiguityProcessorTool : public AthAlgTool, virtual public ITrackAmbiguityProcessorTool 
     {
-      struct Counter;
     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;
     
@@ -68,20 +61,20 @@ namespace Trk {
 	 @param tracks collection of tracks which will have ambiguities resolved. Will not be 
 	 modified.
 	 The tracks will be refitted if no fitQuality is given at input.
-         @param prd_to_track_map on optional prd-to-track map being filled by the processor.
+         @param prdToTrackMap on optional prd-to-track map being filled by the processor.
 	 @return new collections of tracks, with ambiguities resolved. Ownership is passed on 
 	 (i.e. client handles deletion).
 
          If no prd-to-track map is given the processor will create
          one internally (exported to storegate).*/
-      virtual TrackCollection*  process(const TrackCollection*, Trk::PRDtoTrackMap *prd_to_track_map) const override;
+      virtual TrackCollection*  process(const TrackCollection*, Trk::PRDtoTrackMap *prdToTrackMap) const override;
       virtual TrackCollection*  process(const TracksScores* scoredTracks) const override;
 
       /** statistics output to be called by algorithm during finalize. */
       virtual void statistics() override;
     private:
 
-      TrackCollection*  process_vector(std::vector<const Track*> &tracks, Trk::PRDtoTrackMap *prd_to_track_map) const;
+      TrackCollection*  process_vector(std::vector<const Track*> &tracks, Trk::PRDtoTrackMap *prdToTrackMap) const;
 
       /**Add passed TrackCollection, and Trk::PrepRawData from tracks to caches
 	 @param tracks the TrackCollection is looped over, 
@@ -89,19 +82,19 @@ namespace Trk {
 	 The Trk::PrepRawData from each Trk::Track are added to the IPRD_AssociationTool*/
       void addNewTracks(const std::vector<const Track*> &tracks,
                         TrackScoreMap& trackScoreTrackMap,
-                        Trk::PRDtoTrackMap &prd_to_track_map,
-                        Trk::SimpleAmbiguityProcessorTool::Counter &stat) const;
+                        Trk::PRDtoTrackMap &prdToTrackMap,
+                        Counter &stat) const;
 
       void addTrack(Track* track, const bool fitted,
                     TrackScoreMap &trackScoreMap,
-                    Trk::PRDtoTrackMap &prd_to_track_map,
-                    std::vector<std::unique_ptr<const Trk::Track> >& cleanup_tracks,
-                    Trk::SimpleAmbiguityProcessorTool::Counter &stat) const;
+                    Trk::PRDtoTrackMap &prdToTrackMap,
+                    std::vector<std::unique_ptr<const Trk::Track> >& cleanupTracks,
+                    Counter &stat) const;
 
       TrackCollection *solveTracks(TrackScoreMap &trackScoreTrackMap,
-                                   Trk::PRDtoTrackMap &prd_to_track_map,
-                                   std::vector<std::unique_ptr<const Trk::Track> > &cleanup_tracks,
-                                   Trk::SimpleAmbiguityProcessorTool::Counter &stat) const;
+                                   Trk::PRDtoTrackMap &prdToTrackMap,
+                                   std::vector<std::unique_ptr<const Trk::Track> > &cleanupTracks,
+                                   Counter &stat) const;
 
       /** add subtrack to map */
       void addSubTrack( const std::vector<const TrackStateOnSurface*>& tsos) const;
@@ -109,17 +102,17 @@ namespace Trk {
       /** refit track */
       void refitTrack( const Trk::Track* track,
                        TrackScoreMap &trackScoreMap,
-                       Trk::PRDtoTrackMap &prd_to_track_map,
-                       std::vector<std::unique_ptr<const Trk::Track> >& cleanup_tracks,
-                       Trk::SimpleAmbiguityProcessorTool::Counter &stat) const;
+                       Trk::PRDtoTrackMap &prdToTrackMap,
+                       std::vector<std::unique_ptr<const Trk::Track> >& cleanupTracks,
+                       Counter &stat) const;
 
       /** refit PRDs */
-      Track* refitPrds( const Track* track, Trk::PRDtoTrackMap &prd_to_track_map,
-                        Trk::SimpleAmbiguityProcessorTool::Counter &stat) const;
+      Track* refitPrds( const Track* track, Trk::PRDtoTrackMap &prdToTrackMap,
+                        Counter &stat) const;
 
       /** refit ROTs corresponding to PRDs */
       Track* refitRots( const Track* track,
-                        Trk::SimpleAmbiguityProcessorTool::Counter &stat) const;
+                        Counter &stat) const;
 
       /** print out tracks and their scores for debugging*/
       void dumpTracks(const TrackCollection& tracks) const;
@@ -155,13 +148,13 @@ namespace Trk {
       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*/
+	    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.*/
+	    Refitting tool used is configured via jobOptions.*/
       ToolHandle<ITrackFitter> m_fitterTool;
 
       ToolHandle<Trk::IPRDtoTrackMapTool>         m_assoTool
@@ -171,134 +164,17 @@ namespace Trk {
         {this, "TrackSummaryTool", "InDetTrackSummaryToolNoHoleSearch"};
 
       /** selection tool - here the decision which hits remain on a track and
-	  which are removed are made
+	     which are removed are made
       */
       ToolHandle<IAmbiTrackSelectionTool> m_selectionTool;
 
       /** monitoring statistics */
-      enum StatIndex {iAll = 0, iBarrel = 1, iTransi = 2, iEndcap = 3, iDBM = 4, kNRegions=5};
+      //enum RegionIndex {iAll = 0, iBarrel = 1, iTransi = 2, iEndcap = 3, iDBM = 4, nRegions=5};
       std::vector<float> m_etabounds;           //!< eta intervals for internal monitoring
-      struct Counter {
-         enum ECounter {kNcandidates, kNcandScoreZero, kNcandDouble,
-                        kNscoreOk,kNscoreZeroBremRefit,kNscoreZeroBremRefitFailed,kNscoreZeroBremRefitScoreZero,kNscoreZero,
-                        kNaccepted,kNsubTrack,kNnoSubTrack,kNacceptedBrem,
-                        kNbremFits,kNfits,kNrecoveryBremFits,kNgoodFits,kNfailedFits, kNCounter};
-         Counter() {init(); }
-         void init() {
-            for (unsigned int stat_i=0; stat_i < kNCounter; ++stat_i) {
-               std::fill(m_counter[stat_i].begin(),m_counter[stat_i].end(),0);
-            }
-         }
-         void increment(ECounter stat_i, unsigned int eta_bin_i) {
-            if (eta_bin_i>=kNRegions) return;
-            if (stat_i<kNCounter && eta_bin_i < m_counter[stat_i].size()) {} else {  throw std::range_error("out of range"); }
-            ++m_counter[stat_i][eta_bin_i];
-         }
-         void operator +=(const Counter &a) {
-            for (unsigned int stat_i=0; stat_i < kNCounter; ++stat_i) {
-               for (unsigned int eta_bin_i=0; eta_bin_i < a.m_counter[stat_i].size(); ++eta_bin_i) {
-                  m_counter[stat_i][eta_bin_i] += a.m_counter[stat_i][eta_bin_i];
-               }
-            }
-         }
-
-         std::array<int,SimpleAmbiguityProcessorTool::kNRegions> m_counter[kNCounter];
-      };
-      mutable std::atomic<int> m_Nevents;
       mutable std::mutex m_statMutex;
-      mutable Counter m_stat;
-      /** internal monitoring: categories for counting different types of extension results*/
-
-      /** helper for monitoring and validation: does success/failure counting */
-      void increment_by_eta(SimpleAmbiguityProcessorTool::Counter::ECounter counter,
-                            SimpleAmbiguityProcessorTool::Counter &stat,
-                            const Track*,
-                            bool update_all=true) const;
-
-      SimpleAmbiguityProcessorTool::StatIndex etaIndex(double eta) const;
-      void missingTrackOrParameters(const Track* track) const;
-
-      void dumpRegions(MsgStream &out,
-                       const char *head,
-                       SimpleAmbiguityProcessorTool::Counter::ECounter stat_i) const;
-
-//==================================================================================================
-//
-//
-//   FROM HERE EVERYTHING IS DEBUGGING CODE !!!
-//
-//==================================================================================================
-
-#if defined SIMPLEAMBIGPROCNTUPLECODE || defined SIMPLEAMBIGPROCDEBUGCODE
-       virtual void ntupleReset() {}
-       virtual void fillEventData(std::vector<const Track*> &tracks)  { (void) tracks; };
-       virtual void findTrueTracks(std::vector<const Track*> &recTracks)  { (void) recTracks; }; 
-       virtual void fillValidationTree(const Trk::Track* track) const { (void) track; }
-       virtual void resetTrackOutliers() {}
-       virtual void setBarcodeStats(const Trk::Track *a_track, TrackScore score) { (void) a_track; (void) score;}
-       virtual void fillBadTrack(const Trk::Track *a_track, const Trk::PRDtoTrackMap &prd_to_track_map)
-         { (void) a_track; (void) prd_to_track_map; }
-
-       virtual void fillDuplicateTrack(const Trk::Track *a_track) { (void) a_track; }
-       virtual void associateToOrig(const Trk::Track*new_track, const Trk::Track* orig_track) { (void) new_track; (void) orig_track; }
-       virtual void keepTrackOfTracks(const Trk::Track* oldTrack, const Trk::Track* newTrack) { (void) oldTrack; (void) newTrack; }
-       virtual void countTrueTracksInMap(const TrackScoreMap &trackScoreTrackMap) { (void) trackScoreTrackMap; }
-       virtual void rejectedTrack(const Trk::Track*track, const Trk::PRDtoTrackMap &prd_to_track_map)
-         { (void) track; (void) prd_to_track_map; }
-
-       virtual void fitStatReset() {}
-       virtual void keepFittedInputTrack(const Trk::Track *a_track, TrackScore ascore)
-         { (void) a_track; (void) ascore; }
-
-       virtual void acceptedTrack(const Trk::Track*track) { (void) track; }
-       virtual void memoriseOutliers(const Trk::Track*track) { (void) track; }
-       virtual void newCleanedTrack(const Trk::Track*new_track, const Trk::Track* orig_track) { (void) new_track; (void) orig_track; }
-       virtual void eventSummary(const TrackCollection *final_tracks) override {(void) final_tracks; }
-       virtual void fillFailedFit(const Trk::Track *a_track, const Trk::PRDtoTrackMap &prd_to_track_map)
-         { (void) a_track; (void) prd_to_track_map; }
-
-#endif // DebugCode
-    };
-
-    inline
-    SimpleAmbiguityProcessorTool::StatIndex SimpleAmbiguityProcessorTool::etaIndex(double eta) const {
-       eta=std::abs(eta);
-       if (eta < m_etabounds[0]) return Trk::SimpleAmbiguityProcessorTool::iBarrel;
-       else if (eta < m_etabounds[1]) return Trk::SimpleAmbiguityProcessorTool::iTransi;
-       else if (eta < m_etabounds[2]) return Trk::SimpleAmbiguityProcessorTool::iEndcap;
-       else if ((eta > m_etabounds[3]) && (eta < m_etabounds[4])) return Trk::SimpleAmbiguityProcessorTool::iDBM;
-       return Trk::SimpleAmbiguityProcessorTool::kNRegions;
-    }
-
-    inline void SimpleAmbiguityProcessorTool::increment_by_eta(SimpleAmbiguityProcessorTool::Counter::ECounter stat_i,
-                                                               SimpleAmbiguityProcessorTool::Counter &stat,
-                                                               const Track* track,
-                                                               bool updateAll) const
-    {
-       if (updateAll) stat.increment(stat_i,Trk::SimpleAmbiguityProcessorTool::iAll);
-       // test
-       if (track && track->trackParameters() ) {
-          // @TODO make sure that list of track parameters is not empty
-          stat.increment(stat_i, etaIndex(track->trackParameters()->front()->eta()) );
-       }
-       else {
-          missingTrackOrParameters(track);
-       }
-    }
-
-   inline
-   void SimpleAmbiguityProcessorTool::dumpRegions(MsgStream &out,
-                                                  const char *head,
-                                                  SimpleAmbiguityProcessorTool::Counter::ECounter stat_i) const {
-      const int iw=9;
-      out << head;
-      for (unsigned int eta_bin_i=0; eta_bin_i < kNRegions; ++eta_bin_i) {
-         assert( eta_bin_i < m_stat.m_counter[stat_i].size() );
-         out << std::setiosflags(std::ios::dec) << std::setw(iw) << m_stat.m_counter[stat_i][eta_bin_i];
-      }
-      out << "\n";
-   }
+      mutable Counter m_stat ATLAS_THREAD_SAFE;
 
+    };
 } //end ns
 
 #endif // TrackAmbiguityProcessorTool_H