diff --git a/InnerDetector/InDetExample/InDetRecExample/python/InDetJobProperties.py b/InnerDetector/InDetExample/InDetRecExample/python/InDetJobProperties.py index 7c6a85cbd4f4f45b1f6dd62b506ff9de24e68a94..7eadfc2fc9d0b328aa048bcbe99a176bbf296550 100644 --- a/InnerDetector/InDetExample/InDetRecExample/python/InDetJobProperties.py +++ b/InnerDetector/InDetExample/InDetRecExample/python/InDetJobProperties.py @@ -1181,6 +1181,11 @@ class doDigitalROTCreation(InDetFlagsJobProperty): allowedTypes = ['bool'] StoredValue = False +class nnCutLargeD0Threshold(InDetFlagsJobProperty): + """ Threshold for NN cut in large D0 tracking for tracks in ambi""" + statusOn = True + allowedTypes = ['float'] + StoredValue = -1.0 ##----------------------------------------------------------------------------- ## 2nd step @@ -2761,6 +2766,7 @@ _list_InDetJobProperties = [Enabled, doHIP300, checkDeadElementsOnTrack, doDigitalROTCreation, + nnCutLargeD0Threshold, useMuForTRTErrorScaling ] for j in _list_InDetJobProperties: diff --git a/InnerDetector/InDetExample/InDetRecExample/python/TrackingCommon.py b/InnerDetector/InDetExample/InDetRecExample/python/TrackingCommon.py index 55e1033987f25a195e30627c379d48a1e09a6441..de8e47974b79935a896ebc1925a654d03e4dd15d 100644 --- a/InnerDetector/InDetExample/InDetRecExample/python/TrackingCommon.py +++ b/InnerDetector/InDetExample/InDetRecExample/python/TrackingCommon.py @@ -1280,6 +1280,50 @@ def getInDetAmbiScoringTool(NewTrackingCuts, name='InDetAmbiScoringTool', **kwar maxSCTHoles = NewTrackingCuts.maxSCTHoles(), maxDoubleHoles = NewTrackingCuts.maxDoubleHoles())) +@makePublicTool +def getInDetNNScoringToolBase(name='InDetNNScoringTool', **kwargs) : + NewTrackingCuts = kwargs.pop("NewTrackingCuts") + the_name=makeName(name,kwargs) + from InDetRecExample.InDetJobProperties import InDetFlags + from AthenaCommon.DetFlags import DetFlags + have_calo_rois = InDetFlags.doBremRecovery() and InDetFlags.doCaloSeededBrem() and DetFlags.detdescr.Calo_allOn() + if have_calo_rois : + alg=createAndAddEventAlg(getInDetROIInfoVecCondAlg,"InDetROIInfoVecCondAlg") + kwargs=setDefaults(kwargs, CaloROIInfoName = alg.WriteKey ) + from InDetTrackScoringTools.InDetTrackScoringToolsConf import InDet__InDetNNScoringTool + return InDet__InDetNNScoringTool(the_name, + **setDefaults(kwargs, + nnCutConfig = "dev/TrackingCP/LRTAmbiNetwork/20200727_225401/nn-config.json", + nnCutThreshold = InDetFlags.nnCutLargeD0Threshold(), + Extrapolator = getInDetExtrapolator(), + SummaryTool = getInDetTrackSummaryTool(), + DriftCircleCutTool = getInDetTRTDriftCircleCutForPatternReco(), + useAmbigFcn = True, # this is NewTracking + useTRT_AmbigFcn = False, + maxZImp = NewTrackingCuts.maxZImpact(), + maxEta = NewTrackingCuts.maxEta(), + usePixel = NewTrackingCuts.usePixel(), + useSCT = NewTrackingCuts.useSCT(), + doEmCaloSeed = have_calo_rois) + ) + +def getInDetNNScoringTool(NewTrackingCuts, name='InDetNNScoringTool', **kwargs) : + return getInDetNNScoringToolBase(name+NewTrackingCuts.extension(), + **setDefaults( kwargs, + NewTrackingCuts = NewTrackingCuts, + useAmbigFcn = True, # this is NewTracking + useTRT_AmbigFcn = False, + minTRTonTrk = 0, + minTRTPrecisionFraction = 0, + minPt = NewTrackingCuts.minPT(), + maxRPhiImp = NewTrackingCuts.maxPrimaryImpact(), + minSiClusters = NewTrackingCuts.minClusters(), + minPixel = NewTrackingCuts.minPixel(), + maxSiHoles = NewTrackingCuts.maxHoles(), + maxPixelHoles = NewTrackingCuts.maxPixelHoles(), + maxSCTHoles = NewTrackingCuts.maxSCTHoles(), + maxDoubleHoles = NewTrackingCuts.maxDoubleHoles())) + def getInDetTRT_SeededScoringTool(NewTrackingCuts, name='InDetTRT_SeededScoringTool',**kwargs) : from InDetRecExample.InDetJobProperties import InDetFlags return getInDetAmbiScoringToolBase('InDetTRT_SeededScoringTool', diff --git a/InnerDetector/InDetExample/InDetRecExample/share/ConfiguredNewTrackingSiPattern.py b/InnerDetector/InDetExample/InDetRecExample/share/ConfiguredNewTrackingSiPattern.py index 3e35f6f2984935505a73acd67057922cee790213..a214edabc0506b133086b68e384c8a9e8379abbc 100644 --- a/InnerDetector/InDetExample/InDetRecExample/share/ConfiguredNewTrackingSiPattern.py +++ b/InnerDetector/InDetExample/InDetRecExample/share/ConfiguredNewTrackingSiPattern.py @@ -463,9 +463,12 @@ class ConfiguredNewTrackingSiPattern: # if InDetFlags.doCosmics() and NewTrackingCuts.mode() != "DBM": InDetAmbiScoringTool = TrackingCommon.getInDetCosmicsScoringTool(NewTrackingCuts) + elif(NewTrackingCuts.mode() == "R3LargeD0" and InDetFlags.nnCutLargeD0Threshold > 0): + # Set up NN config + InDetAmbiScoringTool = TrackingCommon.getInDetNNScoringTool(NewTrackingCuts) else: InDetAmbiScoringTool = TrackingCommon.getInDetAmbiScoringTool(NewTrackingCuts) - + # # --- load Ambiguity Processor # diff --git a/InnerDetector/InDetRecTools/InDetTrackScoringTools/CMakeLists.txt b/InnerDetector/InDetRecTools/InDetTrackScoringTools/CMakeLists.txt index 0bd16b4251c657a712ad32c48297b4866ee46b2f..bcb33444dd932ddd4119508644d88a8360c39f81 100644 --- a/InnerDetector/InDetRecTools/InDetTrackScoringTools/CMakeLists.txt +++ b/InnerDetector/InDetRecTools/InDetTrackScoringTools/CMakeLists.txt @@ -25,8 +25,9 @@ atlas_depends_on_subdirs( PUBLIC Tracking/TrkEvent/TrkTrackSummary Tracking/TrkExtrapolation/TrkExInterfaces Tracking/TrkEvent/TrkCaloClusterROI - MagneticField/MagFieldElements + MagneticField/MagFieldElements MagneticField/MagFieldConditions + Tools/PathResolver ) @@ -34,6 +35,7 @@ atlas_depends_on_subdirs( PUBLIC # External dependencies: find_package( CLHEP ) find_package( Eigen ) +find_package( lwtnn ) find_package( ROOT COMPONENTS Core Tree MathCore Hist RIO pthread ) # tag rootMathLibs was not recognized in automatic conversion in cmt2cmake @@ -42,8 +44,8 @@ find_package( ROOT COMPONENTS Core Tree MathCore Hist RIO pthread ) atlas_add_component( InDetTrackScoringTools src/*.cxx src/components/*.cxx - INCLUDE_DIRS ${ROOT_INCLUDE_DIRS} ${CLHEP_INCLUDE_DIRS} ${EIGEN_INCLUDE_DIRS} - LINK_LIBRARIES ${ROOT_LIBRARIES} ${CLHEP_LIBRARIES} ${EIGEN_LIBRARIES} AthenaBaseComps AthenaKernel GaudiKernel TrkEventPrimitives TrkToolInterfaces GeoPrimitives InDetIdentifier InDetRIO_OnTrack InDetRecToolInterfaces TrkParameters TrkPseudoMeasurementOnTrack TrkTrack TrkTrackSummary TrkExInterfaces TrkCaloClusterROI MagFieldElements MagFieldConditions BeamSpotConditionsData ) + INCLUDE_DIRS ${ROOT_INCLUDE_DIRS} ${CLHEP_INCLUDE_DIRS} ${EIGEN_INCLUDE_DIRS} ${LWTNN_INCLUDE_DIRS} + LINK_LIBRARIES ${ROOT_LIBRARIES} ${CLHEP_LIBRARIES} ${EIGEN_LIBRARIES} ${LWTNN_LIBRARIES} AthenaBaseComps AthenaKernel GaudiKernel TrkEventPrimitives TrkToolInterfaces GeoPrimitives InDetIdentifier InDetRIO_OnTrack InDetRecToolInterfaces TrkParameters TrkPseudoMeasurementOnTrack TrkTrack TrkTrackSummary TrkExInterfaces TrkCaloClusterROI MagFieldElements MagFieldConditions BeamSpotConditionsData PathResolver ) # Install files from the package: atlas_install_headers( InDetTrackScoringTools ) diff --git a/InnerDetector/InDetRecTools/InDetTrackScoringTools/InDetTrackScoringTools/InDetNNScoringTool.h b/InnerDetector/InDetRecTools/InDetTrackScoringTools/InDetTrackScoringTools/InDetNNScoringTool.h new file mode 100755 index 0000000000000000000000000000000000000000..330763ca60491561fe64fe5832ed36180c0aa725 --- /dev/null +++ b/InnerDetector/InDetRecTools/InDetTrackScoringTools/InDetTrackScoringTools/InDetNNScoringTool.h @@ -0,0 +1,139 @@ +/* + Copyright (C) 2002-2020 CERN for the benefit of the ATLAS collaboration +*/ + +///////////////////////////////// +// Markus Elsing +///////////////////////////////// + +#ifndef INDETNNSCORINGTOOL_H +#define INDETNNSCORINGTOOL_H + +#include "AthenaBaseComps/AthAlgTool.h" +#include "GaudiKernel/ToolHandle.h" +#include "GaudiKernel/ServiceHandle.h" +#include "StoreGate/ReadHandleKey.h" +#include "InDetTrackScoringTools/ROIInfoVec.h" +#include "TrkEventPrimitives/TrackScore.h" +#include "TrkToolInterfaces/ITrackScoringTool.h" +#include "TrkToolInterfaces/ITrackSummaryTool.h" +#include "lwtnn/lightweight_network_config.hh" +#include "lwtnn/LightweightNeuralNetwork.hh" +#include "lwtnn/LightweightGraph.hh" +#include "lwtnn/parse_json.hh" +#include "PathResolver/PathResolver.h" +#include "TrkParameters/TrackParameters.h" +#include "AthenaKernel/CLASS_DEF.h" +#include "AthenaKernel/IOVSvcDefs.h" +// MagField cache +#include "MagFieldConditions/AtlasFieldCacheCondObj.h" +#include "MagFieldElements/AtlasFieldCache.h" +#include <fstream> +#include <vector> +#include <string> +#include "BeamSpotConditionsData/BeamSpotData.h" +#include "ROIInfoVec.h" + +namespace Trk { + class IExtrapolator; + class Track; + class TrackSummary; + +} + +namespace InDet { +class ITrtDriftCircleCutTool; + +/**Concrete implementation of the ITrackScoringTool pABC*/ +class InDetNNScoringTool : virtual public Trk::ITrackScoringTool, + public AthAlgTool +{ + + public: + InDetNNScoringTool(const std::string&,const std::string&,const IInterface*); + virtual ~InDetNNScoringTool (); + virtual StatusCode initialize() override; + virtual StatusCode finalize () override; + /** create a score based on how good the passed track is*/ + virtual Trk::TrackScore score( const Trk::Track& track, const bool suppressHoleSearch ) const override; + + /** create a score based on how good the passed TrackSummary is*/ + virtual Trk::TrackScore simpleScore( const Trk::Track& track, const Trk::TrackSummary& trackSum ) const override; + Trk::TrackScore ambigScore( const Trk::Track& track, const Trk::TrackSummary& trackSum ) const; + Trk::TrackScore calcNnScore( const Trk::Track &track, const Trk::TrackSummary& trackSum , const Trk::Perigee *extrapolatedPerigee) const; + + + private: + void setupScoreModifiers(); + + // DNN tools + std::unique_ptr<lwt::LightweightGraph> m_graph; + std::map<std::string, double> m_DNN_inputValues; + + /** Check if the cluster is compatible with a EM cluster*/ + bool isEmCaloCompatible(const Trk::Track& track) const; + + + //these are used for ScoreModifiers + int m_maxDblHoles, m_maxPixHoles, m_maxSCT_Holes, m_maxHits, m_maxSigmaChi2, m_maxTrtRatio, m_maxTrtFittedRatio, + m_maxB_LayerHits, m_maxPixelHits, m_maxPixLay, m_maxGangedFakes; + std::vector<double> m_factorDblHoles, m_factorPixHoles, m_factorSCT_Holes, m_factorHits, + m_factorSigmaChi2, m_factorB_LayerHits, m_factorPixelHits, m_factorPixLay, m_factorHoles, m_factorGangedFakes; + std::vector<double> m_boundsSigmaChi2, m_boundsHits, + m_boundsTrtRatio, m_factorTrtRatio, m_boundsTrtFittedRatio, m_factorTrtFittedRatio; + + /**\todo make this const, once createSummary method is const*/ + ToolHandle<Trk::ITrackSummaryTool> m_trkSummaryTool; + + /** Returns minimum number of expected TRT drift circles depending on eta. */ + ToolHandle<ITrtDriftCircleCutTool> m_selectortool; + + /**holds the scores assigned to each Trk::SummaryType from the track's Trk::TrackSummary*/ + std::vector<Trk::TrackScore> m_summaryTypeScore; + + SG::ReadCondHandleKey<InDet::BeamSpotData> m_beamSpotKey { this, "BeamSpotKey", "BeamSpotData", "SG key for beam spot" }; + + ToolHandle<Trk::IExtrapolator> m_extrapolator; + + // Read handle for conditions object to get the field cache + SG::ReadCondHandleKey<AtlasFieldCacheCondObj> m_fieldCacheCondObjInputKey {this, "AtlasFieldCacheCondObj", "fieldCondObj", "Name of the Magnetic Field conditions object key"}; + + + /** use the scoring tuned to Ambiguity processing or not */ + bool m_useAmbigFcn; + bool m_useTRT_AmbigFcn; + bool m_useSigmaChi2; + std::string m_nnCutConfig; + double m_nnCutThreshold; + + bool m_usePixel; + bool m_useSCT; + + /** cuts for selecting good tracks*/ + double m_minPt; //!< minimal Pt cut + double m_maxEta; //!< maximal Eta cut + double m_maxRPhiImp; //!< maximal RPhi impact parameter cut + double m_maxZImp; //!< maximal z impact parameter cut + int m_minSiClusters; //!< minimal number of Si clusters + int m_maxDoubleHoles;//|< maximum number of SCT double holes + int m_maxSiHoles; //!< maximal number of holes (Pixel+SCT) + int m_maxPixelHoles; //!< maximal number of Pixel holes + int m_maxSctHoles; //!< maximal number of SCT holes + int m_minTRTonTrk; //!< minimum number of TRT hits + double m_minTRTprecision; //!< minimum fraction of TRT precision hits + int m_minPixel; //!< minimum number of pixel clusters + double m_maxRPhiImpEM; //!< maximal RPhi impact parameter cut track that match EM clusters + + bool m_useEmClusSeed; + float m_phiWidthEm; + float m_etaWidthEm; + + SG::ReadHandleKey<InDet::ROIInfoVec> m_caloROIInfoKey + {this,"CaloROIInfoName", "ROIInfoVec","Name of the calo cluster ROI vector."}; +}; + + +} // namespace InDet + + +#endif diff --git a/InnerDetector/InDetRecTools/InDetTrackScoringTools/src/InDetNNScoringTool.cxx b/InnerDetector/InDetRecTools/InDetTrackScoringTools/src/InDetNNScoringTool.cxx new file mode 100755 index 0000000000000000000000000000000000000000..88180f46a28044e16e052ee5c4a73fdcd3271f4a --- /dev/null +++ b/InnerDetector/InDetRecTools/InDetTrackScoringTools/src/InDetNNScoringTool.cxx @@ -0,0 +1,944 @@ +/* + Copyright (C) 2002-2020 CERN for the benefit of the ATLAS collaboration +*/ + +///////////////////////////////// +// Markus Elsing +///////////////////////////////// + +#include "InDetTrackScoringTools/InDetNNScoringTool.h" +#include "InDetRecToolInterfaces/ITrtDriftCircleCutTool.h" +#include "TrkTrack/Track.h" +#include "TrkTrackSummary/TrackSummary.h" +#include "TrkEventPrimitives/FitQuality.h" +#include "TrkParameters/TrackParameters.h" +#include "TrkExInterfaces/IExtrapolator.h" +#include "CLHEP/GenericFunctions/CumulativeChiSquare.hh" +#include "GeoPrimitives/GeoPrimitives.h" +#include "TrkCaloClusterROI/CaloClusterROI.h" +#include "TrkCaloClusterROI/CaloClusterROI_Collection.h" +#include "StoreGate/ReadHandle.h" +#include "StoreGate/WriteHandle.h" + + +//--------------------------------------------------------------------------------------------------------------------- + +InDet::InDetNNScoringTool::InDetNNScoringTool(const std::string& t, + const std::string& n, + const IInterface* p ) : + AthAlgTool(t,n,p), + // Initialization of ScoreModifiers variables + m_maxDblHoles(-1), + m_maxPixHoles(-1), + m_maxSCT_Holes(-1), + m_maxHits(-1), + m_maxSigmaChi2(-1), + m_maxTrtRatio(-1), + m_maxTrtFittedRatio(-1), + m_maxB_LayerHits(-1), + m_maxPixelHits(-1), + m_maxPixLay(-1), + m_maxGangedFakes(-1), + m_trkSummaryTool("Trk::TrackSummaryTool", this), + m_selectortool("InDet::InDetTrtDriftCircleCutTool", this), + m_summaryTypeScore(Trk::numberOfTrackSummaryTypes), + m_extrapolator("Trk::Extrapolator", this) +{ + declareInterface<Trk::ITrackScoringTool>(this); + + // declare properties + declareProperty("minPt", m_minPt = 500.); + declareProperty("maxEta", m_maxEta = 2.7); + declareProperty("maxRPhiImp", m_maxRPhiImp = 10.); + declareProperty("maxZImp", m_maxZImp = 250.); + + // changed cuts on the selction of tracks + declareProperty("minSiClusters", m_minSiClusters = 7); + declareProperty("maxDoubleHoles", m_maxDoubleHoles = 2); + declareProperty("maxSiHoles", m_maxSiHoles = 5, "max number of Silicon (Pixel+SCT) holes"); + declareProperty("maxPixelHoles", m_maxPixelHoles = 5, "max number of Pixel holes"); + declareProperty("maxSCTHoles", m_maxSctHoles = 5, "max number of SCT holes"); + declareProperty("minTRTonTrk", m_minTRTonTrk = 9); + declareProperty("minTRTPrecisionFraction", m_minTRTprecision = 0.5); + declareProperty("minPixel", m_minPixel = 0); + declareProperty("nnCutConfig", m_nnCutConfig = ""); + declareProperty("nnCutThreshold", m_nnCutThreshold = -0.1); + + // which detectors to use + declareProperty("usePixel", m_usePixel = true); + declareProperty("useSCT", m_useSCT = true); + + // switches and tools + declareProperty("useAmbigFcn", m_useAmbigFcn = true); + declareProperty("useTRT_AmbigFcn", m_useTRT_AmbigFcn = false); + declareProperty("useSigmaChi2", m_useSigmaChi2 = false); + + // tools + declareProperty("Extrapolator", m_extrapolator); + declareProperty("SummaryTool" , m_trkSummaryTool); + declareProperty("DriftCircleCutTool",m_selectortool ); + + declareProperty("maxRPhiImpEM", m_maxRPhiImpEM = 50. ); + declareProperty("doEmCaloSeed", m_useEmClusSeed = true ); + declareProperty("phiWidthEM", m_phiWidthEm = 0.075 ); + declareProperty("etaWidthEM", m_etaWidthEm = 0.05 ); + + //set values for scores + m_summaryTypeScore[Trk::numberOfPixelHits] = 20; + m_summaryTypeScore[Trk::numberOfPixelSharedHits] = -10; // NOT USED --- a shared hit is only half the weight + m_summaryTypeScore[Trk::numberOfPixelHoles] = -10; // a hole is bad + m_summaryTypeScore[Trk::numberOfInnermostPixelLayerHits] = 10; // addition for being b-layer + m_summaryTypeScore[Trk::numberOfInnermostPixelLayerSharedHits] = -5; // NOT USED --- a shared hit is only half the weight + m_summaryTypeScore[Trk::numberOfGangedPixels] = -5; // decrease for being ganged + m_summaryTypeScore[Trk::numberOfGangedFlaggedFakes] = -10; // decrease for being ganged fake + m_summaryTypeScore[Trk::numberOfSCTHits] = 10; // half of a pixel, since only 1dim + m_summaryTypeScore[Trk::numberOfSCTSharedHits] = -5; // NOT USED -- a shared hit is only half the weight + m_summaryTypeScore[Trk::numberOfSCTHoles] = -5; // a hole is bad ! + m_summaryTypeScore[Trk::numberOfSCTDoubleHoles] = -15; // a double hole is even worse ! + m_summaryTypeScore[Trk::numberOfTRTHits] = 1; // 10 straws ~ 1 SCT + m_summaryTypeScore[Trk::numberOfTRTHighThresholdHits] = 0; // addition for being TR + m_summaryTypeScore[Trk::numberOfOutliersOnTrack] = -1; // -ME- TRT oulier should not kill 5 TRT on track (was -5) + + // scoring for Muons not needed + m_summaryTypeScore[Trk::numberOfMdtHits] = 0; + m_summaryTypeScore[Trk::numberOfTgcPhiHits] = 0; + m_summaryTypeScore[Trk::numberOfTgcEtaHits] = 0; + m_summaryTypeScore[Trk::numberOfCscPhiHits] = 0; + m_summaryTypeScore[Trk::numberOfCscEtaHits] = 0; + m_summaryTypeScore[Trk::numberOfRpcPhiHits] = 0; + m_summaryTypeScore[Trk::numberOfRpcEtaHits] = 0; + +} + +//--------------------------------------------------------------------------------------------------------------------- + +InDet::InDetNNScoringTool::~InDetNNScoringTool() +{ +} + +//--------------------------------------------------------------------------------------------------------------------- + +StatusCode InDet::InDetNNScoringTool::initialize() +{ + StatusCode sc = AlgTool::initialize(); + if (sc.isFailure()) return sc; + + sc = m_trkSummaryTool.retrieve(); + if (sc.isFailure()) { + msg(MSG::FATAL) << "Failed to retrieve tool " << m_trkSummaryTool << endmsg; + return StatusCode::FAILURE; + } else + msg(MSG::DEBUG) << "Retrieved tool " << m_trkSummaryTool << endmsg; + + sc = m_extrapolator.retrieve(); + if (sc.isFailure()) { + msg(MSG::FATAL) << "Failed to retrieve tool " << m_extrapolator << endmsg; + return StatusCode::FAILURE; + } else + msg(MSG::DEBUG) << "Retrieved tool " << m_extrapolator << endmsg; + + // Get segment selector tool + // + if(m_selectortool.retrieve().isFailure()) { + msg(MSG::FATAL)<<"Failed to retrieve tool "<< m_selectortool <<endmsg; + return StatusCode::FAILURE; + } else { + msg(MSG::DEBUG) << "Retrieved tool " << m_selectortool << endmsg; + } + + ATH_CHECK(m_beamSpotKey.initialize()); + + if (m_useAmbigFcn && m_useTRT_AmbigFcn) { + msg(MSG::FATAL) << "Both on, normal ambi funciton and the one for back tracking, configuration problem, not recoverable" << endmsg; + return StatusCode::FAILURE; + } + + // Read handle for AtlasFieldCacheCondObj + ATH_CHECK( m_fieldCacheCondObjInputKey.initialize() ); + + if (m_useAmbigFcn || m_useTRT_AmbigFcn) setupScoreModifiers(); + + // lwtnn initialization + if (m_nnCutThreshold > 0.0) { // Load NN only if it will be used + // Locate configuration file + std::string nnCutConfigPath = PathResolverFindCalibFile(m_nnCutConfig); //returns "" if file not found + if (nnCutConfigPath.empty()){ + ATH_MSG_FATAL ( "Failed to find configuration file: " << m_nnCutConfig); + return StatusCode::FAILURE; + } + ATH_MSG_DEBUG ("Loading configuration file:" << nnCutConfigPath); + // Load NN weights + std::ifstream inFile(nnCutConfigPath); + lwt::GraphConfig config(lwt::parse_json_graph(inFile)); + m_graph = std::make_unique<lwt::LightweightGraph>(config); + ATH_MSG_DEBUG ("NN configuration loaded"); + inFile.close(); + } + + ATH_CHECK( m_caloROIInfoKey.initialize(m_useEmClusSeed) ); + + return StatusCode::SUCCESS; +} + +//--------------------------------------------------------------------------------------------------------------------- + +StatusCode InDet::InDetNNScoringTool::finalize() +{ + StatusCode sc = AlgTool::finalize(); + return sc; +} + +//--------------------------------------------------------------------------------------------------------------------- + +Trk::TrackScore InDet::InDetNNScoringTool::score( const Trk::Track& track, const bool suppressHoleSearch ) const +{ + std::unique_ptr<const Trk::TrackSummary> summary; + if ( suppressHoleSearch) { + ATH_MSG_DEBUG ("Get summary for new Track, suppress HoleSearch"); + summary = m_trkSummaryTool->summaryNoHoleSearch(track); + } else { + ATH_MSG_DEBUG ("Get summary for new Track with HoleSearch"); + summary = m_trkSummaryTool->summary(track); + } + + ATH_MSG_VERBOSE ("Track has TrackSummary "<<*summary); + Trk::TrackScore score = Trk::TrackScore( simpleScore(track, *summary) ); + ATH_MSG_DEBUG ("Track has Score: "<<score); + + return score; +} + +//--------------------------------------------------------------------------------------------------------------------- + +Trk::TrackScore InDet::InDetNNScoringTool::simpleScore( const Trk::Track& track, const Trk::TrackSummary& trackSummary ) const +{ + int numPixel = trackSummary.get(Trk::numberOfPixelHits); + int numSCT = trackSummary.get(Trk::numberOfSCTHits); + int numTRT = trackSummary.get(Trk::numberOfTRTHits); + int numTRTTube = trackSummary.get(Trk::numberOfTRTTubeHits); + int numPixelHoles = trackSummary.get(Trk::numberOfPixelHoles); + int numSCTHoles = trackSummary.get(Trk::numberOfSCTHoles); + int numSCTDoubleHoles = trackSummary.get(Trk::numberOfSCTDoubleHoles); + int numPixelDead = trackSummary.get(Trk::numberOfPixelDeadSensors); + int numSCTDead = trackSummary.get(Trk::numberOfSCTDeadSensors); + + if (numPixelDead<0) numPixelDead = 0; + if (numSCTDead<0) numSCTDead = 0; + + // is this a track from the pattern or a fitted track ? + bool ispatterntrack = (track.info().trackFitter()==Trk::TrackInfo::Unknown); + // + // --- reject bad tracks + // + // + // --- the following cuts we only apply to fitted tracks + // + if (ispatterntrack) { + ATH_MSG_DEBUG ("==> this is a pattern track, no hit cuts !"); + } else { + ATH_MSG_DEBUG ("==> this is a refitted track, so we can use the chi2 and other stuff ! "); + + // NdF cut : + if (track.fitQuality()) { + ATH_MSG_DEBUG ("numberDoF = "<<track.fitQuality()->numberDoF()); + } + // Number of double Holes + if (numSCTDoubleHoles>=0) { + if (numSCTDoubleHoles > m_maxDoubleHoles ) { + ATH_MSG_DEBUG ("Track has "<< numSCTDoubleHoles <<" double holes, reject it!"); + return Trk::TrackScore(0); + } + } + // Number of Si (Pixel+SCT) Holes + if (numSCTHoles>=0 && numPixelHoles>=0) { + if (numPixelHoles+numSCTHoles > m_maxSiHoles ) { + ATH_MSG_DEBUG ("Track has "<< numPixelHoles <<" Pixel and " << numSCTHoles << " SCT holes, reject it!"); + return Trk::TrackScore(0); + } + } + // Number of Pixel Holes + if ( numPixelHoles>=0 ) { + if (numPixelHoles > m_maxPixelHoles ) { + ATH_MSG_DEBUG ("Track has "<< numPixelHoles <<" Pixel holes, reject it!"); + return Trk::TrackScore(0); + } + } + // Number of SCT Holes + if ( numSCTHoles>=0 ) { + if ( numSCTHoles > m_maxSctHoles ) { + ATH_MSG_DEBUG ("Track has "<< numSCTHoles << " SCT holes, reject it!"); + return Trk::TrackScore(0); + } + } + // TRT cut + if (numTRT > 0 && numTRT < m_minTRTonTrk) { + ATH_MSG_DEBUG ("Track has " << numTRT << " TRT hits, reject it"); + return Trk::TrackScore(0); + } + // TRT precision hits cut + if (numTRT >= 15 && ((double)(numTRT-numTRTTube))/numTRT < m_minTRTprecision) { + ATH_MSG_DEBUG ("Track has " << ((double)numTRTTube)/numTRT << " TRT tube hit fraction, reject it"); + return Trk::TrackScore(0); + } + // Number of Si Clusters + if ( numSCT>=0 && numPixel>=0) { + if (numPixel+numSCT+numPixelDead+numSCTDead < m_minSiClusters) { + ATH_MSG_DEBUG ("Track has " << numPixel+numSCT << " Si clusters and " << numPixelDead+numSCTDead << " dead sensors, reject it"); + return Trk::TrackScore(0); + } + } + // Number of pixel clusters + if (numPixel>=0 && numPixel < m_minPixel) { + ATH_MSG_DEBUG ("Track has " << numPixel << " pixel hits, reject it"); + return Trk::TrackScore(0); + } + } + // + // --- kinematic selection (done as well on input ?) + // + // --- beam spot position + Amg::Vector3D beamSpotPosition(0,0,0); + SG::ReadCondHandle<InDet::BeamSpotData> beamSpotHandle { m_beamSpotKey }; + if (beamSpotHandle.isValid()) beamSpotPosition = beamSpotHandle->beamVtx().position(); + // --- create surface + Trk::PerigeeSurface perigeeSurface(beamSpotPosition); + + const Trk::TrackParameters* input = track.trackParameters()->front(); + + // cuts on parameters + EventContext ctx = Gaudi::Hive::currentContext(); + SG::ReadCondHandle<AtlasFieldCacheCondObj> readHandle{m_fieldCacheCondObjInputKey, ctx}; + const AtlasFieldCacheCondObj* fieldCondObj{*readHandle}; + if (fieldCondObj == nullptr) { + ATH_MSG_ERROR("simpleScore: Failed to retrieve AtlasFieldCacheCondObj with key " << m_fieldCacheCondObjInputKey.key()); + return Trk::TrackScore(0); + } + MagField::AtlasFieldCache fieldCache; + fieldCondObj->getInitializedCache (fieldCache); + + if (fieldCache.solenoidOn()){ + if (fabs(input->pT()) < m_minPt) { + ATH_MSG_DEBUG ("Track pt < "<<m_minPt<<", reject it"); + return Trk::TrackScore(0); + } + } + if (fabs(input->eta()) > m_maxEta) { + ATH_MSG_DEBUG ("Track eta > "<<m_maxEta<<", reject it"); + return Trk::TrackScore(0); + } + + // uses perigee on track or extrapolates, no material in any case, we cut on impacts + // add back extrapolation without errors + { + std::unique_ptr<const Trk::TrackParameters> parm( m_extrapolator->extrapolateDirectly(*input, perigeeSurface) ); + + const Trk::Perigee*extrapolatedPerigee = dynamic_cast<const Trk::Perigee*> (parm.get()); + if (!extrapolatedPerigee) { + ATH_MSG_WARNING( "Extrapolation of perigee failed, this should never happen" ); + return Trk::TrackScore(0); + } + + ATH_MSG_VERBOSE ("extrapolated perigee: "<<*extrapolatedPerigee); + if (fabs(extrapolatedPerigee->parameters()[Trk::z0]) > m_maxZImp) { + ATH_MSG_DEBUG ("Track Z impact > "<<m_maxZImp<<", reject it"); + return Trk::TrackScore(0); + } + + double maxD0 = m_maxRPhiImp; + if(m_useEmClusSeed) { + if (isEmCaloCompatible( track ) ) { + maxD0 = m_maxRPhiImpEM; + } + } + if (fabs(extrapolatedPerigee->parameters()[Trk::d0]) > maxD0) { + ATH_MSG_DEBUG ("Track Rphi impact > "<<m_maxRPhiImp<<", reject it"); + return Trk::TrackScore(0); + } + + if (m_useAmbigFcn) { + if (m_nnCutThreshold > 0.0) { // check if nn cut is enabled + if (track.fitQuality()) { // check if track has been fitted + if (calcNnScore(track, trackSummary, extrapolatedPerigee) < m_nnCutThreshold) { + ATH_MSG_DEBUG ("Rejecting track for falling below nn threshold"); + return Trk::TrackScore(0); // scores of 0 are rejected by ambisolver + } + } + } + } + } + + // + // --- now start scoring + // + + if ( m_useAmbigFcn || m_useTRT_AmbigFcn) { + + // + // --- use scoring function + // + + return ambigScore(track,trackSummary); + + } else { + + // + // use classical score + // + // score of 100 per track + Trk::TrackScore score (100); + // --- summary score analysis + for (int i=0; i<Trk::numberOfTrackSummaryTypes; ++i) { + int value = trackSummary.get(static_cast<Trk::SummaryType>(i)); + //value is -1 if undefined. + if (value>0) { + score+=m_summaryTypeScore[i]*value; + ATH_MSG_DEBUG ("\tType ["<<i<<"], value \t= "<<value<<"], score \t="<<score); + } + } + // --- prob(chi2,NDF), protect for chi2 <= 0 + if (track.fitQuality()!=0 && track.fitQuality()->chiSquared()>0 && track.fitQuality()->numberDoF()>0 ) { + double p = 1.0-Genfun::CumulativeChiSquare(track.fitQuality()->numberDoF())(track.fitQuality()->chiSquared()); + if ( p > 0 ) + score += log10( p ); + else + score -= 50; + } + + return score; + } + +} + +//--------------------------------------------------------------------------------------------------------------------- + +Trk::TrackScore InDet::InDetNNScoringTool::ambigScore( const Trk::Track& track, const Trk::TrackSummary& trackSummary ) const +{ + // + // --- start with bonus for high pt tracks + // + // double prob = 1.; + double pt = fabs(track.trackParameters()->front()->pT()); + double prob = log10( pt ) - 1.; // 100 MeV is min and gets score 1 + ATH_MSG_DEBUG ("Modifier for pt = " << pt / 1000. << " GeV is: "<< prob); + + // + // --- prob and cuts on holes + // + if (m_usePixel) { + // --- Pixel holes + int iPixHoles = trackSummary.get(Trk::numberOfPixelHoles); + if ( iPixHoles > -1 && m_maxPixHoles > 0) { + if (iPixHoles > m_maxPixHoles) { + prob /= (iPixHoles - m_maxPixHoles + 1); // holes are bad ! + iPixHoles = m_maxPixHoles; + } + prob *= m_factorPixHoles[iPixHoles]; + ATH_MSG_DEBUG ("Modifier for " << iPixHoles << " Pixel holes: "<<m_factorPixHoles[iPixHoles] + << " New score now: " << prob); + } + } + + if (m_useSCT) { + // --- SCT holes + int iSCT_Holes = trackSummary.get(Trk::numberOfSCTHoles); + if (iSCT_Holes > -1 && m_maxSCT_Holes > 0) { + if (iSCT_Holes > m_maxSCT_Holes) { + prob /= (iSCT_Holes - m_maxSCT_Holes + 1); // holes are bad ! + iSCT_Holes = m_maxSCT_Holes; + } + prob *= m_factorSCT_Holes[iSCT_Holes]; + ATH_MSG_DEBUG ("Modifier for " << iSCT_Holes << " SCT holes: "<<m_factorSCT_Holes[iSCT_Holes] + << " New score now: " << prob); + } + // --- SCT double holes + int iDblHoles = trackSummary.get(Trk::numberOfSCTDoubleHoles); + if (iDblHoles > -1 && m_maxDblHoles > 0) { + if (iDblHoles > m_maxDblHoles) { + prob /= (iDblHoles - m_maxDblHoles + 1); // holes are bad ! + iDblHoles = m_maxDblHoles; + } + prob *= m_factorDblHoles[iDblHoles]; + ATH_MSG_DEBUG ("Modifier for " << iDblHoles << " double holes: "<<m_factorDblHoles[iDblHoles] + << " New score now: " << prob); + } + } + // + // --- prob for other counters + // + if (m_usePixel) { + + // ME: this if statement needs to be removed... + // --- count layers only if holes are not searched for + // if (trackSummary.get(Trk::numberOfPixelHoles) == -1) { + + // --- Pixel layers + int iPixLay = trackSummary.get(Trk::numberOfContribPixelLayers); + if (iPixLay > -1 && m_maxPixLay > 0) { + if (iPixLay > m_maxPixLay) { + prob *= (iPixLay - m_maxPixLay + 1); // layers are good ! + iPixLay = m_maxPixLay; + } + prob *= m_factorPixLay[iPixLay]; + ATH_MSG_DEBUG ("Modifier for " << iPixLay << " Pixel layers: "<<m_factorPixLay[iPixLay] + << " New score now: " << prob); + } + + // --- Pixel hits + int pixelHits = trackSummary.get(Trk::numberOfPixelHits); + if (pixelHits > -1 && m_maxPixelHits > 0) { + if (pixelHits > m_maxPixelHits) { + prob *= (pixelHits - m_maxPixelHits + 1); // hits are good ! + pixelHits = m_maxPixelHits; + } + prob *= m_factorPixelHits[pixelHits]; + ATH_MSG_DEBUG ("Modifier for " << pixelHits << " Pixel hits: "<<m_factorPixelHits[pixelHits] + << " New score now: " << prob); + } + // --- Pixel blayer hits + int bLayerHits = trackSummary.get(Trk::numberOfInnermostPixelLayerHits); + if (bLayerHits > -1 && m_maxB_LayerHits > 0) { + if (bLayerHits > m_maxB_LayerHits) { + prob *= (bLayerHits - m_maxB_LayerHits + 1); // hits are good ! + bLayerHits = m_maxB_LayerHits; + } + prob *= m_factorB_LayerHits[bLayerHits]; + ATH_MSG_DEBUG ("Modifier for " << bLayerHits << " b-layer hits: "<<m_factorB_LayerHits[bLayerHits] + << " New score now: " << prob); + } + // --- Pixel Ganged fakes + int pixelGangedFakes = trackSummary.get(Trk::numberOfGangedFlaggedFakes); + if (pixelGangedFakes > -1 && m_maxGangedFakes > 0) { + if (pixelGangedFakes > m_maxGangedFakes) { + prob /= (pixelGangedFakes - m_maxGangedFakes + 1); // ganged are bad ! + pixelGangedFakes = m_maxGangedFakes; + } + prob *= m_factorGangedFakes[pixelGangedFakes]; + ATH_MSG_DEBUG ("Modifier for " << pixelGangedFakes << " ganged fakes hits: "<<m_factorGangedFakes[pixelGangedFakes] + << " New score now: " << prob); + } + } + + int iHits = 0; + iHits += m_usePixel ? trackSummary.get(Trk::numberOfPixelHits) : 3; // if Pixel off, do not count as inefficient + iHits += m_useSCT ? trackSummary.get(Trk::numberOfSCTHits) : 8; // if SCT off, do not count as inefficient + if (iHits > -1 && m_maxHits > 0) { + if (iHits > m_maxHits) { + prob *= (iHits - m_maxHits + 1); // hits are good ! + iHits = m_maxHits; + } + prob *= m_factorHits[iHits]; + ATH_MSG_DEBUG ("Modifier for " << iHits << " Sihits: "<<m_factorHits[iHits] + << " New score now: " << prob); + } + + // + // --- special treatment for TRT hits + // + int iTRT_Hits = trackSummary.get(Trk::numberOfTRTHits); + int iTRT_Outliers = trackSummary.get(Trk::numberOfTRTOutliers); + // + if ( iTRT_Hits > 0 && m_maxTrtRatio > 0) { + // get expected number of TRT hits + double nTrtExpected = 30.; + nTrtExpected = m_selectortool->minNumberDCs(track.trackParameters()->front()); + ATH_MSG_DEBUG ("Expected number of TRT hits: " << nTrtExpected << " for eta: " + << fabs(track.trackParameters()->front()->eta())); + double ratio = (nTrtExpected != 0) ? iTRT_Hits / nTrtExpected : 0; + if (ratio > m_boundsTrtRatio[m_maxTrtRatio]) ratio = m_boundsTrtRatio[m_maxTrtRatio]; + for (int i=0; i<m_maxTrtRatio; ++i) { + if ( m_boundsTrtRatio[i] < ratio && ratio <= m_boundsTrtRatio[i+1]) { + prob*= m_factorTrtRatio[i]; + ATH_MSG_DEBUG ("Modifier for " << iTRT_Hits << " TRT hits (ratio " << ratio + << ") is : "<< m_factorTrtRatio[i] << " New score now: " << prob); + break; + } + } + } + // + if ( iTRT_Hits > 0 && iTRT_Outliers >= 0 && m_maxTrtFittedRatio > 0) { + double fitted = double(iTRT_Hits) / double(iTRT_Hits + iTRT_Outliers); + if (fitted > m_boundsTrtFittedRatio[m_maxTrtFittedRatio]) fitted = m_boundsTrtFittedRatio[m_maxTrtFittedRatio]; + for (int i=0; i<m_maxTrtFittedRatio; ++i) { + if (fitted <= m_boundsTrtFittedRatio[i+1]) { + prob*= m_factorTrtFittedRatio[i]; + ATH_MSG_DEBUG ("Modifier for TRT fitted ratio of " << fitted + << " is : "<< m_factorTrtFittedRatio[i] << " New score now: " << prob); + break; + } + } + } + + // is this a track from the pattern or a fitted track ? + bool ispatterntrack = (track.info().trackFitter()==Trk::TrackInfo::Unknown); + + // + // --- non binned Chi2 + // + if (!ispatterntrack) { + if (track.fitQuality()!=0 && track.fitQuality()->chiSquared()>0 && track.fitQuality()->numberDoF()>0 ) { + int indf = track.fitQuality()->numberDoF(); + double chi2 = track.fitQuality()->chiSquared(); + double fac = 1. / log10 (10. + 10. * chi2 / indf); // very soft chi2 + prob *= fac; + ATH_MSG_DEBUG ("Modifier for chi2 = " << chi2 << " and NDF = " << indf + << " is : "<< fac << " New score now: " << prob); + + } + } + // + // --- fit quality prob + // + if ( !ispatterntrack && (m_useSigmaChi2) && track.fitQuality() ) { + + int ndf = track.fitQuality()->numberDoF(); + double chi2 = track.fitQuality()->chiSquared(); + if (ndf > 0) { + // + // --- special variable for bad chi2 distribution + // + if (m_useSigmaChi2) { + int sigmaChi2times100 = trackSummary.get(Trk::standardDeviationOfChi2OS); + if (sigmaChi2times100 > 0) { + double testvar = double(sigmaChi2times100)/100. - sqrt(2.*chi2/ndf); + if (msgLvl(MSG::VERBOSE)) msg(MSG::VERBOSE) << "sigma chi2 = " << testvar << endmsg; + if ( testvar< m_boundsSigmaChi2[0] ) { + prob *= m_factorSigmaChi2[0]; + ATH_MSG_DEBUG ("Modifier for " << testvar << " sigma chi2: "<< m_factorSigmaChi2[0] + << " New score now: " << prob); + } else if (m_boundsSigmaChi2[m_maxSigmaChi2] <= testvar) { + prob *= m_factorSigmaChi2[m_maxSigmaChi2-1]; + ATH_MSG_DEBUG ("Modifier for " << testvar << " sigma chi2: "<< m_factorSigmaChi2[m_maxSigmaChi2-1] + << " New score now: " << prob); + } else { + for (int i = 0 ; i<m_maxSigmaChi2 ; ++i ) { + if ( m_boundsSigmaChi2[i]<=testvar && testvar<m_boundsSigmaChi2[i+1] ) { + prob *= m_factorSigmaChi2[i]; + ATH_MSG_DEBUG ("Modifier for " << testvar << " sigma chi2: "<< m_factorSigmaChi2[i] + << " New score now: " << prob); + break; + } + } + } + } + } + } + } + + return Trk::TrackScore(prob); +} + +//--------------------------------------------------------------------------------------------------------------------- + +void InDet::InDetNNScoringTool::setupScoreModifiers() +{ + // + // --- number of Pixel holes + // + // --- NewTracking and BackTracking + const int maxPixHoles = 2; // there is an explicit cut + const double goodPixHoles[maxPixHoles+1] = {1.0 , 0.04 , 0.004 }; + const double fakePixHoles[maxPixHoles+1] = {1.0 , 0.30 , 0.200 }; + // put it into the private members + m_maxPixHoles = maxPixHoles; + for (int i=0; i<=m_maxPixHoles; ++i) m_factorPixHoles.push_back(goodPixHoles[i]/fakePixHoles[i]); + + // + // --- number of SCT holes + // + if (!m_useTRT_AmbigFcn) { + // --- NewTracking + const int maxSCT_Holes = 5; // moved from 3 -> 5 , there is an explicit cut anyway + const double goodSCT_Holes[maxSCT_Holes+1] = { 1.0 , 0.06 , 0.010 , 0.0007, 0.0005, 0.0003 }; + const double fakeSCT_Holes[maxSCT_Holes+1] = { 1.0 , 0.15 , 0.100 , 0.0100, 0.0100, 0.0100 }; + // put it into the private members + m_maxSCT_Holes = maxSCT_Holes; + for (int i=0; i<=m_maxSCT_Holes; ++i) m_factorSCT_Holes.push_back(goodSCT_Holes[i]/fakeSCT_Holes[i]); + } else { + // --- BackTracking + const int maxSCT_Holes = 6; + const double goodSCT_Holes[maxSCT_Holes+1] = {0.910, 0.074, 0.014, 0.001, 0.001, 0.00001, 0.00001}; + const double fakeSCT_Holes[maxSCT_Holes+1] = {0.910, 0.192, 0.229, 0.061, 0.065, 0.016 , 0.025}; + // put it into the private members + m_maxSCT_Holes = maxSCT_Holes; + for (int i=0; i<=m_maxSCT_Holes; ++i) m_factorSCT_Holes.push_back(goodSCT_Holes[i]/fakeSCT_Holes[i]); + } + + // + // --- number of SCT double holes + // + // --- NewTracking and BackTracking + const int maxDblHoles = 3; // there is a cut on this anyway ! + const double goodDblHoles[maxDblHoles+1] = { 1. , 0.03 , 0.007 , 0.0003 }; + const double fakeDblHoles[maxDblHoles+1] = { 1. , 0.09 , 0.09 , 0.008 }; + // put it into the private members + m_maxDblHoles = maxDblHoles; + for (int i=0; i<=m_maxDblHoles; ++i) m_factorDblHoles.push_back(goodDblHoles[i]/fakeDblHoles[i]); + + // + // --- number of Blayer hits + // + if (!m_useTRT_AmbigFcn) { + // --- NewTracking + const int maxB_LayerHits = 3; + const double goodB_LayerHits[maxB_LayerHits+1] = {0.203, 0.732, 0.081, 0.010}; + const double fakeB_LayerHits[maxB_LayerHits+1] = {0.808, 0.174, 0.018, 0.002}; + // put it into the private members + m_maxB_LayerHits = maxB_LayerHits; + for (int i=0; i<=m_maxB_LayerHits; ++i) m_factorB_LayerHits.push_back(goodB_LayerHits[i]/fakeB_LayerHits[i]); + } else { + // --- BackTracking + const int maxB_LayerHits = 3; + const double goodB_LayerHits[maxB_LayerHits+1] = {0.605, 0.349, 0.044, 0.010}; + const double fakeB_LayerHits[maxB_LayerHits+1] = {0.865, 0.124, 0.011, 0.002}; + // put it into the private members + m_maxB_LayerHits = maxB_LayerHits; + for (int i=0; i<=m_maxB_LayerHits; ++i) m_factorB_LayerHits.push_back(goodB_LayerHits[i]/fakeB_LayerHits[i]); + } + + // + // --- number of Pixel hits without Blayer + // + if (!m_useTRT_AmbigFcn) { + // --- NewTracking + const int maxPixelHits = 8; // we see up to 8 with IBL (was 6) + const double goodPixelHits[maxPixelHits+1] = {0.095, 0.031, 0.118, 0.615, 0.137, 0.011, 0.01 , 0.011, 0.012}; + const double fakePixelHits[maxPixelHits+1] = {0.658, 0.100, 0.091, 0.124, 0.026, 0.002, 0.001 , 0.001, 0.001}; + m_maxPixelHits = maxPixelHits; + for (int i=0; i<=m_maxPixelHits; ++i) m_factorPixelHits.push_back(goodPixelHits[i]/fakePixelHits[i]); + } else { + // --- BackTracking + const int maxPixelHits = 8; // we see up to 8 with IBL (was 6) + const double goodPixelHits[maxPixelHits+1] = {0.401, 0.079, 0.140, 0.291, 0.011, 0.078, 0.01 , 0.011, 0.012}; + const double fakePixelHits[maxPixelHits+1] = {0.673, 0.138, 0.113, 0.057, 0.002, 0.011, 0.001 , 0.001, 0.001}; + m_maxPixelHits = maxPixelHits; + for (int i=0; i<=m_maxPixelHits; ++i) m_factorPixelHits.push_back(goodPixelHits[i]/fakePixelHits[i]); + } + + // + // --- number of Pixel layers + // + if (!m_useTRT_AmbigFcn) { + // --- NewTracking + const int maxPixLay = 7; // 3 barrel, 3 endcap, IBL, in practice one should see maybe 5 (was 3) + const double goodPixLay[maxPixLay+1] = {0.095, 0.033, 0.131, 0.740, 0.840, 0.940, 1.040,1.140}; + const double fakePixLay[maxPixLay+1] = {0.658, 0.106, 0.092, 0.144, 0.144, 0.144, 0.144,0.144}; + // put it into the private members + m_maxPixLay = maxPixLay; + for (int i=0; i<=m_maxPixLay; ++i) m_factorPixLay.push_back(goodPixLay[i]/fakePixLay[i]); + } else { + // --- BackTracking + const int maxPixLay = 7; // 3 barrel, 3 endcap, IBL, in practice one should see maybe 5 (was 5) + const double goodPixLay[maxPixLay+1] = {0.401, 0.088, 0.152, 0.355, 0.405, 0.455, 0.505, 0.555}; + const double fakePixLay[maxPixLay+1] = {0.673, 0.146, 0.115, 0.065, 0.065, 0.065, 0.065, 0.065}; + // put it into the private members + m_maxPixLay = maxPixLay; + for (int i=0; i<=m_maxPixLay; ++i) m_factorPixLay.push_back(goodPixLay[i]/fakePixLay[i]); + } + + // + // --- number of Pixel Ganged Fakes + // + // --- NewTracking and BackTracking + const int maxGangedFakes = 2; // there is an explicit cut + const double goodGangedFakes[maxGangedFakes+1] = {0.62 , 0.23 , 0.15 }; + const double fakeGangedFakes[maxGangedFakes+1] = {0.12 , 0.41 , 0.47 }; + // put it into the private members + m_maxGangedFakes = maxGangedFakes; + for (int i=0; i<=m_maxGangedFakes; ++i) m_factorGangedFakes.push_back(goodGangedFakes[i]/fakeGangedFakes[i]); + + // + // --- total number of SCT+Pixel hits + // + // --- NewTracking and BackTracking + const int maxHits = 19; // there is a min cut on this anyway ! + const double goodSiHits[maxHits+1] = { 0.001 , 0.002 , 0.003 , 0.004 , 0.01 , 0.01 , 0.01 , + 0.015 , 0.02 , 0.06 , 0.1 , 0.3 , 0.2 , 0.50 , 0.055, + 0.03 , 0.015 , 0.010 , 0.002 , 0.0005 }; + const double fakeSiHits[maxHits+1] = { 1.0 , 1.0 , 1.0 , 1.0 , 0.5 , 0.25 , 0.15 , + 0.20 , 0.1 , 0.2 , 0.08 , 0.07 , 0.035 , 0.08 , 0.008, + 0.004 , 0.0015 , 0.0008 , 0.0001 , 0.00001 }; + // put it into the private members + m_maxHits = maxHits; + for (int i=0; i<=m_maxHits; ++i) m_factorHits.push_back(goodSiHits[i]/fakeSiHits[i]); + + // + // --- ratio of TRT hits over expected + // + // --- NewTracking and BackTracking + const int maxTrtRatio = 7 ; + const double TrtRatioBounds[maxTrtRatio+1] = { 0, 0.2, 0.4, 0.6, 0.8, 1.0, 1.2, 2.4}; + // this needs tuning !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!! + const double goodTrtRatio[maxTrtRatio] = { 0.05, 0.11, 0.12, 0.15, 0.20, 0.16, 0.17}; + const double fakeTrtRatio[maxTrtRatio] = { 0.6 , 0.08, 0.06, 0.05, 0.04, 0.03, 0.03}; + // put it into the private members + m_maxTrtRatio = maxTrtRatio; + for (int i=0; i<m_maxTrtRatio; ++i) m_factorTrtRatio.push_back(goodTrtRatio[i]/fakeTrtRatio[i]); + for (int i=0; i<=m_maxTrtRatio; ++i) m_boundsTrtRatio.push_back(TrtRatioBounds[i]); + + // + // --- ratio of TRT fitted to (fitted+outliers) + // + // --- NewTracking and BackTracking + const int maxTrtFittedRatio = 4; + const double TrtFittedRatioBounds[maxTrtFittedRatio+1] = { 0, 0.3, 0.6, 0.9, 1.0}; + // this needs tuning !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!! + const double goodTrtFittedRatio[maxTrtFittedRatio] = { 0.1, 0.2, 0.3, 0.5}; + const double fakeTrtFittedRatio[maxTrtFittedRatio] = { 0.6, 0.1, 0.1, 0.1}; + // put it into the private members + m_maxTrtFittedRatio = maxTrtFittedRatio; + for (int i=0; i<m_maxTrtFittedRatio; ++i) m_factorTrtFittedRatio.push_back(goodTrtFittedRatio[i]/fakeTrtFittedRatio[i]); + for (int i=0; i<=m_maxTrtFittedRatio; ++i) m_boundsTrtFittedRatio.push_back(TrtFittedRatioBounds[i]); + + + // + // --- sigma chi2 + // + if (!m_useSigmaChi2) { + m_maxSigmaChi2 = -1 ; + } else { + // --- NewTracking and BackTracking + const int maxSigmaChi2 = 13 ; + const double SigmaChi2Bounds[maxSigmaChi2+1] = { -5.,-4.,-3.,-2.,-1.,0.,1.,2.,3.,4.,5.,6.,7.,8.}; + const double goodSigmaChi2[maxSigmaChi2] = {0.00004, 0.0004, 0.002, 0.15, 0.8, 0.015, 0.01 , 0.009, 0.008, 0.0007 , 0.0006 , 0.0005, 0.00004}; + const double fakeSigmaChi2[maxSigmaChi2] = {0.0008 , 0.005 , 0.02 , 0.2 , 0.3, 0.1 , 0.1 , 0.1 , 0.1 , 0.01 , 0.01 , 0.01 , 0.001}; + // put it into the private members + m_maxSigmaChi2 = maxSigmaChi2; + for (int i=0; i<m_maxSigmaChi2; ++i) m_factorSigmaChi2.push_back(goodSigmaChi2[i]/fakeSigmaChi2[i]); + for (int i=0; i<=m_maxSigmaChi2; ++i) m_boundsSigmaChi2.push_back(SigmaChi2Bounds[i]); + } + + // + // --- debug output + // + if (msgLvl(MSG::VERBOSE)) { + + for (int i=0; i<=m_maxPixHoles; ++i) + msg(MSG::VERBOSE) << "Modifier for " << i << " Pixel holes: " << m_factorPixHoles[i] <<endmsg; + + for (int i=0; i<=m_maxSCT_Holes; ++i) + msg(MSG::VERBOSE) << "Modifier for " << i << " SCT holes: " << m_factorSCT_Holes[i] <<endmsg; + + for (int i=0; i<=m_maxDblHoles; ++i) + msg(MSG::VERBOSE) << "Modifier for " << i << " double SCT holes: " << m_factorDblHoles[i] <<endmsg; + + for (int i=0; i<=m_maxPixLay; ++i) + msg(MSG::VERBOSE) << "Modifier for " << i << " Pixel layers: " << m_factorPixLay[i] <<endmsg; + + for (int i=0; i<=m_maxB_LayerHits; ++i) + msg(MSG::VERBOSE) << "Modifier for " << i << " b-layer hits: " << m_factorB_LayerHits[i] <<endmsg; + + for (int i=0; i<=m_maxPixelHits; ++i) + msg(MSG::VERBOSE) << "Modifier for " << i << " Pixel hits: " << m_factorPixelHits[i] <<endmsg; + + for (int i=0; i<=m_maxGangedFakes; ++i) + msg(MSG::VERBOSE) << "Modifier for " << i << " ganged fakes: " << m_factorGangedFakes[i] <<endmsg; + + for (int i=0; i<=m_maxHits; ++i) + msg(MSG::VERBOSE) << "Modifier for " << i << " Si hits: " << m_factorHits[i] <<endmsg; + + for (int i=0; i<m_maxTrtRatio; ++i) + msg(MSG::VERBOSE) << "Modifier for " << m_boundsTrtRatio[i] << " < TRT ratio < " + << m_boundsTrtRatio[i+1] <<" : " <<m_factorTrtRatio[i] <<endmsg; + + for (int i=0; i<m_maxTrtFittedRatio; ++i) + msg(MSG::VERBOSE) << "Modifier for " << m_boundsTrtFittedRatio[i] << " < TRT fitted ratio < " + << m_boundsTrtFittedRatio[i+1] <<" : " <<m_factorTrtFittedRatio[i] <<endmsg; + + + // only if used + for (int i=0; i<m_maxSigmaChi2; ++i) + msg(MSG::VERBOSE) << "Modifier for " << m_boundsSigmaChi2[i] << " < sigma(chi2) - sqrt(2chi2) < " << m_boundsSigmaChi2[i+1] + <<" : " <<m_factorSigmaChi2[i] <<endmsg; + } + +} + +bool InDet::InDetNNScoringTool::isEmCaloCompatible(const Trk::Track& track) const +{ + const Trk::TrackParameters * Tp = track.trackParameters()->front(); + + //Switch to the track parameters of the first measurment instead of the perigee parameters + ATH_MSG_VERBOSE ("--> Looping over TSOS's"); + for (auto tsos : *track.trackStateOnSurfaces() ) { + // get measurment from TSOS + auto meas = tsos->measurementOnTrack(); + auto tp = tsos->trackParameters(); + // if we do not have a measurement, we should just mark it + if (!meas || !tp) { + continue; + } else { + Tp = tp; + break; + } + } + + const double pi = M_PI, pi2 = 2.*M_PI; + + double F = Tp->momentum().phi(); + double E = Tp->momentum().eta(); + double R = Tp->position().perp(); + double Z = Tp->position().z(); + + SG::ReadHandle<InDet::ROIInfoVec> calo(m_caloROIInfoKey); + for( const InDet::ROIInfo &ccROI : *calo) { + + double df = fabs(F-ccROI.emF); + if(df > pi ) df = fabs(pi2-df); + if(df < m_phiWidthEm) { + //Correct eta of cluster to take into account the z postion of the track + double newZ = ccROI.emZ - Z; + double newR = ccROI.emR - R; + double newEta = atanh( newZ / sqrt( newR*newR + newZ*newZ ) ); + double de = fabs(E-newEta); + + if(de < m_etaWidthEm) return true; + } + } + return false; +} + +Trk::TrackScore InDet::InDetNNScoringTool::calcNnScore(const Trk::Track &track, const Trk::TrackSummary &trackSummary, const Trk::Perigee *extrapolatedPerigee) const +{ + ATH_MSG_DEBUG("Using NN Score Function"); + // initialize with dummy score + double DNNscore(-1.0); + + // This calculates a variant of the delta-eta variable used in large-d0 seeding + double d0 = extrapolatedPerigee->parameters()[Trk::d0]; + double z0 = extrapolatedPerigee->parameters()[Trk::z0]; + double deltaEta = std::abs(std::atan2(fabs(d0), z0) - 2 * std::atan(std::exp(-track.trackParameters()->front()->eta()))); + + // Build dictionary of inputs for lwtnn to use + // It is ok to fill this with more variables than the model uses + // as long as no variables are missing + std::map<std::string, double> trackInputs{ + {"pT", track.trackParameters()->front()->pT()}, + {"eta", track.trackParameters()->front()->eta()}, + {"numberOfSCTHoles", (double) trackSummary.get(Trk::numberOfSCTHoles)}, + {"numberOfSCTHits", (double) trackSummary.get(Trk::numberOfSCTHits)}, + {"numberDoF", (double) track.fitQuality()->numberDoF()}, + {"Sihits", (double) (trackSummary.get(Trk::numberOfPixelHits) + trackSummary.get(Trk::numberOfSCTHits))}, + {"d0", d0}, + {"z0", z0}, + {"deltaEta", deltaEta} + }; + + // Set up the nodes used for inputs + std::map<std::string, std::map<std::string, double> > inputs{ + {"trackInputs", trackInputs} + }; + + // Evaluate the network + lwt::ValueMap output = m_graph->compute(inputs); + + // Obtain the discriminant associated with the single output node + DNNscore = output["nnScore"]; + // Return the discriminant as the score + ATH_MSG_DEBUG("DNNscore: " << DNNscore); + if (DNNscore < m_nnCutThreshold) + ATH_MSG_DEBUG("DNNscore is below threshold of " << m_nnCutThreshold << ", rejecting track. "); + if (DNNscore < 0) + ATH_MSG_ERROR("DNNscore should be 0 or greater."); + return Trk::TrackScore(DNNscore); +} + diff --git a/InnerDetector/InDetRecTools/InDetTrackScoringTools/src/components/InDetTrackScoringTools_entries.cxx b/InnerDetector/InDetRecTools/InDetTrackScoringTools/src/components/InDetTrackScoringTools_entries.cxx index 955e13e7ff36227651882df26f486a12b0d348a4..42d50f576f6b184dd8f89369efecc8e874eb87b1 100644 --- a/InnerDetector/InDetRecTools/InDetTrackScoringTools/src/components/InDetTrackScoringTools_entries.cxx +++ b/InnerDetector/InDetRecTools/InDetTrackScoringTools/src/components/InDetTrackScoringTools_entries.cxx @@ -1,9 +1,11 @@ #include "InDetTrackScoringTools/InDetAmbiScoringTool.h" +#include "InDetTrackScoringTools/InDetNNScoringTool.h" #include "InDetTrackScoringTools/InDetCosmicScoringTool.h" #include "InDetTrackScoringTools/InDetTrtTrackScoringTool.h" #include "../ROIInfoVecAlg.h" DECLARE_COMPONENT( InDet::InDetAmbiScoringTool ) +DECLARE_COMPONENT( InDet::InDetNNScoringTool ) DECLARE_COMPONENT( InDet::InDetCosmicScoringTool ) DECLARE_COMPONENT( InDet::InDetTrtTrackScoringTool ) DECLARE_COMPONENT( ROIInfoVecAlg )