Skip to content
Snippets Groups Projects
Forked from atlas / athena
76388 commits behind the upstream repository.
Code owners
Assign users and groups as approvers for specific file changes. Learn more.
InDetRecStatisticsAlg.cxx 36.55 KiB
/*
  Copyright (C) 2002-2020 CERN for the benefit of the ATLAS collaboration
*/

//  file:   InDetRecStatisticsAlg.cxx
//  author: Sven Vahsen (sevahsen AT lbl DOT gov), with contributions from Andrei Gaponenko and Laurent Vacavant
//
//  to do-list:
//     o write out percentage of tracks with bad tracksummary
//     o add energy of mctracks for Michael 
//     o don't save intermediate newTracking track's to ntuple
//     o statistics prints hit association purity, (holes, shared hits in sct/pixels/b-layer, outliers, etc...)
//     o navigation between hits and tracks       
//     X check Propagator defaults (check with Andrei regarding Tool)    
//     o count tracks with without associated hits, without truth, truth without beginvertex
//     o improved navigation between truth and reconstructed tracks
//     o follow atlas naming conventions for all variable and method names

#include "GaudiKernel/SmartDataPtr.h" 
#include "GaudiKernel/IPartPropSvc.h"
#include "HepPDT/ParticleData.hh"
#include "CLHEP/Units/SystemOfUnits.h"
#include <cmath>
#include <memory>
#include <ostream>
#include <iostream>
#include <sstream>

// Private Helpers

// Trk

#include "InDetIdentifier/PixelID.h"
#include "InDetIdentifier/SCT_ID.h"
#include "InDetIdentifier/TRT_ID.h"
#include "TrkEventUtils/RoT_Extractor.h"
#include "TrkRIO_OnTrack/RIO_OnTrack.h"
#include "TrkEventPrimitives/FitQualityOnSurface.h"
#include "TrkEventPrimitives/ResidualPull.h"
#include "TrkSurfaces/Surface.h"
#include "TrkTrack/TrackCollection.h"
#include "TrkTrack/Track.h"
#include "TrkEventPrimitives/FitQuality.h"
#include "TrkSurfaces/PerigeeSurface.h"
#include "TrkSurfaces/PlaneSurface.h"
#include "TrkEventPrimitives/LocalParameters.h"
#include "TrkCompetingRIOsOnTrack/CompetingRIOsOnTrack.h"
#include "TrkTruthData/TrackTruth.h"
#include "TrkTruthData/TrackTruthCollection.h"
#include "TrkEventPrimitives/JacobianThetaPToCotThetaPt.h"
#include "TrkParameters/TrackParameters.h"       //vv
#include "TrkToolInterfaces/IExtendedTrackSummaryTool.h"
#include "TrkToolInterfaces/IUpdator.h"
#include "TrkToolInterfaces/IResidualPullCalculator.h"
#include "TrkToolInterfaces/ITruthToTrack.h"
#include "TrkToolInterfaces/ITrackSelectorTool.h"

// Other
#include "AtlasDetDescr/AtlasDetectorID.h"
#include "IdDictDetDescr/IdDictManager.h"
#include "GeneratorObjects/McEventCollection.h"
#include "InDetRIO_OnTrack/TRT_DriftCircleOnTrack.h"
#include "VxVertex/VxContainer.h"
#include "VxVertex/RecVertex.h"

#include "InDetRecStatistics/InDetRecStatisticsAlg.h"
#include "InDetRecStatistics/TrackStatHelper.h"
#include "AtlasHepMC/GenParticle.h"
#include "TruthHelper/PileUpType.h"
#include "IdDictDetDescr/IdDictManager.h" 




static const char * const s_linestr ATLAS_THREAD_SAFE = "----------------------------------------------------------------------------------------------------------------------------------------------";
static const char * const s_linestr2 ATLAS_THREAD_SAFE= "..............................................................................................................................................";

