From 161b7f548aa494ecd8d8dc2c3379037be1ffe9e3 Mon Sep 17 00:00:00 2001 From: Bruno Lenzi <Bruno.Lenzi@cern.ch> Date: Thu, 4 Sep 2014 11:47:15 +0200 Subject: [PATCH] InDetConversionTrackSelectorTool: flag to check TRT PID only if all hits are Xe (false by default) (InDetTrackSelectorTool-01-00-11) --- .../InDetConversionTrackSelectorTool.h | 93 ++ .../InDetCosmicTrackSelectorTool.h | 77 ++ .../InDetDetailedTrackSelectorTool.h | 173 +++ .../InDetIsoTrackSelectorTool.h | 72 + .../InDetTrackSelectorTool.h | 83 ++ .../InDetTrtDriftCircleCutTool.h | 52 + .../InDetTrackSelectorTool/cmt/requirements | 37 + .../doc/images/TrackSelectorVariables.png | Bin 0 -> 61211 bytes .../doc/images/TrackSelectorVariables.xls | Bin 0 -> 17408 bytes .../InDetTrackSelectorTool/doc/mainpage.h | 27 + .../src/InDetConversionTrackSelectorTool.cxx | 403 ++++++ .../src/InDetCosmicTrackSelectorTool.cxx | 286 ++++ .../src/InDetDetailedTrackSelectorTool.cxx | 1202 +++++++++++++++++ .../src/InDetIsoTrackSelectorTool.cxx | 183 +++ .../src/InDetTrackSelectorTool.cxx | 195 +++ .../src/InDetTrtDriftCircleCutTool.cxx | 90 ++ .../InDetTrackSelectorTool_entries.cxx | 26 + .../InDetTrackSelectorTool_load.cxx | 3 + 18 files changed, 3002 insertions(+) create mode 100644 InnerDetector/InDetRecTools/InDetTrackSelectorTool/InDetTrackSelectorTool/InDetConversionTrackSelectorTool.h create mode 100644 InnerDetector/InDetRecTools/InDetTrackSelectorTool/InDetTrackSelectorTool/InDetCosmicTrackSelectorTool.h create mode 100644 InnerDetector/InDetRecTools/InDetTrackSelectorTool/InDetTrackSelectorTool/InDetDetailedTrackSelectorTool.h create mode 100644 InnerDetector/InDetRecTools/InDetTrackSelectorTool/InDetTrackSelectorTool/InDetIsoTrackSelectorTool.h create mode 100644 InnerDetector/InDetRecTools/InDetTrackSelectorTool/InDetTrackSelectorTool/InDetTrackSelectorTool.h create mode 100644 InnerDetector/InDetRecTools/InDetTrackSelectorTool/InDetTrackSelectorTool/InDetTrtDriftCircleCutTool.h create mode 100644 InnerDetector/InDetRecTools/InDetTrackSelectorTool/cmt/requirements create mode 100644 InnerDetector/InDetRecTools/InDetTrackSelectorTool/doc/images/TrackSelectorVariables.png create mode 100644 InnerDetector/InDetRecTools/InDetTrackSelectorTool/doc/images/TrackSelectorVariables.xls create mode 100644 InnerDetector/InDetRecTools/InDetTrackSelectorTool/doc/mainpage.h create mode 100644 InnerDetector/InDetRecTools/InDetTrackSelectorTool/src/InDetConversionTrackSelectorTool.cxx create mode 100644 InnerDetector/InDetRecTools/InDetTrackSelectorTool/src/InDetCosmicTrackSelectorTool.cxx create mode 100644 InnerDetector/InDetRecTools/InDetTrackSelectorTool/src/InDetDetailedTrackSelectorTool.cxx create mode 100644 InnerDetector/InDetRecTools/InDetTrackSelectorTool/src/InDetIsoTrackSelectorTool.cxx create mode 100644 InnerDetector/InDetRecTools/InDetTrackSelectorTool/src/InDetTrackSelectorTool.cxx create mode 100644 InnerDetector/InDetRecTools/InDetTrackSelectorTool/src/InDetTrtDriftCircleCutTool.cxx create mode 100644 InnerDetector/InDetRecTools/InDetTrackSelectorTool/src/components/InDetTrackSelectorTool_entries.cxx create mode 100644 InnerDetector/InDetRecTools/InDetTrackSelectorTool/src/components/InDetTrackSelectorTool_load.cxx diff --git a/InnerDetector/InDetRecTools/InDetTrackSelectorTool/InDetTrackSelectorTool/InDetConversionTrackSelectorTool.h b/InnerDetector/InDetRecTools/InDetTrackSelectorTool/InDetTrackSelectorTool/InDetConversionTrackSelectorTool.h new file mode 100644 index 00000000000..61365aa4b8f --- /dev/null +++ b/InnerDetector/InDetRecTools/InDetTrackSelectorTool/InDetTrackSelectorTool/InDetConversionTrackSelectorTool.h @@ -0,0 +1,93 @@ +/* + Copyright (C) 2002-2017 CERN for the benefit of the ATLAS collaboration +*/ + +#ifndef InDetTrackSelectorTool_InDetConversionTrackSelectorTool_H +#define InDetTrackSelectorTool_InDetConversionTrackSelectorTool_H + +//#include "GaudiKernel/MsgStream.h" +#include "AthenaBaseComps/AthAlgTool.h" +#include "GaudiKernel/ToolHandle.h" +#include "GaudiKernel/ServiceHandle.h" +#include "TrkToolInterfaces/ITrackSelectorTool.h" +#include "xAODTracking/TrackParticle.h" + +/** + * A tool to be used for track preselection in conversion + * vertex finding. + * + * Thomas Koffas <Thomas.Koffas@cern.ch> + * June 2008 + */ + +class IBeamCondSvc; + +namespace Trk +{ + class ITrackSummaryTool; + class Vertex; + class IExtrapolator; + class Track; + class TrackParticleBase; +} + +namespace InDet +{ + + class InDetConversionTrackSelectorTool : virtual public Trk::ITrackSelectorTool, public AthAlgTool + { + + public: + + StatusCode initialize(); + + StatusCode finalize(); + + InDetConversionTrackSelectorTool(const std::string& t, const std::string& n, const IInterface* p); + + ~InDetConversionTrackSelectorTool(); + + /** Select a Trk::Track */ + bool decision(const Trk::Track& track,const Trk::Vertex* vertex) const; + + /** Select a Trk::TrackParticleBase */ + bool decision(const Trk::TrackParticleBase& track,const Trk::Vertex* vertex) const; + + bool decision(const xAOD::TrackParticle&,const xAOD::Vertex*) const ; + + + + private: + + int getCount( const xAOD::TrackParticle& tp, xAOD::SummaryType type ) const { + uint8_t val; + if( !tp.summaryValue(val,type) ) return 0; + return val > 0 ? val : 0; + } + + + ToolHandle <Trk::ITrackSummaryTool> m_trkSumTool; //!< Track summary tool + ToolHandle<Trk::IExtrapolator> m_extrapolator; //!< Extrapolator tool + ServiceHandle<IBeamCondSvc> m_iBeamCondSvc; //!< pointer to the beam condition service + + /** Properties for track selection:all cuts are ANDed */ + double m_maxSiD0; //!< Maximal d0 at (0,0,0) for tracks with Si hits + double m_maxTrtD0; //!< Maximal d0 at (0,0,0) for standalone TRT tracks + double m_maxSiZ0; //!< Maximal z0 at (0,0,0) + double m_maxTrtZ0; //!< Maximal z0 at (0,0,0) for standalone TRT tracks + double m_minPt; //!< Minimum Pt of tracks + double m_trRatio1; //!< TR ratio for tracks with 15-20 TRT hits + double m_trRatio2; //!< TR ratio for tracks with 20-25 TRT hits + double m_trRatio3; //!< TR ratio for tracks with >25 TRT hits + double m_trRatioTRT;//!< TR ratio for TRT only tracks + double m_trRatioV0;//!< TR ratio for pion selection during V0 reconstruction + double m_sD0_Si; //!< Cut on D0 significance of Si tracks + double m_sD0_Trt; //!< Cut on D0 significance of TRT tracks + double m_sZ0_Trt; //!< Cut on Z0 significance of TRT tracks + bool m_isConv; //!< Conversion flag + bool m_PIDonlyForXe; //!< Only check TRT PID if all hits are Xe hits + + }; //end of class definitions +} //end of namespace definitions + +#endif diff --git a/InnerDetector/InDetRecTools/InDetTrackSelectorTool/InDetTrackSelectorTool/InDetCosmicTrackSelectorTool.h b/InnerDetector/InDetRecTools/InDetTrackSelectorTool/InDetTrackSelectorTool/InDetCosmicTrackSelectorTool.h new file mode 100644 index 00000000000..33b7281ebe3 --- /dev/null +++ b/InnerDetector/InDetRecTools/InDetTrackSelectorTool/InDetTrackSelectorTool/InDetCosmicTrackSelectorTool.h @@ -0,0 +1,77 @@ +/* + Copyright (C) 2002-2017 CERN for the benefit of the ATLAS collaboration +*/ + +#ifndef InDetTrackSelectorTool_InDetCosmicTrackSelectorTool_H +#define InDetTrackSelectorTool_InDetCosmicTrackSelectorTool_H + +#include "AthenaBaseComps/AthAlgTool.h" +#include "GaudiKernel/ToolHandle.h" +#include "GaudiKernel/ServiceHandle.h" +#include "TrkToolInterfaces/ITrackSelectorTool.h" +#include "TrkEventPrimitives/ParticleHypothesis.h" +#include "TrkParameters/TrackParameters.h" + +namespace Trk +{ + class IMagneticFieldTool; + class ITrackSummaryTool; + class Vertex; + class TrackParticleBase; + class Track; +} + +namespace MagField { + class IMagFieldSvc; +} + +namespace InDet +{ + + class InDetCosmicTrackSelectorTool : virtual public Trk::ITrackSelectorTool, public AthAlgTool + { + + public: + + StatusCode initialize(); + + StatusCode finalize(); + + InDetCosmicTrackSelectorTool(const std::string& t, const std::string& n, const IInterface* p); + + ~InDetCosmicTrackSelectorTool(); + + bool decision(const Trk::Track& track,const Trk::Vertex* vertex) const; + + bool decision(const Trk::TrackParticleBase& track,const Trk::Vertex* vertex) const; + + bool decision(const xAOD::TrackParticle&,const xAOD::Vertex*) const { + ATH_MSG_WARNING("xAOD::TrackParticle selection not implemented yet"); + return false; + } + + private: + + int getNSiHits(const Trk::Track* track, bool top) const; + bool decision(const Trk::TrackParameters* track, const Trk::Vertex* vertex, const Trk::ParticleHypothesis) const; + double m_maxZ0; //!< Maximum z0 of tracks + double m_maxD0; //!< Maximum d0 of tracks + double m_minPt; //!< Minimum pT of tracks + int m_numberOfPixelHits; //!< Minimum number of Pixel hits + int m_numberOfSCTHits; //!< Minimum number of SCT hits + int m_numberOfTRTHits; //!< Minimum number of TRT hits + int m_numberOfSiHits; //!< Minimum number of Silicon hits + int m_numberOfSiHitsTop; //!< Minimum number of Silicon hits + int m_numberOfSiHitsBottom; //!< Minimum number of Silicon hits + + ToolHandle<Trk::ITrackSummaryTool> m_trackSumTool; + bool m_trackSumToolAvailable; + + ServiceHandle<MagField::IMagFieldSvc> m_magFieldSvc; + + + + }; //end of class definitions +} //end of namespace definitions + +#endif //TrkMultipleVertexSeedFinders_PVFindingTrackSelectoTool_H diff --git a/InnerDetector/InDetRecTools/InDetTrackSelectorTool/InDetTrackSelectorTool/InDetDetailedTrackSelectorTool.h b/InnerDetector/InDetRecTools/InDetTrackSelectorTool/InDetTrackSelectorTool/InDetDetailedTrackSelectorTool.h new file mode 100644 index 00000000000..6817f9d9457 --- /dev/null +++ b/InnerDetector/InDetRecTools/InDetTrackSelectorTool/InDetTrackSelectorTool/InDetDetailedTrackSelectorTool.h @@ -0,0 +1,173 @@ +/* + Copyright (C) 2002-2017 CERN for the benefit of the ATLAS collaboration +*/ + +#ifndef InDetDetailedTrackSelectorTool_InDetDetailedTrackSelectorTool_H +#define InDetDetailedTrackSelectorTool_InDetDetailedTrackSelectorTool_H + +#include "AthenaBaseComps/AthAlgTool.h" +#include "GaudiKernel/ToolHandle.h" +#include "GaudiKernel/ServiceHandle.h" +#include "TrkToolInterfaces/ITrackSelectorTool.h" +#include "TrkParameters/TrackParameters.h" +#include "xAODTracking/TrackParticle.h" +#include "xAODTracking/VertexFwd.h" + +/** + * @file InDetDetailedTrackSelectorTool.h + * @class InDetDetailedTrackSelectorTool + * + * @brief TrackSelector for general use + * + * The option for anyDirection: + * Required for cosmic tracks: mixture of tracks with different reo logic. + * Default is the extrapolation oppositeToMomentum, which is required for collision tracks. + * + * @author Giacinto Piacquadio <giacinto.piacquadio@physik.uni-freiburg.de> + * @author Kirill Prokofiev <Kirill.Prokofiev@cern.ch> + * @author Daniel Kollar <daniel.kollar@cern.ch> + */ + +class IBeamCondSvc; + + +namespace MagField { + class IMagFieldSvc; +} + +namespace Trk +{ + class IMagneticFieldTool; + class ITrackSummaryTool; + class IExtrapolator; + class Vertex; + class RecVertex; + class FitQuality; + class TrackSummary; + class Track; + class TrackParticleBase; +} + +namespace InDet +{ + class ITrtDriftCircleCutTool; + class IInDetTestBLayerTool; + + + class InDetDetailedTrackSelectorTool : virtual public Trk::ITrackSelectorTool, public AthAlgTool + { + + public: + + enum Grade { Undefined, Good, Shared, nbGrades }; + + StatusCode initialize(); + + StatusCode finalize(); + + InDetDetailedTrackSelectorTool(const std::string& t, const std::string& n, const IInterface* p); + + ~InDetDetailedTrackSelectorTool(); + + bool decision(const Trk::Track& track,const Trk::Vertex* vertex) const; + + bool decision(const Trk::TrackParticleBase& track,const Trk::Vertex* vertex) const; + + bool decision(const xAOD::TrackParticle& track,const xAOD::Vertex* vertex) const; + + private: + int getCount( const xAOD::TrackParticle& tp, xAOD::SummaryType type ) const { + uint8_t val; + if( !tp.summaryValue(val,type) ) return 0; + return val > 0 ? val : 0; + } + bool decision(const Trk::Perigee* track,const AmgSymMatrix(3)* covariancePosition) const; + bool decision(const Trk::FitQuality* TrkQuality) const; + bool decision(double chi2, int ndf ) const; + bool decision(const Trk::TrackSummary* summary,bool useSharedHitInfo,bool useTrtHitInfo, + const Trk::Perigee* track) const; + + bool preselectionBeforeExtrapolation(const Trk::Perigee & myPerigee) const; + + double m_pTMin; //<! min. pT: |pT|>pTMin + double m_pMin; //<! min. p = pT/cos(theta): |p| > pMin + double m_IPd0Max; //<! max. d0: |d0|<d0Max + double m_IPz0Max; //<! max. z0: |z0*sin(theta)|<z0Max + double m_z0Max; //<! max. z0: |z0|<z0Max + double m_sigIPd0Max; //<! max sig IP d0: + double m_sigIPz0Max; //<! max sig IP z0 (error only due to z0)*sin(theta) + double m_d0significanceMax; //<! max IP significance d0 (-1 switches it off) + double m_z0significanceMax; //<! max IP significance z0 (-1 switches it off) + double m_etaMax; //<! max. pseudo-rapidity + + bool m_useTrackSummaryInfo; //<! if false the following cuts are ignored + + int m_nHitBLayer; //<! at least n hits in Blayer + int m_nHitPix; //<! at least n hits in pixels + int m_nHitBLayerPlusPix; //<! at least n hits in blayer+pixel + int m_nHitSct; //<! at least n hits in SCT + int m_nHitSi; //<! at least n hits in pixels+SCT + + int m_nHitPixPhysical; //!< at least n physical hits in pixel + int m_nHitSiPhysical; //!< at least n physical hits in pixel+SCT + + mutable int m_nHitTrt; //<! at least n hits in TRT + mutable int m_nHitTrtPlusOutliers; //<! at least n hits in TRT (including outliers) + + //<! for selecting electrons (soft E-ID) + int m_nHitTrtHighE; //<! at least n high threshold hits in TRT + int m_nHitTrtPlusOutliersHighE; //<! at least n high threshold hits in TRT (including outliers) + //<! for rejecting electrons (tau-ID) + double m_nHitTrtHighEFraction; //<! maximum x fraction of transition hits in TRT + double m_nHitTrtHighEFractionWithOutliers; //<! maximum x fraction of transition hits in TRT (including outliers) + + double m_TrtMaxEtaAcceptance;//<! limit of eta regions where trt hits are expected + bool m_useSharedHitInfo; //<! if false the following cuts are ignored + int m_nSharedBLayer;//<! max. number of shared hits in B layer + int m_nSharedPix; //<! max. number of shared hits in pixels + int m_nSharedSct; //<! max. number of shared hits in SCT + int m_nSharedSi; //<! max. number of shared hits in pixels+SCT + + int m_nHoles; //<! max. number of holes in pixel+SCT + int m_nDoubleHoles; //<! max number of double-holes in SCT + int m_nHolesPix; //<! max. number of holes in pixels + int m_nHolesSct; //<! max. number of holes in SCT + + bool m_useTrackQualityInfo; //<! if false the following cuts are ignored + double m_fitChi2; //<! max. fit chi2 + double m_fitProb; //<! min. fit chi2 probability + double m_fitChi2OnNdfMax; //<! max. fitchi2/ndf + + double m_scaleMinHitTrt; //<! scale the eta dependent minimum number of TRT hits; scaling is only applied if m_addToMinHitTrt==0 + int m_addToMinHitTrt; //<! add to/subtract from eta dependent minimum nimber of TRT hits + double m_scaleMinHitTrtWithOutliers; //<! scale the eta dependent minimum number of TRT hits + outliers; scaling is only applied if m_addToMinHitTrtWithOutliers==0 + int m_addToMinHitTrtWithOutliers; //<! add to/subtract from eta dependent minimum nimber of TRT hits + outliers + + bool m_usePreselectionCuts; + double m_d0MaxPreselection; + + bool m_useEtaDepententMinHitTrt; + bool m_useEtaDepententMinHitTrtWithOutliers; + + ToolHandle<Trk::ITrackSummaryTool> m_trackSumTool; //!< Track summary tool + ToolHandle<Trk::IExtrapolator> m_extrapolator; //!< Extrapolator tool + ServiceHandle<IBeamCondSvc> m_iBeamCondSvc; //!< pointer to the beam condition service + ServiceHandle<MagField::IMagFieldSvc> m_magFieldSvc; + ToolHandle<ITrtDriftCircleCutTool> m_trtDCTool; //!< Tool to get eta dependent cut on number of TRT hits + + ToolHandle< InDet::IInDetTestBLayerTool > m_inDetTestBLayerTool; //Tool to test if the track crosses a dead module on the b-layer + + bool m_trackSumToolAvailable; + +// chnages for the pt-dependent sct cut + bool m_usePtDependentCuts; + + std::vector<float> m_ptBenchmarks; + + std::vector<int> m_nSCTValues; + + }; //end of class definitions + +} //end of namespace definitions + +#endif //TrkMultipleVertexSeedFinders_PVFindingTrackSelectoTool_H diff --git a/InnerDetector/InDetRecTools/InDetTrackSelectorTool/InDetTrackSelectorTool/InDetIsoTrackSelectorTool.h b/InnerDetector/InDetRecTools/InDetTrackSelectorTool/InDetTrackSelectorTool/InDetIsoTrackSelectorTool.h new file mode 100644 index 00000000000..b282fadd429 --- /dev/null +++ b/InnerDetector/InDetRecTools/InDetTrackSelectorTool/InDetTrackSelectorTool/InDetIsoTrackSelectorTool.h @@ -0,0 +1,72 @@ +/* + Copyright (C) 2002-2017 CERN for the benefit of the ATLAS collaboration +*/ + +#ifndef InDetIsoTrackSelectorTool_InDetIsoTrackSelectorTool_H +#define InDetIsoTrackSelectorTool_InDetIsoTrackSelectorTool_H + +#include "AthenaBaseComps/AthAlgTool.h" +#include "GaudiKernel/ToolHandle.h" +#include "TrkToolInterfaces/IIsoTrackSelectorTool.h" +#include "TrkParameters/TrackParameters.h" + +/** + * @file InDetIsoTrackSelectorTool.h + * @class InDetIsoTrackSelectorTool + * + * @brief A tool to be used for track preselection in isolation, + * the given AtaLine is the transported lepton to the BeamLine + * tracks can be checkec w.r.t to it + * + * @author Andreas Salzburger +*/ + +namespace Trk { + class IExtrapolator; + class ITrackSelectorTool; + class Track; + class TrackParticleBase; +} + +namespace InDet +{ + class InDetIsoTrackSelectorTool : virtual public Trk::IIsoTrackSelectorTool, public AthAlgTool + { + + public: + /** Athena AlgTool methods */ + StatusCode initialize(); + StatusCode finalize(); + + /** Constructor / Destructor */ + InDetIsoTrackSelectorTool(const std::string& t, const std::string& n, const IInterface* p); + ~InDetIsoTrackSelectorTool(); + + /** ESD type interface */ + bool decision(const Trk::AtaStraightLine&, const Trk::Track& track) const; + + /** AOD type interface */ + bool decision(const Trk::AtaStraightLine&, const Trk::TrackParticleBase& trackParticle) const; + + /** Work-horse interface - will ignore TrackSelector */ + bool decision(const Trk::AtaStraightLine&, const Trk::TrackParameters& trackPars) const; + + private: + /** Robust cut window setting */ + bool m_robustCuts; + bool m_applySinThetaCorrection; + double m_d0max; + double m_z0stMax; + /** Sophisticated cut window setting : d0/z0 significance - only when robustCuts off*/ + double m_d0Significance; + double m_z0Significance; + + ToolHandle<Trk::IExtrapolator> m_extrapolator; //<! Extrapolator tool + /** Extra checks on hits & holes */ + ToolHandle<Trk::ITrackSelectorTool> m_trackSelector; //!< track selector tool + + + }; //end of class definitions +} //end of namespace definitions + +#endif //TrkMultipleVertexSeedFinders_PVFindingTrackSelectoTool_H diff --git a/InnerDetector/InDetRecTools/InDetTrackSelectorTool/InDetTrackSelectorTool/InDetTrackSelectorTool.h b/InnerDetector/InDetRecTools/InDetTrackSelectorTool/InDetTrackSelectorTool/InDetTrackSelectorTool.h new file mode 100644 index 00000000000..3545328ac00 --- /dev/null +++ b/InnerDetector/InDetRecTools/InDetTrackSelectorTool/InDetTrackSelectorTool/InDetTrackSelectorTool.h @@ -0,0 +1,83 @@ +/* + Copyright (C) 2002-2017 CERN for the benefit of the ATLAS collaboration +*/ + +#ifndef InDetTrackSelectorTool_InDetTrackSelectorTool_H +#define InDetTrackSelectorTool_InDetTrackSelectorTool_H + +#include "AthenaBaseComps/AthAlgTool.h" +#include "GaudiKernel/ToolHandle.h" +#include "TrkToolInterfaces/ITrackSelectorTool.h" +#include "TrkEventPrimitives/ParticleHypothesis.h" +#include "TrkParameters/TrackParameters.h" + +/** + * @file InDetTrackSelectorTool.h + * @class InDetTrackSelectorTool + * + * @brief A tool to be used for track preselection in primary + * vertex finding. One possible implementation of the + * track selector tool. Here all possible cuts used in the + * primary vertex finding will be implemented. The particular + * cuts will be turned on and off by user through the python + * jobOptions. + * + * @author Kirill Prokofiev <Kirill.Prokofiev@cern.ch> + * @date Mai 2007 + * + * @author Daniel Kollar <daniel.kollar@cern.ch> + */ + +namespace Trk +{ + class ITrackSummaryTool; + class Vertex; + class IExtrapolator; + class Track; + class TrackParticleBase; +} + +namespace InDet +{ + class InDetTrackSelectorTool : virtual public Trk::ITrackSelectorTool, public AthAlgTool + { + + public: + + StatusCode initialize(); + + StatusCode finalize(); + + InDetTrackSelectorTool(const std::string& t, const std::string& n, const IInterface* p); + + ~InDetTrackSelectorTool(); + + bool decision(const Trk::Track& track,const Trk::Vertex* vertex) const; + + bool decision(const Trk::TrackParticleBase& track,const Trk::Vertex* vertex) const; + + bool decision(const xAOD::TrackParticle&,const xAOD::Vertex*) const { + ATH_MSG_WARNING("xAOD::TrackParticle selection not implemented yet"); + return false; + } + + private: + + bool decision(const Trk::TrackParameters* track, const Trk::Vertex* vertex, const Trk::ParticleHypothesis) const; + + double m_minPt; //!< Minimum Pt of tracks + double m_IPz0Max; //!< max. z0: |z0*sin(theta)| < z0Max + double m_maxZ0; //!< Maximum z0 of tracks + double m_maxD0; //!< Maximum d0 of tracks + double m_maxD0overSigmaD0; //!< Maximum d0/sigmad0 of tracks + int m_numberOfPixelHits; //!< Check for silicon hits ? + int m_numberOfBLayerHits; + ToolHandle<Trk::ITrackSummaryTool> m_trackSumTool; //<! Track summary tool + bool m_trackSumToolAvailable; + + ToolHandle<Trk::IExtrapolator> m_extrapolator; //<! Extrapolator tool + + }; //end of class definitions +} //end of namespace definitions + +#endif //TrkMultipleVertexSeedFinders_PVFindingTrackSelectoTool_H diff --git a/InnerDetector/InDetRecTools/InDetTrackSelectorTool/InDetTrackSelectorTool/InDetTrtDriftCircleCutTool.h b/InnerDetector/InDetRecTools/InDetTrackSelectorTool/InDetTrackSelectorTool/InDetTrtDriftCircleCutTool.h new file mode 100644 index 00000000000..291aabe9785 --- /dev/null +++ b/InnerDetector/InDetRecTools/InDetTrackSelectorTool/InDetTrackSelectorTool/InDetTrtDriftCircleCutTool.h @@ -0,0 +1,52 @@ +/* + Copyright (C) 2002-2017 CERN for the benefit of the ATLAS collaboration +*/ + +#ifndef InDetTrackSelectorTool_InDetTrtDriftCircleCutTool_H +#define InDetTrackSelectorTool_InDetTrtDriftCircleCutTool_H + +#include "AthenaBaseComps/AthAlgTool.h" +#include "GaudiKernel/ToolHandle.h" +#include "GaudiKernel/ServiceHandle.h" +#include "InDetRecToolInterfaces/ITrtDriftCircleCutTool.h" + +/** + * A tool to be used for trt segment pre-selection + * + * Thomas Koffas <Thomas.Koffas@cern.ch> + * April 2009 + */ + +class ITRT_ActiveFractionSvc; + +namespace InDet{ + + class InDetTrtDriftCircleCutTool : virtual public ITrtDriftCircleCutTool, public AthAlgTool + { + + public: + + StatusCode initialize(); + + StatusCode finalize(); + + InDetTrtDriftCircleCutTool(const std::string& t, const std::string& n, const IInterface* p); + + ~InDetTrtDriftCircleCutTool(); + + /** @brief Minimum number of drift circles using the track scoring tool */ + int minNumberDCs(const Trk::TrackParameters*) const; + + private: + + ServiceHandle<ITRT_ActiveFractionSvc> m_trtCondSvc; //!< TRT active fraction service + + /** Properties for track selection:all cuts are ANDed */ + int m_minOffset; //!< Minimum number of TRT drit circles required + bool m_param; //!< Use the new or the old parameterization + bool m_useTRT; //!< Use the TRT active fraction services to correct for dead straws + + }; //end of class definitions +} //end of namespace + +#endif diff --git a/InnerDetector/InDetRecTools/InDetTrackSelectorTool/cmt/requirements b/InnerDetector/InDetRecTools/InDetTrackSelectorTool/cmt/requirements new file mode 100644 index 00000000000..a0dc9a55b89 --- /dev/null +++ b/InnerDetector/InDetRecTools/InDetTrackSelectorTool/cmt/requirements @@ -0,0 +1,37 @@ +package InDetTrackSelectorTool + +author Kirill Prokofiev <Kirill.Prokofiev@cern.ch> + +private + +use DataModel DataModel-* Control +use AtlasCLHEP AtlasCLHEP-* External +use AtlasROOT AtlasROOT-* External +use TrkSurfaces TrkSurfaces-* Tracking/TrkDetDescr +use TrkTrack TrkTrack-* Tracking/TrkEvent +use TrkTrackSummary TrkTrackSummary-* Tracking/TrkEvent +use TrkParticleBase TrkParticleBase-* Tracking/TrkEvent +use TrkExInterfaces TrkExInterfaces-* Tracking/TrkExtrapolation +use VxVertex VxVertex-* Tracking/TrkEvent +use InDetBeamSpotService InDetBeamSpotService-* InnerDetector/InDetConditions +use TrkRIO_OnTrack TrkRIO_OnTrack-* Tracking/TrkEvent +use InDetRIO_OnTrack InDetRIO_OnTrack-* InnerDetector/InDetRecEvent +use TRT_ConditionsServices TRT_ConditionsServices-* InnerDetector/InDetConditions +use MagFieldInterfaces MagFieldInterfaces-* MagneticField +use GeoPrimitives GeoPrimitives-* DetectorDescription +use EventPrimitives EventPrimitives-* Event + +public + +use AtlasPolicy AtlasPolicy-* +use GaudiInterface GaudiInterface-* External +use AthenaBaseComps AthenaBaseComps-* Control +use TrkEventPrimitives TrkEventPrimitives-* Tracking/TrkEvent +use TrkToolInterfaces TrkToolInterfaces-* Tracking/TrkTools +use InDetRecToolInterfaces InDetRecToolInterfaces-* InnerDetector/InDetRecTools +use TrkParameters TrkParameters-* Tracking/TrkEvent +use xAODTracking xAODTracking-* Event/xAOD + +library InDetTrackSelectorTool *.cxx -s=components *.cxx +apply_pattern component_library +macro DOXYGEN_IMAGE_PATH "../doc/images" diff --git a/InnerDetector/InDetRecTools/InDetTrackSelectorTool/doc/images/TrackSelectorVariables.png b/InnerDetector/InDetRecTools/InDetTrackSelectorTool/doc/images/TrackSelectorVariables.png new file mode 100644 index 0000000000000000000000000000000000000000..05a12100b8707a765928692464cd49edead19c35 GIT binary patch literal 61211 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 YYtVMp71zrS1K?7US9@9_YxeH{0B?~s2mk;8 literal 0 HcmV?d00001 diff --git a/InnerDetector/InDetRecTools/InDetTrackSelectorTool/doc/images/TrackSelectorVariables.xls b/InnerDetector/InDetRecTools/InDetTrackSelectorTool/doc/images/TrackSelectorVariables.xls new file mode 100644 index 0000000000000000000000000000000000000000..d90eb65211a5745f0db2eb43e58503d2917807d6 GIT binary patch literal 17408 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 literal 0 HcmV?d00001 diff --git a/InnerDetector/InDetRecTools/InDetTrackSelectorTool/doc/mainpage.h b/InnerDetector/InDetRecTools/InDetTrackSelectorTool/doc/mainpage.h new file mode 100644 index 00000000000..52880b23cfb --- /dev/null +++ b/InnerDetector/InDetRecTools/InDetTrackSelectorTool/doc/mainpage.h @@ -0,0 +1,27 @@ +/* + Copyright (C) 2002-2017 CERN for the benefit of the ATLAS collaboration +*/ + +/** +@mainpage The InDetTrackSelectorTool package + +@author Andreas.Wildauer@cern.ch +@author Daniel.Kollar@cern.ch + +@section introductionInDetTrackSelectorTool Introduction +This package contains the concrete implementation of the inner detector track selector tools. The interface can be found +in Tracking/TrkTools/TrkToolInterfaces. + +@section selectorsInDetTrackSelectorTool Selectors +The implementations in this package are + +- InDetTrackSelector: has mostly cuts on perigee parameters +- InDetDetailedTrackSelector: in addition can cut on hits and other variables +- InDetConversionTrackSelector: a track selector dedicated for conversion finding + +The cuts implemented in each version are shown below. + +@image html TrackSelectorVariables.png + +*/ + diff --git a/InnerDetector/InDetRecTools/InDetTrackSelectorTool/src/InDetConversionTrackSelectorTool.cxx b/InnerDetector/InDetRecTools/InDetTrackSelectorTool/src/InDetConversionTrackSelectorTool.cxx new file mode 100644 index 00000000000..ed5989a42ae --- /dev/null +++ b/InnerDetector/InDetRecTools/InDetTrackSelectorTool/src/InDetConversionTrackSelectorTool.cxx @@ -0,0 +1,403 @@ +/* + Copyright (C) 2002-2017 CERN for the benefit of the ATLAS collaboration +*/ + +#include "InDetTrackSelectorTool/InDetConversionTrackSelectorTool.h" +// forward declare +#include "TrkToolInterfaces/ITrackSummaryTool.h" +#include "TrkExInterfaces/IExtrapolator.h" +#include "VxVertex/Vertex.h" +#include "TrkTrack/Track.h" +#include "InDetBeamSpotService/IBeamCondSvc.h" +#include "TrkParticleBase/TrackParticleBase.h" +// normal includes +#include "TrkTrackSummary/TrackSummary.h" +#include "TrkSurfaces/PerigeeSurface.h" +#include "VxVertex/RecVertex.h" +#include "TrkParameters/TrackParameters.h" +#include "xAODTracking/Vertex.h" + + +namespace InDet +{ + + InDetConversionTrackSelectorTool::InDetConversionTrackSelectorTool(const std::string& t, const std::string& n, const IInterface* p) + :AthAlgTool(t,n,p), + m_trkSumTool("Trk::TrackSummaryTool"), + m_extrapolator("Trk::Extrapolator"), + m_iBeamCondSvc ("BeamCondSvc",n), + m_maxSiD0 (35.), + m_maxTrtD0 (100.), + m_maxSiZ0 (200.), + m_maxTrtZ0 (1200), + m_minPt (500.), + m_trRatio1 (0.5), + m_trRatio2 (0.1), + m_trRatio3 (0.05), + m_trRatioTRT(0.1), + m_trRatioV0 (1.), + m_sD0_Si (2.), + m_sD0_Trt (0.5), + m_sZ0_Trt (3.), + m_isConv(true) + { + declareInterface<ITrackSelectorTool>(this); + declareProperty("TrackSummaryTool", m_trkSumTool); + declareProperty("Extrapolator", m_extrapolator); + declareProperty("maxSiD0", m_maxSiD0); + declareProperty("maxTrtD0", m_maxTrtD0); + declareProperty("maxSiZ0", m_maxSiZ0); + declareProperty("maxTrtZ0", m_maxTrtZ0); + declareProperty("minPt", m_minPt); + declareProperty("RatioCut1", m_trRatio1); + declareProperty("RatioCut2", m_trRatio2); + declareProperty("RatioCut3", m_trRatio3); + declareProperty("RatioTRT", m_trRatioTRT); + declareProperty("RatioV0", m_trRatioV0); + declareProperty("significanceD0_Si", m_sD0_Si); + declareProperty("significanceD0_Trt", m_sD0_Trt); + declareProperty("significanceZ0_Trt", m_sZ0_Trt); + declareProperty("IsConversion", m_isConv); + declareProperty("BeamPositionSvc", m_iBeamCondSvc); + declareProperty("BeamPositionSvc", m_iBeamCondSvc); + declareProperty("PIDonlyForXe", m_PIDonlyForXe = false, + "Only check TRT PID if all hits are Xe hits"); + } + + InDetConversionTrackSelectorTool::~InDetConversionTrackSelectorTool() + {} + + StatusCode InDetConversionTrackSelectorTool::initialize() + { + StatusCode sc = AthAlgTool::initialize(); + if(sc.isFailure()){ + msg(MSG::ERROR)<<" Unable to initialize the AlgTool"<<endreq; + return StatusCode::FAILURE; + } + + /* Get the track summary tool from ToolSvc */ + if ( m_trkSumTool.retrieve().isFailure() ) { + msg(MSG::ERROR) << "Failed to retrieve tool " << m_trkSumTool << endreq; + return StatusCode::FAILURE; + } else { + msg(MSG::INFO) << "Retrieved tool " << m_trkSumTool << endreq; + } + + /* Get the extrapolator tool from ToolSvc */ + if ( m_extrapolator.retrieve().isFailure() ) { + msg(MSG::ERROR) << "Failed to retrieve tool " << m_extrapolator << endreq; + return StatusCode::FAILURE; + } else { + msg(MSG::INFO) << "Retrieved tool " << m_extrapolator << endreq; + } + + /* Get BeamCondSvc */ + sc = m_iBeamCondSvc.retrieve(); + if (sc.isFailure()) { + msg(MSG::INFO) << "Could not find BeamCondSvc. Will use (0,0,0) if no vertex is given and extrapolation is needed." << endreq; + } + + return StatusCode::SUCCESS; + } + + StatusCode InDetConversionTrackSelectorTool::finalize() + { + msg(MSG::INFO) << "Finalize successful" << endreq; + return StatusCode::SUCCESS; + } + + bool InDetConversionTrackSelectorTool::decision(const Trk::Track& track,const Trk::Vertex* vx) const + { + bool pass = false; + + const Trk::Perigee* perigee=dynamic_cast<const Trk::Perigee*>(track.perigeeParameters()); + const Trk::Vertex* myVertex=vx; + //in case no Vertex is provided by the user, beam position will be used if available + if (myVertex==0) { + if (!m_iBeamCondSvc.empty()) { + myVertex=new Trk::RecVertex(m_iBeamCondSvc->beamVtx()); + } else { + msg(MSG::WARNING) << " Cannot get beamSpot center from iBeamCondSvc. Using (0,0,0)... " << endreq; + myVertex=new Trk::Vertex(Amg::Vector3D(0,0,0)); + } + } + + Trk::PerigeeSurface perigeeSurface(myVertex->position()); + const Trk::TrackParameters *firstmeaspar=0; + for (unsigned int i=0;i<track.trackParameters()->size();i++){ + if ( (*track.trackParameters())[i]->covariance() && !dynamic_cast<const Trk::Perigee*>((*track.trackParameters())[i])) { + firstmeaspar=(*track.trackParameters())[i]; + break; + } + } + if (!firstmeaspar) { + //assumes perigeeParameters exist... + //no track selection if firstmeas + perigee does not exist ! + firstmeaspar=track.perigeeParameters(); + if (!firstmeaspar){ + msg(MSG::WARNING) << " First measurment on track is missing. Using perigee Parameters, but they are missing: 0 pointer! Track selection failed " << endreq; + //clean up vertex + if (myVertex!=vx) { + delete myVertex; + myVertex=0; + } + return false; + } + } + + const Trk::TrackParameters * extrapolatedParameters= m_extrapolator->extrapolate(*firstmeaspar,perigeeSurface,Trk::anyDirection,true,track.info().particleHypothesis() ); +// const Trk::TrackParameters * extrapolatedParameters= firstmeaspar ? m_extrapolator->extrapolate(*firstmeaspar,perigeeSurface,Trk::anyDirection,true,track.info().particleHypothesis() ) : 0; + perigee = extrapolatedParameters ? dynamic_cast<const Trk::Perigee*>(extrapolatedParameters) : 0; + if (perigee==0 || !perigee->covariance() ) { + msg(MSG::WARNING) << "Track Selector failed to extrapolate track to the vertex: " << myVertex->position() << endreq; + if (extrapolatedParameters!=0) { + msg(MSG::WARNING) << "The return object of the extrapolator was not a perigee even if a perigeeSurface was used!" << endreq; + delete extrapolatedParameters; + if (myVertex!=vx) delete myVertex; + return false; + } + return false; + } + + double qOverP = perigee->parameters()[Trk::qOverP]; + double pt = fabs(1/qOverP)*sin(perigee->parameters()[Trk::theta]); + double d0 = perigee->parameters()[Trk::d0]; + double z0 = perigee->parameters()[Trk::z0]; + const Trk::TrackSummary* tSum = m_trkSumTool->createSummaryNoHoleSearch(track); + if(tSum){ + double ratioTrk = 1.0; + int nclus = tSum->get(Trk::numberOfPixelHits) + tSum->get(Trk::numberOfSCTHits); + int nTrtHits = tSum->get(Trk::numberOfTRTHits); + int nTrtOutliers = tSum->get(Trk::numberOfTRTOutliers); + int ntrt = nTrtHits + nTrtOutliers; + int nTrtXenonHits = tSum->get(Trk::numberOfTRTXenonHits); + + if(m_isConv) { + + if(ntrt > 0 && (!m_PIDonlyForXe || nTrtXenonHits==ntrt) ) // only check TRT PID if m_PIDonlyForXe is false or all TRT hits are Xenon hits + ratioTrk = tSum->getPID(Trk::eProbabilityComb); + + if ( pt >= m_minPt ) { + if ( (nclus==0 && fabs(d0)<=m_maxTrtD0) || (nclus>0 && fabs(d0)<=m_maxSiD0) ) { + if ( (nclus==0 && fabs(z0)<=m_maxTrtZ0) || (nclus>0 && fabs(z0)<=m_maxSiZ0) ) { + if (nclus>0) { + if((ntrt<=15 && ratioTrk>=m_trRatio1) || + (ntrt>15 && ntrt<=25 && ratioTrk>=m_trRatio2) || + (ntrt>25 && ratioTrk>=m_trRatio3)) pass = true; + } else if (ratioTrk>=m_trRatioTRT) pass = true; + } + } + } + } else { + //The cuts below are necessary for the V0 track selection + const AmgSymMatrix(5)& err = *perigee->covariance(); + double sd0sq = err(0,0); + double sd0 = (sd0sq>0.)?sqrt(sd0sq):0.; + double sz0sq = err(1,1); + double sz0 = (sz0sq>0.)?sqrt(sz0sq):0.; + if(nclus == 0){ + if(fabs(d0)>=m_sD0_Trt*sd0 && fabs(d0)<=m_maxTrtD0 && fabs(z0)<=m_sZ0_Trt*sz0 && pt>=m_minPt) pass = true; + }else{ + if(fabs(d0)>=m_sD0_Si*sd0 && fabs(z0)<=m_maxSiZ0 && pt>=m_minPt) pass = true; + } + + ratioTrk = 1.0; + if(ntrt > 0 && (!m_PIDonlyForXe || nTrtXenonHits==ntrt) ) // only check TRT PID if m_PIDonlyForXe is false or all TRT hits are Xenon hits + ratioTrk = tSum->getPID(Trk::eProbabilityComb); + + if(ratioTrk>m_trRatioV0) pass = false; + } + + delete tSum; + } else pass = false; + + if (myVertex!=vx) delete myVertex; + if (perigee!=track.perigeeParameters()) delete perigee; + + return pass; + } + + bool InDetConversionTrackSelectorTool::decision(const Trk::TrackParticleBase& track,const Trk::Vertex* vx) const + { + bool pass = false; + + const Trk::TrackParameters* definintParameters=&(track.definingParameters()); + const Trk::Perigee* perigee=dynamic_cast<const Trk::Perigee*>(definintParameters); + const Trk::Vertex* myVertex=vx; + //in case no Vertex is provided by the user, beam position will be used if available + if (myVertex==0) { + if (!m_iBeamCondSvc.empty()) { + myVertex=new Trk::RecVertex(m_iBeamCondSvc->beamVtx()); + } else { + msg(MSG::WARNING) << " Cannot get beamSpot center from iBeamCondSvc. Using (0,0,0)... " << endreq; + myVertex=new Trk::Vertex(Amg::Vector3D(0,0,0)); + } + } + + Trk::PerigeeSurface perigeeSurface(myVertex->position()); + const Trk::TrackParameters *firstmeaspar=0; + for (unsigned int i=0;i<track.trackParameters().size();i++){ + if ( (track.trackParameters())[i]->covariance() && !dynamic_cast<const Trk::Perigee*>((track.trackParameters())[i])) { + firstmeaspar=(track.trackParameters())[i]; + break; + } + } + + if (!firstmeaspar) { + //using perigee instead of firstmeasurement, since first measurement was not found... + firstmeaspar=&(track.definingParameters()); + if (!firstmeaspar){ + msg(MSG::DEBUG) << " Track Paraemters at first measurement not found. Perigee not found. Cannot do TrackSelection..." << endreq; + if (myVertex!=vx) { + delete myVertex; + myVertex=0; + } + return false; + } + } + + const Trk::TrackParameters * extrapolatedParameters= m_extrapolator->extrapolate(*firstmeaspar,perigeeSurface,Trk::anyDirection,true,Trk::pion ); + //const Trk::TrackParameters * extrapolatedParameters= firstmeaspar ? m_extrapolator->extrapolate(*firstmeaspar,perigeeSurface,Trk::anyDirection,true,Trk::pion ) : 0; + perigee = extrapolatedParameters ? dynamic_cast<const Trk::Perigee*>(extrapolatedParameters) : 0; + if (perigee==0 || !perigee->covariance()) { + msg(MSG::WARNING) << "Track Selector failed to extrapolate track to the vertex: " << myVertex->position() << endreq; + if (extrapolatedParameters!=0) { + msg(MSG::WARNING) << "The return object of the extrapolator was not a perigee even if a perigeeSurface was used!" << endreq; + delete extrapolatedParameters; + if (myVertex!=vx) delete myVertex; + return false; + } + return false; + } + + double qOverP = perigee->parameters()[Trk::qOverP]; + double pt = fabs(1/qOverP)*sin(perigee->parameters()[Trk::theta]); + double d0 = perigee->parameters()[Trk::d0]; + double z0 = perigee->parameters()[Trk::z0]; + const Trk::TrackSummary* tSum = track.trackSummary(); + if(tSum){ + double ratioTrk = 1.0; + int nclus = tSum->get(Trk::numberOfPixelHits) + tSum->get(Trk::numberOfSCTHits); + int nTrtHits = tSum->get(Trk::numberOfTRTHits); + int nTrtOutliers = tSum->get(Trk::numberOfTRTOutliers); + int ntrt = nTrtHits + nTrtOutliers; + int nTrtXenonHits = tSum->get(Trk::numberOfTRTXenonHits); + + if(m_isConv){ + + if(ntrt > 0 && (!m_PIDonlyForXe || nTrtXenonHits==ntrt) ) // only check TRT PID if m_PIDonlyForXe is false or all TRT hits are Xenon hits + ratioTrk = tSum->getPID(Trk::eProbabilityComb); + + if ( pt >= m_minPt ) { + if ( (nclus==0 && fabs(d0)<=m_maxTrtD0) || (nclus>0 && fabs(d0)<=m_maxSiD0) ) { + if ( (nclus==0 && fabs(z0)<=m_maxTrtZ0) || (nclus>0 && fabs(z0)<=m_maxSiZ0) ) { + if (nclus > 0) { + if((ntrt<=15 && ratioTrk>=m_trRatio1) || + (ntrt>15 && ntrt<=25 && ratioTrk>=m_trRatio2) || + (ntrt>25 && ratioTrk>=m_trRatio3)) pass = true; + } else if (ratioTrk>=m_trRatioTRT) pass = true; + } + } + } + } else { + //The cuts below are necessary for the V0 track selection + const AmgSymMatrix(5)& err = *perigee->covariance(); + double sd0sq = err(0,0); + double sd0 = (sd0sq>0.)?sqrt(sd0sq):0.; + double sz0sq = err(1,1); + double sz0 = (sz0sq>0.)?sqrt(sz0sq):0.; + if(nclus == 0){ + if(fabs(d0)>=m_sD0_Trt*sd0 && fabs(d0)<= m_maxTrtD0 && fabs(z0)<=m_sZ0_Trt*sz0 && pt>=m_minPt) pass = true; + }else{ + if(fabs(d0)>=m_sD0_Si*sd0 && fabs(z0)<=m_maxSiZ0 && pt>=m_minPt) pass = true; + } + + ratioTrk = 1.0; + if(ntrt > 0 && (!m_PIDonlyForXe || nTrtXenonHits==ntrt) ) // only check TRT PID if m_PIDonlyForXe is false or all TRT hits are Xenon hits + ratioTrk = tSum->getPID(Trk::eProbabilityComb); + if(ratioTrk>m_trRatioV0) pass = false; + } + } else pass = false; + + if (myVertex!=vx) delete myVertex; + if (perigee!=&(track.definingParameters())) delete perigee; + + return pass; + } + + + // --------------------------------------------------------------------- + bool InDetConversionTrackSelectorTool::decision(const xAOD::TrackParticle& tp,const xAOD::Vertex* vertex) const + { + + + + + bool pass = false; + + const Trk::Perigee& perigee=tp.perigeeParameters(); + + //in case no Vertex is provided by the user, beam position will be used if available + + Trk::PerigeeSurface perigeeSurface( vertex ? vertex->position() : (!m_iBeamCondSvc.empty() ? m_iBeamCondSvc->beamVtx().position() : Amg::Vector3D(0,0,0) ) ); + + const Trk::TrackParameters* extrapolatedParameters= m_extrapolator->extrapolate(perigee,perigeeSurface,Trk::anyDirection,false,Trk::pion ); + if (extrapolatedParameters==0) { + ATH_MSG_WARNING( "Extrapolation to the vertex failed: " << perigeeSurface << std::endl << perigee ); + return false; + } + + double qOverP = perigee.parameters()[Trk::qOverP]; + double pt = fabs(1/qOverP)*sin(perigee.parameters()[Trk::theta]); + double d0 = extrapolatedParameters->parameters()[Trk::d0]; + double z0 = extrapolatedParameters->parameters()[Trk::z0]; + + double ratioTrk = 1.0; + int nclus = getCount(tp,xAOD::numberOfPixelHits) + getCount(tp,xAOD::numberOfSCTHits); + int nTrtHits = getCount(tp,xAOD::numberOfTRTHits); + int nTrtOutliers = getCount(tp,xAOD::numberOfTRTOutliers); + int ntrt = nTrtHits + nTrtOutliers; + int nTrtXenonHits = getCount(tp,xAOD::numberOfTRTXenonHits); + + if(m_isConv){ + float temp(0); + if(ntrt > 0 && (!m_PIDonlyForXe || nTrtXenonHits==ntrt) ){ // only check TRT PID if m_PIDonlyForXe is false or all TRT hits are Xenon hits + ratioTrk = tp.summaryValue(temp,xAOD::eProbabilityComb) ? temp: 0 ; + } + + if ( pt >= m_minPt ) { + if ( (nclus==0 && fabs(d0)<=m_maxTrtD0) || (nclus>0 && fabs(d0)<=m_maxSiD0) ) { + if ( (nclus==0 && fabs(z0)<=m_maxTrtZ0) || (nclus>0 && fabs(z0)<=m_maxSiZ0) ) { + if (nclus > 0) { + if((ntrt<=15 && ratioTrk>=m_trRatio1) || + (ntrt>15 && ntrt<=25 && ratioTrk>=m_trRatio2) || + (ntrt>25 && ratioTrk>=m_trRatio3)) pass = true; + } else if (ratioTrk>=m_trRatioTRT) pass = true; + } + } + } + } else { + //The cuts below are necessary for the V0 track selection + const AmgSymMatrix(5)& err = *perigee.covariance(); + double sd0sq = err(0,0); + double sd0 = (sd0sq>0.)?sqrt(sd0sq):0.; + double sz0sq = err(1,1); + double sz0 = (sz0sq>0.)?sqrt(sz0sq):0.; + if(nclus == 0){ + if(fabs(d0)>=m_sD0_Trt*sd0 && fabs(d0)<= m_maxTrtD0 && fabs(z0)<=m_sZ0_Trt*sz0 && pt>=m_minPt) pass = true; + }else{ + if(fabs(d0)>=m_sD0_Si*sd0 && fabs(z0)<=m_maxSiZ0 && pt>=m_minPt) pass = true; + } + + ratioTrk = 1.0; + float temp(0); + if(ntrt > 0 && (!m_PIDonlyForXe || nTrtXenonHits==ntrt) ) // only check TRT PID if m_PIDonlyForXe is false or all TRT hits are Xenon hits + ratioTrk = tp.summaryValue(temp,xAOD::eProbabilityComb) ? temp: 0 ; + if(ratioTrk>m_trRatioV0) pass = false; + } + + + delete extrapolatedParameters; + return pass; + } +}//end of namespace definitions diff --git a/InnerDetector/InDetRecTools/InDetTrackSelectorTool/src/InDetCosmicTrackSelectorTool.cxx b/InnerDetector/InDetRecTools/InDetTrackSelectorTool/src/InDetCosmicTrackSelectorTool.cxx new file mode 100644 index 00000000000..b9cd19fe987 --- /dev/null +++ b/InnerDetector/InDetRecTools/InDetTrackSelectorTool/src/InDetCosmicTrackSelectorTool.cxx @@ -0,0 +1,286 @@ +/* + Copyright (C) 2002-2017 CERN for the benefit of the ATLAS collaboration +*/ + +#include "InDetTrackSelectorTool/InDetCosmicTrackSelectorTool.h" + +// forward declares +#include "TrkToolInterfaces/ITrackSummaryTool.h" +#include "MagFieldInterfaces/IMagFieldSvc.h" +#include "VxVertex/Vertex.h" +#include "TrkTrack/Track.h" +#include "TrkParticleBase/TrackParticleBase.h" + +// normal includes +#include "TrkTrackSummary/TrackSummary.h" +#include "TrkRIO_OnTrack/RIO_OnTrack.h" +#include "InDetRIO_OnTrack/SiClusterOnTrack.h" +#include "InDetRIO_OnTrack/SCT_ClusterOnTrack.h" +#include "DataModel/DataVector.h" + + +namespace InDet +{ + //---------------------------------------------------------------------------- + InDetCosmicTrackSelectorTool::InDetCosmicTrackSelectorTool(const std::string& t, const std::string& n, const IInterface* p) + : AthAlgTool(t,n,p) + , m_magFieldSvc("AtlasFieldSvc",n) + { + declareInterface<ITrackSelectorTool>(this); + declareProperty("maxZ0", m_maxZ0 = 150.); + declareProperty("maxD0", m_maxD0 = 2.5); + declareProperty("minPt", m_minPt = 0.); + declareProperty("numberOfPixelHits", m_numberOfPixelHits = 0); + declareProperty("numberOfSCTHits", m_numberOfSCTHits = 0); + declareProperty("numberOfTRTHits", m_numberOfTRTHits = 15); + declareProperty("numberOfSiliconHits", m_numberOfSiHits = 8); + declareProperty("numberOfSiliconHitsTop", m_numberOfSiHitsTop = -1); + declareProperty("numberOfSiliconHitsBottom", m_numberOfSiHitsBottom = -1); + declareProperty("TrackSummaryTool", m_trackSumTool); + declareProperty("MagFieldSvc", m_magFieldSvc); + } + + //---------------------------------------------------------------------------- + InDetCosmicTrackSelectorTool::~InDetCosmicTrackSelectorTool() + {} + + //---------------------------------------------------------------------------- + StatusCode InDetCosmicTrackSelectorTool::initialize() + { + if(AthAlgTool::initialize().isFailure()) { + msg(MSG::ERROR)<<" Unable to initialize the AlgTool"<<endreq; + return StatusCode::FAILURE; + } + + m_trackSumToolAvailable = false; + if (!m_trackSumTool.empty()) { + if(m_trackSumTool.retrieve().isFailure()) + { + msg(MSG::ERROR)<<" Unable to retrieve "<<m_trackSumTool<<endreq; + return StatusCode::FAILURE; + } + ATH_MSG_INFO("Track summary tool retrieved"); + m_trackSumToolAvailable = true; + } + + if (m_magFieldSvc.retrieve().isFailure()) { + msg(MSG::FATAL) << "Failed to retrieve tool " << m_magFieldSvc << endreq; + return StatusCode::FAILURE; + } + ATH_MSG_INFO("Retrieved tool "<<m_magFieldSvc); + + return StatusCode::SUCCESS; + } + + //---------------------------------------------------------------------------- + StatusCode InDetCosmicTrackSelectorTool::finalize() + { + ATH_MSG_INFO("Finalize successful"); + return StatusCode::SUCCESS; + } + + //---------------------------------------------------------------------------- + bool InDetCosmicTrackSelectorTool::decision(const Trk::Track & track, const Trk::Vertex * vertex) const + { + + // decision based on the track parameters + if(!decision(track.perigeeParameters(), vertex, track.info().particleHypothesis())) + return false; + + // number of hits, silicon hits, b-layer + // first ask track for summary + const Trk::TrackSummary * summary = track.trackSummary(); + if (summary == 0 && m_trackSumToolAvailable) { + // ugly but one needs to cast the const away because the method needs to update the track (the tool is a friend of track) + Trk::Track& nonConstTrack = const_cast<Trk::Track&>(track); + m_trackSumTool->updateTrack(nonConstTrack); + // now get it from the track (the track has OWNERSHIP) + summary = nonConstTrack.trackSummary(); + } + + if (0==summary) { + ATH_MSG_DEBUG( "Track preselection: cannot create a track summary. This track will not pass." ); + return false; + } + + int nPixHits = summary->get(Trk::numberOfPixelHits); + int nSCTHits = summary->get(Trk::numberOfSCTHits); + int nTRTHits = summary->get(Trk::numberOfTRTHits); + int nSiHits = summary->get(Trk::numberOfPixelHits) * 2 + summary->get(Trk::numberOfSCTHits); + int nSiHitsTop = getNSiHits(&track,true); + int nSiHitsBottom = getNSiHits(&track,false); + + if(nPixHits<m_numberOfPixelHits) { + ATH_MSG_DEBUG("Track rejected because of numberOfPixelHits "<<nPixHits<<"<"<<m_numberOfPixelHits); + return false; + } + + if(nSCTHits<m_numberOfSCTHits) { + ATH_MSG_DEBUG("Track rejected because of numberOfSCTHits "<<nSCTHits<<"<"<<m_numberOfSCTHits); + return false; + } + + if(nTRTHits<m_numberOfTRTHits) { + ATH_MSG_DEBUG("Track rejected because of numberOfTRTHits "<<nTRTHits<<"<"<<m_numberOfTRTHits); + return false; + } + + if(nSiHits<m_numberOfSiHits) { + ATH_MSG_DEBUG("Track rejected because of numberOfSiHits "<<nSiHits<<"<"<<m_numberOfSiHits); + return false; + } + + if(nSiHitsTop<m_numberOfSiHitsTop) { + ATH_MSG_DEBUG("Track rejected because of nSiHitsTop "<<nSiHitsTop<<"<"<<m_numberOfSiHitsTop); + return false; + } + + if(nSiHitsBottom<m_numberOfSiHitsBottom) { + ATH_MSG_DEBUG("Track rejected because of numberOfSiHitsBottom "<<nSiHitsBottom<<"<"<<m_numberOfSiHitsBottom); + return false; + } + + // all ok + return true; + } + + //---------------------------------------------------------------------------- + bool InDetCosmicTrackSelectorTool::decision(const Trk::TrackParticleBase & track,const Trk::Vertex * vertex) const + { + if(!decision(&(track.definingParameters()), vertex, Trk::pion)) + return false; + + const Trk::TrackSummary * summary = track.trackSummary(); + if (0==summary ) { + ATH_MSG_DEBUG( "TrackParticleBase does not have a Track Summary. Rejected." ); + return false; + } + const Trk::Track * otrack= track.originalTrack(); + + if(otrack==0){ + ATH_MSG_DEBUG( "TrackParticleBase does not contain the original cosmic track. Rejected." ); + return false; + } + + int nPixHits = summary->get(Trk::numberOfPixelHits); + int nSCTHits = summary->get(Trk::numberOfSCTHits); + int nTRTHits = summary->get(Trk::numberOfTRTHits); + int nSiHits = summary->get(Trk::numberOfPixelHits)*2+summary->get(Trk::numberOfSCTHits); + int nSiHitsTop = getNSiHits(otrack,true); + int nSiHitsBottom = getNSiHits(otrack,false); + + if(nPixHits<m_numberOfPixelHits) { + ATH_MSG_DEBUG("Track rejected because of numberOfPixelHits "<<nPixHits<<"<"<<m_numberOfPixelHits); + return false; + } + + if(nSCTHits<m_numberOfSCTHits) { + ATH_MSG_DEBUG("Track rejected because of numberOfSCTHits "<<nSCTHits<<"<"<<m_numberOfSCTHits); + return false; + } + + if(nTRTHits<m_numberOfTRTHits) { + ATH_MSG_DEBUG("Track rejected because of numberOfTRTHits "<<nTRTHits<<"<"<<m_numberOfTRTHits); + return false; + } + + if(nSiHits<m_numberOfSiHits) { + ATH_MSG_DEBUG("Track rejected because of numberOfSiHits "<<nSiHits<<"<"<<m_numberOfSiHits); + return false; + } + + if(nSiHitsTop<m_numberOfSiHitsTop) { + ATH_MSG_DEBUG("Track rejected because of nSiHitsTop "<<nSiHitsTop<<"<"<<m_numberOfSiHitsTop); + return false; + } + + if(nSiHitsBottom<m_numberOfSiHitsBottom) { + ATH_MSG_DEBUG("Track rejected because of numberOfSiHitsBottom "<<nSiHitsBottom<<"<"<<m_numberOfSiHitsBottom); + return false; + } + + // all ok + return true; + } + + //---------------------------------------------------------------------------- + bool InDetCosmicTrackSelectorTool::decision(const Trk::TrackParameters* track, const Trk::Vertex *, const Trk::ParticleHypothesis) const + { + // checking pointer first + if(0==track) { + ATH_MSG_DEBUG( "Track preselection: Zero pointer to parameterbase* received (most likely a track without perigee). This track will not pass." ); + return false; + } + + // getting the perigee parameters of the track + const Trk::Perigee * perigee(0); + perigee = dynamic_cast<const Trk::Perigee *>(track); + + if(!perigee || !perigee->covariance()) { + ATH_MSG_DEBUG( "Track preselection: cannot make a measured perigee. This track will not pass." ); + return false; + } + + Amg::VectorX trackParameters = perigee->parameters(); + + // d0 and z0 cuts + double d0 = trackParameters[Trk::d0]; + if(fabs(d0) > fabs(m_maxD0)) { + ATH_MSG_DEBUG("Track rejected because of d0 "<<fabs(d0)<<">"<<m_maxD0); + return false; + } + + double z0 = trackParameters[Trk::z0]; + if(fabs(z0) > fabs(m_maxZ0)) { + ATH_MSG_DEBUG("Track rejected because of z0 "<<fabs(z0)<<">"<<m_maxZ0); + return false; + } + + // only check pt if mag. field is on + if (m_magFieldSvc->solenoidOn()) { + if (trackParameters[Trk::qOverP] == 0.) { + ATH_MSG_DEBUG("Track rejected because of qOverP == 0."); + return false; + } + + double pt = fabs(1./trackParameters[Trk::qOverP])*sin(trackParameters[Trk::theta]); + if (pt < m_minPt) { + ATH_MSG_DEBUG("Track rejected because of pt " << pt << " < " << m_minPt); + return false; + } + } + return true; + } + + //---------------------------------------------------------------------------- + int InDetCosmicTrackSelectorTool::getNSiHits(const Trk::Track * track, bool top) const + { + int nsilicon = 0; + + //loop over all measurements on Track + DataVector<const Trk::MeasurementBase>::const_iterator it = track->measurementsOnTrack()->begin(); + DataVector<const Trk::MeasurementBase>::const_iterator itEnd = track->measurementsOnTrack()->end(); + for ( ; it!=itEnd; ++it) { + const Trk::RIO_OnTrack *rot = dynamic_cast<const Trk::RIO_OnTrack *>(*it); + if (!rot) + continue; + const InDet::SiClusterOnTrack *siclus = dynamic_cast<const InDet::SiClusterOnTrack *>(rot); + if(!siclus) + continue; + + if(top && siclus->globalPosition().y()<0) + continue; + if(!top && siclus->globalPosition().y()>0) + continue; + + const SCT_ClusterOnTrack *sctclus = dynamic_cast<const SCT_ClusterOnTrack *>(siclus); + if(!sctclus) + //Pixel hit + nsilicon += 2; + else + nsilicon += 1; + } + return nsilicon; + } + +} //end of namespace definitions diff --git a/InnerDetector/InDetRecTools/InDetTrackSelectorTool/src/InDetDetailedTrackSelectorTool.cxx b/InnerDetector/InDetRecTools/InDetTrackSelectorTool/src/InDetDetailedTrackSelectorTool.cxx new file mode 100644 index 00000000000..423cd5b2460 --- /dev/null +++ b/InnerDetector/InDetRecTools/InDetTrackSelectorTool/src/InDetDetailedTrackSelectorTool.cxx @@ -0,0 +1,1202 @@ +/* + Copyright (C) 2002-2017 CERN for the benefit of the ATLAS collaboration +*/ + +#include "InDetTrackSelectorTool/InDetDetailedTrackSelectorTool.h" +// forward declares +#include "TrkToolInterfaces/ITrackSummaryTool.h" +#include "TrkExInterfaces/IExtrapolator.h" +#include "VxVertex/Vertex.h" +#include "VxVertex/RecVertex.h" +#include "TrkEventPrimitives/FitQuality.h" +#include "TrkTrack/Track.h" +#include "TrkTrackSummary/TrackSummary.h" +#include "TrkParticleBase/TrackParticleBase.h" +#include "InDetBeamSpotService/IBeamCondSvc.h" +#include "MagFieldInterfaces/IMagFieldSvc.h" +#include "InDetRecToolInterfaces/ITrtDriftCircleCutTool.h" +#include "InDetRecToolInterfaces/IInDetTestBLayerTool.h" + +#include "xAODTracking/TrackParticle.h" +#include "xAODTracking/Vertex.h" + + +// normal includes +#include "CLHEP/GenericFunctions/CumulativeChiSquare.hh" +#include "TrkSurfaces/PerigeeSurface.h" +#include "GeoPrimitives/GeoPrimitives.h" +#include "EventPrimitives/EventPrimitives.h" +#include <TMath.h> + +using CLHEP::GeV; +using CLHEP::mm; + +namespace InDet +{ + + // --------------------------------------------------------------------- + InDetDetailedTrackSelectorTool::InDetDetailedTrackSelectorTool(const std::string& t, const std::string& n, const IInterface* p) + : AthAlgTool(t,n,p) + , m_trackSumTool("Trk::TrackSummaryTool") + , m_extrapolator("Trk::Extrapolator") + , m_iBeamCondSvc ("BeamCondSvc",n) + , m_magFieldSvc("AtlasFieldSvc",n) + , m_trtDCTool("InDet::InDetTrtDriftCircleCutTool") + // , m_inDetTestBLayerTool("InDet::InDetTestBLayerTool") + , m_inDetTestBLayerTool("") + , m_trackSumToolAvailable(true) + , m_usePtDependentCuts(false) + // , m_ptBenchmarks(1, 0) // create with dummy length 1 filled with 0 + // , m_nSCTValues(1, 0) // same + + { + declareInterface<ITrackSelectorTool>(this); + declareProperty("pTMin" , m_pTMin = 1.*GeV); + declareProperty("pMin" , m_pMin = 0.); + declareProperty("IPd0Max" , m_IPd0Max = 2.*mm); + declareProperty("IPz0Max" , m_IPz0Max = 1.5*mm); + declareProperty("z0Max" , m_z0Max = 9999.*mm); + declareProperty("sigIPd0Max" , m_sigIPd0Max = 999.*mm); + declareProperty("sigIPz0Max" , m_sigIPz0Max = 999.*mm); + declareProperty("d0significanceMax", m_d0significanceMax = -1.); + declareProperty("z0significanceMax", m_z0significanceMax = -1.); + declareProperty("etaMax" , m_etaMax = 9999.); + + declareProperty("useTrackSummaryInfo", m_useTrackSummaryInfo = true); + + declareProperty("nHitBLayer" , m_nHitBLayer = 1); + declareProperty("nHitPix" , m_nHitPix = 2); + declareProperty("nHitBLayerPlusPix", m_nHitBLayerPlusPix = 0); + declareProperty("nHitSct" , m_nHitSct = 0); + declareProperty("nHitSi" , m_nHitSi = 7); + + declareProperty("nHitPixPhysical", m_nHitPixPhysical = 0); + declareProperty("nHitSiPhysical", m_nHitSiPhysical = 3); + + declareProperty("nHitTrt" , m_nHitTrt = 0); + declareProperty("nHitTrtPlusOutliers" , m_nHitTrtPlusOutliers = 0); + declareProperty("nHitTrtHighE" , m_nHitTrtHighE = 0); + declareProperty("nHitTrtPlusOutliersHighE" , m_nHitTrtPlusOutliersHighE = 0); + declareProperty("nHitTrtHighEFractionMax" , m_nHitTrtHighEFraction = 999); + declareProperty("nHitTrtHighEFractionWithOutliersMax", m_nHitTrtHighEFractionWithOutliers = 999); + + declareProperty("useSharedHitInfo", m_useSharedHitInfo = false); + declareProperty("nSharedBLayer" , m_nSharedBLayer = 0); + declareProperty("nSharedPix" , m_nSharedPix = 0); + declareProperty("nSharedSct" , m_nSharedSct = 1); + declareProperty("nSharedSi" , m_nSharedSi = 999); + + declareProperty("nHoles" , m_nHoles = 999); + declareProperty("nDoubleHoles", m_nDoubleHoles = 999); + declareProperty("nHolesPixel" , m_nHolesPix = 999); + declareProperty("nHolesSct" , m_nHolesSct = 999); + + declareProperty("useTrackQualityInfo", m_useTrackQualityInfo = true); + declareProperty("fitChi2" , m_fitChi2 = 99999.); + declareProperty("fitProb" , m_fitProb = -1.); + declareProperty("fitChi2OnNdfMax" , m_fitChi2OnNdfMax = 999.); + declareProperty("TrtMaxEtaAcceptance", m_TrtMaxEtaAcceptance = 999.); + + declareProperty("usePreselectionCuts", m_usePreselectionCuts = false); + declareProperty("d0MaxPreselection" , m_d0MaxPreselection = 10.); + + declareProperty("useEtaDepententMinHitTrt", m_useEtaDepententMinHitTrt = false); + declareProperty("scaleMinHitTrt" , m_scaleMinHitTrt = 1.); + declareProperty("addToMinHitTrt" , m_addToMinHitTrt = 0); + + declareProperty("useEtaDepententMinHitTrtWithOutliers", m_useEtaDepententMinHitTrtWithOutliers = false); + declareProperty("scaleMinHitTrtWithOutliers" , m_scaleMinHitTrtWithOutliers = 1.); + declareProperty("addToMinHitTrtWithOutliers" , m_addToMinHitTrtWithOutliers = 0); + + declareProperty("TrackSummaryTool" , m_trackSumTool); + declareProperty("Extrapolator" , m_extrapolator); + declareProperty("BeamPositionSvc" , m_iBeamCondSvc); + declareProperty("MagFieldSvc", m_magFieldSvc); + declareProperty("TrtDCCutTool" , m_trtDCTool); + declareProperty("InDetTestBLayerTool", m_inDetTestBLayerTool); + + //pt-dependent cuts; default vector values (can be done much smarter, but I want + // to have an explicit code..) + + // std::vector<float> loc_bench; + // loc_bench.push_back(100.); + // loc_bench.push_back(200.); + // loc_bench.push_back(300.); + + // std::vector<int> loc_nsct; + // loc_nsct.push_back(2); + // loc_nsct.push_back(4); + // loc_nsct.push_back(6); + + declareProperty("UsePtDependentCuts", m_usePtDependentCuts = false); + declareProperty("PtBenchmarks" , m_ptBenchmarks); + declareProperty("SCTCutValues" , m_nSCTValues); + } + + // --------------------------------------------------------------------- + InDetDetailedTrackSelectorTool::~InDetDetailedTrackSelectorTool() + {} + + // --------------------------------------------------------------------- + StatusCode InDetDetailedTrackSelectorTool::initialize() + { + StatusCode sc = AthAlgTool::initialize(); + if(sc.isFailure()) + { + msg(MSG::ERROR)<<" Unable to initialize the AlgTool"<<endreq; + return StatusCode::FAILURE; + } + + m_trackSumToolAvailable=false; + if (!m_trackSumTool.empty()) + { + if(m_trackSumTool.retrieve().isFailure()) + { + msg(MSG::INFO)<<" Unable to retrieve. OK if running on AOD. "<<m_trackSumTool<<endreq; + } + else + { + msg(MSG::INFO)<<"Track summary tool retrieved"<<endreq; + m_trackSumToolAvailable=true; + } + } + + if ( m_extrapolator.retrieve().isFailure() ) + { + msg(MSG::ERROR) << "Failed to retrieve tool " << m_extrapolator << endreq; + return StatusCode::FAILURE; + } + ATH_MSG_INFO("Retrieved tool " << m_extrapolator); + + sc = m_iBeamCondSvc.retrieve(); + if (sc.isFailure()) + ATH_MSG_INFO("Could not find BeamCondSvc. Will use (0,0,0) if no vertex is given and extrapolation is needed."); + + if (m_useEtaDepententMinHitTrt || m_useEtaDepententMinHitTrtWithOutliers) + { + if(m_trtDCTool.empty()) { + msg(MSG::ERROR)<<" Eta delendent cut on number of TRT hits requested but TrtDCCutTool not specified. "<<endreq; + return StatusCode::FAILURE; + } + else if(m_trtDCTool.retrieve().isFailure()) { + msg(MSG::ERROR)<<" Unable to retrieve tool "<<m_trtDCTool<<endreq; + return StatusCode::FAILURE; + } + ATH_MSG_INFO("Retrieved tool "<<m_trtDCTool); + + if(m_useEtaDepententMinHitTrt) + ATH_MSG_INFO("Using eta dependent cut on number of TRT hits."); + if(m_useEtaDepententMinHitTrtWithOutliers) + ATH_MSG_INFO("Using eta dependent cut on number of TRT hits + outliers."); + } + + if (m_magFieldSvc.retrieve().isFailure()) + { + msg(MSG::FATAL) << "Failed to retrieve " << m_magFieldSvc << endreq; + return StatusCode::FAILURE; + } + ATH_MSG_INFO("Retrieved tool "<<m_magFieldSvc); + + if(m_inDetTestBLayerTool.empty()) + { + msg(MSG::INFO)<<" The BLayerTool not specified, turning off cut. "<<endreq; + } + else if ( m_inDetTestBLayerTool.retrieve().isFailure() ) + { + msg(MSG::ERROR)<< "Failed to retrieve tool " << m_inDetTestBLayerTool<<endreq; + return StatusCode::FAILURE; + } + ATH_MSG_INFO("Using cuts on the number of Silicon hits"); + + if(m_usePtDependentCuts) + { + //checking whether sizes of cuts and pt interval expressed in vectors match + if( m_ptBenchmarks.size() != m_nSCTValues.size()) + { + msg(MSG::ERROR)<< "Number of cuts DOES NOT match the number of intervals to apply. Please check jobOptions. "<<endreq; + return StatusCode::FAILURE; + } else if (m_ptBenchmarks.size() == 0) + { + msg(MSG::ERROR)<< "Zero vectors for number of cuts and pt intervals. Please check jobOptions. "<<endreq; + return StatusCode::FAILURE; + }//end of vector size protection block + }//end of memory protection + + return StatusCode::SUCCESS; + } + + // --------------------------------------------------------------------- + StatusCode InDetDetailedTrackSelectorTool::finalize() + { + msg(MSG::INFO) << "Finalize successful" << endreq; + return StatusCode::SUCCESS; + } + + // --------------------------------------------------------------------- + bool InDetDetailedTrackSelectorTool::decision(const Trk::Track& track,const Trk::Vertex* vertex) const + { + const Trk::Perigee* perigeeBeforeExtrapolation= + dynamic_cast<const Trk::Perigee*>(track.perigeeParameters()); + + if (perigeeBeforeExtrapolation && m_usePreselectionCuts) + { + bool preselectionDecision=preselectionBeforeExtrapolation(*perigeeBeforeExtrapolation); + if (!preselectionDecision) { + ATH_MSG_DEBUG("Track rejected because of preselection decision!"); + return false; + } + } + else if (m_usePreselectionCuts) + { + ATH_MSG_INFO( " Preselection was requested but cannot be made since no Perigee in Track is available. This is not an error." ); + } + + const Trk::Vertex* myVertex=vertex; + + //in case no Vertex is provided by the user, beam position will be used if available + + if (myVertex==0) { + //ATH_MSG_DEBUG( "No vertex given, using beam spot or 0,0,0" ); + if (!m_iBeamCondSvc.empty()) { + myVertex=new Trk::RecVertex(m_iBeamCondSvc->beamVtx()); + } else { + ATH_MSG_WARNING( " Cannot get beamSpot center from iBeamCondSvc. Using (0,0,0)... " ); + myVertex=new Trk::Vertex(Amg::Vector3D(0,0,0)); + } + } + + Trk::PerigeeSurface perigeeSurface(myVertex->position()); + const Trk::TrackParameters *firstmeaspar=0; + for (unsigned int i=0;i<track.trackParameters()->size();i++){ + if ( (*track.trackParameters())[i]->covariance() && !dynamic_cast<const Trk::Perigee*>((*track.trackParameters())[i])) { + firstmeaspar=(*track.trackParameters())[i]; + break; + } + } + + if (!firstmeaspar) { + //assumes perigeeParameters exist... + //no track selection if firstmeas + perigee does not exist ! + firstmeaspar=track.perigeeParameters(); + if (!firstmeaspar) + { + ATH_MSG_WARNING( " First measurment on track is missing. Using perigee Parameters, but they are missing: 0 pointer! Track selection failed " ); + //clean up vertex + if (myVertex!=vertex) { + delete myVertex; + myVertex=0; + } + return false; + } + } + + const Trk::TrackParameters* extrapolatedParameters= firstmeaspar ? + m_extrapolator->extrapolate(*firstmeaspar,perigeeSurface,Trk::anyDirection,true,track.info().particleHypothesis() ) : 0; + const Trk::Perigee* extrapolatedPerigee = extrapolatedParameters ? dynamic_cast<const Trk::Perigee*>(extrapolatedParameters) : 0; + + if (!extrapolatedPerigee || !extrapolatedPerigee->covariance() ) { + ATH_MSG_WARNING( "Track Selector failed to extrapolate track to the vertex: " << myVertex->position() ); + if (extrapolatedParameters!=0) { + ATH_MSG_WARNING( "The return object of the extrapolator was not a perigee even if a perigeeSurface was used!" ); + delete extrapolatedParameters; + } + } + + //decision based on the track parameters + const Trk::RecVertex* recVertex = dynamic_cast<const Trk::RecVertex*>(myVertex); + bool dec = decision(extrapolatedPerigee, recVertex ? &recVertex->covariancePosition() : 0 ); + + if (myVertex!=vertex) { + delete myVertex; + myVertex=0; + } + + bool isInTrtAcceptance=true; + + if (!extrapolatedPerigee || fabs(extrapolatedPerigee->momentum().eta())>m_TrtMaxEtaAcceptance) { + isInTrtAcceptance=false; + } + + if (extrapolatedPerigee!=track.perigeeParameters()) { + delete extrapolatedPerigee; + extrapolatedPerigee=0; + } + + if(!dec) { + ATH_MSG_DEBUG("Track rejected because of perigee parameters!"); + return false; + } + + if (m_useTrackQualityInfo) { + + const Trk::FitQuality* TrkQuality=track.fitQuality(); + + if (TrkQuality==0) { + ATH_MSG_WARNING( "Requested cut on track quality was not possible. Track has no FitQuality object attached. Selection failed." ); + return false; + } + + if (!decision(TrkQuality)) { + return false; + } + } + + if (m_useTrackSummaryInfo) { + //number of hits, silicon hits, b-layer + + const Trk::TrackSummary* summary = 0; + + // first ask track for summary + summary = track.trackSummary(); + + if (m_trackSumToolAvailable && summary == 0) { + // ugly but one needs to cast the const away because the method needs to update the track (the tool is a friend of track) + Trk::Track& nonConstTrack = const_cast<Trk::Track&>(track); + m_trackSumTool->updateTrack(nonConstTrack); + summary = nonConstTrack.trackSummary(); + } + + if (!m_trackSumToolAvailable) { + ATH_MSG_WARNING( " No Track Summary Tool available. This should be the case only when running on AOD" ); + } + + if (0==summary ) { + ATH_MSG_WARNING( "Track preselection: cannot create a track summary (but useTrackSummary is true). Selection failed." ); + return false; + } + + // get the minimum nimber of TRT hits based on eta of the track + if(m_useEtaDepententMinHitTrt) { + m_nHitTrt = m_trtDCTool->minNumberDCs( (*track.trackParameters())[0] ); + if(m_addToMinHitTrt!=0) + m_nHitTrt += m_addToMinHitTrt; + else + m_nHitTrt = (int)((double)m_nHitTrt*m_scaleMinHitTrt); + } + + // get the minimum nimber of TRT hits + outliers based on eta of the track + if(m_useEtaDepententMinHitTrtWithOutliers) { + m_nHitTrtPlusOutliers = m_trtDCTool->minNumberDCs( (*track.trackParameters())[0] ); + if(m_addToMinHitTrtWithOutliers!=0) + m_nHitTrtPlusOutliers += m_addToMinHitTrtWithOutliers; + else + m_nHitTrtPlusOutliers = (int)((double)m_nHitTrtPlusOutliers*m_scaleMinHitTrtWithOutliers); + } + + if (!decision(summary,m_useSharedHitInfo,isInTrtAcceptance, perigeeBeforeExtrapolation)) { + summary=0; + return false; + } + summary=0; + } + + //all ok + return true; + } + + // --------------------------------------------------------------------- + bool InDetDetailedTrackSelectorTool::decision(const Trk::TrackParticleBase& track,const Trk::Vertex* vertex) const + { + + const Trk::TrackParameters* definintParameters=&(track.definingParameters()); + + const Trk::Perigee* perigeeBeforeExtrapolation= + dynamic_cast<const Trk::Perigee*>(definintParameters); + + if (perigeeBeforeExtrapolation && m_usePreselectionCuts) { + bool preselectionDecision=preselectionBeforeExtrapolation(*perigeeBeforeExtrapolation); + if (!preselectionDecision) { + ATH_MSG_DEBUG("Track rejected because of preselection decision!"); + return false; + } + } + else if (m_usePreselectionCuts) { + ATH_MSG_WARNING( " Preselection was requested but cannot be made since the Perigee is not the defining Parameter of the TrackParticle. This is not an error." ); + } + + + bool isInTrtAcceptance=true; + if (!perigeeBeforeExtrapolation || fabs(perigeeBeforeExtrapolation->momentum().eta())>m_TrtMaxEtaAcceptance) { + isInTrtAcceptance=false; + } + + + if (m_useTrackQualityInfo) { + + const Trk::FitQuality* TrkQuality=track.fitQuality(); + + if (TrkQuality==0) { + ATH_MSG_WARNING( "Requested cut on track quality was not possible. TrackParticleBase has no FitQuality object attached. Selection failed." ); + return false; + } + + if (!decision(TrkQuality)) { + return false; + } + + } + + if (m_useTrackSummaryInfo) { + //number of hits, silicon hits, b-layer + const Trk::TrackSummary* summary = track.trackSummary(); + + if (0==summary ) { + ATH_MSG_WARNING( "Track preselection: cannot create a track summary (but useTrackSummary is true). Selection failed." ); + return false; + } + + if(m_useEtaDepententMinHitTrt) { + m_nHitTrt = m_trtDCTool->minNumberDCs( (track.trackParameters())[0] ); + if(m_addToMinHitTrt!=0) + m_nHitTrt += m_addToMinHitTrt; + else + m_nHitTrt = (int)((double)m_nHitTrt*m_scaleMinHitTrt); + } + + if(m_useEtaDepententMinHitTrtWithOutliers) { + m_nHitTrtPlusOutliers = m_trtDCTool->minNumberDCs( (track.trackParameters())[0] ); + if(m_addToMinHitTrtWithOutliers!=0) + m_nHitTrtPlusOutliers += m_addToMinHitTrtWithOutliers; + else + m_nHitTrtPlusOutliers = (int)((double)m_nHitTrtPlusOutliers*m_scaleMinHitTrtWithOutliers); + } + + if (!decision(summary, m_useSharedHitInfo, isInTrtAcceptance, perigeeBeforeExtrapolation)) { + return false; + } + } + + const Trk::Perigee* extrapolatedPerigee=dynamic_cast<const Trk::Perigee*>(definintParameters); + + const Trk::Vertex* myVertex=vertex; + + if (vertex==0) { + //ATH_MSG_DEBUG( "No vertex given, using beam spot or 0,0,0" ); + if (!m_iBeamCondSvc.empty()) { + myVertex=new Trk::RecVertex(m_iBeamCondSvc->beamVtx()); + } else { + ATH_MSG_WARNING( " Cannot get beamSpot center from iBeamCondSvc. Using (0,0,0)... " ); + myVertex=new Trk::Vertex(Amg::Vector3D(0,0,0)); + } + } + + Trk::PerigeeSurface perigeeSurface(myVertex->position()); + + const Trk::TrackParameters *firstmeaspar=0; + + for (unsigned int i=0;i<track.trackParameters().size();i++) { + if ((track.trackParameters())[i]->covariance() && + !dynamic_cast<const Trk::Perigee*>((track.trackParameters())[i])) { + firstmeaspar=(track.trackParameters())[i]; + break; + } + } + + if (!firstmeaspar) { + if (!extrapolatedPerigee || !extrapolatedPerigee->covariance() ) { + ATH_MSG_DEBUG( " Track Paraemters at first measurement not found. Perigee not found. Cannot do TrackSelection..." ); + if (myVertex!=vertex) { + delete myVertex; + myVertex=0; + } + return false; + } + //using perigee instead of firstmeasurement, since first measurement was not found... + firstmeaspar=&(track.definingParameters()); + } + + ATH_MSG_VERBOSE ("Input to extrapolation: " << *firstmeaspar); + ATH_MSG_VERBOSE ("Extrapolating to position: " << myVertex->position()[0] << " , " << + myVertex->position()[1] << " , " << myVertex->position()[2]); + + const Trk::TrackParameters* extrapolatedParameters= firstmeaspar ? + m_extrapolator->extrapolate(*firstmeaspar,perigeeSurface,Trk::anyDirection,true,Trk::pion ) : 0; + + extrapolatedPerigee = extrapolatedParameters ? dynamic_cast<const Trk::Perigee*>(extrapolatedParameters) : 0; + + + if (extrapolatedPerigee==0 || !extrapolatedPerigee->covariance()) { + ATH_MSG_WARNING( "Track Selector failed to extrapolate track to the vertex: " << myVertex->position() ); + if (extrapolatedParameters!=0) { + ATH_MSG_WARNING( "The return object of the extrapolator was not a perigee even if a perigeeSurface was used!" ); + delete extrapolatedParameters; + } + } + + ATH_MSG_VERBOSE ("Result: " << *extrapolatedParameters); + + const Trk::RecVertex* recVertex = dynamic_cast<const Trk::RecVertex*>(myVertex); + bool dec = decision(extrapolatedPerigee, recVertex ? &recVertex->covariancePosition() : 0 ); + + if (myVertex!=vertex) { + delete myVertex; + myVertex=0; + } + if (extrapolatedPerigee!=&(track.definingParameters())) { + delete extrapolatedPerigee; + extrapolatedPerigee=0; + } + + if(!dec) { + ATH_MSG_DEBUG("Track rejected because of perigee parameters!"); + return false; + } + + return true; + } + + + // --------------------------------------------------------------------- + bool InDetDetailedTrackSelectorTool::decision(const xAOD::TrackParticle& tp,const xAOD::Vertex* vertex) const + { + + const Trk::Perigee& perigee=tp.perigeeParameters(); + if (m_usePreselectionCuts && !preselectionBeforeExtrapolation(perigee)) { + ATH_MSG_DEBUG("Track rejected because of preselection decision!"); + return false; + } + + if (m_useTrackQualityInfo && !decision(tp.chiSquared(),tp.numberDoF())) { + ATH_MSG_DEBUG("Track rejected because of bad fit quality!"); + return false; + } + + if (m_useTrackSummaryInfo) { + //number of hits, silicon hits, b-layer + + if(m_useEtaDepententMinHitTrt) { + m_nHitTrt = m_trtDCTool->minNumberDCs( &perigee ); + if(m_addToMinHitTrt!=0) + m_nHitTrt += m_addToMinHitTrt; + else + m_nHitTrt = (int)((double)m_nHitTrt*m_scaleMinHitTrt); + } + + if(m_useEtaDepententMinHitTrtWithOutliers) { + m_nHitTrtPlusOutliers = m_trtDCTool->minNumberDCs( &perigee ); + if(m_addToMinHitTrtWithOutliers!=0) + m_nHitTrtPlusOutliers += m_addToMinHitTrtWithOutliers; + else + m_nHitTrtPlusOutliers = (int)((double)m_nHitTrtPlusOutliers*m_scaleMinHitTrtWithOutliers); + } + + + int nb = getCount(tp,xAOD::numberOfBLayerHits ); + int np = getCount(tp,xAOD::numberOfPixelHits ); + int npd = getCount(tp,xAOD::numberOfPixelDeadSensors ); + int ns = getCount(tp,xAOD::numberOfSCTHits ); + int nhp = getCount(tp,xAOD::numberOfPixelHoles ); + int nhs = getCount(tp,xAOD::numberOfSCTHoles ); + int ndhs = getCount(tp,xAOD::numberOfSCTDoubleHoles); + + //**----------------------------------------------------------------------- + if(m_usePtDependentCuts) { + + double pt = tp.pt(); + + unsigned int it = 0; + for(; it< m_ptBenchmarks.size()-1; ++it ) { + if(pt>m_ptBenchmarks[it] && pt <=m_ptBenchmarks[it+1] && ns < m_nSCTValues[it]) { + ATH_MSG_DEBUG("Track rejected because of Pt-Dependent SCT Hit cut (CAREFUL! Excludes dead modules)") ; + return false; + } + }//end of pt intervals loop + + //now cutting all the rest by the last value in the vector + if(pt>m_ptBenchmarks[it+1] && ns < m_nSCTValues[it+1]) { + ATH_MSG_DEBUG("Track rejected because of Pt-Dependent SCT Hit cut (CAREFUL! Excludes dead modules)") ; + return false; + } + } + + //*-------------------------------------------------------------------------------- + + //normal cuts in all their variety + + if(nb == 0 && nb < m_nHitBLayer) { + ATH_MSG_DEBUG("Track rejected because of nHitBLayer "<<nb<<" < "<<m_nHitBLayer); + if(m_inDetTestBLayerTool.empty()) { + ATH_MSG_DEBUG("and no blayer tool configured, so will not try to recover track"); + return false; + } else if (m_inDetTestBLayerTool->expectHitInBLayer(&perigee)) { + ATH_MSG_DEBUG("and track rejected because of Number of b-layer hits ACCOUNTING for those expected") ; + return false; + }else ATH_MSG_DEBUG("recovered track as no b-layer expected") ; + }//end of checking the b-layer + + if(np+npd < m_nHitPix) { + ATH_MSG_DEBUG("Track rejected because of nHitPix "<<np+npd<<" < "<<m_nHitPix); + return false; + } + + if(np < m_nHitPixPhysical) { + ATH_MSG_DEBUG("Track rejected because of nHitPixPhysical "<<np<<" < "<<m_nHitPixPhysical); + return false; + } + + int nsd = getCount(tp,xAOD::numberOfSCTDeadSensors); + if(ns+nsd < m_nHitSct) { + ATH_MSG_DEBUG("Track rejected because of nHitSct "<<ns+nsd<<" < "<<m_nHitSct); + return false; + } + + if(np+ns+npd+nsd < m_nHitSi) { + ATH_MSG_DEBUG("Track rejected because of nHitSi "<<np+npd+ns+nsd<<" < "<<m_nHitSi); + return false; + } + + if(np+ns < m_nHitSiPhysical) { + ATH_MSG_DEBUG("Track rejected because of nHitSiPhysical "<<np+ns<<" < "<<m_nHitSiPhysical); + return false; + } + + if (nb+np+npd< m_nHitBLayerPlusPix){ + ATH_MSG_DEBUG("Track rejected because of nHitBLayerPlusPix "<<nb+np+npd<<" < "<<m_nHitBLayerPlusPix); + return false; + } + + // Cuts on number of Holes + if (nhp+nhs > m_nHoles){ + ATH_MSG_DEBUG("Track rejected because of nHolesPixPlusSCT "<<nhp+nhs<<" > "<<m_nHoles); + return false; + } + + if(ndhs > m_nDoubleHoles){ + ATH_MSG_DEBUG("Track rejected because of nDoubleHolesSCT "<<ndhs<<" > "<<m_nDoubleHoles); + return false; + } + + if(nhp > m_nHolesPix){ + ATH_MSG_DEBUG("Track rejected because of nHolesPix "<<nhp<<" > "<<m_nHolesPix); + return false; + } + + if (nhs > m_nHolesSct){ + ATH_MSG_DEBUG("Track rejected because of nHolesSct "<<nhs<<" > "<<m_nHolesSct); + return false; + } + + if (fabs(tp.eta())>m_TrtMaxEtaAcceptance) { + int nh = getCount(tp,xAOD::numberOfTRTHits); + if(nh < m_nHitTrt) { + ATH_MSG_DEBUG("Track rejected because of nHitTrt "<<nh<<" < "<<m_nHitTrt); + return false; + } + + int nhh = getCount(tp, xAOD::numberOfTRTHits ) + getCount(tp, xAOD::numberOfTRTOutliers ); + if (nhh<m_nHitTrtPlusOutliers) { + ATH_MSG_DEBUG("Track rejected because of nHitTrtPlusOutliers "<<nhh<<" < "<<m_nHitTrtPlusOutliers); + return false; + } + + int nhthits= getCount(tp,xAOD::numberOfTRTHighThresholdHits); + if (nhthits<m_nHitTrtHighE) { + ATH_MSG_DEBUG("Track rejected because of nHitTrtHighE "<<nhthits<<" < "<<m_nHitTrtHighE); + return false; + } + + int nhthitsWithOutliers= getCount(tp,xAOD::numberOfTRTHighThresholdHits) + getCount(tp,xAOD::numberOfTRTHighThresholdOutliers); + if (nhthitsWithOutliers<m_nHitTrtPlusOutliersHighE) { + ATH_MSG_DEBUG("Track rejected because of nHitTrtPlusOutliersHighE "<<nhthitsWithOutliers<<" < "<<m_nHitTrtPlusOutliersHighE); + return false; + } + + if ( getCount(tp, xAOD::numberOfTRTHits )>0) { + double nhe = getCount(tp,xAOD::numberOfTRTHighThresholdHits); + nhe /= getCount(tp, xAOD::numberOfTRTHits); + if(nhe > m_nHitTrtHighEFraction ) { + ATH_MSG_DEBUG("Track rejected because of nHitTrtHighEFraction "<<nhe<<" < "<<m_nHitTrtHighEFraction); + return false; + } + } + + if ( getCount(tp, xAOD::numberOfTRTHits ) + getCount(tp, xAOD::numberOfTRTOutliers ) > 0 ) { + double nheh = (double)(getCount(tp,xAOD::numberOfTRTHighThresholdHits) + getCount(tp,xAOD::numberOfTRTHighThresholdOutliers))/ + (double)(getCount(tp, xAOD::numberOfTRTHits) + getCount(tp, xAOD::numberOfTRTOutliers ) ); + if(nheh<0.) nheh=0.; + if (nheh>1.) nheh=1.; + if(nheh > m_nHitTrtHighEFractionWithOutliers ) { + ATH_MSG_DEBUG("Track rejected because of nHitTrtHighEFractionWithOutliers "<<nheh<<" < "<<m_nHitTrtHighEFractionWithOutliers); + return false; + } + } + } + + if (m_useSharedHitInfo) { + + int nbs = getCount(tp,xAOD::numberOfBLayerSharedHits); + if (nbs>1) nbs=1; + if(nbs>m_nSharedBLayer) { + ATH_MSG_DEBUG("Track rejected because of nSharedBLayer "<<nbs<<" < "<<m_nSharedBLayer); + return false; + } + + int nps = getCount(tp,xAOD::numberOfPixelSharedHits); + if(nps>m_nSharedPix) { + ATH_MSG_DEBUG("Track rejected because of nSharedPix "<<nps<<" < "<<m_nSharedPix); + return false; + } + + int nss = getCount(tp,xAOD::numberOfSCTSharedHits); + if(nss > m_nSharedSct) { + ATH_MSG_DEBUG("Track rejected because of nSharedSct "<<nss<<" < "<<m_nSharedSct); + return false; + } + + int nst = nps + nss; + if(nst>m_nSharedSi) { + ATH_MSG_DEBUG("Track rejected because of nSharedSi "<<nst<<" < "<<m_nSharedSi); + return false; + } + } + } + Trk::PerigeeSurface perigeeSurface( vertex ? vertex->position() : (!m_iBeamCondSvc.empty() ? m_iBeamCondSvc->beamVtx().position() : Amg::Vector3D(0,0,0) ) ); + + const Trk::TrackParameters* extrapolatedParameters= m_extrapolator->extrapolate(perigee,perigeeSurface,Trk::anyDirection,true,Trk::pion ); + const Trk::Perigee* extrapolatedPerigee = extrapolatedParameters ? dynamic_cast<const Trk::Perigee*>(extrapolatedParameters) : 0; + if (extrapolatedPerigee==0) { + ATH_MSG_WARNING( "Extrapolation to the vertex failed: " << perigeeSurface << std::endl << perigee ); + if (extrapolatedParameters!=0) { + ATH_MSG_WARNING( "The return object of the extrapolator was not a perigee even if a perigeeSurface was used!" ); + delete extrapolatedParameters; + } + return false; + } + bool dec = false; + if( vertex ){ + // for now copy the position error + AmgSymMatrix(3) vertexError = vertex->covariancePosition(); + dec = decision(extrapolatedPerigee,&vertexError); + }else{ + dec = decision(extrapolatedPerigee,0); + } + + delete extrapolatedPerigee; + + if(!dec) { + ATH_MSG_DEBUG("Track rejected because of perigee parameters!"); + return false; + } + + return true; + } + + + // --------------------------------------------------------------------- + bool InDetDetailedTrackSelectorTool::decision(const Trk::Perigee* track,const AmgSymMatrix(3)* covariancePosition) const { + + // checking pointer first + if(0==track || !track->covariance()) { + ATH_MSG_WARNING( "Decision on measured perigee: Zero pointer to measured perigee passed. Selection failed." ); + return false; + } + + const AmgVector(5)& perigeeParms = track->parameters(); + + if (m_magFieldSvc->solenoidOn()) { + if (perigeeParms[Trk::qOverP] == 0.) { + ATH_MSG_DEBUG("Track rejected because of qOverP == 0."); + return false; + } + double p = fabs(1./perigeeParms[Trk::qOverP]); + if (p<m_pMin) { + ATH_MSG_DEBUG("Track rejected because of p " << p << " < " << m_pMin); + return false; + } + double pt = p*sin(perigeeParms[Trk::theta]); + if (pt<m_pTMin) { + ATH_MSG_DEBUG("Track rejected because of pt " << pt << " < " << m_pTMin); + return false; + } + } + + if (fabs(perigeeParms[Trk::d0]) > m_IPd0Max) { + ATH_MSG_DEBUG("Track rejected because of fabs(d0) " << fabs(perigeeParms[Trk::d0]) << " > " << m_IPd0Max); + return false; + } + + if (fabs(perigeeParms[Trk::z0]*sin(perigeeParms[Trk::theta])) > m_IPz0Max) { + ATH_MSG_DEBUG("Track rejected because of fabs(z0*sin(theta)) " << fabs(perigeeParms[Trk::z0]*sin(perigeeParms[Trk::theta])) << " > " << m_IPz0Max); + return false; + } + + if (fabs(perigeeParms[Trk::z0]) > m_z0Max) { + ATH_MSG_DEBUG("Track rejected because of fabs(z0) " << fabs(perigeeParms[Trk::z0]) << " > " << m_z0Max); + return false; + } + + if (sqrt( (*track->covariance())(Trk::z0,Trk::z0) )*sin(perigeeParms[Trk::theta])>m_sigIPz0Max) { + ATH_MSG_DEBUG("Track rejected because of err(z0)*sin(theta) " << sqrt( (*track->covariance())(Trk::z0,Trk::z0) )*sin(perigeeParms[Trk::theta]) << " > " << m_sigIPz0Max); + return false; + } + + if (sqrt( (*track->covariance())(Trk::d0,Trk::d0) )>m_sigIPd0Max) { + ATH_MSG_DEBUG("Track rejected because of err(d0) " << sqrt( (*track->covariance())(Trk::d0,Trk::d0) ) << " > " << m_sigIPd0Max); + return false; + } + + if (m_d0significanceMax>0 || m_z0significanceMax>0) { + + double sinTheta = sin(perigeeParms[Trk::theta]); + double cosTheta = cos(perigeeParms[Trk::theta]); + double d0wrtPriVtx = perigeeParms[Trk::d0]; + double deltaZ = perigeeParms[Trk::z0]; + double z0wrtPriVtx = deltaZ*sinTheta; + double testtrackSigD0 = sqrt( (*track->covariance())(Trk::d0,Trk::d0) ); + double testtrackSigZ0 = sqrt( (*track->covariance())(Trk::z0,Trk::z0) ); + double testtrackSigTh = sqrt( (*track->covariance())(Trk::theta,Trk::theta) ); + // error on IP: + double trackPhi = perigeeParms[Trk::phi]; + double dIPdx = sin(trackPhi); + double dIPdy = -cos(trackPhi); + double DD0 = testtrackSigD0*testtrackSigD0; + double newD0Err=0; + if (covariancePosition) { + double DXX = dIPdx*dIPdx* (*covariancePosition)(0,0); + double DYY = dIPdy*dIPdy* (*covariancePosition)(1,1); + double DXY = 2.*dIPdx*dIPdy* (*covariancePosition)(0,1); + newD0Err = DD0 + DXX + DYY + DXY; + } else { + newD0Err = DD0; + } + + double d0ErrwrtPriVtx = (newD0Err>0 ? sqrt(newD0Err) : -10e-9); + + if (d0ErrwrtPriVtx<0) { + ATH_MSG_WARNING( " error on d0 is negative: numeric error... (not expected. please report!)" ); + } + + if (m_d0significanceMax>0) { + if (fabs(d0wrtPriVtx/d0ErrwrtPriVtx)>m_d0significanceMax) { + ATH_MSG_DEBUG("Track rejected because of fabs(d0wrtPriVtx/d0ErrwrtPriVtx) " << fabs(d0wrtPriVtx/d0ErrwrtPriVtx) << " > " << m_d0significanceMax); + return false; + } + } + + if (m_z0significanceMax>0) { + + // error on zIP: + double dZIPdTheta = deltaZ*cosTheta; + double dZIPdz0 = sinTheta; + double dZIPdzV = -sinTheta; + double DTheta2 = dZIPdTheta*dZIPdTheta*testtrackSigTh*testtrackSigTh; + double DZ02 = dZIPdz0*dZIPdz0*testtrackSigZ0*testtrackSigZ0; + double DThetaZ0 = 2.*dZIPdTheta*dZIPdz0*(*track->covariance())(Trk::theta,Trk::z0); + double newZ0Err(0); + if (covariancePosition) { + double DZV2 = dZIPdzV*dZIPdzV* (*covariancePosition)(2,2); + newZ0Err = DTheta2 + DZ02 + DZV2 + DThetaZ0; + } else { + newZ0Err = DTheta2 + DZ02 + DThetaZ0; + } + + double z0ErrwrtPriVtx = (newZ0Err>0 ? sqrt(newZ0Err) : -10e-9); + + if (z0ErrwrtPriVtx<0) { + ATH_MSG_WARNING( " error on z0 is negative: numeric error... (not expected. please report!)" ); + } + + if (fabs(z0wrtPriVtx/z0ErrwrtPriVtx)>m_z0significanceMax) { + ATH_MSG_DEBUG("Track rejected because of fabs(z0wrtPriVtx/z0ErrwrtPriVtx) " << fabs(z0wrtPriVtx/z0ErrwrtPriVtx) << " > " << m_z0significanceMax); + return false; + } + } + + } + + if (fabs(track->momentum().eta())>m_etaMax) { + ATH_MSG_DEBUG("Track rejected because of fabs(eta) " << fabs(track->momentum().eta()) << " > " << m_etaMax); + return false; + } + + return true; + } + + // --------------------------------------------------------------------- + bool InDetDetailedTrackSelectorTool::decision(const Trk::FitQuality* trkQuality) const + { + if(0 == trkQuality) { + ATH_MSG_WARNING( "Null FitQuality pointer passed. No track Quality cut possible. Selection failed." ); + return false; + } + return decision(trkQuality->chiSquared(),trkQuality->numberDoF()); + } + + bool InDetDetailedTrackSelectorTool::decision(double chi2, int ndf ) const{ + + double proba = 1.; + + if(ndf>0 && chi2>=0.) { + Genfun::CumulativeChiSquare myCumulativeChiSquare(ndf); + proba = 1.-myCumulativeChiSquare(chi2); + } + + if(chi2>m_fitChi2) { + ATH_MSG_DEBUG("Track rejected because of chi2 "<<chi2<<" > "<<m_fitChi2); + return false; + } + + if(proba<m_fitProb) { + ATH_MSG_DEBUG("Track rejected because of fit probability "<<proba<<" > "<<m_fitProb); + return false; + } + if(ndf>0 && chi2/double(ndf)>m_fitChi2OnNdfMax) { + ATH_MSG_DEBUG("Track rejected because of chi2/ndof "<<chi2/double(ndf)<<" > "<<m_fitChi2OnNdfMax); + return false; + } + + return true; + } + + + // --------------------------------------------------------------------- + bool InDetDetailedTrackSelectorTool::decision(const Trk::TrackSummary* summary,bool useSharedHitInfo,bool useTrtHitInfo, + const Trk::Perigee * track) const + { + if (summary==0) { + ATH_MSG_WARNING( "Null TrackSummary pointer passed. Selection failed." ); + return false; + } + + int nb = summary->get(Trk::numberOfBLayerHits); + + if(nb<0) nb=0; + + int np = summary->get(Trk::numberOfPixelHits); + if(np<0) np=0; + + int npd = summary->get(Trk::numberOfPixelDeadSensors); + if(npd<0) npd=0; + + int ns = summary->get(Trk::numberOfSCTHits); + if(ns<0) ns=0; + + int nhp = summary->get(Trk::numberOfPixelHoles); + if (nhp < 0) nhp = 0; + + int nhs = summary->get(Trk::numberOfSCTHoles); + if (nhs < 0) nhs = 0; + + int ndhs = summary->get(Trk::numberOfSCTDoubleHoles); + if (ndhs < 0) ndhs = 0; + + //**----------------------------------------------------------------------- + + if(m_usePtDependentCuts) { + + const AmgVector(5)& perigeeParms = track->parameters(); + double p = fabs(1./perigeeParms[Trk::qOverP]); + double pt = p*sin(perigeeParms[Trk::theta]); + + unsigned int it = 0; + for(; it< m_ptBenchmarks.size()-1; ++it ) { + if(pt>m_ptBenchmarks[it] && pt <=m_ptBenchmarks[it+1] && ns < m_nSCTValues[it]) { + ATH_MSG_DEBUG("Track rejected because of Pt-Dependent SCT Hit cut (CAREFUL! Excludes dead modules)") ; + return false; + } + }//end of pt intervals loop + + //now cutting all the rest by the last value in the vector + if(pt>m_ptBenchmarks[it+1] && ns < m_nSCTValues[it+1]) { + ATH_MSG_DEBUG("Track rejected because of Pt-Dependent SCT Hit cut (CAREFUL! Excludes dead modules)") ; + return false; + } + + } + + //*-------------------------------------------------------------------------------- + + //normal cuts in all their variety + + if(nb == 0 && nb < m_nHitBLayer) { + ATH_MSG_DEBUG("Track rejected because of nHitBLayer "<<nb<<" < "<<m_nHitBLayer); + if(m_inDetTestBLayerTool.empty()) { + ATH_MSG_DEBUG("and no blayer tool configured, so will not try to recover track"); + return false; + } else if (m_inDetTestBLayerTool->expectHitInBLayer(track)) { + ATH_MSG_DEBUG("and track rejected because of Number of b-layer hits ACCOUNTING for those expected") ; + return false; + }else ATH_MSG_DEBUG("recovered track as no b-layer expected") ; + }//end of checking the b-layer + + if(np+npd < m_nHitPix) { + ATH_MSG_DEBUG("Track rejected because of nHitPix "<<np+npd<<" < "<<m_nHitPix); + return false; + } + + if(np < m_nHitPixPhysical) { + ATH_MSG_DEBUG("Track rejected because of nHitPixPhysical "<<np<<" < "<<m_nHitPixPhysical); + return false; + } + + int nsd = summary->get(Trk::numberOfSCTDeadSensors); + if(nsd<0) + nsd=0; + + if(ns+nsd < m_nHitSct) + { + ATH_MSG_DEBUG("Track rejected because of nHitSct "<<ns+nsd<<" < "<<m_nHitSct); + return false; + } + + if((np+ns+npd+nsd) < m_nHitSi) + { + ATH_MSG_DEBUG("Track rejected because of nHitSi "<<np+npd+ns+nsd<<" < "<<m_nHitSi); + return false; + } + + if((np+ns) < m_nHitSiPhysical) + { + ATH_MSG_DEBUG("Track rejected because of nHitSiPhysical "<<np+ns<<" < "<<m_nHitSiPhysical); + return false; + } + + if ((nb+np+npd)< m_nHitBLayerPlusPix) + { + ATH_MSG_DEBUG("Track rejected because of nHitBLayerPlusPix "<<nb+np+npd<<" < "<<m_nHitBLayerPlusPix); + return false; + } + + // Cuts on number of Holes + + if ((nhp+nhs) > m_nHoles) + { + ATH_MSG_DEBUG("Track rejected because of nHolesPixPlusSCT "<<nhp+nhs<<" > "<<m_nHoles); + return false; + } + + if (ndhs > m_nDoubleHoles) + { + ATH_MSG_DEBUG("Track rejected because of nDoubleHolesSCT "<<ndhs<<" > "<<m_nDoubleHoles); + return false; + } + + if (nhp > m_nHolesPix) + { + ATH_MSG_DEBUG("Track rejected because of nHolesPix "<<nhp<<" > "<<m_nHolesPix); + return false; + } + + if (nhs > m_nHolesSct) + { + ATH_MSG_DEBUG("Track rejected because of nHolesSct "<<nhs<<" > "<<m_nHolesSct); + return false; + } + + if (useTrtHitInfo) { + + int nh = summary->get(Trk::numberOfTRTHits); + if(nh<0) nh=0; + if(nh < m_nHitTrt) { + ATH_MSG_DEBUG("Track rejected because of nHitTrt "<<nh<<" < "<<m_nHitTrt); + return false; + } + + int nhh = summary->get( Trk::numberOfTRTHits ) + summary->get( Trk::numberOfTRTOutliers ); + if (nhh<0) nhh=0; + if (nhh<m_nHitTrtPlusOutliers) { + ATH_MSG_DEBUG("Track rejected because of nHitTrtPlusOutliers "<<nhh<<" < "<<m_nHitTrtPlusOutliers); + return false; + } + + int nhthits=summary->get(Trk::numberOfTRTHighThresholdHits); + if (nhthits<0) nhthits=0; + if (nhthits<m_nHitTrtHighE) { + ATH_MSG_DEBUG("Track rejected because of nHitTrtHighE "<<nhthits<<" < "<<m_nHitTrtHighE); + return false; + } + + int nhthitsWithOutliers=summary->get(Trk::numberOfTRTHighThresholdHits) + summary->get(Trk::numberOfTRTHighThresholdOutliers); + if (nhthitsWithOutliers<0) nhthitsWithOutliers=0; + if (nhthitsWithOutliers<m_nHitTrtPlusOutliersHighE) { + ATH_MSG_DEBUG("Track rejected because of nHitTrtPlusOutliersHighE "<<nhthitsWithOutliers<<" < "<<m_nHitTrtPlusOutliersHighE); + return false; + } + + if (summary->get( Trk :: numberOfTRTHits )>0) { + double nhe = (double)summary->get(Trk::numberOfTRTHighThresholdHits) / (double)summary->get( Trk::numberOfTRTHits ); + if(nhe<0.) nhe=0.; + if(nhe > m_nHitTrtHighEFraction ) { + ATH_MSG_DEBUG("Track rejected because of nHitTrtHighEFraction "<<nhe<<" < "<<m_nHitTrtHighEFraction); + return false; + } + } + + if ( summary->get( Trk :: numberOfTRTHits ) + summary->get( Trk :: numberOfTRTOutliers ) > 0 ) { + double nheh = (double)(summary->get(Trk::numberOfTRTHighThresholdHits) + summary->get(Trk::numberOfTRTHighThresholdOutliers))/ + (double)(summary->get( Trk::numberOfTRTHits) + summary->get( Trk :: numberOfTRTOutliers ) ); + if(nheh<0.) nheh=0.; + if (nheh>1.) nheh=1.; + if(nheh > m_nHitTrtHighEFractionWithOutliers ) { + ATH_MSG_DEBUG("Track rejected because of nHitTrtHighEFractionWithOutliers "<<nheh<<" < "<<m_nHitTrtHighEFractionWithOutliers); + return false; + } + } + } + + if (useSharedHitInfo) { + + int nbs = summary->get(Trk::numberOfBLayerSharedHits); + if(nbs < 0) nbs = 0; + if (nbs>1) nbs=1; + if(nbs>m_nSharedBLayer) { + ATH_MSG_DEBUG("Track rejected because of nSharedBLayer "<<nbs<<" < "<<m_nSharedBLayer); + return false; + } + + int nps = summary->get(Trk::numberOfPixelSharedHits); + if(nps < 0) nps = 0; + if(nps>m_nSharedPix) { + ATH_MSG_DEBUG("Track rejected because of nSharedPix "<<nps<<" < "<<m_nSharedPix); + return false; + } + + int nss = summary->get(Trk::numberOfSCTSharedHits); + if(nss < 0) nss = 0; + if(nss > m_nSharedSct) { + ATH_MSG_DEBUG("Track rejected because of nSharedSct "<<nss<<" < "<<m_nSharedSct); + return false; + } + + int nst = nps + nss; + if(nst>m_nSharedSi) { + ATH_MSG_DEBUG("Track rejected because of nSharedSi "<<nst<<" < "<<m_nSharedSi); + return false; + } + } + + return true; + + } + + // --------------------------------------------------------------------- + bool InDetDetailedTrackSelectorTool::preselectionBeforeExtrapolation(const Trk::Perigee & myPerigee) const + { + const AmgVector(5)& perigeeParms = myPerigee.parameters(); + + if (m_magFieldSvc->solenoidOn()) { + if (perigeeParms[Trk::qOverP] == 0.) { + ATH_MSG_DEBUG("Track rejected because of perigee qOverP == 0."); + return false; + } + double p = fabs(1./perigeeParms[Trk::qOverP]); + if (p<m_pMin) { + ATH_MSG_DEBUG("Track rejected because of p " << p << " < " << m_pMin); + return false; + } + double pt = p*sin(perigeeParms[Trk::theta]); + if (pt<m_pTMin) { + ATH_MSG_DEBUG("Track rejected because of pt " << pt << " < " << m_pTMin); + return false; + } + } + + if (fabs(perigeeParms[Trk::d0]) > m_d0MaxPreselection) { + ATH_MSG_DEBUG("Track rejected because of fabs(d0) "<<fabs(perigeeParms[Trk::d0])<<" < "<<m_d0MaxPreselection); + return false; + } + + return true; + } + +} //end of namespace definitions diff --git a/InnerDetector/InDetRecTools/InDetTrackSelectorTool/src/InDetIsoTrackSelectorTool.cxx b/InnerDetector/InDetRecTools/InDetTrackSelectorTool/src/InDetIsoTrackSelectorTool.cxx new file mode 100644 index 00000000000..006dbe6a78d --- /dev/null +++ b/InnerDetector/InDetRecTools/InDetTrackSelectorTool/src/InDetIsoTrackSelectorTool.cxx @@ -0,0 +1,183 @@ +/* + Copyright (C) 2002-2017 CERN for the benefit of the ATLAS collaboration +*/ + +#include "InDetTrackSelectorTool/InDetIsoTrackSelectorTool.h" +#include "TrkToolInterfaces/ITrackSelectorTool.h" +// forward declares +#include "TrkExInterfaces/IExtrapolator.h" +#include "TrkTrack/Track.h" +#include "TrkParticleBase/TrackParticleBase.h" +#include "TrkSurfaces/StraightLineSurface.h" + +using CLHEP::mm; + +//_______________________________________________________________________________ +InDet::InDetIsoTrackSelectorTool::InDetIsoTrackSelectorTool(const std::string & t, const std::string & n, const IInterface * p) + : AthAlgTool(t,n,p), + m_robustCuts(true), + m_applySinThetaCorrection(true), + m_d0max(1.5*mm), + m_z0stMax(1.5*mm), + m_d0Significance(3), + m_z0Significance(3), + m_extrapolator("Trk::Extrapolator/InDetExtrapolator"), + m_trackSelector("") +{ + declareInterface<Trk::IIsoTrackSelectorTool>(this); + // properties via python binding + declareProperty("RobustCuts", m_robustCuts); + declareProperty("SinThetaCorrection", m_applySinThetaCorrection); + declareProperty("maxD0", m_d0max); + declareProperty("maxZ0", m_z0stMax); + declareProperty("maxD0overSigmaD0", m_d0Significance); + declareProperty("maxZ0overSigmaZ0", m_z0Significance); + // tools + declareProperty("Extrapolator", m_extrapolator); + declareProperty("TrackSelector", m_trackSelector); +} + +//_______________________________________________________________________________ +InDet::InDetIsoTrackSelectorTool::~InDetIsoTrackSelectorTool() +{} + +//_______________________________________________________________________________ +StatusCode InDet::InDetIsoTrackSelectorTool::initialize() +{ + + // get the extrapolator + if ( m_extrapolator.retrieve().isFailure() ){ + ATH_MSG_ERROR("Could not retrieve Extrapolator '" << m_extrapolator << "' (essential). Abort."); + return StatusCode::FAILURE; + } else + ATH_MSG_DEBUG("Successfully retrieved " << m_extrapolator); + + // get the track selector if needed + if ( !m_trackSelector.empty() && m_trackSelector.retrieve().isFailure() ){ + ATH_MSG_ERROR("Could not retrieve TrackSelector '" << m_trackSelector <<"' although configured. Abort."); + return StatusCode::FAILURE; + } + // done + return StatusCode::SUCCESS; +} + +//_______________________________________________________________________________ +StatusCode InDet::InDetIsoTrackSelectorTool::finalize() +{ + ATH_MSG_INFO("Finalize successful"); + return StatusCode::SUCCESS; +} + +//_______________________________________________________________________________ +bool InDet::InDetIsoTrackSelectorTool::decision(const Trk::AtaStraightLine& atl, const Trk::Track& track) const +{ + const Trk::Perigee* tPerigee = track.perigeeParameters(); + if (!tPerigee){ + ATH_MSG_DEBUG("No perigee on track, discard this one."); + return false; + } + // call the workhorse interface + bool passed = decision(atl,*tPerigee); + // only check if needed + passed = (!passed || m_trackSelector.empty()) ? passed : ( passed && m_trackSelector->decision(track) ); + // return what you have + ATH_MSG_VERBOSE("Track " << ( passed ? "passed" : "did not pass") << " isolation track selector."); + return passed; +} + + +//_______________________________________________________________________________ +bool InDet::InDetIsoTrackSelectorTool::decision(const Trk::AtaStraightLine& atl, const Trk::TrackParticleBase& trackParticle) const +{ + + // get the paramters base + const Trk::TrackParameters* definintParameters = &(trackParticle.definingParameters()); + const Trk::TrackParameters* trackParameters= + dynamic_cast<const Trk::Perigee*>(definintParameters); + if (!trackParameters){ + ATH_MSG_DEBUG("No parameters to start from on track, discard this one."); + return false; + } + // call the workhorse interface + bool passed = decision(atl,*trackParameters); + // only check if needed + passed = (!passed || m_trackSelector.empty()) ? passed : ( passed && m_trackSelector->decision(trackParticle) ); + // return what you have + ATH_MSG_VERBOSE("TrackParticle " << ( passed ? "passed" : "did not pass") << " isolation track selector."); + return passed; +} + +//_______________________________________________________________________________ +bool InDet::InDetIsoTrackSelectorTool::decision(const Trk::AtaStraightLine& atl, const Trk::TrackParameters& trackPars) const +{ + // get the surface + bool passed = false; + const Trk::StraightLineSurface& alSurface = atl.associatedSurface(); + // no surface: bail out + // get the track to the BeamLine Parameters ( given by AtaStrainghtLine) + const Trk::TrackParameters* trackAtBL = m_extrapolator->extrapolate(trackPars, + alSurface, + Trk::anyDirection, + false); + // no parameterisation : bail out + if (!trackAtBL) return false; + // d0,z0 wrt BL for reference and track + double d0track_wrtBL = trackAtBL->parameters()[Trk::d0]; + double sinTheta = m_applySinThetaCorrection ? 1. : sin(trackAtBL->parameters()[Trk::theta]); + double z0track_wrtBL = trackAtBL->parameters()[Trk::z0]*sinTheta; + double sinThetaRef = m_applySinThetaCorrection ? 1. : sin(atl.parameters()[Trk::theta]); + double z0ref_wrtBL = atl.parameters()[Trk::z0] * sinThetaRef; + if (m_robustCuts){ + // check d0 cut with respect to BL + passed = (d0track_wrtBL*d0track_wrtBL < m_d0max*m_d0max); + ATH_MSG_VERBOSE("TrackParameters " << ( passed ? "passed" : "did not pass" ) << " d0 cut wrt BL : " + << d0track_wrtBL << " (cut is : | " << m_d0max << " | )."); + // check z0 cut with respect to reference + passed = ( (z0track_wrtBL-z0ref_wrtBL)*(z0track_wrtBL-z0ref_wrtBL) < m_z0stMax*m_z0stMax ); + ATH_MSG_VERBOSE("TrackParameters " << ( passed ? "passed" : "did not pass" ) << " z0 " << ( m_applySinThetaCorrection ? "*sin(theta)" : "") + << " cut wrt reference :" + << (z0track_wrtBL-z0ref_wrtBL) << " (cut is : | " << m_z0stMax << " | )."); + } else { + // cast to measured parameters + if (!trackAtBL->covariance()){ + ATH_MSG_VERBOSE("Can not apply signficance cut on Parameters w/o Error. Ignore Track."); + return false; + } + // get the error on the track + double covTrackD0 = (*trackAtBL->covariance())(Trk::d0,Trk::d0); + double covTrackZ0 = (*trackAtBL->covariance())(Trk::z0,Trk::z0); + // check d0 signficiance cut with respect to BL + passed = (d0track_wrtBL*d0track_wrtBL)/(covTrackD0) < m_d0Significance*m_d0Significance; + ATH_MSG_VERBOSE("TrackParameters " << ( passed ? "passed" : "did not pass" ) << " d0 signficance cut wrt BL : " + << (d0track_wrtBL*d0track_wrtBL)/(covTrackD0) << " (cut is : | " << m_d0Significance << " | )."); + double deltaZ = z0ref_wrtBL - z0track_wrtBL; + if (m_applySinThetaCorrection){ + double covTrackTheta = (*trackAtBL->covariance())(Trk::theta,Trk::theta); + double covTrackZ0Theta = (*trackAtBL->covariance())(Trk::z0,Trk::theta); + // check z0 signficance cut with respect to reference -- apply theta projection into longitudinal track frame + double cosTheta = cos(trackAtBL->parameters()[Trk::theta]); + // derivatives + apply jacobian transormation + double dZIPdTheta = deltaZ*cosTheta; + double dZIPdz0 = sinTheta; + double DTheta2 = dZIPdTheta*dZIPdTheta*covTrackTheta; + double DZ02 = dZIPdz0*dZIPdz0*covTrackZ0; + double DThetaZ0 = 2.*dZIPdTheta*dZIPdz0*covTrackZ0Theta; + // check for it + double newZ0Err = DTheta2 + DZ02 + DThetaZ0; + passed = (deltaZ*deltaZ)/(newZ0Err) < m_z0Significance*m_z0Significance; + ATH_MSG_VERBOSE("TrackParameters " << ( passed ? "passed" : "did not pass" ) << " z0*sin(theta) signficance cut wrt BL : " + << (deltaZ*deltaZ)/(newZ0Err) << " (cut is : | " << m_z0Significance << " | )."); + + } else { + // check z0 signficiance cut with respect to BL + passed = (deltaZ*deltaZ)/(covTrackZ0) < m_z0Significance*m_z0Significance; + ATH_MSG_VERBOSE("TrackParameters " << ( passed ? "passed" : "did not pass" ) << " z0 signficance cut wrt BL : " + << (deltaZ*deltaZ)/(covTrackZ0) << " (cut is : | " << m_z0Significance << " | )."); + + } + } + // memory cleanup + delete trackAtBL; + return passed; +} + diff --git a/InnerDetector/InDetRecTools/InDetTrackSelectorTool/src/InDetTrackSelectorTool.cxx b/InnerDetector/InDetRecTools/InDetTrackSelectorTool/src/InDetTrackSelectorTool.cxx new file mode 100644 index 00000000000..e4811046328 --- /dev/null +++ b/InnerDetector/InDetRecTools/InDetTrackSelectorTool/src/InDetTrackSelectorTool.cxx @@ -0,0 +1,195 @@ +/* + Copyright (C) 2002-2017 CERN for the benefit of the ATLAS collaboration +*/ + +#include "InDetTrackSelectorTool/InDetTrackSelectorTool.h" +// forward declares +#include "TrkToolInterfaces/ITrackSummaryTool.h" +#include "TrkExInterfaces/IExtrapolator.h" +#include "VxVertex/Vertex.h" +#include "TrkParticleBase/TrackParticleBase.h" +#include "TrkTrack/Track.h" +// normal includes +#include "TrkTrackSummary/TrackSummary.h" +#include "CLHEP/Matrix/Vector.h" + +using CLHEP::mm; + +namespace InDet +{ + +//_______________________________________________________________________________ +InDetTrackSelectorTool::InDetTrackSelectorTool(const std::string & t, const std::string & n, const IInterface * p) + : AthAlgTool(t,n,p) + , m_minPt(500.) + , m_IPz0Max(10.*mm) + , m_maxZ0(99999.) + , m_maxD0(2.*mm) + , m_maxD0overSigmaD0(3.) + , m_numberOfPixelHits(2) + , m_numberOfBLayerHits(1) + , m_extrapolator("Trk::Extrapolator") +{ + declareInterface<ITrackSelectorTool>(this); + declareProperty("minPt", m_minPt); + declareProperty("IPz0Max", m_IPz0Max); // cut on |z|*sin(theta) + declareProperty("maxZ0", m_maxZ0); + declareProperty("maxD0", m_maxD0); + declareProperty("maxD0overSigmaD0", m_maxD0overSigmaD0); + declareProperty("numberOfPixelHits", m_numberOfPixelHits); + declareProperty("numberOfBLayerHits", m_numberOfBLayerHits); + declareProperty("TrackSummaryTool", m_trackSumTool); + declareProperty("Extrapolator", m_extrapolator); +} + +//_______________________________________________________________________________ +InDetTrackSelectorTool::~InDetTrackSelectorTool() +{} + +//_______________________________________________________________________________ +StatusCode InDetTrackSelectorTool::initialize() +{ + StatusCode sc = AthAlgTool::initialize(); + if(sc.isFailure()) { + msg(MSG::ERROR)<<" Unable to initialize the AlgTool"<<endreq; + return StatusCode::FAILURE; + } + + m_trackSumToolAvailable = false; + if (!m_trackSumTool.empty()) + { + if(m_trackSumTool.retrieve().isFailure()) { + msg(MSG::ERROR)<<" Unable to retrieve "<<m_trackSumTool<<endreq; + return StatusCode::FAILURE; + } + else { + ATH_MSG_INFO("Track summary tool retrieved"); + m_trackSumToolAvailable = true; + } + } + + if ( m_extrapolator.retrieve().isFailure() ) { + msg(MSG::ERROR) << "Failed to retrieve tool " << m_extrapolator << endreq; + return StatusCode::FAILURE; + } + ATH_MSG_INFO("Retrieved tool " << m_extrapolator); + + return StatusCode::SUCCESS; +} + +//_______________________________________________________________________________ +StatusCode InDetTrackSelectorTool::finalize() +{ + ATH_MSG_INFO("Finalize successful"); + return StatusCode::SUCCESS; +} + +//_______________________________________________________________________________ +bool InDetTrackSelectorTool::decision(const Trk::Track & track, const Trk::Vertex * vertex) const +{ + // decision based on the track parameters + if(!decision(track.perigeeParameters(), vertex, track.info().particleHypothesis())) + return false; + + // number of hits, silicon hits, b-layer + // first ask track for summary + const Trk::TrackSummary * summary = track.trackSummary(); + if (summary == 0 && m_trackSumToolAvailable) { + // ugly but one needs to cast the const away because the method needs to update the track (the tool is a friend of track) + Trk::Track & nonConstTrack = const_cast<Trk::Track &>(track); + m_trackSumTool->updateTrack(nonConstTrack); + // now get it from the track (the track has OWNERSHIP) + summary = nonConstTrack.trackSummary(); + } + + if (0==summary) { + ATH_MSG_DEBUG( "Track preselection: cannot create a track summary. This track will not pass." ); + return false; + } + + int nPixelHits = summary->get(Trk::numberOfPixelHits); + int nPixelDead = summary->get(Trk::numberOfPixelDeadSensors); + if (nPixelDead<0) + nPixelDead=0; + + int nBLayerHits = summary->get(Trk::numberOfBLayerHits); + + if(nPixelHits+nPixelDead<m_numberOfPixelHits || nBLayerHits<m_numberOfBLayerHits ) + return false; + + // all ok + return true; +} + +//_______________________________________________________________________________ +bool InDetTrackSelectorTool::decision(const Trk::TrackParticleBase & track, const Trk::Vertex * vertex) const +{ + if(!decision(&(track.definingParameters()), vertex, Trk::pion)) + return false; + + const Trk::TrackSummary * summary = track.trackSummary(); + if (summary == 0) { + ATH_MSG_INFO( "TrackParticleBase does not have a Track Summary. Rejected." ); + return false; + } + int nPixelHits = summary->get(Trk::numberOfPixelHits); + int nPixelDead = summary->get(Trk::numberOfPixelDeadSensors); + if (nPixelDead<0) + nPixelDead=0; + + int nBLayerHits = summary->get(Trk::numberOfBLayerHits); + + if(nPixelHits+nPixelDead<m_numberOfPixelHits || nBLayerHits<m_numberOfBLayerHits ) + return false; + return true; +} + +//_______________________________________________________________________________ +bool InDetTrackSelectorTool::decision(const Trk::TrackParameters * track, const Trk::Vertex * vertex, const Trk::ParticleHypothesis hyp) const +{ + // checking pointer first + if(0==track || !track->covariance()) { + ATH_MSG_WARNING( "Track preselection: Zero pointer to parameterbase* received (most likely a track without perigee). This track will not pass." ); + return false; + } + + // getting the perigee parameters of the track + const Trk::Perigee * perigee(0); + if(vertex == 0) + perigee = dynamic_cast<const Trk::Perigee *>(track); + else { + Trk::PerigeeSurface perigeeSurface(vertex->position()); + perigee = dynamic_cast<const Trk::Perigee *>(m_extrapolator->extrapolate(*track,perigeeSurface,Trk::anyDirection,true,hyp)); + } + + if(0 == perigee || !perigee->covariance() ) { + ATH_MSG_INFO( "Track preselection: cannot make a measured perigee. This track will not pass." ); + return false; + } + + AmgVector(5) trackParameters = perigee->parameters(); + + // d0 and z0 cuts + double d0 = trackParameters[Trk::d0]; + if(fabs(d0) > m_maxD0) { if(vertex != 0) { delete perigee; } return false; } + + double z0 = trackParameters[Trk::z0]; + if (fabs(z0)*sin(trackParameters[Trk::theta]) > m_IPz0Max) + { if(vertex != 0) { delete perigee; } return false; } + if (fabs(z0) > m_maxZ0) + { if(vertex != 0) { delete perigee; } return false; } + + // transverse momentum + double pt = perigee->momentum().perp(); + if(pt<m_minPt) { if(vertex != 0) { delete perigee; } return false; } + + // d0 significance + double d0Significance=fabs(trackParameters[Trk::d0]/sqrt( (*perigee->covariance())(Trk::d0,Trk::d0) )); + if (d0Significance>m_maxD0overSigmaD0) + { if(vertex != 0) { delete perigee; } return false; } + + if(vertex != 0) { delete perigee; } + return true; +} //end of selection method + +} //end of namespace definitions diff --git a/InnerDetector/InDetRecTools/InDetTrackSelectorTool/src/InDetTrtDriftCircleCutTool.cxx b/InnerDetector/InDetRecTools/InDetTrackSelectorTool/src/InDetTrtDriftCircleCutTool.cxx new file mode 100644 index 00000000000..87cb4913023 --- /dev/null +++ b/InnerDetector/InDetRecTools/InDetTrackSelectorTool/src/InDetTrtDriftCircleCutTool.cxx @@ -0,0 +1,90 @@ +/* + Copyright (C) 2002-2017 CERN for the benefit of the ATLAS collaboration +*/ + +#include "InDetTrackSelectorTool/InDetTrtDriftCircleCutTool.h" +#include "TRT_ConditionsServices/ITRT_ActiveFractionSvc.h" + +StatusCode InDet::InDetTrtDriftCircleCutTool::initialize() +{ + StatusCode sc = AthAlgTool::initialize(); + + /* Get the trt active fraction tool */ + if(m_useTRT){ + if ( m_trtCondSvc.retrieve().isFailure() ) { + msg(MSG::ERROR) << "Failed to retrieve tool " << m_trtCondSvc << endreq; + return StatusCode::FAILURE; + } else { + msg(MSG::INFO) << "Retrieved tool " << m_trtCondSvc << endreq; + } + } + + if(sc.isFailure()){ + msg(MSG::ERROR)<<" Unable to initialize the AlgTool"<<endreq; + return StatusCode::FAILURE; + } + + return StatusCode::SUCCESS; +} + +StatusCode InDet::InDetTrtDriftCircleCutTool::finalize() +{ + msg(MSG::INFO) << "Finalize successful" << endreq; + return StatusCode::SUCCESS; +} + +InDet::InDetTrtDriftCircleCutTool::InDetTrtDriftCircleCutTool(const std::string& t, const std::string& n, const IInterface* p) + :AthAlgTool(t,n,p), + m_trtCondSvc("TRT_ActiveFractionSvc",n), + m_minOffset(0), + m_param(false), + m_useTRT(true) +{ + declareInterface<ITrtDriftCircleCutTool>(this); + declareProperty("TrtConditionsSvc", m_trtCondSvc); + declareProperty("MinOffsetDCs", m_minOffset ); + declareProperty("UseNewParameterization", m_param ); + declareProperty("UseActiveFractionSvc", m_useTRT ); +} + +InDet::InDetTrtDriftCircleCutTool::~InDetTrtDriftCircleCutTool() +{} + +int InDet::InDetTrtDriftCircleCutTool::minNumberDCs(const Trk::TrackParameters* trkp) const { + if(!m_param){ + const double TrtEtaBin[6] = {0., 0.65, 0.85, 1.25, 1.80, 2.10}; + const double TrtA [5] = { 29., 31., 20., 36., 34. }; + const double TrtB [5] = { 2./0.65, -11./0.20, 16./0.40, -2./0.55, -24./0.3}; + + double eta= fabs(trkp->momentum().eta()); + + for(int i=0; i!=5; ++i) { + if(eta <= TrtEtaBin[i+1]) { + return int(TrtA[i]+TrtB[i]*(eta-TrtEtaBin[i])-m_minOffset); + } + } + return int(m_minOffset); + } else { + const double TrtEtaBin[7] = {0., 0.1, 0.6255, 1.07, 1.304, 1.752, 2.0 }; + const double TrtA [6] = { 33.28, 30.40, 182.38, -226.18, -351.56, -250.2 }; + const double TrtB [6] = { -79.4, 18.79, -371.9, 495.12, 777.5, 377.9 }; + const double TrtC [6] = { 589.7, -42.73, 213.3, -314.96 , -512.3, -128.7 }; + const double TrtD [6] = { 0., 32.53, 0. , 69.42 , 111.0, 3.4 }; + const double TrtO [6] = { 9., 11., 10., 7., 9., 12. }; + + double eta = fabs(trkp->momentum().eta()); + + for(int i=0; i!=6; ++i) { + if(eta <= TrtEtaBin[i+1]) { + double diff = eta; + double nDiffTRT = TrtA[i]+TrtB[i]*diff+TrtC[i]*diff*diff+TrtD[i]*diff*diff*diff-TrtO[i]; + double activeF = 1.; + if(m_useTRT) activeF = m_trtCondSvc->getActiveFraction(trkp); + nDiffTRT = nDiffTRT*activeF; + if (nDiffTRT>=1) return int(nDiffTRT); + else return int(m_minOffset); + } + } + return int(m_minOffset); + } +} diff --git a/InnerDetector/InDetRecTools/InDetTrackSelectorTool/src/components/InDetTrackSelectorTool_entries.cxx b/InnerDetector/InDetRecTools/InDetTrackSelectorTool/src/components/InDetTrackSelectorTool_entries.cxx new file mode 100644 index 00000000000..f48544f66c1 --- /dev/null +++ b/InnerDetector/InDetRecTools/InDetTrackSelectorTool/src/components/InDetTrackSelectorTool_entries.cxx @@ -0,0 +1,26 @@ +#include "GaudiKernel/DeclareFactoryEntries.h" +#include "InDetTrackSelectorTool/InDetTrackSelectorTool.h" +#include "InDetTrackSelectorTool/InDetIsoTrackSelectorTool.h" +#include "InDetTrackSelectorTool/InDetCosmicTrackSelectorTool.h" +#include "InDetTrackSelectorTool/InDetDetailedTrackSelectorTool.h" +#include "InDetTrackSelectorTool/InDetConversionTrackSelectorTool.h" +#include "InDetTrackSelectorTool/InDetTrtDriftCircleCutTool.h" + +using namespace InDet; + +DECLARE_TOOL_FACTORY( InDetTrackSelectorTool ) +DECLARE_TOOL_FACTORY( InDetIsoTrackSelectorTool ) +DECLARE_TOOL_FACTORY( InDetCosmicTrackSelectorTool ) +DECLARE_TOOL_FACTORY( InDetDetailedTrackSelectorTool ) +DECLARE_TOOL_FACTORY( InDetConversionTrackSelectorTool ) +DECLARE_TOOL_FACTORY( InDetTrtDriftCircleCutTool ) + +DECLARE_FACTORY_ENTRIES( InDetTrackSelectorTool ) +{ + DECLARE_TOOL( InDetTrackSelectorTool ); + DECLARE_TOOL( InDetIsoTrackSelectorTool ); + DECLARE_TOOL( InDetCosmicTrackSelectorTool ); + DECLARE_TOOL( InDetDetailedTrackSelectorTool ); + DECLARE_TOOL( InDetConversionTrackSelectorTool ); + DECLARE_TOOL( InDetTrtDriftCircleCutTool ); +} diff --git a/InnerDetector/InDetRecTools/InDetTrackSelectorTool/src/components/InDetTrackSelectorTool_load.cxx b/InnerDetector/InDetRecTools/InDetTrackSelectorTool/src/components/InDetTrackSelectorTool_load.cxx new file mode 100644 index 00000000000..4877876e806 --- /dev/null +++ b/InnerDetector/InDetRecTools/InDetTrackSelectorTool/src/components/InDetTrackSelectorTool_load.cxx @@ -0,0 +1,3 @@ +#include "GaudiKernel/LoadFactoryEntries.h" + +LOAD_FACTORY_ENTRIES( InDetTrackSelectorTool ) -- GitLab