InDet::InDetRecStatisticsAlg::InDetRecStatisticsAlg(const std::string& name, ISvcLocator* pSvcLocator) :
  AthReentrantAlgorithm(name, pSvcLocator),
  m_particleDataTable          (nullptr),
  m_trtID                      (nullptr),
  m_idDictMgr                  (nullptr),
  m_truthToTrack               ("Trk::TruthToTrack"),
  m_trkSummaryTool             ("Trk::TrackSummaryTool/InDetTrackSummaryTool"),
  m_updatorHandle              ("Trk::KalmanUpdator/TrkKalmanUpdator"),
  m_updator                    (nullptr),
  m_residualPullCalculator     ("Trk::ResidualPullCalculator/ResidualPullCalculator"),
  m_McTrackCollection_key      ("TruthEvent"),
  m_trackSelectorTool          ("InDet::InDetDetailedTrackSelectorTool"),
  m_doSharedHits               (true),
  m_UseTrackSummary            (true),
  m_printSecondary             (false),
  m_minPt                      (1000),
  m_maxEta                     (2.7),
  m_maxEtaBarrel               (0.8),
  m_maxEtaTransition           (1.6),
  m_maxEtaEndcap               (2.5),
  m_fakeTrackCut               (0.9),
  m_fakeTrackCut2              (0.7),
  m_matchTrackCut              (0.5),
  m_maxRStartPrimary           (  25.0*CLHEP::mm),
  m_maxRStartSecondary         ( 360.0*CLHEP::mm),
  m_maxZStartPrimary           ( 200.0*CLHEP::mm),
  m_maxZStartSecondary         (2000.0*CLHEP::mm),
  m_minREndPrimary             ( 400.0*CLHEP::mm),
  m_minREndSecondary           (1000.0*CLHEP::mm), 
  m_minZEndPrimary             (2300.0*CLHEP::mm),
  //m_maxZIndet                (),
  m_minZEndSecondary           (3200.0*CLHEP::mm),
  m_useTrackSelection          (false),
  m_doTruth                    (true),
  m_minEtaDBM                  (2.5),
  m_maxEtaDBM                  (10.0),
  m_isUnbiased                 (0),
  m_events_processed           (0)
{
  // m_RecTrackCollection_keys.push_back(std::string("Tracks"));
  // m_TrackTruthCollection_keys.push_back(std::string("TrackTruthCollection"));

  // Algorithm properties
  declareProperty("SummaryTool",                m_trkSummaryTool);
  declareProperty("TruthToTrackTool",           m_truthToTrack);
  declareProperty("UpdatorTool",                m_updatorHandle,
		  "Measurement updator to calculate unbiased track states");
  declareProperty("ResidualPullCalculatorTool", m_residualPullCalculator,
		  "Tool to calculate residuals and pulls");
  declareProperty("TrackCollectionKeys",        m_RecTrackCollection_keys);
  declareProperty("McTrackCollectionKey",       m_McTrackCollection_key);
  declareProperty("TrackTruthCollectionKeys",   m_TrackTruthCollection_keys);
  declareProperty("UseTrackSelection"       ,   m_useTrackSelection);
  declareProperty("DoTruth"                 ,   m_doTruth);
  declareProperty("TrackSelectorTool"       ,   m_trackSelectorTool);
  declareProperty("DoSharedHits",               m_doSharedHits);
  declareProperty("UseTrackSummary",            m_UseTrackSummary);
  declareProperty("PrintSecondary",             m_printSecondary);
  declareProperty("minPt",		        m_minPt);
  declareProperty("maxEta",		        m_maxEta);
  declareProperty("maxEtaBarrel",               m_maxEtaBarrel  );
  declareProperty("maxEtaTransition",           m_maxEtaTransition);
  declareProperty("maxEtaEndcap",               m_maxEtaEndcap);
  declareProperty("maxEtaDBM", m_maxEtaDBM);
  declareProperty("minEtaDBM", m_minEtaDBM);
  declareProperty("fakeTrackCut",               m_fakeTrackCut);
  declareProperty("fakeTrackCut2",              m_fakeTrackCut2);
  declareProperty("matchTrackCut",              m_matchTrackCut);
  declareProperty("maxRStartPrimary",	        m_maxRStartPrimary);
  declareProperty("maxRStartSecondary",	        m_maxRStartSecondary);
  declareProperty("maxZStartPrimary",	        m_maxZStartPrimary);
  declareProperty("maxZStartSecondary",         m_maxZStartSecondary);
  declareProperty("minREndPrimary",		m_minREndPrimary);
  declareProperty("minREndSecondary",		m_minREndSecondary);
  declareProperty("minZEndPrimary",		m_minZEndPrimary);
  declareProperty("minZEndSecondary",	        m_minZEndSecondary);   
  m_idHelper  = NULL;
  m_pixelID   = NULL;
  m_sctID     = NULL;
  m_UpdatorWarning = false;
  m_pullWarning = false;
}


// * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *
StatusCode InDet::InDetRecStatisticsAlg::initialize(){

  // Part 1: Get the messaging service, print where you are
  ATH_MSG_DEBUG("initialize()");

  ATH_CHECK(m_assoTool.retrieve());

  StatusCode sc1 = getServices();           // retrieve store gate service etc
  if (sc1.isFailure()) {
    ATH_MSG_FATAL("Error retrieving services !");
    return StatusCode::FAILURE;
  }   

  if (m_RecTrackCollection_keys.size()<=0) {
    ATH_MSG_ERROR("No reco track collection specified! Aborting.");
    return StatusCode::FAILURE;
  }

  if (m_doTruth && m_RecTrackCollection_keys.size() != m_TrackTruthCollection_keys.size()) {
    ATH_MSG_ERROR("You have specified "
		  << m_RecTrackCollection_keys.size() 
		  << " TrackCollection keys, and " <<  m_TrackTruthCollection_keys.size() 
		  << " TrackTruthCollection keys."
		  << " You have to specify one TrackTruthCollection for each" 
		  << " TrackCollection! Exiting."
		  );
    return StatusCode::FAILURE;
  }

  // ----------------------------------
  // use updator to get unbiased states
  if ( ! m_updatorHandle.empty() ) {
    if (m_updatorHandle.retrieve().isFailure()) {
      ATH_MSG_FATAL("Could not retrieve measurement updator tool: "
	  << m_updatorHandle);
      return StatusCode::FAILURE;
    }
    m_updator = &(*m_updatorHandle);
  } else {
    ATH_MSG_DEBUG(
      "No Updator for unbiased track states given, use normal states!");
    m_updator = 0;
  }
  
  
  //get residual and pull calculator
  if (m_residualPullCalculator.empty()) {
    ATH_MSG_INFO(
      "No residual/pull calculator for general hit residuals configured."
	);
    ATH_MSG_INFO(
      "It is recommended to give R/P calculators to the det-specific tool"
	<< " handle lists then.");
  } else if (m_residualPullCalculator.retrieve().isFailure()) {
    ATH_MSG_FATAL("Could not retrieve "<< m_residualPullCalculator 
	<<" (to calculate residuals and pulls) ");
    
  } else {
    ATH_MSG_INFO("Generic hit residuals&pulls will be calculated in one or both "
		 << "available local coordinates");
  }

  // create one TrackStatHelper object of each trackCollection --- this is used to accumulate track and hit statistics

  struct cuts ct;
  ct.maxEtaBarrel=  m_maxEtaBarrel;
  ct.maxEtaTransition= m_maxEtaTransition;
  ct.maxEtaEndcap=        m_maxEtaEndcap;
  ct.fakeTrackCut=	  m_fakeTrackCut;
  ct.fakeTrackCut2=	  m_fakeTrackCut2;
  ct.matchTrackCut	=  m_matchTrackCut;
  ct.maxRStartPrimary	 = m_maxRStartPrimary;
  ct.maxRStartSecondary	 = m_maxRStartSecondary;
  ct.maxZStartPrimary	 = m_maxZStartPrimary;
  ct.maxZStartSecondary	 = m_maxZStartSecondary;
  ct.minREndPrimary	 = m_minREndPrimary;
  ct.minREndSecondary	 = m_minREndSecondary;
  ct.minZEndPrimary	 = m_minZEndPrimary;
  ct.minZEndSecondary  	 = m_minZEndSecondary;  
  ct.minPt               = m_minPt;
  ct.minEtaDBM = m_minEtaDBM;
  ct.maxEtaDBM = m_maxEtaDBM;

  unsigned int nCollections = 0;
  for (SG::ReadHandleKeyArray<TrackCollection>::const_iterator 
       it = m_RecTrackCollection_keys.begin(); 
       it < m_RecTrackCollection_keys.end(); ++ it) {
    InDet::TrackStatHelper * collection = 
      new TrackStatHelper(it->key(),(m_doTruth ? m_TrackTruthCollection_keys[nCollections].key() : ""), m_doTruth);  
    nCollections ++;
    collection->SetCuts(ct);        
    m_SignalCounters.push_back(collection); 
  }
  
  StatusCode sc3 = resetStatistics();     // reset all statistic counters
  if (sc3.isFailure()) {
    ATH_MSG_FATAL("Error in resetStatistics !");
    return StatusCode::FAILURE;
  }     

  ATH_CHECK( m_RecTrackCollection_keys.initialize() );
  ATH_CHECK( m_McTrackCollection_key.initialize(m_doTruth && !m_McTrackCollection_key.key().empty()) );
  ATH_CHECK( m_TrackTruthCollection_keys.initialize() );

  return StatusCode :: SUCCESS;

}


// * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *

StatusCode InDet::InDetRecStatisticsAlg::execute(const EventContext &ctx)  const {

    ATH_MSG_DEBUG("entering execute()");

    // Get reconstructed tracks , generated tracks, and truth from storegate
    SG::ReadHandle<McEventCollection> SimTracks;

    if (m_doTruth) {
      SimTracks=SG::ReadHandle<McEventCollection>(m_McTrackCollection_key,ctx);
      if (!SimTracks.isValid()) {
        // @TODO warning ?
        ATH_MSG_WARNING("Error retrieving collections !");
        return StatusCode::SUCCESS;
      }
    }

    // Doesn't take account of pileup:
    //m_gen_tracks_processed += (*(SimTracks->begin()))->particles_size();
    m_events_processed ++;
    CounterLocal counter;

    // select charged and stable generated tracks
    // apply pt, eta etc cuts to generated tracks
    // devide generated tracks into primary, truncated, secondary

    std::vector <std::pair<HepMC::GenParticlePtr,int> > GenSignal;
    //     GenSignalPrimary, GenSignalTruncated, GenSignalSecondary;   
    unsigned int inTimeStart = 0;
    unsigned int inTimeEnd   = 0;
    if (m_doTruth) selectGenSignal ((SimTracks.isValid() ? &(*SimTracks) : nullptr), GenSignal, inTimeStart, inTimeEnd, counter);

    // step through the various reconstructed TrackCollections and 
    // corresponding TrackTruthCollections and produce statistics for each

    if (m_SignalCounters.size()<=0) {
      ATH_MSG_ERROR("No reco track collection specified! Aborting." 
	);
      return StatusCode::FAILURE;
    }

    std::vector< SG::ReadHandle<TrackCollection> > rec_track_collections = m_RecTrackCollection_keys.makeHandles(ctx);
    std::vector< SG::ReadHandle<TrackTruthCollection> > truth_track_collections;
    if (m_doTruth && !m_TrackTruthCollection_keys.empty()) {
      truth_track_collections = m_TrackTruthCollection_keys.makeHandles(ctx);
      if (truth_track_collections.size() != rec_track_collections.size()) {
        ATH_MSG_ERROR("Different number of reco and truth track collections (" << rec_track_collections.size() << "!=" << truth_track_collections.size() << ")" );
      }
    }
    if (m_SignalCounters.size() != rec_track_collections.size()) {
        ATH_MSG_ERROR("Number expected reco track collections does not match the actual number of such collections (" 
                      << m_SignalCounters.size() << "!=" << rec_track_collections.size() << ")" );
    }

    std::vector< SG::ReadHandle<TrackCollection> >::iterator rec_track_collections_iter = rec_track_collections.begin();
    std::vector< SG::ReadHandle<TrackTruthCollection> >::iterator truth_track_collections_iter = truth_track_collections.begin();
    for (std::vector <class TrackStatHelper *>::const_iterator statHelper 
	 =  m_SignalCounters.begin();
	 statHelper !=  m_SignalCounters.end();
         ++statHelper, ++rec_track_collections_iter) {
      assert( rec_track_collections_iter != rec_track_collections.end());

      ATH_MSG_DEBUG("Acessing TrackCollection " <<  m_RecTrackCollection_keys.at(rec_track_collections_iter - rec_track_collections.begin()).key());
      const TrackCollection       * RecCollection = &(**rec_track_collections_iter);
      const TrackTruthCollection  * TruthMap  = NULL;

      if (RecCollection)  ATH_MSG_DEBUG("Retrieved "
			      << RecCollection->size()
			      << " reconstructed tracks from storegate"
			);

      if (m_doTruth) {
        ATH_MSG_DEBUG("Acessing TrackTruthCollection " <<  m_TrackTruthCollection_keys.at(truth_track_collections_iter - truth_track_collections.begin()).key());
        assert( truth_track_collections_iter != truth_track_collections.end());
        TruthMap = &(**truth_track_collections_iter);
        if (TruthMap)   ATH_MSG_DEBUG("Retrieved " << TruthMap->size() 
			    << " TrackTruth elements from storegate");
        ++truth_track_collections_iter;
      }

      //start process of getting correct track summary

      // clean up association tool
      std::unique_ptr<Trk::PRDtoTrackMap> prd_to_track_map;
      if (m_doSharedHits) {
        prd_to_track_map = m_assoTool->createPRDtoTrackMap();
	// clear prdAssociationTool (this may be altered)
	// loop over tracks and add PRD 
	TrackCollection::const_iterator trackIt    = RecCollection->begin();
	TrackCollection::const_iterator trackItEnd = RecCollection->end();
	for ( ; trackIt != trackItEnd ; ++trackIt) {
	  if ( (m_assoTool->addPRDs(*prd_to_track_map, **trackIt)).isFailure() ) {
	    ATH_MSG_ERROR("could not add PRDs to association tool" );
	  }
	}
      }
      
      std::vector <const Trk::Track *>          RecTracks, RecSignal;    
      selectRecSignal                     (RecCollection, RecTracks,RecSignal,counter);

      ATH_MSG_DEBUG( 
		    "  RecTracks.size()="          << RecTracks.size()        
		    << ", GenSignal.size()="          << GenSignal.size());

      ATH_MSG_DEBUG("Accumulating Statistics...");
      (*statHelper)->addEvent    (RecCollection, 
				  RecTracks, 
                                  prd_to_track_map.get(),
				  GenSignal, 
				  TruthMap, 
				  m_idHelper, 
				  m_pixelID, 
				  m_sctID, 
				  m_trkSummaryTool.operator->(),
				  m_UseTrackSummary,
				  &inTimeStart,
				  &inTimeEnd);

      counter.m_counter[kN_rec_tracks_processed] += RecCollection->size();

      for (  TrackCollection::const_iterator it = RecCollection->begin() ; 
	     it < RecCollection->end(); ++ it){
	std::vector<const Trk::RIO_OnTrack*> rioOnTracks;
	Trk::RoT_Extractor::extract( rioOnTracks, 
				     (*it)->measurementsOnTrack()->stdcont() );
	counter.m_counter[kN_spacepoints_processed] += rioOnTracks.size();
      }

    }
    m_counter += counter;

    ATH_MSG_DEBUG("leaving execute()");
    return StatusCode::SUCCESS;
}


// * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *

StatusCode InDet :: InDetRecStatisticsAlg :: finalize() {

  // Part 1: Get the messaging service, print where you are
  ATH_MSG_DEBUG("finalize()");

  printStatistics();

  for (std::vector <class TrackStatHelper *>::const_iterator collection =  
       m_SignalCounters.begin(); collection !=  m_SignalCounters.end(); 
       collection++) {
    ATH_MSG_DEBUG(s_linestr2);
    delete (*collection);
  } 
  m_SignalCounters.clear();
  return StatusCode::SUCCESS;
}
 

StatusCode InDet :: InDetRecStatisticsAlg :: getServices ()
{
    // get the Particle Properties Service
    IPartPropSvc* partPropSvc = 0;
    StatusCode sc = evtStore()->service("PartPropSvc", partPropSvc, true);

    if (sc.isFailure()) {
        ATH_MSG_FATAL(" Could not initialize Particle Properties Service" 
	);
        return StatusCode::FAILURE;
    }
      
    m_particleDataTable = partPropSvc->PDT();

    //Set up ATLAS ID helper to be able to identify the RIO's det-subsystem.
  
    // Get the dictionary manager from the detector store
    const IdDictManager*  idDictMgr = 0;
    sc = detStore()->retrieve(idDictMgr, "IdDict");
    if (sc.isFailure()) {
      ATH_MSG_FATAL("Could not get IdDictManager !");
      return StatusCode::FAILURE;
    }
    
    // Initialize the helper with the dictionary information.
    sc = detStore()->retrieve(m_idHelper, "AtlasID");
    if (sc.isFailure()) {
      ATH_MSG_FATAL("Could not get AtlasDetectorID helper.");
      return StatusCode::FAILURE;
    }
   
   //get Pixel, SCT, TRT managers and helpers
 
   if (detStore()->retrieve(m_pixelID, "PixelID").isFailure()) {
     msg(MSG::FATAL) << "Could not get Pixel ID helper" << endmsg;
     return StatusCode::FAILURE;
   }
   if (detStore()->retrieve(m_sctID, "SCT_ID").isFailure()) {
     msg(MSG::FATAL) << "Could not get SCT ID helper" << endmsg;
     return StatusCode::FAILURE;
   }

   //retrieve the TRT helper only if not-SLHC layout used 
   sc = detStore()->retrieve(m_idDictMgr, "IdDict");
   if (sc.isFailure()) {
     ATH_MSG_FATAL("Could not get IdDictManager !");
     return StatusCode::FAILURE;
   } 
   const IdDictDictionary* dict = m_idDictMgr->manager()->find_dictionary("InnerDetector");
   if(!dict) {
     ATH_MSG_FATAL(" Cannot access InnerDetector dictionary ");
     return StatusCode::FAILURE;
   }

   bool isSLHC = false;
   if (dict->file_name().find("SLHC")!=std::string::npos) isSLHC=true;

   if(!isSLHC){
     if (detStore()->retrieve(m_trtID, "TRT_ID").isFailure()) {
       msg(MSG::FATAL) << "Could not get TRT ID helper" << endmsg;
       return StatusCode::FAILURE;
     }
   }
   //
  
   if (m_UseTrackSummary) {
     if (m_trkSummaryTool.retrieve().isFailure() ) {
       ATH_MSG_FATAL("Failed to retrieve tool " 
	   << m_trkSummaryTool);
       return StatusCode::FAILURE;
     } else {
       ATH_MSG_INFO("Retrieved tool " << m_trkSummaryTool);
     }
   } else {
     m_trkSummaryTool.disable();
   }

   if (m_doSharedHits) {
     if ( m_assoTool.retrieve().isFailure() ) {
       ATH_MSG_FATAL("Failed to retrieve tool " << m_assoTool);
       return StatusCode::FAILURE;
     } else {
       ATH_MSG_INFO("Retrieved tool " << m_assoTool);
     }
   } else {
     m_assoTool.disable();
   }

   // AG: init truthToTrack
   if (m_doTruth) {
     if (m_truthToTrack.retrieve().isFailure() ) {
       ATH_MSG_FATAL("Failed to retrieve tool " << m_truthToTrack);
       return StatusCode::FAILURE;
     } else {
       ATH_MSG_INFO("Retrieved tool " << m_truthToTrack);
     }
   } else {
     m_truthToTrack.disable();
   }
   
   //adding track selector tool
   if(m_useTrackSelection){
     if ( m_trackSelectorTool.retrieve().isFailure() ) {
       ATH_MSG_FATAL("Failed to retrieve tool " << m_trackSelectorTool);
       return StatusCode::FAILURE;   
     } else {
       ATH_MSG_INFO("Retrieved tool " << m_trackSelectorTool);
     }
   } else {
     m_trackSelectorTool.disable();
   }
   return StatusCode :: SUCCESS;
}

StatusCode InDet :: InDetRecStatisticsAlg :: resetStatistics() {
    m_counter.reset();
    m_events_processed           = 0;
  
    for (std::vector<InDet::TrackStatHelper *>::const_iterator counter = 
	   m_SignalCounters.begin(); 
	 counter != m_SignalCounters.end(); ++ counter) {
      (*counter)->reset();
    }
    return StatusCode :: SUCCESS;
}

void InDet::InDetRecStatisticsAlg::selectRecSignal(const TrackCollection* RecCollection, 
						   std::vector <const Trk::Track *> & RecTracks ,
						   std::vector <const Trk::Track *> & RecSignal,
                                                   InDet::InDetRecStatisticsAlg::CounterLocal &counter) const {
  
  for (  TrackCollection::const_iterator it = RecCollection->begin() ;
	 it != RecCollection->end(); ++ it){
    RecTracks.push_back(*it);
    const DataVector<const Trk::TrackParameters>* trackpara = 
      (*it)->trackParameters();
    
    if(trackpara->size() > 0){
      const Trk::TrackParameters* para = trackpara->front();
      if (para){
	if (para->pT() >  m_minPt && fabs(para->eta()) < m_maxEta) {
	  RecSignal.push_back(*it);
	}
      }
    }
    else {
      counter.m_counter[kN_rec_tracks_without_perigee] ++;
    }
  }
 return;
}

// select charged, stable particles in allowed pt and eta range
void InDet :: InDetRecStatisticsAlg ::
selectGenSignal  (const McEventCollection* SimTracks, 
		  std::vector <std::pair<HepMC::GenParticlePtr,int> > & GenSignal,
		  unsigned int /*inTimeStart*/, unsigned int /*inTimeEnd*/,
                  InDet::InDetRecStatisticsAlg::CounterLocal &counter) const //'unused' compiler warning
{
  if (! SimTracks) return;

  unsigned int nb_mc_event = SimTracks->size();  
  std::unique_ptr<PileUpType>  put = std::make_unique<PileUpType>(SimTracks);

  McEventCollection::const_iterator inTimeMBend;
  McEventCollection::const_iterator inTimeMBbegin;

  if (put)
    {
      inTimeMBbegin = put->in_time_minimum_bias_event_begin();
      inTimeMBend = put->in_time_minimum_bias_event_end();
    }

  for(unsigned int ievt=0; ievt<nb_mc_event; ++ievt)
    {
      const HepMC::GenEvent* genEvent = SimTracks->at(ievt);
#ifdef HEPMC3
      counter.m_counter[kN_gen_tracks_processed] += genEvent->particles().size();
#else
      counter.m_counter[kN_gen_tracks_processed] += genEvent->particles_size();
#endif
      if (put && inTimeMBbegin != inTimeMBend) // if not, inTimeStart and End are untouched
	{
	  //if (genEvent == *inTimeMBbegin) inTimeStart = ievt;
	  //if (genEvent == *inTimeMBend)   inTimeEnd   = ievt;
	}
      for (auto particle: *genEvent)
	{
	  // require stable particle from generation or simulation\	  s
	  if ((particle->status()%1000) != 1 )
	    continue;
	  int   pdgCode = particle->pdg_id();
	  const HepPDT::ParticleData* pd = m_particleDataTable->particle(std::abs(pdgCode));
	  if (!pd) {
	    ATH_MSG_DEBUG("Could not get particle data for particle with "
			 <<"pdgCode="<<pdgCode<< ", status=" << particle->status() 
			 << ", barcode=" << HepMC::barcode(particle));
	    ATH_MSG_DEBUG("GenParticle= " << particle);
	    continue;
	  }
	  float charge = pd->charge();
	  if (fabs(charge)<0.5)
	      continue;
	  if (fabs(particle->momentum().perp()) >  m_minPt  &&  
	      fabs(particle->momentum().pseudoRapidity()) < m_maxEta ) { 
	    std::pair<HepMC::GenParticlePtr,int> thisPair(particle,ievt);
	    GenSignal.push_back(thisPair);
	  }
	} // End of a particle iteration
    } // End of one GenEvent iteration
  return;
}

namespace {

   template <class T_Stream>
   class RestoreStream
   {
   public:
      RestoreStream(T_Stream &out) : m_stream(&out),m_precision(out.precision()) { }
      ~RestoreStream() { (*m_stream).precision(m_precision); }
   private:
      T_Stream  *m_stream;
      int        m_precision;
   };
}

void InDet :: InDetRecStatisticsAlg :: printStatistics() {
  if (!msgLvl(MSG::INFO)) return;

  ATH_MSG_INFO(" ********** Beginning InDetRecStatistics Statistics Table ***********");
  ATH_MSG_INFO("For documentation see https://twiki.cern.ch/twiki/bin/view/Atlas/InDetRecStatistics");
  ATH_MSG_INFO("(or for guaranteed latest version: http://atlas-sw.cern.ch/cgi-bin/viewcvs-atlas.cgi/offline/InnerDetector/InDetValidation/InDetRecStatistics/doc/mainpage.h?&view=markup )");
  ATH_MSG_INFO(" ********************************************************************");

  std::stringstream outstr;
  int def_precision(outstr.precision());
  outstr << "\n"
         << MSG::INFO 
	 << std::setiosflags(std::ios::fixed | std::ios::showpoint)  
	 << std::setw(7) << std::setprecision(2)
	 << s_linestr << "\n"
         << "Summary" << "\n" 
         << "\tProcessed              : " << m_events_processed
	 << " events, "  << m_counter.m_counter[kN_rec_tracks_processed]
	 << " reconstructed tracks with " << m_counter.m_counter[kN_spacepoints_processed]
	 << " hits, and "  << m_counter.m_counter[kN_gen_tracks_processed]
	 << " truth particles" << "\n"
         << "\tProblem objects        : " <<  m_counter.m_counter[kN_rec_tracks_without_perigee]
	 << " tracks without perigee, " 
	 << m_counter.m_counter[kN_unknown_hits] << " unknown hits" << "\n"
         << "\t" << "Reco  TrackCollections : ";
  bool first = true;
  for (std::vector <class TrackStatHelper *>::const_iterator collection =  
	 m_SignalCounters.begin();
       collection !=  m_SignalCounters.end(); collection++)
    {
      if (first) { 
      	first = false;
      } 
      else {
	outstr << ", ";
      }
      outstr << "\"" << (*collection)->key() << "\"";
    }
  ATH_MSG_INFO(outstr.str());
  outstr.str("");

  if (m_doTruth)
    {
      outstr.str("");
      outstr << "\n"
             << "\t" << "TrackTruthCollections  : ";
      first = true;
      for (std::vector <class TrackStatHelper *>::const_iterator collection =  m_SignalCounters.begin();
	   collection !=  m_SignalCounters.end(); collection++)
	{
	  if (first) { 
	    first = false;
	  } 
	  else {
	    outstr << ", ";
	  }
	  outstr << "\"" << (*collection)->Truthkey() << "\"";
	}
      ATH_MSG_INFO(outstr.str());
      outstr.str("");
    }
   outstr.str(""); 
   outstr << "\n" 
	  << s_linestr2 << "\n"
	  << "Cuts and Settings for Statistics Table" << "\n" 
	  << "\t" << "TrackSummary Statistics" << "\t" 
	  << (m_UseTrackSummary     ? "YES" : "NO") << "\n" 
	  << "\t" << "Signal                \t" << "pT > " 
	  << m_minPt/1000 << " GeV/c, |eta| < " << m_maxEta << "\t\t"
	  << "\t" << "Primary track start   \t" << "R < " 
	  << m_maxRStartPrimary << "mm and |z| < " 
	  << m_maxZStartPrimary << "mm" << "\n"
	  << "\t" << "Barrel                \t" << 0.0                
	  << "< |eta| < " << m_maxEtaBarrel     << "\t\t\t"
	  << "\t" << "Primary track end     \t" << "R > " 
	  << m_minREndPrimary   << "mm or |z| > " << m_minZEndPrimary   
	  << "mm" << "\n"
	  << "\t" << "Transition Region     \t" << m_maxEtaBarrel     
	  << "< |eta| < " << m_maxEtaTransition << "\t\t\t"
	  << "\t" << "Secondary (non-Primary) start \t" 
	  << " R < "    << m_maxRStartSecondary << "mm and" 
	  << " |z| < "  << m_maxZStartSecondary << " mm" << "\n"
	  << "\t" << "Endcap                \t" << m_maxEtaTransition 
	  << "< |eta| < " << m_maxEtaEndcap     << "\t\t\t"
	  << "\t" << "Secondary (non-primary) end   \t"
	  << " R > "    << m_minREndSecondary   << "mm or"
	  << " |z| > "  << m_minREndSecondary   << "mm" << "\n"
          << "\t" << "Forward                \t"
          << "|eta| > " << m_minEtaDBM     << "\n"
	  << "\t" << "Low prob tracks #1    \t" << "< "               
	  << m_fakeTrackCut  << " of hits from single Truth Track " 
	  << "\n"  
	  << "\t" << "Low prob tracks #2    \t" << "< "               
	  << m_fakeTrackCut2 << " of hits from single Truth Track " 
	  << "\n"  
	  << "\t" << "No link tracks        \t  Track has no link associated to an HepMC Particle" << "\n"
	  << "\t" << "Good reco tracks      \t" << "> "               
	  << m_matchTrackCut << " of hits from single Truth Track + a link !";
  ATH_MSG_INFO(outstr.str());
  outstr.str("");

  MsgStream &out = msg(MSG::INFO);
  {
  RestoreStream<MsgStream> restore(out);
  for (std::vector <class TrackStatHelper *>::const_iterator collection =  
	 m_SignalCounters.begin();
       collection !=  m_SignalCounters.end(); collection++) {
     if ((*collection)->key()=="CombinedInDetTracks"){
         out << "\n" << s_linestr2 << "\n";
         (*collection)->print(out);
     }
  }
  if (m_UseTrackSummary) {
    std::string track_stummary_type_header = TrackStatHelper::getSummaryTypeHeader();
    out << "\n"
        << s_linestr2 << "\n"
        << "Detailed Statistics for Hits on Reconstructed tracks, using TrackSummary: (Preselection of tracks as described above.)" << "\n"
        << s_linestr2 << "\n"
        << "----------------------------------------------------------------------------------------------------------------------------------------------------" << "\n"
        << "  Reco Tracks                           .........................................hits/track.......................................................  " << "\n"
        << "----------------------------------------------------------------------------------------------------------------------------------------------------" << "\n"
        << "  in BARREL                tracks/event " << track_stummary_type_header << "\n"
        << "----------------------------------------------------------------------------------------------------------------------------------------------------" << "\n";
    printTrackSummary (out, ETA_BARREL);

    out<< "\n"
       << "----------------------------------------------------------------------------------------------------------------------------------------------------" << "\n"
       << "  in TRANSITION region     tracks/event  " << track_stummary_type_header << "\n"
       << "----------------------------------------------------------------------------------------------------------------------------------------------------"
       << "\n";
    printTrackSummary (out, ETA_TRANSITION);

    out << "\n"
        << "----------------------------------------------------------------------------------------------------------------------------------------------------" << "\n"
        << "  in ENDCAP                tracks/event " << track_stummary_type_header << "\n"
        << "----------------------------------------------------------------------------------------------------------------------------------------------------" << "\n";
    printTrackSummary (out, ETA_ENDCAP);

    out << "\n"
        << "----------------------------------------------------------------------------------------------------------------------------------------------------" << "\n"
        << "  in FORWARD region        tracks/event  " << track_stummary_type_header << "\n"
        << "----------------------------------------------------------------------------------------------------------------------------------------------------" << "\n";
    printTrackSummary (out, ETA_DBM);
  }

  if(m_printSecondary){
    outstr.str("");    
    outstr << "\n" << std::setprecision(def_precision)
           <<s_linestr<<"\n"
           <<"Statistics for Secondaries (non-Primaries)"<<"\n"
           << "\t" << "Secondary track start \t" 
	   << " R < "   << m_maxRStartSecondary << "mm and" 
	   << " |z| < " << m_maxZStartSecondary << " mm" << "\n"
           << "\t" << "Secondary track end   \t"
	   << " R > "    << m_minREndSecondary << "mm or"
           << " |z| > "  << m_minZEndSecondary << "mm";
    ATH_MSG_INFO(outstr.str()); 
    outstr.str("");
    for (std::vector <class TrackStatHelper *>::const_iterator collection =  
	   m_SignalCounters.begin();
	 collection !=  m_SignalCounters.end(); collection++) {
     if ((*collection)->key()=="CombinedInDetTracks"){
         out << "\n" << s_linestr2 << "\n";
         (*collection)->printSecondary(out);
     }
    }
  }
  }
  out << endmsg;

  ATH_MSG_INFO(" ********** Ending InDetRecStatistics Statistics Table ***********");
  ATH_MSG_INFO( "\n"
               << s_linestr );
}


void InDet :: InDetRecStatisticsAlg ::printTrackSummary (MsgStream &out, enum eta_region eta_reg)
{
  bool printed = false;
  for (std::vector <class TrackStatHelper *>::const_iterator collection =  
	 m_SignalCounters.begin();
       collection !=  m_SignalCounters.end(); collection++) {
     if ((*collection)->key()=="CombinedInDetTracks"){
         printed = (*collection)->printTrackSummaryRegion(out, TRACK_ALL, eta_reg) || printed;
     }
  }
  if (printed) {
     out <<  "\n"
         << "----------------------------------------------------------------------------------------------------------------------------------------------" << "\n";
  }
  printed = false;
  for (std::vector <class TrackStatHelper *>::const_iterator collection =  
	 m_SignalCounters.begin();
       collection !=  m_SignalCounters.end(); collection++) {
     if ((*collection)->key()=="CombinedInDetTracks"){
         printed = (*collection)->printTrackSummaryRegion(out, TRACK_LOWTRUTHPROB, eta_reg) || printed;
     }
  }
  if (printed) {
     out << "\n"
         << "----------------------------------------------------------------------------------------------------------------------------------------------" << "\n";
  }
  for (std::vector <class TrackStatHelper *>::const_iterator collection =  
	 m_SignalCounters.begin();
       collection !=  m_SignalCounters.end(); collection++) {
     if ((*collection)->key()=="CombinedInDetTracks"){
         (*collection)->printTrackSummaryRegion(out, TRACK_LOWTRUTHPROB2, eta_reg);
     }
  }
}

// =================================================================================================================
// calculatePull 
// =================================================================================================================
float InDet :: InDetRecStatisticsAlg :: calculatePull(const float residual, 
						      const float trkErr, 
						      const float hitErr){
  double ErrorSum;
  ErrorSum = sqrt(pow(trkErr, 2) + pow(hitErr, 2));
  if (ErrorSum != 0) { return residual/ErrorSum; }
  else { return 0; }
}

const Trk::TrackParameters *  InDet::InDetRecStatisticsAlg::getUnbiasedTrackParameters(const Trk::TrackParameters* trkParameters, const Trk::MeasurementBase* measurement ){
    

  const Trk::TrackParameters *unbiasedTrkParameters = 0;
  
 // -----------------------------------------
  // use unbiased track states or normal ones?
  // unbiased track parameters are tried to retrieve if the updator tool
  //    is available and if unbiased track states could be produced before
  //    for the current track (ie. if one trial to get unbiased track states
  //    fail						      

  if (m_updator && (m_isUnbiased==1) ) {
    if ( trkParameters->covariance() ) {
      // Get unbiased state
      ATH_MSG_VERBOSE(" getting unbiased params");
      unbiasedTrkParameters =
	m_updator->removeFromState( *trkParameters,
				    measurement->localParameters(),
				    measurement->localCovariance());
      
      if (!unbiasedTrkParameters) {
	ATH_MSG_WARNING("Could not get unbiased track parameters, "
	    <<"use normal parameters");
	m_isUnbiased = 0;
      }
    } else if(!m_UpdatorWarning) {
      // warn only once!
      ATH_MSG_WARNING("TrackParameters contain no covariance: "
	  <<"Unbiased track states can not be calculated "
	  <<"(ie. pulls and residuals will be too small)");
      m_UpdatorWarning = true;
      m_isUnbiased = 0;
    } else {
      m_isUnbiased = 0;
    }
  } // end if no measured track parameter
  return unbiasedTrkParameters;  
}


Identifier  InDet::InDetRecStatisticsAlg::getIdentifier(const Trk::MeasurementBase* measurement ){

  
  Identifier id;
  const Trk::CompetingRIOsOnTrack *comprot = 0;
  // identify by ROT:
  const Trk::RIO_OnTrack *rot = 
    dynamic_cast<const Trk::RIO_OnTrack*>(measurement);
  if (rot) {
    id = rot->identify();
  } else {
    // identify by CompetingROT:
    comprot = dynamic_cast<const Trk::CompetingRIOsOnTrack*>(measurement);
    if (comprot) {
      rot = &comprot->rioOnTrack(comprot->indexOfMaxAssignProb());
      id = rot->identify();
    } else {
      ATH_MSG_DEBUG("measurement is neither ROT nor competingROT:"
	  <<" can not determine detector type");
      id.clear();
    }
  }
  delete comprot;
  return id; 
}