From 3214584c16cc05aa83ee651db1bde625c4acdcb4 Mon Sep 17 00:00:00 2001 From: Gabriel Facini <gabriel.facini@cern.ch> Date: Tue, 3 Nov 2020 19:47:11 +0000 Subject: [PATCH] two bug fixes in portion focused on conversions (pairSelection) - reset counter of N split shared pixels to 0 - set hasSharedPixel consistently with rest of tool --- .../share/ConfiguredNewTrackingSiPattern.py | 2 +- .../InDetDenseEnvAmbiTrackSelectionTool.h | 328 +-- .../InDetDenseEnvAmbiTrackSelectionTool.cxx | 1797 +++++++++-------- .../PROCTools/data/master_q221_AOD_digest.ref | 10 +- .../PROCTools/data/master_q431_AOD_digest.ref | 18 +- 5 files changed, 1166 insertions(+), 989 deletions(-) mode change 100755 => 100644 InnerDetector/InDetRecTools/InDetAmbiTrackSelectionTool/InDetAmbiTrackSelectionTool/InDetDenseEnvAmbiTrackSelectionTool.h mode change 100755 => 100644 InnerDetector/InDetRecTools/InDetAmbiTrackSelectionTool/src/InDetDenseEnvAmbiTrackSelectionTool.cxx diff --git a/InnerDetector/InDetExample/InDetRecExample/share/ConfiguredNewTrackingSiPattern.py b/InnerDetector/InDetExample/InDetRecExample/share/ConfiguredNewTrackingSiPattern.py index 9257ceddacd..33db3f13da4 100644 --- a/InnerDetector/InDetExample/InDetRecExample/share/ConfiguredNewTrackingSiPattern.py +++ b/InnerDetector/InDetExample/InDetRecExample/share/ConfiguredNewTrackingSiPattern.py @@ -458,7 +458,7 @@ class ConfiguredNewTrackingSiPattern: InDetAmbiTrackSelectionTool.phiWidth = 0.1 #Split cluster ROI size InDetAmbiTrackSelectionTool.etaWidth = 0.1 #Split cluster ROI size InDetAmbiTrackSelectionTool.InputEmClusterContainerName = InDetKeys.CaloClusterROIContainer() - InDetAmbiTrackSelectionTool.doEmCaloSeed = False #Only split in cluster in region of interest + InDetAmbiTrackSelectionTool.doEmCaloSeed = True #Only split in cluster in region of interest InDetAmbiTrackSelectionTool.minPtConv = 10000 #Only allow split clusters on track withe pt greater than this MeV InDetAmbiTrackSelectionTool.phiWidthEM = 0.05 #Split cluster ROI size InDetAmbiTrackSelectionTool.etaWidthEM = 0.05 #Split cluster ROI size diff --git a/InnerDetector/InDetRecTools/InDetAmbiTrackSelectionTool/InDetAmbiTrackSelectionTool/InDetDenseEnvAmbiTrackSelectionTool.h b/InnerDetector/InDetRecTools/InDetAmbiTrackSelectionTool/InDetAmbiTrackSelectionTool/InDetDenseEnvAmbiTrackSelectionTool.h old mode 100755 new mode 100644 index 652827d17ed..327630f1a66 --- a/InnerDetector/InDetRecTools/InDetAmbiTrackSelectionTool/InDetAmbiTrackSelectionTool/InDetDenseEnvAmbiTrackSelectionTool.h +++ b/InnerDetector/InDetRecTools/InDetAmbiTrackSelectionTool/InDetAmbiTrackSelectionTool/InDetDenseEnvAmbiTrackSelectionTool.h @@ -66,9 +66,16 @@ namespace InDet /** standard Athena-Algorithm method */ virtual StatusCode initialize() override; - /** standard Athena-Algorithm method */ - virtual StatusCode finalize() override; + /** + * Decide what to do with a candidate track + * - count and characterize hits on track + * - not those which are used too often (decideWhichHitsToKeep) + * - accept the track as is, remove hits and make a subtrack, or + * reject track + * - track candidate are also checked against accepted tracks to + * ensure accepted tracks are not pushed over threshold + * */ virtual std::tuple<Trk::Track*,bool> getCleanedOutTrack(const Trk::Track *track, const Trk::TrackScore score, Trk::ClusterSplitProbabilityContainer &splitProbContainer, @@ -84,112 +91,143 @@ namespace InDet SplitSharedHit = 2, // A measurement shared with another track SharedHit = 3, + // A hit that needs to be removed from the track + // because it is used on too many tracks already + RejectedHitOverUse = 4, + // A hit that needs to be removed from the track + // because sharing it would invalidate an accepted track + RejectedHitInvalid = 5, // A hit that needs to be removed from the track - RejectedHit = 4, + // reason other than the above two + RejectedHit = 6, // an outlier, to be copied in case - Outlier = 5, + Outlier = 7, // other TSOS types to be copied in case - OtherTsos = 6 + OtherTsos = 8 }; struct TrackHitDetails { - bool isPatternTrack ; - bool inROI ; - bool thishasblayer ; //Track has a hit in the b-layer - bool hassharedblayer ; //Track has a shared it in the b-layer - bool hassharedpixel ; //Track has a shared pixel hit - bool firstisshared ; //The first hit on track is shared + bool m_isPatternTrack ; + bool m_thisHasIBLHit ; //Track has a hit in the IBL + bool m_hasSharedIBLHit ; //Track has a shared hit in the IBL + bool m_hasSharedPixel ; //Track has a shared pixel hit (does not include IBL) + bool m_firstPixIsShared ; //The first pixel hit on track is shared (includes IBL) + bool m_passHadronicROI ; //Track is within hadronic ROI + bool m_passConversionSel ; //Track is compatible with a conversion + bool m_trkCouldBeAccepted ; //No rejected hits on track - int numPixelDeadSensor ;// I don't think i need to explain these - int numSCTDeadSensor ; - int numPixelHits ; - int numPixelHoles ; - int numSCTHoles ; - int numSCTHits ; + int m_numPixelDeadSensor ; //Taken from track summary. Stored value not changed in this tool + int m_numSCTDeadSensor ; //Taken from track summary. Stored value not changed in this tool + int m_numPixelHits ; //Taken from track summary. Stored value not changed in this tool + int m_numPixelHoles ; //Taken from track summary. Stored value not changed in this tool + int m_numSCTHoles ; //Taken from track summary. Stored value not changed in this tool + int m_numSCTHits ; //Taken from track summary. Stored value not changed in this tool - int numUnused ; //Number of unique hits - int numTRT_Unused ; //Number of unique TRT hits - int numSCT_Unused ; //Number of unique SCT hits - int numPseudo ; //Number of pseudo measurements on track - - float averageSplit1 ; //Average split prob1 - float averageSplit2 ; //Averege split prob2 + // values counted in this tool + int m_numUnused ; //Number of unique hits + int m_numTRT_Unused ; //Number of unique TRT hits (NOT included within m_numUnused) + int m_numSCT_Unused ; //Number of unique SCT hits ( included within m_numUnused) + int m_numPseudo ; //Number of pseudo measurements on track - int numSplitSharedPix ; //Number of Pixel clusters comptaible with being split that are also shared - int numSplitSharedSCT ; //Number of SCT clusters comptaible with being split that are also shared - int numSharedOrSplit ; //Number of split + shared clusters - int numSharedOrSplitPixels; //Number of pixel clusters that are either split or shared - int numShared ; //Number of shared hits on track - int numWeightedShared ; //Weighted number of shared hits on trak (pixels count for 2) - + int m_numSplitSharedPix ; //Number of Pixel clusters comptaible with being split that are also shared + int m_numSplitSharedSCT ; //Number of SCT clusters comptaible with being split that are also shared + int m_numShared ; //Number of shared hits on track (does not include SplitShared) + int m_numSCT_Shared ; //Number of shared sct hits on track (included within m_numShared) + int m_numWeightedShared ; //Weighted number of shared hits on track used to test shared module cuts (pixels count for 2) + TrackHitDetails() { - isPatternTrack = true; - inROI = false; - thishasblayer = false; - hassharedblayer = false; - hassharedpixel = false; - firstisshared = true; + m_isPatternTrack = true; + m_thisHasIBLHit = false; + m_hasSharedIBLHit = false; + m_hasSharedPixel = false; + m_firstPixIsShared = false; + m_passHadronicROI = false; + m_passConversionSel = false; + m_trkCouldBeAccepted = true; - numPixelDeadSensor = -1; - numSCTDeadSensor = -1; - numPixelHits = 0; - numPixelHoles = 0; - numSCTHoles = 0; - numSCTHits = 0; + m_numPixelDeadSensor = -1; + m_numSCTDeadSensor = -1; + m_numPixelHits = 0; + m_numPixelHoles = 0; + m_numSCTHoles = 0; + m_numSCTHits = 0; - numUnused = 0; - numSCT_Unused = 0; - numTRT_Unused = 0; - numPseudo = 0; - - averageSplit1 = 0; - averageSplit2 = 0; + m_numUnused = 0; + m_numSCT_Unused = 0; + m_numTRT_Unused = 0; + m_numPseudo = 0; - numSplitSharedPix = 0; - numSplitSharedSCT = 0; - numSharedOrSplit = 0; - numSharedOrSplitPixels = 0; - numShared = 0; - numWeightedShared = 0; + m_numSplitSharedPix = 0; + m_numSplitSharedSCT = 0; + m_numShared = 0; + m_numSCT_Shared = 0; + m_numWeightedShared = 0; } - - int totalSiHits() + + // All SiHits including shared + int totalSiHits() const + { + return (m_numUnused + m_numPixelDeadSensor + m_numSCTDeadSensor + m_numSplitSharedPix + m_numSplitSharedSCT + m_numShared); + }; + + // SplitShared are not counted as shared (no penality) + // since are compatible with originating from multiple particles + int totalUniqueSiHits() const + { + return (totalSiHits() - m_numShared); + }; + + // No counters, for pixel hits. Solve for them to avoid too many counters + int totalUniquePixelHits() const { - return numUnused + numPixelDeadSensor + numSCTDeadSensor + numSplitSharedPix + numSplitSharedSCT + (inROI ? numShared/2 : 0) ; + // m_numTRT_Unused not included in m_numUnused + return (m_numUnused - m_numSCT_Unused); + }; + + // No counters, for pixel hits. Solve for them to avoid too many counters + int totalSharedPixelHits() const + { + return (m_numShared - m_numSCT_Shared); + }; + + int totalPixelHits() const + { + return (totalUniquePixelHits() + totalSharedPixelHits() + m_numSplitSharedPix + m_numPixelDeadSensor); }; - void dumpInfo() + void dumpInfo() const { - std::cout << "isPatternTrack: " << isPatternTrack << std::endl; - std::cout << "thishasblayer : " << thishasblayer << std::endl; - std::cout << "hassharedblayer:" << hassharedblayer << std::endl; - std::cout << "hassharedpixel: " << hassharedpixel << std::endl; - std::cout << "firstisshared: " << firstisshared << std::endl; + std::cout << "isPatternTrack : " << m_isPatternTrack << std::endl; + std::cout << "thisHasIBLHit : " << m_thisHasIBLHit << std::endl; + std::cout << "hasSharedIBLHit : " << m_hasSharedIBLHit << std::endl; + std::cout << "hasSharedPixel : " << m_hasSharedPixel << std::endl; + std::cout << "firstPixIsShared : " << m_firstPixIsShared << std::endl; + std::cout << "passHadronicROI : " << m_passHadronicROI << std::endl; + std::cout << "passConversionSel : " << m_passConversionSel << std::endl; + std::cout << "trkCouldBeAccepted: " << m_trkCouldBeAccepted<< std::endl; - std::cout << "Dead Pixels: " << numPixelDeadSensor<< std::endl; - std::cout << "Dead SCT: " << numSCTDeadSensor << std::endl; - std::cout << "Pixel hit " << numPixelHits << std::endl; - std::cout << "Pixel holes " << numPixelHoles << std::endl; - std::cout << "SCT hits " << numSCTHits << std::endl; - std::cout << "SCT holes " << numSCTHoles << std::endl; + std::cout << "Dead Pixels: " << m_numPixelDeadSensor<< std::endl; + std::cout << "Dead SCT: " << m_numSCTDeadSensor << std::endl; + std::cout << "Pixel hit " << m_numPixelHits << std::endl; + std::cout << "Pixel holes " << m_numPixelHoles << std::endl; + std::cout << "SCT hits " << m_numSCTHits << std::endl; + std::cout << "SCT holes " << m_numSCTHoles << std::endl; - std::cout << "Unique hits " << numUnused << std::endl; - std::cout << "Unique SCT " << numSCT_Unused << std::endl; - std::cout << "Unique TRT " << numTRT_Unused << std::endl; - std::cout << "Pseudo " << numPseudo << std::endl; + std::cout << "Unique hits " << m_numUnused << std::endl; + std::cout << "Unique SCT " << m_numSCT_Unused << std::endl; + std::cout << "Unique TRT " << m_numTRT_Unused << std::endl; + std::cout << "Unique Pix " << totalUniquePixelHits() << std::endl; + std::cout << "Pseudo " << m_numPseudo << std::endl; - std::cout << "Average Split1 " << averageSplit1 << std::endl; - std::cout << "Average Split2 " << averageSplit2 << std::endl; - - std::cout << "SplitSharedPix " << numSplitSharedPix << std::endl; - std::cout << "SplitSharedSCT " << numSplitSharedSCT << std::endl; - std::cout << "Shared/split " << numSharedOrSplit << std::endl; - std::cout << "Shared/split px " << numSharedOrSplitPixels << std::endl; - std::cout << "Shared " << numShared << std::endl; - std::cout << "Weighted shared " << numWeightedShared << std::endl; + std::cout << "SplitSharedPix " << m_numSplitSharedPix << std::endl; + std::cout << "SplitSharedSCT " << m_numSplitSharedSCT << std::endl; + std::cout << "Shared " << m_numShared << std::endl; + std::cout << "Shared SCT " << m_numSCT_Shared << std::endl; + std::cout << "Shared Pix " << totalSharedPixelHits() << std::endl; + std::cout << "Weighted shared " << m_numWeightedShared << std::endl; }; }; @@ -208,15 +246,15 @@ namespace InDet struct TSoS_Details { - unsigned int nTSoS; - std::vector<int> type; // The type of TSOS - std::vector<int> detType; // The Detector type 1== Pixel, 11 = b-layer, 2 SCT, 3 TRT - std::vector<int> hitIsShared; // Number of tracks the hit is shared with - std::vector<float> splitProb1; // The Probablilty that the cluster on that surface is from 2 tracks - std::vector<float> splitProb2; // The Probablilty that the cluster on that surface is from 3 or more tracks - std::vector<const Trk::RIO_OnTrack*> RIO; // The cluster on track - std::multimap<const Trk::Track*, int, lessTrkTrack > overlappingTracks; // The tracks that overlap with the current track - std::multimap< int, const Trk::Track*> tracksSharingHit; // The tracks that overlap with the current track + unsigned int m_nTSoS; + std::vector<int> m_type; // The type of TSOS + std::vector<int> m_detType; // The Detector type 1== Pixel, 11 = b-layer, 2 SCT, 3 TRT + std::vector<int> m_hitIsShared; // Number of tracks the hit is shared with + std::vector<float> m_splitProb1; // The Probablilty that the cluster on that surface is from 2 tracks + std::vector<float> m_splitProb2; // The Probablilty that the cluster on that surface is from 3 or more tracks + std::vector<const Trk::RIO_OnTrack*> m_RIO; // The cluster on track + std::multimap<const Trk::Track*, int, lessTrkTrack > m_overlappingTracks; // The tracks that overlap with the current track + std::multimap< int, const Trk::Track*> m_tracksSharingHit; // The tracks that overlap with the current track TSoS_Details() { @@ -225,20 +263,20 @@ namespace InDet TSoS_Details(unsigned int temp_nTSoS) { - nTSoS = temp_nTSoS; - type.resize(nTSoS,OtherTsos); - detType.resize(nTSoS,-1.); - hitIsShared.resize(nTSoS, 0 ); - splitProb1.resize(nTSoS,-1.) ; - splitProb2.resize(nTSoS,-1.) ; - RIO.resize(nTSoS,0); + m_nTSoS = temp_nTSoS; + m_type.resize(m_nTSoS,OtherTsos); + m_detType.resize(m_nTSoS,-1.); + m_hitIsShared.resize(m_nTSoS, 0 ); + m_splitProb1.resize(m_nTSoS,-1.) ; + m_splitProb2.resize(m_nTSoS,-1.) ; + m_RIO.resize(m_nTSoS,0); }; int findIndexOfPreviousMeasurement( int currentIndex ) const { int indexPreviousMeasurement = currentIndex-1; while(indexPreviousMeasurement >= 0){ - if ( type[indexPreviousMeasurement] != OtherTsos ){ + if ( m_type[indexPreviousMeasurement] != OtherTsos ){ break; } else { --indexPreviousMeasurement; @@ -252,9 +290,17 @@ namespace InDet struct CacheEntry { EventContext::ContextEvt_t m_evt{EventContext::INVALID_CONTEXT_EVT}; - int m_maxShared; // Max shared hits -- calulated from m_maxSharedModules - int m_minNotShared; // Min number of hits that are not shared -- can change if we are in ROI - int m_minSiHits; // Min number of hits before we allow split sharing of hits -- can change if we are in ROI + // Max shared modules -- calulated from m_maxSharedModules + // 1 pixel hit is 1 module + // a double sided SCT hit (2 SCT hits) is 1 module + // so count by 2s for shared pixel hits and 1 per SCT (single sided hit) hit + int m_maxSharedModules; + // Min number of unique hits that are not already used on any other track + // but split hits can be used on multiple tracks and be considered unique + // - can change in ROI + int m_minNotShared; + // Min number of hits before we allow split sharing of hits -- can change if we are in ROI + int m_minSiHits; std::vector<double> m_hadF; std::vector<double> m_hadE; @@ -278,20 +324,38 @@ namespace InDet TrackHitDetails& trackHitDetails, TSoS_Details& tsosDetails ) const; - /** Determine which hits to keep on this track*/ - bool decideWhichHitsToKeep(const Trk::Track*, + /** Determine which hits to keep on this track + * Look at the hits on track and decided if they should be kept on the track or rejected. + * The decision focuses on the track in question and how often clusters are used + * Within getCleanedOutTrack (from which this is called), accepted tracks are checked + * to see if they are pushed over limits + * */ + void decideWhichHitsToKeep(const Trk::Track*, const Trk::TrackScore score, Trk::ClusterSplitProbabilityContainer &splitProbContainer, Trk::PRDtoTrackMap &prd_to_track_map, TrackHitDetails& trackHitDetails, TSoS_Details& tsosDetails, - int nCutTRT, CacheEntry* ent) const; + /** Specific logic for identifing conversions with the goal + * of passing those tracks through to the final collection + * will as little loss as possible + * */ + bool performConversionCheck(const Trk::Track* ptrTrack, + Trk::PRDtoTrackMap &prd_to_track_map, + TrackHitDetails& trackHitDetails, + TSoS_Details& tsosDetails, + CacheEntry* ent) const; + + /** Update the pixel clusters split information*/ void setPixelClusterSplitInformation(TSoS_Details& tsosDetails, Trk::ClusterSplitProbabilityContainer &clusterSplitProbMap) const; + /** Does track pass criteria for hadronic ROI? */ + bool inHadronicROI(const Trk::Track* ptrTrack, CacheEntry* ent) const; + /** Check if the cluster is compatible with a hadronic cluster*/ bool isHadCaloCompatible(const Trk::TrackParameters& Tp, CacheEntry* ent) const; @@ -301,19 +365,17 @@ namespace InDet /** Fill hadronic & EM cluster map*/ void newEvent(CacheEntry* ent) const; - /** Returns the number of track that use that hit already - Need to let it know if that cluster is splittable - maxiShared = max number of shared hits on a shared track - which has maxothernpixel pixe hits and blayer hit if maxotherhasblayer is true + /** Returns true if accepted tracks remain about thresholds, false otherwise + maxiShared = max number of shared modules on an accepted shared track + which has maxOtherNPixel pixel hits and blayer hit if maxOtherHasIBL is true */ - int checkOtherTracksValidity(const Trk::RIO_OnTrack*, - bool isSplitable, + bool checkOtherTracksValidity(TSoS_Details& tsosDetails, + int index, Trk::ClusterSplitProbabilityContainer &splitProbContainer, Trk::PRDtoTrackMap &prd_to_track_map, int& maxiShared, - int& maxothernpixel, - bool& maxotherhasblayer, - bool& failMinHits, + int& maxOtherNPixel, + bool& maxOtherHasIBL, CacheEntry* ent) const; @@ -322,12 +384,25 @@ namespace InDet getOverlapTrackParameters(int n, const Trk::Track* track1, const Trk::Track* track2, const Trk::PRDtoTrackMap &prd_to_track_map, - int numSplitSharedPix ) const; + int splitSharedPix ) const; /** Check if two sets of track paremeters are compatible with being from a the same low mass particle decay. It is assumed that the track parmeters are on the same surface.*/ bool isNearbyTrackCandidate(const Trk::TrackParameters* paraA, const Trk::TrackParameters* paraB) const; + /** Simple helper functions to tell is cluster is split*/ + bool clusCanBeSplit(float splitProb1, float splitProb2) const; + bool isTwoPartClus(float splitProb1, float splitProb2) const; + bool isMultiPartClus(float splitProb2) const; + + void rejectHitOverUse(TrackHitDetails& trackHitDetails, TSoS_Details& tsosDetails, int index) const; + void rejectHit (TrackHitDetails& trackHitDetails, TSoS_Details& tsosDetails, int index) const; + void rejectSharedHit (TrackHitDetails& trackHitDetails, TSoS_Details& tsosDetails, int index) const; + void rejectSharedHitInvalid (TrackHitDetails& trackHitDetails, TSoS_Details& tsosDetails, int index) const; + void sharedToSplitPix(TrackHitDetails& trackHitDetails, TSoS_Details& tsosDetails, int index) const; + void addSharedHit (TrackHitDetails& trackHitDetails, TSoS_Details& tsosDetails, int index) const; + void increaseSharedHitCounters(TrackHitDetails& trackHitDetails, bool isPix, bool isSCT) const; + void decreaseSharedHitCounters(TrackHitDetails& trackHitDetails, bool isPix, bool isSCT) const; /** TRT minimum number of drift circles tool- returns allowed minimum number of TRT drift circles */ PublicToolHandle<ITrtDriftCircleCutTool> m_selectortool{this, "DriftCircleCutTool", "InDet::InDetTrtDriftCircleCutTool"}; @@ -343,10 +418,10 @@ namespace InDet IntegerProperty m_minHits{this, "minHits", 5, "Min Number of hits on track"}; IntegerProperty m_minTRT_Hits{this, "minTRTHits", 0, "Min Number of TRT hits on track"}; IntegerProperty m_maxSharedModules{this, "maxShared", 1, "Max number of shared modules"}; - IntegerProperty m_maxSharedModulesInROI{this, "maxSharedModulesInROI", 2, "Max number of shared modules in ROI. Test value for recovering B jet efficiency at high pt"}; - IntegerProperty m_maxTracksPerPRD{this, "maxTracksPerSharedPRD", 2, "Max number of tracks per hit if it is nor split"}; - IntegerProperty m_minNotSharedModules{this, "minNotShared", 6, "Min number of non shared modules"}; - IntegerProperty m_minNotSharedModulesInROI{this, "minNotSharedInROI", 4, "Min number of non shared modules in ROI. Test value for recovering B jet efficiency at high pt"}; + IntegerProperty m_maxSharedModulesInROI{this, "maxSharedModulesInROI", 2, "Max number of shared modules in a hadronic ROI. Test value for recovering B jet efficiency at high pt"}; + IntegerProperty m_maxTracksPerPRD{this, "maxTracksPerSharedPRD", 2, "Max number of tracks per hit. When NN is used, other flags set the limits."}; + IntegerProperty m_minNotSharedHits{this, "minNotShared", 6, "Min number of non shared hits"}; + IntegerProperty m_minNotSharedHitsInROI{this, "minNotSharedInROI", 4, "Min number of non shared hits in ROI. Test value for recovering B jet efficiency at high pt"}; FloatProperty m_minScoreShareTracks{this, "minScoreShareTracks", 0.0, "Min track score to alow it to share hits"}; BooleanProperty m_cosmics{this, "Cosmics", false, "Trying to reco cosmics?"}; BooleanProperty m_parameterization{this, "UseParameterization", true, "Use table of min number DCs"}; @@ -359,7 +434,11 @@ namespace InDet IntegerProperty m_minUniqueSCTHits{this, "minUniqueSCTHits", 2, "Min number of hits in the SCT that we need before we allow hit sharing in the SCT"}; IntegerProperty m_minSiHitsToAllowSplitting{this, "minSiHitsToAllowSplitting", 9, "Min number of hits before we allow split sharing of hits"}; IntegerProperty m_minSiHitsToAllowSplittingInROI{this, "minSiHitsToAllowSplittingInROI", 7, "Min number of hits before we allow split sharing of hits In ROI. Test value for recovering B jet efficiency"}; - IntegerProperty m_maxPixMultiCluster{this, "maxPixMultiCluster", 4, "Max number of tracks that can be associated to a split cluster"}; + IntegerProperty m_maxPixOnePartCluster{this, "maxPixOnePartCluster", 2, "Max number of tracks that can be associated to a 1 particle cluster"}; + IntegerProperty m_maxPixTwoPartCluster{this, "maxPixTwoPartCluster", 2, "Max number of tracks that can be associated to a 2 particle cluster"}; + IntegerProperty m_maxPixMultiCluster{this, "maxPixMultiCluster", 4, "Max number of tracks that can be associated to a >= 3 particle cluster"}; + BooleanProperty m_shareSplitHits{this, "shareSplitHits", false, "Allow shared hits to be shared on 1 more track"}; + IntegerProperty m_minPixHitAccepted{this, "minPixHitAccepted", 2, "Min number of pixel hits needed to be allowed to push accepted tracks over shared module limits"}; // ROI stuff BooleanProperty m_useHClusSeed{this, "doHadCaloSeed", false}; @@ -379,13 +458,8 @@ namespace InDet //Track Pair Selection BooleanProperty m_doPairSelection{this, "doPairSelection", true}; FloatProperty m_minPairTrackPt{this, "minPairTrackPt", 1000., "In MeV"}; - FloatProperty m_pairDeltaX{this, "pairDeltaX", 0.5, "Seperation distance in mm"}; - FloatProperty m_pairDeltaY{this, "pairDeltaY", 2.0}; - FloatProperty m_pairDeltaPhi{this, "pairDeltaPhi", 5e-2, "Seperation distance in rad"}; - FloatProperty m_pairDeltaEta{this, "pairDeltaEta", 5e-2}; BooleanProperty m_monitorTracks{this, "MonitorAmbiguitySolving", false, "to track observeration/monitoring (default is false)"}; - BooleanProperty m_doSCTSplitting{this, "doSCTSplitting", false}; //WPM }; } // end of namespace diff --git a/InnerDetector/InDetRecTools/InDetAmbiTrackSelectionTool/src/InDetDenseEnvAmbiTrackSelectionTool.cxx b/InnerDetector/InDetRecTools/InDetAmbiTrackSelectionTool/src/InDetDenseEnvAmbiTrackSelectionTool.cxx old mode 100755 new mode 100644 index 01664c47c1f..6b028612f05 --- a/InnerDetector/InDetRecTools/InDetAmbiTrackSelectionTool/src/InDetDenseEnvAmbiTrackSelectionTool.cxx +++ b/InnerDetector/InDetRecTools/InDetAmbiTrackSelectionTool/src/InDetDenseEnvAmbiTrackSelectionTool.cxx @@ -5,6 +5,7 @@ /////////////////////////////////////////////////////////////////// // InDetDenseEnvAmbiTrackSelectionTool.cxx, (c) ATLAS Detector software // Anthony Morley based on the orginal tool by Markus Elsing +// Oct 2020 - Clean-up for rel22 - Gabriel Facini /////////////////////////////////////////////////////////////////// #include "InDetAmbiTrackSelectionTool/InDetDenseEnvAmbiTrackSelectionTool.h" @@ -65,18 +66,9 @@ StatusCode InDet::InDetDenseEnvAmbiTrackSelectionTool::initialize() ATH_CHECK(m_inputHadClusterContainerName.initialize(m_useHClusSeed)); ATH_CHECK(m_inputEmClusterContainerName.initialize(m_useEmClusSeed)); - ATH_MSG_INFO( "initialize() successful in " << name() ); return StatusCode::SUCCESS; } -//================ Finalisation ================================================= - -StatusCode InDet::InDetDenseEnvAmbiTrackSelectionTool::finalize() -{ - StatusCode sc = AlgTool::finalize(); - return sc; -} - // @TODO move cluster "map" creation to separate algorithm void InDet::InDetDenseEnvAmbiTrackSelectionTool::newEvent(CacheEntry* ent) const @@ -117,32 +109,30 @@ void InDet::InDetDenseEnvAmbiTrackSelectionTool::newEvent(CacheEntry* ent) const } } + //============================================================================================ std::tuple<Trk::Track*,bool> InDet::InDetDenseEnvAmbiTrackSelectionTool::getCleanedOutTrack(const Trk::Track *ptrTrack, const Trk::TrackScore score, Trk::ClusterSplitProbabilityContainer &splitProbContainer, Trk::PRDtoTrackMap &prd_to_track_map) const { + + // Test to see if we have a new event const EventContext& ctx{Gaudi::Hive::currentContext()}; std::lock_guard<std::mutex> lock{m_mutex}; CacheEntry* ent{m_cache.get(ctx)}; if (ent->m_evt!=ctx.evt()) { // New event in this slot - // compute the number of shared hits from the number of max shared modules - ent->m_maxShared = 2*m_maxSharedModules+1; - ent->m_minNotShared = m_minNotSharedModules; - ent->m_minSiHits = m_minSiHitsToAllowSplitting; - //Fill ROI's newEvent(ent); ent->m_evt = ctx.evt(); } - ATH_MSG_DEBUG ("getcleanedouttrack just got called "); //WPM - // compute the number of shared hits from the number of max shared modules - ent->m_maxShared = 2*m_maxSharedModules+1; - ent->m_minNotShared = m_minNotSharedModules; + // reset every track as could be changed for tracks within an ROI + // ROI matching is done within decideWhichHitsToKeep. Note mulitple ROI types + ent->m_maxSharedModules = 2*m_maxSharedModules+1; // see header for meaning + ent->m_minNotShared = m_minNotSharedHits; ent->m_minSiHits = m_minSiHitsToAllowSplitting; // cut on TRT hits, might use eta dependent cuts here @@ -150,7 +140,7 @@ std::tuple<Trk::Track*,bool> InDet::InDetDenseEnvAmbiTrackSelectionTool::getClea if (m_parameterization) { const DataVector<const Trk::TrackParameters>* vpar = ptrTrack->trackParameters(); const Trk::TrackParameters* par = (*vpar)[0]; - // ME bugfix + // ME bugfix TODO ... how old is this comment?? int expected = m_selectortool->minNumberDCs(par); if (expected > nCutTRT) nCutTRT = expected; } @@ -160,201 +150,174 @@ std::tuple<Trk::Track*,bool> InDet::InDetDenseEnvAmbiTrackSelectionTool::getClea ATH_MSG_DEBUG ("Study new Track "<< ptrTrack<<"\t , it has "<<tsos->size()<<"\t track states"); //Create structs to hold track information + //Values in here are used to decide if a track is kept or not TrackHitDetails trackHitDetails; ATH_MSG_DEBUG ("Filling in TrackDetails"); TSoS_Details tsosDetails(tsos->size()); - // Fill structs will information + // Fill structs with information fillTrackDetails( ptrTrack, splitProbContainer, prd_to_track_map, trackHitDetails, tsosDetails); //Decide which hits to keep - ATH_MSG_DEBUG ("DecideWhichHitsToKeep"); - bool TrkCouldBeAccepted = decideWhichHitsToKeep( ptrTrack, score, splitProbContainer, prd_to_track_map, trackHitDetails, tsosDetails, nCutTRT, ent ); - - ATH_MSG_DEBUG ("DecidedWhichHitsToKeep " << TrkCouldBeAccepted ); - - //WPM add in a loop to check how many splitable SCT clusters there are here!!!! - ATH_MSG_DEBUG ("How many SCT clusters can be split? "); - + //This is a major function which checks the usage of each hit on the candidate track + ATH_MSG_DEBUG ("decideWhichHitsToKeep"); + decideWhichHitsToKeep( ptrTrack, score, splitProbContainer, prd_to_track_map, trackHitDetails, tsosDetails, ent ); - // counter for the weighted number of added shared hits - int merged_sct = 0; + ATH_MSG_DEBUG ("decideWhichHitsToKeep" << trackHitDetails.m_trkCouldBeAccepted ); - if (m_doSCTSplitting){ - - // new TSOS vector - std::vector<const Trk::TrackStateOnSurface*> newTSOS_sct; - - // loop over all TSOS (and types) and copy the good ones over - DataVector<const Trk::TrackStateOnSurface>::const_iterator iTsos_sct = tsos->begin(); - DataVector<const Trk::TrackStateOnSurface>::const_iterator iTsosEnd_sct = tsos->end(); - - for (int index_sct = 0 ; iTsos_sct != iTsosEnd_sct ; ++iTsos_sct,++index_sct ) { + // + // now see what to do with the track + // + + ATH_MSG_DEBUG ("totalSiHits " << trackHitDetails.totalSiHits()); + ATH_MSG_DEBUG ("totalUniqueSiHits " << trackHitDetails.totalUniqueSiHits()); + ATH_MSG_DEBUG ("score " << score ); - const Trk::RIO_OnTrack* rot_sct = tsosDetails.RIO[index_sct]; - - if (!rot_sct) { - ATH_MSG_WARNING ("No ROTs failed, should never happen !"); - continue; - } - - if (m_detID->is_sct(rot_sct->identify())){ //WPM - - bool isSplitable = tsosDetails.splitProb1[index_sct] >= m_sharedProbCut || tsosDetails.splitProb2[index_sct] >= m_sharedProbCut2; - - if (isSplitable){ - merged_sct++; - ATH_MSG_DEBUG ("+1 Merged SCT "); - - } - } + //------------------------------------------------------------------------------------// + // if have passed the conversion selection, send to the track to the final collection + // before checking basic cuts + if( trackHitDetails.m_passConversionSel ) { + ATH_MSG_DEBUG ("track m_passConversionSel, so accept it as is"); + // Change pixel hits property for shared hits as this track will be + // accepted into the final track colection + if (!trackHitDetails.m_isPatternTrack){ + setPixelClusterSplitInformation( tsosDetails, splitProbContainer ); } - - ATH_MSG_DEBUG ("There are "<<merged_sct<<" merged SCT clusters."); + return std::make_tuple(static_cast<Trk::Track *>(nullptr),true); // keep input track } + //------------------------------------------------------------------------------------// + //------------------------------------------------------------------------------------// // - // now see what to do with the track + // All tracks must pass a minimum set of criteria // - - int totalSiHits = trackHitDetails.totalSiHits(); - ATH_MSG_DEBUG ("totalSiHits " << totalSiHits ); - ATH_MSG_DEBUG ("score " << score ); + // 1. Needs a minimum number of hits on track + // This cut is also implmeneted in the scoring tool and usually the same values are set. + // A track which fails to have the minimum number of hits, gets a score of 0 + // and will not make it this far. Might not be true for all versions of scoring tools. + // The cut here maintains an explicit threshold + // + // 2. Needs enough TRT hits. This is an important cut for back-tracking + // + // 3. Needs to have enough unique hits (not shared with an accepted track) + // + //------------------------------------------------------------------------------------// + bool passBasicCuts(true); + if( trackHitDetails.totalSiHits() < m_minHits ) { passBasicCuts = false; } + if( trackHitDetails.m_numTRT_Unused < nCutTRT ) { passBasicCuts = false; } + if( trackHitDetails.totalUniqueSiHits() < ent->m_minNotShared ) { passBasicCuts = false; } + if( !passBasicCuts ) { + ATH_MSG_DEBUG ("reject track; failed basic cuts"); + return std::make_tuple(static_cast<Trk::Track *>(nullptr),false); // reject input track + } + //------------------------------------------------------------------------------------// + + //------------------------------------------------------------------------------------// + // + // Decide to keep track or not based on more complex criteria + // 1. Check if track passes some criteria, including decision from decideWhichHitsToKeep + // If it passes, put the track into the output collection + // 2. Those which fail are tested on a second set of criteria + // If it passes, strip off "RejectedHits" (decided in decideWhichHitsToKeep) + // and build new subtrack from all non-shared hits and the + // set of shared hits which pass some cuts. + // If 1. new track would have same hit content, save the original track + // 2. if the new subtrack has less hits, and more than the min, created + // subtrack and reject the original + // 3. if the new subtrack is below min hit cuts, junk it + // 3. Those which fail are rejected with no chance for recovery + // + //------------------------------------------------------------------------------------// + + //------------------------------------------------------------------------------------// + // Set some booleans for the up coming if/else statement - // best case, we like this track and it passes this complex if statement - if ( TrkCouldBeAccepted && // we did not mark the track as bad before - ( !trackHitDetails.hassharedblayer || trackHitDetails.numPixelHoles<=1 ) && // if blayer, at most 1 pixel hole - !trackHitDetails.hassharedpixel && // no shared pixel hits - ( ( totalSiHits >= m_minHits && trackHitDetails.numShared == 0 ) || // no shared and enough hits OR - ( totalSiHits >= ent->m_minNotShared && trackHitDetails.numWeightedShared < ent->m_maxShared && // shared hits and enough unique hits and shared hits with good quality - ( totalSiHits + std::min(trackHitDetails.numShared, ent->m_maxShared) ) >= m_minHits && score > m_minScoreShareTracks ) ) ) { - ATH_MSG_DEBUG ("=> Suggest to keep track with "<<trackHitDetails.numShared<<" shared hits !"); + // no shared hit at all + // if shared hits, have additional requirements to check (3) + bool noSharedHits( trackHitDetails.m_numShared == 0 ); + + // set 2 bools for criteria placed on tracks with shared hits each criteria + // 1/2 - too many shared modules? + bool passSharedModulesCut( trackHitDetails.m_numWeightedShared < ent->m_maxSharedModules ); + + // 2/2 - good quality? + // Note, all tracks with a score of 0 are already removed + bool passScoreCut( score > m_minScoreShareTracks ); + //------------------------------------------------------------------------------------// + + + //------------------------------------------------------------------------------------// + // Execute logic outlined above + // + // BEST CASE, we like this track and it passes this if statement + // if have shared hits, not too many shared, and score ("quality") (note unique hits checked above) + if( trackHitDetails.m_trkCouldBeAccepted && + ( noSharedHits || (passSharedModulesCut && passScoreCut) ) ) { + ATH_MSG_DEBUG ("=> Suggest to keep track with "<<trackHitDetails.m_numShared<<" shared hits !"); // Change pixel hits property for shared hits as this track will be accepted into the final track colection - if (!trackHitDetails.isPatternTrack){ + if (!trackHitDetails.m_isPatternTrack){ setPixelClusterSplitInformation( tsosDetails, splitProbContainer ); } return std::make_tuple(static_cast<Trk::Track *>(nullptr),true); // keep input track - // ok, failed that one, can we recover the track ? - /* - } else if ( trackHitDetails.numTRT_Unused >= nCutTRT && // TRT track or no TRT at all (back tracking) - ( totalSiHits >= m_minHits || // we have enough hits OR - ( totalSiHits >= ent->m_minNotShared && // shared hits and enough unique hits and shared hits with good quality - totalSiHits+std::min(trackHitDetails.numShared, ent->m_maxShared) >= m_minHits && score > m_minScoreShareTracks ) ) ) { - */ - } else if ( trackHitDetails.numTRT_Unused >= nCutTRT && // TRT track or no TRT at all (back tracking) - ( - ( totalSiHits >= m_minHits || // we have enough hits OR - ( totalSiHits >= ent->m_minNotShared && // shared hits and enough unique hits and shared hits with good quality - totalSiHits+std::min(trackHitDetails.numShared, ent->m_maxShared) >= m_minHits && score > m_minScoreShareTracks ) ) //That is the traditional statement - || //here comes WPM's addendum, which should allow tracks with many merged sct hits to pass: - ( m_doSCTSplitting && totalSiHits+merged_sct >= m_minHits && score > m_minScoreShareTracks ) - ) - ) { - //WPM - ATH_MSG_DEBUG ("Passed track hits if? "); //WPM + } + // Track failed to be accepted as is. + // Can we recover the track? + else if ( passScoreCut ) { + // catch, if this is cosmics, accept the incoming track if (m_cosmics) { ATH_MSG_DEBUG ("=> Cosmics, accept input track even with shared hits"); return std::make_tuple(static_cast<Trk::Track *>(nullptr),true); // keep input track } - // Track is potentially ok, create a stripped down version from the unused hits and the allowed shared hits - // join shared to unused hits, if requirements are met + // + // Track is potentially ok, create a stripped down version + // from all hits not rejected + // - ATH_MSG_VERBOSE ("Trying to recover track, allow for some shared hits is possible."); - - // new TSOS vector + ATH_MSG_VERBOSE ("Trying to recover track...gathering hits."); + + // decision on hits are already made + // check the cleaning cuts and see if any of the rejected hits can be added back in + // otherwise, go with what we have + // + // A candidate below the total hit cut will never make it this far. + // We are only extend tracks here if ever decide to override rejected hit decisions + + // loop over all TSOS (and types) and copy the good + // ones over to new TSOS vector std::vector<const Trk::TrackStateOnSurface*> newTSOS; - // counter for the weighted number of added shared hits - int cntIns = 0; - - // loop over all TSOS (and types) and copy the good ones over + // iterators for looping DataVector<const Trk::TrackStateOnSurface>::const_iterator iTsos = tsos->begin(); DataVector<const Trk::TrackStateOnSurface>::const_iterator iTsosEnd = tsos->end(); - + for (int index = 0 ; iTsos != iTsosEnd ; ++iTsos,++index ) { - + // remove rejected hits - if (tsosDetails.type[index] == RejectedHit) { + if( tsosDetails.m_type[index] == RejectedHitOverUse || + tsosDetails.m_type[index] == RejectedHitInvalid || + tsosDetails.m_type[index] == RejectedHit ) { ATH_MSG_VERBOSE ("-> Dropping rejected hit"); - } else if (tsosDetails.type[index] != SharedHit ) { - ATH_MSG_VERBOSE ("-> Copy good TSOS"); - newTSOS.push_back(*iTsos); - } else if (cntIns + 1 >= ent->m_maxShared) { - ATH_MSG_VERBOSE ("-> Too many share hits, dropping outer hit(s)"); - } else { - ATH_MSG_VERBOSE ("-> Try to recover a shared hit"); + continue; + } - // get ROT from this TSOS - const Trk::RIO_OnTrack* rot = tsosDetails.RIO[index]; - - if (!rot) { - ATH_MSG_WARNING ("No ROTs failed, should never happen !"); - continue; - } + ATH_MSG_VERBOSE ("-> Copy good TSOS"); + newTSOS.push_back(*iTsos); - // is it a pixel cluster ? - bool isPixel = m_detID->is_pixel(rot->identify()); - - int maxiShared = -1; - int maxothernpixel = 0; - bool maxotherhasblayer = false; - bool otherfailsMinUniqueHits = false; - - bool isSplitable = tsosDetails.splitProb1[index] >= m_sharedProbCut || tsosDetails.splitProb2[index] >= m_sharedProbCut2; - - int numberOfTracksWithThisPrd = checkOtherTracksValidity( rot, isSplitable, splitProbContainer, prd_to_track_map, maxiShared, maxothernpixel, maxotherhasblayer, otherfailsMinUniqueHits, ent); - - - // now decide what to do, can we keep the shared hit - /* - if ( numberOfTracksWithThisPrd < m_maxTracksPerPRD && // number of tracks sharing hit - score > m_minScoreShareTracks && // score cut - (!isPixel || !trackHitDetails.hassharedblayer || trackHitDetails.numPixelHoles <= 0) && // shared b-layer only if no pixel holes - !otherfailsMinUniqueHits && //It will not invalidate another track - ( maxiShared < ent->m_maxShared || (isPixel && !trackHitDetails.firstisshared) ) && // do not allow other accepted track to exceed the shared limit, if first pixel hit is shared - (!isPixel || trackHitDetails.thishasblayer == maxotherhasblayer ) && // only allow shared pixel if both have blayer or both not - (!isPixel || trackHitDetails.numPixelHits >= maxothernpixel ) ) { // only allow shared pixel if new track as at least as many pixel hits - */ - if ( ( numberOfTracksWithThisPrd < m_maxTracksPerPRD && // number of tracks sharing hit - score > m_minScoreShareTracks && // score cut - (!isPixel || !trackHitDetails.hassharedblayer || trackHitDetails.numPixelHoles <= 0) && // shared b-layer only if no pixel holes - !otherfailsMinUniqueHits && //It will not invalidate another track - ( maxiShared < ent->m_maxShared || (isPixel && !trackHitDetails.firstisshared) ) && // do not allow other accepted track to exceed the shared limit, if first pixel hit is shared - (!isPixel || trackHitDetails.thishasblayer == maxotherhasblayer ) && // only allow shared pixel if both have blayer or both not - (!isPixel || trackHitDetails.numPixelHits >= maxothernpixel ) ) || ( m_doSCTSplitting && m_detID->is_sct(rot->identify()) && isSplitable ) ) { //WPM only allow shared pixel if new track as at least as many pixel hits - - ATH_MSG_VERBOSE ("---> Accepted hit shared with " << numberOfTracksWithThisPrd << " tracks !"); - - newTSOS.push_back(*iTsos); - ++trackHitDetails.numUnused; // update counter - - // update shared hit counter - //cntIns += isPixel ? 2 : 1; - if (isPixel) {cntIns += 2;} - else if ( m_detID->is_sct(rot->identify()) && isSplitable ){ cntIns += 0;} - else{cntIns += 1;} + } // loop over TSOS - } else { - ATH_MSG_VERBOSE ("---> Reject hit shared with " << numberOfTracksWithThisPrd << " tracks !"); - } - } - } - - // this still may happen per (**) see above. - //if ( ( trackHitDetails.numUnused+trackHitDetails.numPixelDeadSensor+trackHitDetails.numSCTDeadSensor+trackHitDetails.numSplitSharedPix < m_minHits || newTSOS.size() <= 3 ) || ( m_doSCTSplitting && trackHitDetails.numUnused+trackHitDetails.numPixelDeadSensor+trackHitDetails.numSCTDeadSensor+trackHitDetails.numSplitSharedPix+merged_sct < m_minHits || newTSOS.size() <= 3 ) ) { - if ( trackHitDetails.numUnused+trackHitDetails.numPixelDeadSensor+trackHitDetails.numSCTDeadSensor+trackHitDetails.numSplitSharedPix+merged_sct < m_minHits || newTSOS.size() <= 3 ) { - //WPM another problematic if statment - ATH_MSG_DEBUG ("=> Too few hits, reject track with shared hits"); + // newTSOS size would be hits on new track...how can the limit be 3? Is this backtracking? + // Missing something? What configuration is relying on this cut? TODO + if ( newTSOS.size() <= 3 ) { ATH_MSG_VERBOSE ("newTSOS.size(): "<<newTSOS.size() ); ATH_MSG_DEBUG ("reject track; Too few hits, reject track with shared hits"); return std::make_tuple(static_cast<Trk::Track *>(nullptr),false); // reject input track @@ -365,7 +328,7 @@ std::tuple<Trk::Track*,bool> InDet::InDetDenseEnvAmbiTrackSelectionTool::getClea ATH_MSG_DEBUG ("=> Recovered input track, accept it !"); // Change pixel hits property for shared hits as this is track will be accepeted into the final track colection - if (!trackHitDetails.isPatternTrack){ + if (!trackHitDetails.m_isPatternTrack){ setPixelClusterSplitInformation( tsosDetails, splitProbContainer ); } ATH_MSG_DEBUG ("reject track; maybe track was mark as rejected, but we recoverd it so no rejection"); @@ -389,112 +352,135 @@ std::tuple<Trk::Track*,bool> InDet::InDetDenseEnvAmbiTrackSelectionTool::getClea ATH_MSG_DEBUG ("=> Successfully created subtrack with shared hits recovered !"); return std::make_tuple(newTrack,false); // create new, cleaned track and reject input track } - } else { - ATH_MSG_DEBUG ("=> Track is recommended to be dropped"); - ATH_MSG_DEBUG ("reject track; other"); } + + // if made it this far, junk the track + ATH_MSG_DEBUG ("=> Track is recommended to be dropped"); + ATH_MSG_DEBUG ("reject track; other"); return std::make_tuple(static_cast<Trk::Track *>(nullptr),false); // reject input track + } -int InDet::InDetDenseEnvAmbiTrackSelectionTool::checkOtherTracksValidity(const Trk::RIO_OnTrack* rot, - const bool isSplitable, - Trk::ClusterSplitProbabilityContainer &splitProbContainer, - Trk::PRDtoTrackMap &prd_to_track_map, - int& maxiShared, - int& maxothernpixel, - bool& maxotherhasblayer, - bool& failMinHits, - CacheEntry* ent) const + +// +// Check if a shared hit invalidates any accepted track, if so, return false +// otherwise return true +// ONLY Shared hits are expected. We assume the decision to split has already been made +bool InDet::InDetDenseEnvAmbiTrackSelectionTool::checkOtherTracksValidity(TSoS_Details& tsosDetails, + int index, + Trk::ClusterSplitProbabilityContainer &splitProbContainer, + Trk::PRDtoTrackMap &prd_to_track_map, + int& maxiShared, + int& maxOtherNPixel, + bool& maxOtherHasIBL, + CacheEntry* ent) const { - // find out how many tracks use this hit already - Trk::PRDtoTrackMap::ConstPrepRawDataTrackMapRange range = prd_to_track_map.onTracks(*(rot->prepRawData())); - int numberOfTracksWithThisPrd = std::distance(range.first,range.second); - ATH_MSG_VERBOSE ("---> number of tracks with this shared Prd: " << numberOfTracksWithThisPrd << " maxtracks: " << m_maxTracksPerPRD); + // Hits here are only shared hits. + // Assumption: the decision to split has been done outside this function + if( tsosDetails.m_type[index] != SharedHit ) { + ATH_MSG_WARNING("Calling checkOtherTracksValidity with a hit that is not shared!"); + return true; + } - // check if this newly shared hit would exceed the shared hits limit of the already accepted track (**) + // needed? + const Trk::RIO_OnTrack* rot = tsosDetails.m_RIO[index]; + + // get list of tracks that use this hit already + int numberOfTracksWithThisPrd = tsosDetails.m_hitIsShared[index]; + ATH_MSG_VERBOSE ("---> number of tracks with this shared Prd: " << numberOfTracksWithThisPrd << " maxtracks: " << m_maxTracksPerPRD); + // check if adding one more shared hit would push any accepted track + // -over the limit of shared hits + // -under the limit of unique hits maxiShared = -1; bool otherwillFailMinHits = false; bool otherwillFailSCTuniqueHits = false; - if ( numberOfTracksWithThisPrd > 0 ) { - //Determine of the hit we are checking is a SCT or Pixel hit - bool isSCT = m_detID->is_sct( rot->prepRawData()->identify() ); - bool isPix = m_detID->is_pixel( rot->prepRawData()->identify() ); - - //Setup counters - int iShared = 0; //Number of Shared hits on the test track if this new hit is going to be shared - int iNotShared = 0; //Number of unshared hits on the test track - int iSctUnique = 0; //Number of unique SCT hits on the test track - int iPixel = 0; //Number of pixel hits on the test track - int iSCT = 0; //Number of SCT hits on the test track - bool iHasBlayer = false; // Does the test track have a b-layer hit - - - // Use the track with most shared hits as the one to compare to -- - // This will probably be the worst track compete - for ( auto track = range.first; track != range.second; ++track ){ - //Count up the hit properties of the track you are inspecting - iShared = isSplitable ? 0 : isPix ? 2 : 1; //You share this new hit now so. - iNotShared = isSplitable ? 0 : -1; //You will now be sharing this hit so start off at -1 - iSctUnique = isSCT ? -1 : 0; //Reduce the number unique SCT hits by one if PRD in question is shared - iPixel = 0; - iHasBlayer = false; - iSCT = 0; - - auto prdsToCheck = m_assoTool->getPrdsOnTrack(prd_to_track_map, *(track->second)); - for ( const auto& prdToCheck: prdsToCheck) { - bool isPixel(false); - bool isSplitPixel(false); - if (m_detID->is_pixel(prdToCheck->identify())) { - isPixel = true; - const InDet::PixelCluster* constPixelCluster = dynamic_cast<const InDet::PixelCluster*> ( prdToCheck ); - if (constPixelCluster){ - const Trk::ClusterSplitProbabilityContainer::ProbabilityInfo &splitProb = splitProbContainer.splitProbability(constPixelCluster); - if ( splitProb.isSplit() ) { - isSplitPixel = true; - } + //Setup counters + int iSharedMod = 0; //Number of Shared modules on the accepted track (will include this hit) + int iNotShared = 0; //Number of unshared hits on the accepted track + int iSctUnique = 0; //Number of unique SCT hits on the accepted track + int iPixel = 0; //Number of pixel hits on the accepted track + int iSCT = 0; //Number of SCT hits on the accepted track + bool iHasBlayer = false; // Does the accepted track have a b-layer hit + + // loop over all tracks that have this hit and make sure none fail + // - requirement on unique hits + // - requirement on shared modules + // - requirement on unique sct hits + // send back some information about the most overlapping track + auto currentHitsSharedTracks = tsosDetails.m_tracksSharingHit.equal_range(index); + for ( auto track = currentHitsSharedTracks.first; track != currentHitsSharedTracks.second; ++track ){ + + //Count up the hit properties of the track you are inspecting + iSharedMod = 0; + iNotShared = 0; + iSctUnique = 0; + iPixel = 0; + iHasBlayer = false; + iSCT = 0; + + std::vector< const Trk::PrepRawData* > prdsToCheck = m_assoTool->getPrdsOnTrack(prd_to_track_map, *(track->second)); + for (const Trk::PrepRawData* prdToCheck : prdsToCheck) { + bool isPixel(false); + bool isSplitPixel(false); + if (m_detID->is_pixel(prdToCheck->identify())) { + isPixel = true; + const InDet::PixelCluster* constPixelCluster = dynamic_cast<const InDet::PixelCluster*> ( prdToCheck ); + if (constPixelCluster){ + const Trk::ClusterSplitProbabilityContainer::ProbabilityInfo &splitProb = splitProbContainer.splitProbability(constPixelCluster); + if ( splitProb.isSplit() ) { + isSplitPixel = true; } - - ++iPixel; - if (m_detID->is_blayer(prdToCheck->identify()) ) iHasBlayer=true; - } - - if ( m_detID->is_sct(prdToCheck->identify()) ) { - ++iSCT; } - - if (prd_to_track_map.isShared( *prdToCheck )){ - iShared += isSplitPixel ? 0 : isPixel ? 2 : 1; - } else { - ++iNotShared; - if (m_detID->is_sct(prdToCheck->identify())){ - ++iSctUnique; - } + + ++iPixel; + if (m_detID->is_blayer(prdToCheck->identify()) ) iHasBlayer=true; + } + + if ( m_detID->is_sct(prdToCheck->identify()) ) { + ++iSCT; + } + + // + // count for general cases considering current flags (i.e. if split can be shared) + // hit which are overused, are rejected and should not be in this part of the code + // if hit is new one to be shared, count it as shared + // - the new cluster to be shared is not a split cluster (that is why we are here) + // - this will count correctly if a split hit can also be shared + if ( rot->prepRawData() == prdToCheck ) { + iSharedMod += isPixel ? 2 : 1; + // else if hit is not the new hit to be shared, then see if it is already shared + // - if so, count considering if it is split or not + } else if ( prd_to_track_map.isShared( *prdToCheck ) ) { + iSharedMod += isSplitPixel ? 0 : isPixel ? 2 : 1; + // else + // - not a shared cluster + } else { + ++iNotShared; + if (m_detID->is_sct(prdToCheck->identify())){ + ++iSctUnique; } } + } // loop over PRDs + + ATH_MSG_VERBOSE( "Track " << track->second << " will has " << iNotShared << " unique hits and " << iSctUnique << " unique SCT hits."); + // You are sharing too many hits reject the new track + // TODO does not include dead modules! Can we get that from the track summary? + if ( iNotShared < ent->m_minNotShared ) otherwillFailMinHits = true; + // You are sharing SCT hits and don't have enough to share -reject hit. + if ( iSCT > iSctUnique && iSctUnique < m_minUniqueSCTHits ) otherwillFailSCTuniqueHits = true; + } // loop over tracks - ATH_MSG_VERBOSE( "Track " << track->second << " will has " << iNotShared << " unique hits and " << iSctUnique << " unique SCT hits."); - // You are sharing too many hits reject the new track - if ( iNotShared < ent->m_minNotShared ) otherwillFailMinHits = true; - // You are sharing too many shared SCT hits and you don't have enough to share -reject hit. - if ( iSCT <= m_minUniqueSCTHits && iSCT > iSctUnique ) otherwillFailSCTuniqueHits = true; - } - - // Update details for the track with the most shared hits - if ( iShared > maxiShared){ - maxiShared = iShared; - maxothernpixel = iPixel; - maxotherhasblayer = iHasBlayer; - } + // Update details for the track with the most shared hits + if ( iSharedMod > maxiShared){ + maxiShared = iSharedMod; + maxOtherNPixel = iPixel; + maxOtherHasIBL = iHasBlayer; } - - failMinHits = otherwillFailMinHits || otherwillFailSCTuniqueHits; - - return numberOfTracksWithThisPrd; - + return !( otherwillFailMinHits || otherwillFailSCTuniqueHits ); } @@ -506,16 +492,14 @@ void InDet::InDetDenseEnvAmbiTrackSelectionTool::fillTrackDetails(const Trk::Tra TSoS_Details& tsosDetails) const { - ATH_MSG_DEBUG ("filltrackdetails just got called "); //WPM - // get all TSOS the track const DataVector<const Trk::TrackStateOnSurface>* tsos = ptrTrack->trackStateOnSurfaces(); ATH_MSG_DEBUG ("Study new Track "<< ptrTrack<<"\t , it has "<<tsos->size()<<"\t track states"); // is this a track from the pattern or a fitted track ? - trackHitDetails.isPatternTrack = (ptrTrack->info().trackFitter()==Trk::TrackInfo::Unknown); - if (trackHitDetails.isPatternTrack) { + trackHitDetails.m_isPatternTrack = (ptrTrack->info().trackFitter()==Trk::TrackInfo::Unknown); + if (trackHitDetails.m_isPatternTrack) { ATH_MSG_DEBUG ("-> this is a pattern track, outliers are good hits (reintegration) ! " << ptrTrack->perigeeParameters() ); } else { ATH_MSG_DEBUG ("-> this is a refitted track, so we can use the chi2 ! " << ptrTrack->perigeeParameters()); @@ -525,27 +509,31 @@ void InDet::InDetDenseEnvAmbiTrackSelectionTool::fillTrackDetails(const Trk::Tra const Trk::TrackSummary* trkSummary=ptrTrack->trackSummary(); if (trkSummary) { ATH_MSG_VERBOSE ("--> Found summary information"); - trackHitDetails.numPixelDeadSensor = trkSummary->get(Trk::numberOfPixelDeadSensors); - trackHitDetails.numSCTDeadSensor = trkSummary->get(Trk::numberOfSCTDeadSensors); - trackHitDetails.numPixelHits = trkSummary->get(Trk::numberOfPixelHits); - trackHitDetails.numPixelHoles = trkSummary->get(Trk::numberOfPixelHoles); - trackHitDetails.numSCTHoles = trkSummary->get(Trk::numberOfSCTHoles); - trackHitDetails.numSCTHits = trkSummary->get(Trk::numberOfSCTHits); + trackHitDetails.m_numPixelDeadSensor = trkSummary->get(Trk::numberOfPixelDeadSensors); + trackHitDetails.m_numSCTDeadSensor = trkSummary->get(Trk::numberOfSCTDeadSensors); + trackHitDetails.m_numPixelHits = trkSummary->get(Trk::numberOfPixelHits); + trackHitDetails.m_numPixelHoles = trkSummary->get(Trk::numberOfPixelHoles); + trackHitDetails.m_numSCTHoles = trkSummary->get(Trk::numberOfSCTHoles); + trackHitDetails.m_numSCTHits = trkSummary->get(Trk::numberOfSCTHits); + } else { + ATH_MSG_WARNING("Did not find track summary. Some cuts will be less efficienct!"); } // set nDeadSensors to 0 in case trkSummary wasn't called with HoleSearch // (i.e. number of deadSensors not available) - if (trackHitDetails.numPixelDeadSensor == -1) trackHitDetails.numPixelDeadSensor = 0; - if (trackHitDetails.numSCTDeadSensor == -1) trackHitDetails.numSCTDeadSensor = 0; - ATH_MSG_VERBOSE ("--- Number of dead si sensors: " << trackHitDetails.numPixelDeadSensor + trackHitDetails.numSCTDeadSensor); + if (trackHitDetails.m_numPixelDeadSensor == -1) trackHitDetails.m_numPixelDeadSensor = 0; + if (trackHitDetails.m_numSCTDeadSensor == -1) trackHitDetails.m_numSCTDeadSensor = 0; + ATH_MSG_VERBOSE ("--- Number of dead si sensors: " << trackHitDetails.m_numPixelDeadSensor + trackHitDetails.m_numSCTDeadSensor); - // loop over TSOS + // + // loop over TSOS and save information about each + // label each TSOS as Outlier, UnusedHit, SharedHit or RejectedHit (only for errors here) + // labels are used refined in decideWhichHitsToKeep ATH_MSG_VERBOSE ("--> Looping over TSOS's"); DataVector<const Trk::TrackStateOnSurface>::const_iterator iTsos = tsos->begin(); DataVector<const Trk::TrackStateOnSurface>::const_iterator iTsosEnd = tsos->end(); - //int numissplit = 0; //WPM for (int index = 0 ; iTsos != iTsosEnd ; ++iTsos, ++index) { // get measurment from TSOS @@ -553,8 +541,8 @@ void InDet::InDetDenseEnvAmbiTrackSelectionTool::fillTrackDetails(const Trk::Tra // if we do not have a measurement, we should just mark it if (!meas) { - ATH_MSG_VERBOSE ( Form("---%3d No measurement on TSOS, it is another type, to be copied over.",index) ); - tsosDetails.type[index] = OtherTsos; + ATH_MSG_VERBOSE ( Form("---> No measurement on TSOS, it is another type, %2d",index) ); + tsosDetails.m_type[index] = OtherTsos; continue; } @@ -564,17 +552,17 @@ void InDet::InDetDenseEnvAmbiTrackSelectionTool::fillTrackDetails(const Trk::Tra // could be a Pseudo-Measurement ? const Trk::PseudoMeasurementOnTrack* pseudo = dynamic_cast <const Trk::PseudoMeasurementOnTrack*> (meas); if (pseudo){ - ATH_MSG_VERBOSE ( Form("---%3d Copy pseudo measurement.",index) ); - ++trackHitDetails.numPseudo; // increase counter + ATH_MSG_VERBOSE ( Form("---> Pseudo measurement, %2d",index) ); + ++trackHitDetails.m_numPseudo; // increase counter } else { - ATH_MSG_WARNING ( Form("---%3d Measurement is not a pseudo measurment, not yet supported, try to copy !",index)); + ATH_MSG_WARNING ( Form("---> Measurement is not a pseudo measurment, not yet supported! %2d",index)); } - tsosDetails.type[index] = OtherTsos; + tsosDetails.m_type[index] = OtherTsos; continue; } //Store RIO into vector for later use - tsosDetails.RIO[index] = rot; + tsosDetails.m_RIO[index] = rot; // // we have a TSOS with a measurement, keep analysing it @@ -585,11 +573,15 @@ void InDet::InDetDenseEnvAmbiTrackSelectionTool::fillTrackDetails(const Trk::Tra bool isTRT = m_detID->is_trt(id); bool isPixel = m_detID->is_pixel(id); bool isSCT = m_detID->is_sct(id); - bool isBlayer = isPixel ? m_detID->is_blayer(id) : false; + bool isIBL = isPixel ? m_detID->is_blayer(id) : false; // checks layer 0 bool isoutlier = (*iTsos)->type(Trk::TrackStateOnSurface::Outlier); - tsosDetails.detType[index] = isTRT * 3 + isSCT * 2 + isPixel * 1 + isBlayer * 10; + tsosDetails.m_detType[index] = isTRT * 3 + isSCT * 2 + isPixel * 1 + isIBL * 10; + // Do we have a IBL hit on the track? + if ( isIBL && (!isoutlier || trackHitDetails.m_isPatternTrack ) ) { + trackHitDetails.m_thisHasIBLHit = true; // we may reintegrate outliers from pattern + } // Add splitting information about the cluster if (isPixel) { @@ -597,110 +589,74 @@ void InDet::InDetDenseEnvAmbiTrackSelectionTool::fillTrackDetails(const Trk::Tra const InDet::PixelCluster* clus = dynamic_cast <const InDet::PixelCluster*> (rot->prepRawData()); if ( !clus ) { ATH_MSG_WARNING ("---> Cast to Pixel cluster failed, should not happen !"); - tsosDetails.type[index] = RejectedHit; + tsosDetails.m_type[index] = RejectedHit; continue; } else { const Trk::ClusterSplitProbabilityContainer::ProbabilityInfo &splitProb = splitProbContainer.splitProbability(clus); if ( !splitProb.isTooBigToBeSplit() ) { - tsosDetails.splitProb1[index] = splitProb.splitProbability1(); - tsosDetails.splitProb2[index] = splitProb.splitProbability2(); - } else { - tsosDetails.splitProb1[index] = 0.51; - tsosDetails.splitProb2[index] = 0.51; + tsosDetails.m_splitProb1[index] = splitProb.splitProbability1(); + tsosDetails.m_splitProb2[index] = splitProb.splitProbability2(); + } else { + // cluster too big to split are default to 3 particle cluster + // rigorously checked? + tsosDetails.m_splitProb1[index] = m_sharedProbCut - 0.01; + tsosDetails.m_splitProb2[index] = m_sharedProbCut2 + 0.01; } } - } + } // isPixel - if (isSCT) { - if (m_doSCTSplitting){ - ATH_MSG_DEBUG ("Entered doSCTSplitting. Getting cluster parameters."); - const InDet::SCT_Cluster* clussct = dynamic_cast <const InDet::SCT_Cluster*> (rot->prepRawData()); - if (!clussct){ - ATH_MSG_WARNING ("---> Cast to SCT cluster failed, should not happen !"); - tsosDetails.type[index] = RejectedHit; - continue; - } - if ( std::abs((*iTsos)->surface().normal()(2)) < 0.1 ){ - float px = (*iTsos)->trackParameters()->momentum()(0); - float py = (*iTsos)->trackParameters()->momentum()(1); - float nx = (*iTsos)->surface().normal()(0); - float ny = (*iTsos)->surface().normal()(1); - - //lphi will be the momentum's angle in the x-y plane minus the surface's normal angle - double lphi = std::atan2( py, px ) - std::atan2( ny, nx ); - - double diff = ((285*std::abs( std::tan(lphi)-std::tan(-0.07)) ) - 80*clussct->width().colRow()(0)); - ATH_MSG_DEBUG ("Calculated width - observed width? "<< diff ); - - //track pT would be sqrt( ( px * px ) + ( py * py ) ) - //isStereo?: (*iTsos)->surface().isStereo() - //Number of split pixel clusters: numissplit <- would have to uncomment stuff out from above - - if (std::abs(diff) > 80){ - tsosDetails.splitProb1[index] = .99; - tsosDetails.splitProb2[index] = .99; - } else { - tsosDetails.splitProb1[index] = 0; - tsosDetails.splitProb2[index] = 0; - } - //This ends the "isBarrel" if statement; no endcap clusters are split - } else { - tsosDetails.splitProb1[index] = 0; - tsosDetails.splitProb2[index] = 0; - } - } else { //Always set to 0 if splitting not allowed - tsosDetails.splitProb1[index] = 0; - tsosDetails.splitProb2[index] = 0; - } - } + // + // define each hit + // continue once definition set + // + // is this cluster used on an accepted track? bool isUsed = prd_to_track_map.isUsed(*(rot->prepRawData())); - // Do we have an outlier (and not a pattern track) ? - if ( (isoutlier && !isUsed && !trackHitDetails.isPatternTrack) || !(m_detID->is_indet(id)) ) { - ATH_MSG_VERBOSE ( Form("---%3d Prd is outlier on a fitter track (or not InDet), copy it over.", index) ); - tsosDetails.type[index] = Outlier; + // assign outlier label using isoutlier bool above + // or if not inDet (does this even happen? Historical criteria) + // further criteria on keeping a hit or not is done in decideWhichHitsToKeep + // NOTE outliers can be shared but cannot save both in tsosDetails + if( isoutlier || !(m_detID->is_indet(id))) { + ATH_MSG_VERBOSE ( Form("---> Prd is outlier, %d", index) ); + tsosDetails.m_type[index] = Outlier; + // if it is used, we need to send that information to the rest of the code + // in decideWhichHitsToKeep we reject any outlier used on another track + // if that logic was to change, and the number of tracks was needed, this would + // need to change + if(isUsed) { tsosDetails.m_hitIsShared[index] = 1; } continue; } - // let's check if this is a shared hit (even if it is an outlier on a pattern track) ? + if (!isUsed) { - if ( !isoutlier ) { - ATH_MSG_VERBOSE ( Form("---%3d Prd is unused, copy it over", index) ); - } else { - ATH_MSG_VERBOSE ( Form("---%3d Prd is outlier on a pattern track and is unused, copy it over", index) ); - } - tsosDetails.type[index] = UnusedHit; + ATH_MSG_VERBOSE ( Form("---> Prd is unused, %d", index) ); + tsosDetails.m_type[index] = UnusedHit; continue; } // - // ok, we have a shared hit + // we have a shared hit // - // do we have an outlier and a pattern track, but the hit is shared, so reject it (we reintegrate it otherwise) - if ( isoutlier && trackHitDetails.isPatternTrack ) { - ATH_MSG_VERBOSE ( Form("---%3d Prd is outlier on a pattern track, we do not want to reintegrate it, so reject it.", index) ); - tsosDetails.type[index] = RejectedHit; - continue; - } - // first check if it is a shared TRT hit, this is not allowed + // check if it is a shared TRT hit, this is not allowed if (isTRT) { - ATH_MSG_VERBOSE ( Form("---%3d Share TRT hit, drop it !", index) ); - tsosDetails.type[index] = RejectedHit; + ATH_MSG_VERBOSE ( Form("---> Share TRT hit, drop it !, %d", index) ); + tsosDetails.m_type[index] = RejectedHit; continue; } /* Allow a hit to be a shared one, if - not too many tracks share this hit already - the score of the track is high enough to allow for shared hits + store information here but make decisions in decideWhichHitsToKeep */ Trk::PRDtoTrackMap::ConstPrepRawDataTrackMapRange range = prd_to_track_map.onTracks(*(rot->prepRawData())); int numberOfTracksWithThisPrd = std::distance(range.first,range.second); - ATH_MSG_VERBOSE ( Form("---%3d Number of tracks with this share Prd: %2d maxtracks: %2d",index, numberOfTracksWithThisPrd, m_maxTracksPerPRD.value()) ); - tsosDetails.hitIsShared[index] = numberOfTracksWithThisPrd; + ATH_MSG_VERBOSE ( Form("---> Number of tracks with this share Prd %d: %2d maxtracks: %2d",index, numberOfTracksWithThisPrd, m_maxTracksPerPRD.value()) ); + tsosDetails.m_hitIsShared[index] = numberOfTracksWithThisPrd; // get iterators for range @@ -708,529 +664,608 @@ void InDet::InDetDenseEnvAmbiTrackSelectionTool::fillTrackDetails(const Trk::Tra Trk::PRDtoTrackMap::PrepRawDataTrackMap::const_iterator mapItEnd = range.second; // simple for loop instead of fancier remove_if above for ( ;mapIt!=mapItEnd; ++mapIt) { - tsosDetails.overlappingTracks.insert( std::pair<const Trk::Track*, int >(mapIt->second, index) ); - tsosDetails.tracksSharingHit.insert(std::pair< int, const Trk::Track* >(index, mapIt->second ) ); + tsosDetails.m_overlappingTracks.insert( std::pair<const Trk::Track*, int >(mapIt->second, index) ); + tsosDetails.m_tracksSharingHit.insert(std::pair< int, const Trk::Track* >(index, mapIt->second ) ); } ATH_MSG_VERBOSE ("-----> Mark this hits as shared -- Try and recover later!"); - ATH_MSG_VERBOSE ("------ Index: "<< index << " Type: " << tsosDetails.detType[index] << " splitprob1 " << tsosDetails.splitProb1[index]); - tsosDetails.type[index] = SharedHit; + ATH_MSG_VERBOSE ("------ Index: "<< index << " Type: " << tsosDetails.m_detType[index] << " splitprob1 " << tsosDetails.m_splitProb1[index]); + tsosDetails.m_type[index] = SharedHit; } // End loop over TSOS's return; } -bool InDet::InDetDenseEnvAmbiTrackSelectionTool::decideWhichHitsToKeep(const Trk::Track* ptrTrack, - const Trk::TrackScore score, - Trk::ClusterSplitProbabilityContainer &splitProbContainer, - Trk::PRDtoTrackMap &prd_to_track_map, - TrackHitDetails& trackHitDetails, - TSoS_Details& tsosDetails, - int nCutTRT, - CacheEntry* ent)const +//========================================================================================== +// +// look at cluster properties and how often they are used to determine if can stay on track +// +void InDet::InDetDenseEnvAmbiTrackSelectionTool::decideWhichHitsToKeep(const Trk::Track* ptrTrack, + const Trk::TrackScore score, + Trk::ClusterSplitProbabilityContainer &splitProbContainer, + Trk::PRDtoTrackMap &prd_to_track_map, + TrackHitDetails& trackHitDetails, + TSoS_Details& tsosDetails, + CacheEntry* ent) const { // Can the track can automatically be accpeted without further checks - bool TrkCouldBeAccepted(true); + trackHitDetails.m_trkCouldBeAccepted = true; + + // Does this track fall into an hadronic ROI? + trackHitDetails.m_passHadronicROI = false; + if( m_useHClusSeed && inHadronicROI(ptrTrack, ent) ) { + trackHitDetails.m_passHadronicROI = true; + ent->m_maxSharedModules = 2*m_maxSharedModulesInROI+1; // see header for meaning + ent->m_minNotShared = m_minNotSharedHitsInROI; + ent->m_minSiHits = m_minSiHitsToAllowSplittingInROI; + } + + + //------------------------------------------------------------------// + // Should a shared hit be called shared or is it compatible with multiple clusters? + // this flag controls if the additional information is conisdered and shared hits on this track + // are "recovered" from the shared state to the split state + // + // First criteria are checked which would NOT allow recovery + // Then override criteria are checked + bool recoverSharedHits(true); + // reasons NOT to consider the information + // not above pT for splitting + if( ptrTrack->trackParameters()->front()->pT() < m_minPtSplit ) { recoverSharedHits = false; } + // score too low + if(score <= m_minScoreShareTracks) { recoverSharedHits = false; } + // the following 2 cuts use information from the track summary stored in the details struct + // not enough SiHits + if(trackHitDetails.m_numPixelHits+trackHitDetails.m_numSCTHits < m_minSiHitsToAllowSplitting) { + recoverSharedHits = false; + } + // too many holes + if(trackHitDetails.m_numPixelHoles>1) { recoverSharedHits = false; } + // + // OVERRIDE criteria + if( m_useHClusSeed && trackHitDetails.m_passHadronicROI ) { recoverSharedHits = true; } + //------------------------------------------------------------------// - // let's remember the last 2 ROTs on the track - const Trk::RIO_OnTrack* lastrot = 0; - const Trk::RIO_OnTrack* lastbutonerot = 0; - int lastrotindex = 0; - // Are we in a ROI? - bool inROIandPTok(true); - bool inROI(true); - if ( ptrTrack->trackParameters()->front() ){ - if ( ptrTrack->trackParameters()->front()->pT() < m_minPtSplit ) { - inROIandPTok = false; - } - - if ( ptrTrack->trackParameters()->front()->pT() < m_minPtBjetROI ) { - inROI = false; + //------------------------------------------------------------------// + // + // loop over all measurements, make decisions, increment counters + // + for (unsigned int index(0); index < tsosDetails.m_nTSoS; ++index ){ + //Skip all non-measurement TSOS's + if (tsosDetails.m_type[index] == OtherTsos) { continue; } + + // in fillTrackDetails, if an error, cluster could be rejected + // also shared TRT hits are rejected there + if (tsosDetails.m_type[index] == RejectedHit) { // only generic rejects at that point + trackHitDetails.m_trkCouldBeAccepted = false; // we have to remove at least one PRD + continue; } - if (inROI){ - inROI = m_useHClusSeed && isHadCaloCompatible(*ptrTrack->trackParameters()->front(), ent); - - // If we are in a ROI change the shared hit cut; - if (inROI){ - ent->m_maxShared = 2*m_maxSharedModulesInROI+1; - ent->m_minNotShared = m_minNotSharedModulesInROI; - ent->m_minSiHits = m_minSiHitsToAllowSplittingInROI; + // Keep all unused hits + if (tsosDetails.m_type[index] == UnusedHit ){ + if ( tsosDetails.m_detType[index] == 3 ) { + ++trackHitDetails.m_numTRT_Unused; + } else { + ++trackHitDetails.m_numUnused; + if ( tsosDetails.m_detType[index] == 2 ) { ++trackHitDetails.m_numSCT_Unused; } } + continue; } - } - - - - // Try and recover shared hits on this track if.. - bool recoverSharedHits = inROIandPTok && // Track is in ROI and has enough PT - score > m_minScoreShareTracks && // score needs to be good - trackHitDetails.numPixelHits+trackHitDetails.numSCTHits >= m_minSiHitsToAllowSplitting && - trackHitDetails.numPixelHoles<=1 ; // we do not share pixels if there are too many holes in pixels + //===================================================================// + // + // OUTLIERS - not type Outlier is given to both Shared and UnShared hits. Sort it out here + // Note in fillTrackDetails, for outliers we saved "1" in m_hitIsShared for any used hit, + // even if the true value is higher. As we will reject them here, it does not matter + // how many it is shared with + // if a pattern track + // - used : reject the hit + // - unused : call it unused and move on (reintegration of pattern outliers) + // if fitted track + // - used : reject the hit + // - unused : keep it but do not call it an unused hit (not counted towards total SiHit count) + // + if( tsosDetails.m_type[index] == Outlier ) { - // loop over all measurements - for (unsigned int index(0); index < tsosDetails.nTSoS; ++index ){ - //Skip all non-measurement TSOS's - if (tsosDetails.type[index] == OtherTsos) continue; - - - // Do we have some b-layer hit in the track? - if (tsosDetails.detType[index] == 11 && (!(tsosDetails.type[index]== Outlier) || trackHitDetails.isPatternTrack)) { - trackHitDetails.thishasblayer = true; // we may reintegrate outliers from pattern - } + // if on another track, get it off of this one + // for an outlier, we need to check m_hitIsShared to see if it used + if( tsosDetails.m_hitIsShared[index]>0 ) { // hit is used on another track + ATH_MSG_VERBOSE( Form("---> Prd is outlier and shared, reject it. %d", index) ); + rejectHit(trackHitDetails, tsosDetails, index); + continue; + } - // Keep all unused hits - if (tsosDetails.type[index] == UnusedHit ){ - if (tsosDetails.detType[index] == 3) { - ++trackHitDetails.numTRT_Unused; - } else { - ++trackHitDetails.numUnused; + if(trackHitDetails.m_isPatternTrack) { + + // For pattern tracks: + // if used : reject it --> see above + // if unused : reintegrate it and send to track fit + ATH_MSG_VERBOSE ( Form("---> Prd is outlier on a pattern track and is unused, %d", index) ); + // change to unused hit, increment counter + tsosDetails.m_type[index] = UnusedHit; // change name so m_numUnused matches types on track + ++trackHitDetails.m_numUnused; + if( tsosDetails.m_detType[index]%10 == 2 ) { ++trackHitDetails.m_numSCT_Unused; } + continue; } - - // remember the last 2 ROTs - lastbutonerot = lastrot; - lastrot = tsosDetails.RIO[index]; - lastrotindex = index; - continue; + else { // is outlier on fitted track and ... + // used : reject the hit --> see above + // unused: send it through, but do not count it towards the hit content + ATH_MSG_DEBUG( Form("---> Prd is outlier on a fitted track and is unused, %d", index) ); + continue; + } // m_isPatternTrack or not + } // isOutlier or not + //===================================================================// + + // cleaning cut: fitted track with 1 pixel hit without an IBL hit + /* hurts conversion performance, slighly better perf in min-bias without it + * but high pT jets can use this in the core + if(!trackHitDetails.m_isPatternTrack && // fitted track + trackHitDetails.m_numPixelHits==1 && // 1 pixel hit + !trackHitDetails.m_thisHasIBLHit && // no IBL hits + tsosDetails.m_detType[index]%10 == 1 && // index is the pixel hit + !(tsosDetails.m_type[index]==Outlier)) { // and it is not an outlier) + ATH_MSG_VERBOSE ("-> Special case, problematic single pixel hit on fitted track, reject it !"); + TrkCouldBeAccepted = false; // we have to remove at least one PRD + tsosDetails.m_type[index] = RejectedHit; + continue; } + */ - // special cut to remove problematic combinations in the pixels - // So far left this in need to check if it make a difference - if ( tsosDetails.detType[index]%10 == 1 && !trackHitDetails.thishasblayer && trackHitDetails.numPixelHoles>0 // a pixel hit, no b-layer, we do have pixel holes - && ( ( trackHitDetails.numPixelHits==1 && !(tsosDetails.type[index]==Outlier) ) // one pixel on track, it is not an additional outlier - || ( trackHitDetails.isPatternTrack && trackHitDetails.numPixelHits==0 && (tsosDetails.type[index]==Outlier) ) ) ) { // pattern track, no pixels, but an outlier (we may reintegrate it) - ATH_MSG_VERBOSE ("-> Special case, problematic single pixel hit on track, reject it !"); - tsosDetails.type[index] = RejectedHit; - // Mark track as bad ! - TrkCouldBeAccepted = false; - ATH_MSG_DEBUG ("reject track; Special case, problematic single pixel hit on track, reject it !"); - continue; + // At this point, only hits labeled shared from fillTrackDetails + if( tsosDetails.m_type[index] != SharedHit ) { + ATH_MSG_ERROR("A NON-Shared hit is being treated as one!"); } - // Try and recover shared hits if.. - if ( recoverSharedHits ) { + //===================================================================// + // Try and recover shared hits if + // - pixel cluster splitting flag is turned on + // - track passes criteria for cluster splitting + // - is a pixel hit + if ( m_doPixelClusterSplitting && recoverSharedHits && tsosDetails.m_detType[index]%10 == 1 ) { //Find the index of the previous measurement on track int indexPreviousMeasurement = tsosDetails.findIndexOfPreviousMeasurement(index); if (indexPreviousMeasurement > 0 ) { ATH_MSG_VERBOSE ("--> Previous Measurement was at : " << indexPreviousMeasurement - << " and was a: " << tsosDetails.type[indexPreviousMeasurement] - << " with splitprob1 " << tsosDetails.splitProb1[indexPreviousMeasurement] - << " and splitprob2 " << tsosDetails.splitProb2[indexPreviousMeasurement]); + << " and was a: " << tsosDetails.m_type[indexPreviousMeasurement] + << " with splitprob1 " << tsosDetails.m_splitProb1[indexPreviousMeasurement] + << " and splitprob2 " << tsosDetails.m_splitProb2[indexPreviousMeasurement]); } - // Special treatment of share split pixel clusters... - if (m_doPixelClusterSplitting && tsosDetails.detType[index]%10 == 1) { - - // If there is an earlier hit on the track and it is a pixel hit check to see if it's shared or split. - // This effectively means that singular shared hits in the pixel detector are only allowed in the first layer. - // Otherwise we make the assumption that a shared in nth layer means that - // there should be a shared in n-1 th layer. i.e. collimated tracks - // This breaks down in overlap regions hence it is disabled - if ( false && indexPreviousMeasurement > 0 && - !( tsosDetails.type[indexPreviousMeasurement] == SplitSharedHit || tsosDetails.type[indexPreviousMeasurement] == SharedHit || - tsosDetails.splitProb1[indexPreviousMeasurement] >= m_sharedProbCut || tsosDetails.splitProb2[indexPreviousMeasurement] >= m_sharedProbCut2) ) { - ATH_MSG_VERBOSE ("---> Previous hit was not shared or compatible with a split hit!!!"); - TrkCouldBeAccepted = false; // we have to remove at least one PRD - tsosDetails.type[index] = RejectedHit; - continue; - } - - // If the previous measurement is a shared pixel and the current pixel wants to be shared - // and is compatible with being so allow the previous measurement to be shared with up to m_maxTracksPerPRD tracks without penalty - if ( indexPreviousMeasurement >= 0 && - tsosDetails.type[indexPreviousMeasurement] == SharedHit && - tsosDetails.hitIsShared[indexPreviousMeasurement] < m_maxTracksPerPRD - && (tsosDetails.splitProb1[index] >= m_sharedProbCut || tsosDetails.splitProb2[index] >= m_sharedProbCut2)){ - - // Check if the previous shared hit shared on the same track as this one - bool sharedbetweenthesametracks = false; - auto previousHitsSharedTracks = tsosDetails.tracksSharingHit.equal_range(indexPreviousMeasurement); - auto currentHitsSharedTracks = tsosDetails.tracksSharingHit.equal_range(index); - for (auto iteratorP = previousHitsSharedTracks.first; iteratorP != previousHitsSharedTracks.second; ++iteratorP) { - for (auto iteratorC = currentHitsSharedTracks.first; iteratorC != currentHitsSharedTracks.second; ++iteratorC) { - if ( iteratorC->second == iteratorP->second){ - sharedbetweenthesametracks = true; - break; - } + // If the previous measurement is a shared pixel and the current pixel + // - wants to be shared + // - and is compatible with being from multiple clusters + // allow the previous measurement to be shared with up to m_maxTracksPerPRD tracks without penalty + if ( indexPreviousMeasurement >= 0 && + tsosDetails.m_type[indexPreviousMeasurement] == SharedHit && + tsosDetails.m_hitIsShared[indexPreviousMeasurement] < m_maxTracksPerPRD && + clusCanBeSplit(tsosDetails.m_splitProb1[index],tsosDetails.m_splitProb2[index]) ) { + + // Check if the previous shared hit shared on the same track as this one + bool sharedbetweenthesametracks = false; + auto previousHitsSharedTracks = tsosDetails.m_tracksSharingHit.equal_range(indexPreviousMeasurement); + auto currentHitsSharedTracks = tsosDetails.m_tracksSharingHit.equal_range(index); + for (auto iteratorP = previousHitsSharedTracks.first; + iteratorP != previousHitsSharedTracks.second; ++iteratorP) { + for (auto iteratorC = currentHitsSharedTracks.first; + iteratorC != currentHitsSharedTracks.second; ++iteratorC) { + if ( iteratorC->second == iteratorP->second){ + sharedbetweenthesametracks = true; + break; } - if (sharedbetweenthesametracks) break; } - if (sharedbetweenthesametracks){ - tsosDetails.type[indexPreviousMeasurement] = SplitSharedHit; - trackHitDetails.numShared--; // decrease counter - trackHitDetails.numWeightedShared -= 2; // decrease counter - trackHitDetails.numSplitSharedPix++; - } + if (sharedbetweenthesametracks) break; + } + if (sharedbetweenthesametracks){ + sharedToSplitPix(trackHitDetails, tsosDetails, indexPreviousMeasurement); + } + } + + // + // Check the number network. + // - check if the particle is compatible with 2 particles + // - else check if particle is compatible with >= 3 particles + // - else it is a 1 particle cluster + // Is a 2 particle cluster? + if ( isTwoPartClus(tsosDetails.m_splitProb1[index],tsosDetails.m_splitProb2[index]) ) { + + // can be split, but how many accepted tracks use the hit? + // okay to share + if (tsosDetails.m_hitIsShared[index] < m_maxPixTwoPartCluster) { + ATH_MSG_VERBOSE ("---> Pixel cluster is to be split shared with another track: Split Prob1 " << tsosDetails.m_splitProb1[index] ); + tsosDetails.m_type[index] = SplitSharedHit; + ++trackHitDetails.m_numSplitSharedPix; + continue; + } else if(m_shareSplitHits && tsosDetails.m_hitIsShared[index] == m_maxPixTwoPartCluster) { + // if we allow split hits to also be shared + // - the first m_maxPixTwoPartCluster cluster get to use it without penalty + // - the m_maxPixTwoPartCluster+1 cluster gets called shared + ATH_MSG_VERBOSE ("---> Pixel cluster is split, but must be called shared to stay on this track!"); + addSharedHit(trackHitDetails, tsosDetails, index); + continue; + } else { + ATH_MSG_VERBOSE ("---> Pixel split but shared between too many tracks -- will be removed from the track!!!"); + rejectHitOverUse(trackHitDetails, tsosDetails, index); + continue; } - // If cluster can only be shared by two tracks - if ( tsosDetails.splitProb1[index] >= m_sharedProbCut && tsosDetails.splitProb2[index] < m_sharedProbCut2){ - if (tsosDetails.hitIsShared[index] >= 2){ - ATH_MSG_VERBOSE ("---> Pixel cluster is split, and sheared between too many tracks -- hit will be removed from the track!!!"); - TrkCouldBeAccepted = false; // Flag that we need to remove the at least one hit - tsosDetails.type[index] = RejectedHit; - continue; - } else { - ATH_MSG_VERBOSE ("---> Pixel cluster is to be split shared with another track: Split Prob1 " << tsosDetails.splitProb1[index] ); - // Check if this first hit -- if it is not check if the pervious hit has been shared - // For now just print some debug output - if ( msg().level() <=MSG::VERBOSE && indexPreviousMeasurement>0){ - if (tsosDetails.type[indexPreviousMeasurement] == SplitSharedHit){ - ATH_MSG_VERBOSE("----- Previous Hit ("<< indexPreviousMeasurement <<") Shared and Split"); - } else if (tsosDetails.type[indexPreviousMeasurement] == SharedHit) { - ATH_MSG_VERBOSE("----- Previous Hit ("<< indexPreviousMeasurement<<") Shared"); - } else if (tsosDetails.type[indexPreviousMeasurement] == UnusedHit) { - ATH_MSG_VERBOSE("----- Previous Hit ("<< indexPreviousMeasurement <<") Unused hit"); - } else if (tsosDetails.type[indexPreviousMeasurement] == Outlier) { - ATH_MSG_VERBOSE("----- Previous Hit ("<< indexPreviousMeasurement <<") Outlier"); - } - } - tsosDetails.type[index] = SplitSharedHit; - ++trackHitDetails.numSplitSharedPix; - // remember the last 2 ROTs - lastbutonerot = lastrot; - lastrot = tsosDetails.RIO[index]; - lastrotindex = index; - continue; - } - // If cluster can shared by more than 2 tracks - } else if ( tsosDetails.splitProb2[index] >= m_sharedProbCut2){ - if (tsosDetails.hitIsShared[index] >= m_maxPixMultiCluster ){ - ATH_MSG_VERBOSE ("---> Pixel cluster is split, and sheared between too many tracks -- hit will be removed from the track!!!"); - TrkCouldBeAccepted = false; // Flag that we need to remove the at least one hit - tsosDetails.type[index] = RejectedHit; - continue; - } else { - ATH_MSG_VERBOSE ("---> Pixel cluster is to be split shared with another track: Split Prob2 " << tsosDetails.splitProb2[index] ); - // Check if this is the first hit -- if it is not check if the pervious hit has been shared - // For now just print some debug output - if (msg().level() <=MSG::VERBOSE && indexPreviousMeasurement>0){ - if (tsosDetails.type[indexPreviousMeasurement] == SplitSharedHit){ - ATH_MSG_VERBOSE("---- Previous Hit ("<< indexPreviousMeasurement <<") Shared and Split"); - } else if (tsosDetails.type[indexPreviousMeasurement] == SharedHit) { - ATH_MSG_VERBOSE("---- Previous Hit ("<< indexPreviousMeasurement <<") Shared"); - } else if (tsosDetails.type[indexPreviousMeasurement] == UnusedHit) { - ATH_MSG_VERBOSE("---- Previous Hit ("<< indexPreviousMeasurement <<") Unused hit"); - } else if (tsosDetails.type[indexPreviousMeasurement] == Outlier) { - ATH_MSG_VERBOSE("---- Previous Hit ("<< indexPreviousMeasurement <<") Outlier"); - } - } - tsosDetails.type[index] = SplitSharedHit; - ++trackHitDetails.numSplitSharedPix; - - // remember the last 2 ROTs - lastbutonerot = lastrot; - lastrot = tsosDetails.RIO[index]; - lastrotindex = index; - continue; - } - } // only split pixel clusters if there are few hole and the tracks have a good score - - ATH_MSG_VERBOSE("---> Pixel cluster is not compatible with being shared (splitProb1 = " - << tsosDetails.splitProb1[index] << "), (splitProb2 = " - << tsosDetails.splitProb2[index] << ") , reject shared hit !!!"); - if ( tsosDetails.hitIsShared[index] >= 2 ) { - TrkCouldBeAccepted = false; // we have to remove at least one PRD - ATH_MSG_DEBUG ("reject track; Too many hits shared - we have to remove at least one PRD 105"); - tsosDetails.type[index] = RejectedHit; - continue; - } + // Is a 3+ particle cluster? + } else if ( isMultiPartClus(tsosDetails.m_splitProb2[index]) ) { + + // can be split, but how many accepted tracks use the hit? + // okay to share + if (tsosDetails.m_hitIsShared[index] < m_maxPixMultiCluster ){ + ATH_MSG_VERBOSE ("---> Pixel cluster is to be split shared with another track: Split Prob2 " << tsosDetails.m_splitProb2[index] ); + tsosDetails.m_type[index] = SplitSharedHit; + ++trackHitDetails.m_numSplitSharedPix; + continue; + } else if(m_shareSplitHits && tsosDetails.m_hitIsShared[index] == m_maxPixMultiCluster) { + // if we allow split hits to also be shared + // - the first m_maxPixMultiCluster cluster get to use it without penalty + // - the m_maxPixMultiCluster+1 cluster gets called shared + ATH_MSG_VERBOSE ("---> Pixel cluster is split, but must be called shared to stay on this track!"); + addSharedHit(trackHitDetails, tsosDetails, index); + continue; + } else { + ATH_MSG_VERBOSE ("---> Pixel split but shared between too many tracks -- will be removed from the track!!!"); + rejectHitOverUse(trackHitDetails, tsosDetails, index); + continue; + } + + } // end of checking number network output + + ATH_MSG_VERBOSE("---> Pixel cluster is not compatible with being shared (splitProb1 = " + << tsosDetails.m_splitProb1[index] << "), (splitProb2 = " + << tsosDetails.m_splitProb2[index] << ") , reject shared hit !!!"); + if ( tsosDetails.m_hitIsShared[index] < m_maxPixOnePartCluster ) { + // this is a shared cluster + addSharedHit(trackHitDetails, tsosDetails, index); + continue; + } else { + ATH_MSG_DEBUG ("reject track; Too many hits shared - we have to remove at least one PRD"); + rejectHitOverUse(trackHitDetails, tsosDetails, index); + continue; } }// End Attempt to recover shared hits - + //===================================================================// + + if( tsosDetails.m_hitIsShared[index] == 0 ) { + ATH_MSG_ERROR("A hit is not shared but is where only shared hits should be"); + } + //For all other shared hits - if ( tsosDetails.hitIsShared[index] > 0 && tsosDetails.hitIsShared[index] < m_maxTracksPerPRD ){ // we do not allow to share with to many tracks + if ( tsosDetails.m_hitIsShared[index] < m_maxTracksPerPRD ){ // we do not allow to share with to many tracks ATH_MSG_VERBOSE ("---> Shared hit, but good track, let's enter hit in the list and try to keep it !"); - ATH_MSG_VERBOSE ("----- Index: "<< index << " Type: " << tsosDetails.detType[index] << " splitprob1 " << tsosDetails.splitProb1[index]); - tsosDetails.type[index] = SharedHit; - ++trackHitDetails.numShared; // increase counter - trackHitDetails.numWeightedShared += (tsosDetails.detType[index]%10== 1 ? 2 : 1); // increase counter - // remember the last 2 ROTs - lastbutonerot = lastrot; - lastrot = tsosDetails.RIO[index]; - lastrotindex = index; - continue; - } else if (tsosDetails.type[index] == Outlier && tsosDetails.hitIsShared[index] <= 0){ + ATH_MSG_VERBOSE ("----- Index: "<< index << " Type: " << tsosDetails.m_detType[index] << " splitprob1 " << tsosDetails.m_splitProb1[index]); + addSharedHit(trackHitDetails, tsosDetails, index); continue; } else { - ATH_MSG_DEBUG ("reject track; Too many hits shared - we have to remove at least one PRD 106"); - TrkCouldBeAccepted = false; // we have to remove at least one PRD - tsosDetails.type[index] = RejectedHit; + ATH_MSG_DEBUG ("reject track; Too many hits shared - we have to remove at least one PRD"); + rejectHitOverUse(trackHitDetails, tsosDetails, index); continue; } - } - - // If there are no hits on track compatible with be being split and are shared - // We will make use of the NN information to determine if we should allow that hit to be shared - /* Don't do this for now - if ( m_doPixelClusterSplitting && trackHitDetails.numSplitSharedPix < 1){ - for (unsigned int index(0); index < tsosDetails.nTSoS; ++index ){ - if ( tsosDetails.type[index] == SharedHit && - tsosDetails.detType[index] % 10 == 1 && - tsosDetails.splitProb1[index] < m_minsharedProbCut && - tsosDetails.splitProb2[index] < m_minsharedProbCut){ - tsosDetails.type[index] = RejectedHit; - trackHitDetails.numShared--; // decrease counter - trackHitDetails.numWeightedShared -= 2; // decrease counter - } - } - } - */ - - // special cut, do not allow the last hit to be to far away or after to many holes - if ( trackHitDetails.isPatternTrack && // pattern track and - trackHitDetails.totalSiHits() > m_minHits && // we have enough hits on the track - ( trackHitDetails.numSCTHoles > 3 || !lastrot || !lastbutonerot - ||(lastrot->globalPosition()-lastbutonerot->globalPosition()).mag()>1000*CLHEP::mm)) { // to many holes or distance cut - ATH_MSG_DEBUG ("Special cut on distance or too many holes, reject last hit on track !"); - tsosDetails.type[lastrotindex] = RejectedHit; - if (tsosDetails.type[lastrotindex] == UnusedHit) { - trackHitDetails.numUnused -= 1; // update counter - } - // mark track as bad ! - TrkCouldBeAccepted = false; - ATH_MSG_DEBUG ("reject track; Special cut on distance or too many holes, reject last hit on track"); - } + ATH_MSG_ERROR("Reached end of TSOS loop without a decision." ); + } // loop over TSOS + //------------------------------------------------------------------// + //------------------------------------------------------------------// + // + // COUNTERS have been set above. From here on, if change the state + // of any hit, must also adjust counters + // + //------------------------------------------------------------------// - // Add up how many hits of each type there are - bool firstMeasurement(true); - for (unsigned int index(0); index <tsosDetails.nTSoS; ++index ){ - // remember if first hit is shared, we need that later - if (firstMeasurement && tsosDetails.type[index] != OtherTsos){ - firstMeasurement = false; - if (tsosDetails.type[index] != SharedHit) trackHitDetails.firstisshared = false; - } - - if (tsosDetails.type[index] == SharedHit ){ - if (tsosDetails.detType[index] == 11 ){ // Blayer - trackHitDetails.hassharedblayer = true; - } else if ( tsosDetails.detType[index] == 1 ){ - trackHitDetails.hassharedpixel = true; - } - } - - if (tsosDetails.type[index] == SharedHit || tsosDetails.type[index] == SplitSharedHit){ - ++trackHitDetails.numSharedOrSplit; - if (tsosDetails.detType[index]%10==1){ - ++trackHitDetails.numSharedOrSplitPixels; - trackHitDetails.averageSplit1 += tsosDetails.splitProb1[index]; - trackHitDetails.averageSplit2 += tsosDetails.splitProb2[index]; - } - } - + //------------------------------------------------------------------// + // Check if the pair is compatible with being a light particle decay + // This focuses on conversions + // The track in question must + // - have an overlapping hit with an accepted track + // - those two track have a small separation + // + trackHitDetails.m_passConversionSel = false; // make sure off to start + if (m_doPairSelection && tsosDetails.m_overlappingTracks.size() > 0) { + trackHitDetails.m_passConversionSel = performConversionCheck(ptrTrack, + prd_to_track_map, trackHitDetails, tsosDetails, ent); + } + // if pass conversion selection, don't mess with it further + if( trackHitDetails.m_passConversionSel ) { return; } + //------------------------------------------------------------------// - if ( tsosDetails.detType[index]==2 && tsosDetails.type[index] == UnusedHit ){ - ++trackHitDetails.numSCT_Unused; + + //------------------------------------------------------------------// + // + // Three cuts which can pull shared hits off of the track (no order) + // 1. min unique SCT hits to share hits + // 2. min chi2/ndf to share hits + // + // We shared SCT hits when we don't really have enough to share + // Reject SCT shared hits on the track + if ( trackHitDetails.m_numSCT_Unused != trackHitDetails.m_numSCTHits && // have shared SCT + trackHitDetails.m_numSCT_Unused < m_minUniqueSCTHits ){ + for (unsigned int index( 0 ); index > tsosDetails.m_nTSoS; ++index ){ + if ( tsosDetails.m_detType[index]==2 && tsosDetails.m_type[index] == SharedHit){ + rejectSharedHit(trackHitDetails, tsosDetails, index); + } } } - // Calculate average pixel split prob for all of those pixels that are either shared or want to be shared - if (trackHitDetails.numSharedOrSplitPixels > 0 ){ - trackHitDetails.averageSplit1/=trackHitDetails.numSharedOrSplitPixels; - trackHitDetails.averageSplit2/=trackHitDetails.numSharedOrSplitPixels; - } + // Cut on chi2/NDF if shared hits on track + // if fail cuts, remove all shared hits and reject track + if ( !trackHitDetails.m_isPatternTrack && trackHitDetails.m_numShared > 0) { + double trackchi2 = 0; + if (ptrTrack->fitQuality() && ptrTrack->fitQuality()->numberDoF()>0 ) { + trackchi2 = ptrTrack->fitQuality()->chiSquared()/ptrTrack->fitQuality()->numberDoF(); + } + + // if track fails cut for shared hits, remove the shared hits + if ( trackchi2 > m_minTrackChi2ForSharedHits ) { + ATH_MSG_DEBUG ("Shared hits, we have a bad chi2 track, mark it as bad !"); + // remove shared hits and see if track survives + for (unsigned int index( 0 ); index > tsosDetails.m_nTSoS; ++index ){ + if ( tsosDetails.m_type[index] != SharedHit ) { continue; } + rejectSharedHit(trackHitDetails, tsosDetails, index); + } + } // fails cut + } // is not a pattern track and has shared hits + + //------------------------------------------------------------------// - // Check if the pair is compatible with being a light particle decay - bool passPairSelection =false; - if (m_doPairSelection){ - - //Find the accepted track that shares the most hits our proposed track - const Trk::Track* mostOverlappingTrack(0); - int mostOverlappingNumberOfHits(0); - int indexOfFirstOverlappingHit(0); - for ( std::multimap<const Trk::Track*,int>::iterator it = tsosDetails.overlappingTracks.begin(), end = tsosDetails.overlappingTracks.end(); - it != end; it = tsosDetails.overlappingTracks.upper_bound(it->first)) { - int numberOfHitsSharedWithThisTrack = std::distance( it, tsosDetails.overlappingTracks.upper_bound(it->first)); - ATH_MSG_DEBUG(it->first <<" shares " << numberOfHitsSharedWithThisTrack << " hits with this track " ); - if (mostOverlappingNumberOfHits < numberOfHitsSharedWithThisTrack){ - mostOverlappingNumberOfHits = numberOfHitsSharedWithThisTrack; - mostOverlappingTrack = it->first; - indexOfFirstOverlappingHit = it->second; + //------------------------------------------------------------------// + // Check accepted tracks with the surviving list of shared hits + // Remove shared hits which push track over shared module cut + // Set flags + // + // add up weighted count of shared hits on track, start removing + // hits after counter is above cut. This preferences inner hits + int newNumWeightedShared = 0; // tmp counter + bool firstMeasurement(true); + trackHitDetails.m_firstPixIsShared = false; + // was already set in fillTrackDetails, but set again depending if blayer was rejected or not + trackHitDetails.m_thisHasIBLHit = false; + for (unsigned int index(0); index <tsosDetails.m_nTSoS; ++index ){ + + // don't count rejected hits when setting flags + if (tsosDetails.m_type[index] == RejectedHitOverUse || + tsosDetails.m_type[index] == RejectedHitInvalid || + tsosDetails.m_type[index] == RejectedHit ){ continue; } + + // Any track which is still labeled as SharedHit has to be checked + // against the accepted tracks. Accepted track should not be pushed + // above cuts imposed here, some historic cuts remain + if (tsosDetails.m_type[index] == SharedHit) { + + int maxiShared = -1; + int maxOtherNPixel = 0; + bool maxOtherHasIBL = false; + bool otherPassMinUniqueHits = checkOtherTracksValidity( tsosDetails, index, + splitProbContainer, prd_to_track_map, maxiShared, maxOtherNPixel, + maxOtherHasIBL, ent); + + if (!otherPassMinUniqueHits) { + ATH_MSG_DEBUG ("reject track; Tracks shared hits does not leave enough unique hits on accepted track"); + rejectSharedHitInvalid(trackHitDetails, tsosDetails, index); + continue; } - } - //If an overlapping track if found get the track parameters on the first shared surface - if ( mostOverlappingTrack ){ - auto tpPair = getOverlapTrackParameters(indexOfFirstOverlappingHit, ptrTrack, mostOverlappingTrack, prd_to_track_map, trackHitDetails.numSplitSharedPix ); - if (tpPair.first && tpPair.second){ - // Check if both tracks are above threshold - bool passPt = tpPair.first->pT() > m_minPairTrackPt && tpPair.second->pT() > m_minPairTrackPt; - //Check if it is in a ROI - trackHitDetails.inROI = m_useEmClusSeed && isEmCaloCompatible( *tpPair.first, ent ); - //If it is then See if it passes the pair selection - if ( passPt && (!m_useEmClusSeed || trackHitDetails.inROI) ){ - passPairSelection = isNearbyTrackCandidate(tpPair.first, tpPair.second ); - if ( mostOverlappingNumberOfHits >= 2 && mostOverlappingNumberOfHits >= trackHitDetails.numShared){ - passPairSelection = true; - } + // + // do not allow other accepted track to exceed the shared limit... + // ...IF first pixel hit is shared (historic cut) + // NOTE: here "pixel" includes IBL + // tightening cut by dropping shared hit clause impacts performance in high pT jet cores + if( maxiShared >= ent->m_maxSharedModules ){ + + // if this is the first hit (it is shared), and a pixel, reject + if( (tsosDetails.m_detType[index] % 10 == 1) && firstMeasurement ) { + ATH_MSG_DEBUG ("reject track; Tracks shared hits pushes accepted track above shared module limit"); + rejectSharedHitInvalid(trackHitDetails, tsosDetails, index); + continue; } - if (passPairSelection) ATH_MSG_DEBUG ("Possible photon conversion"); - } else if ( trackHitDetails.isPatternTrack - && mostOverlappingNumberOfHits >= 2 - && mostOverlappingNumberOfHits >= trackHitDetails.numShared){ - ATH_MSG_DEBUG ("Possible photon conversion - for pattern track"); - trackHitDetails.inROI = true; - passPairSelection = true; + // if first pixel was shared (and this is not that hit) + if( trackHitDetails.m_firstPixIsShared ) { + ATH_MSG_DEBUG ("reject track; Tracks shared hits pushes accepted track above shared module limit"); + rejectSharedHitInvalid(trackHitDetails, tsosDetails, index); + continue; + } + + // unlinked (no truth particle) tracks tend to have low hit counts + // don't let track that look like this touch accepted tracks (new) + if( trackHitDetails.totalPixelHits() < m_minPixHitAccepted ) { + rejectSharedHitInvalid(trackHitDetails, tsosDetails, index); + continue; + } + + } // accepted track exceeds shared module cuts + + + // + // only allow shared pixel if both have IBL or both not (historic cut) + // if this is IBL hit, and other does not have IBL hit, remove shared IBL hit + if( tsosDetails.m_detType[index] == 11 && !maxOtherHasIBL ) { + ATH_MSG_VERBOSE ("---> Remove shared IBL as MaxShared accepted does not have an IBL hit"); + rejectSharedHit(trackHitDetails, tsosDetails, index); + continue; + } + // if this is pixel hit, and candidate does not match IBL content of MaxShared accepted, remove shared hit + if(tsosDetails.m_detType[index] == 1 && (trackHitDetails.m_thisHasIBLHit != maxOtherHasIBL) ) { + ATH_MSG_VERBOSE ("---> Only allow shared pixel if candidate and accepted have same IBL hit content"); + rejectSharedHit(trackHitDetails, tsosDetails, index); + continue; } - } + // number of shared modules to be added to new sub-track + // add shared hit to temporary counter + newNumWeightedShared += (tsosDetails.m_detType[index]%10== 1 ? 2 : 1); // increase counter + // should remain beow the threshold + if (newNumWeightedShared >= ent->m_maxSharedModules) { + ATH_MSG_VERBOSE ("-> Too many share hits, dropping outer hit(s) " + << newNumWeightedShared << "\t" << ent->m_maxSharedModules); + newNumWeightedShared -= (tsosDetails.m_detType[index]%10== 1 ? 2 : 1); // decrease counter + rejectSharedHit(trackHitDetails, tsosDetails, index); + continue; + } - ATH_MSG_DEBUG ("Number of unused SCT hits: " << trackHitDetails.numSCT_Unused); - ATH_MSG_DEBUG ("The track has "<< trackHitDetails.numSharedOrSplit << " shared hits. Track "<< mostOverlappingTrack << " shares " << mostOverlappingNumberOfHits ); - ATH_MSG_DEBUG ("The track has "<< trackHitDetails.numSharedOrSplitPixels << " shared pixel hits. Average splitProb1 "<< trackHitDetails.averageSplit1 << " splitProb2 " << trackHitDetails.averageSplit2 ); + //------------------------------------------// + // if still shared and not rejected by above, set flags + if( tsosDetails.m_detType[index] % 10 == 1 ) { + if (firstMeasurement) { + trackHitDetails.m_firstPixIsShared = true; + } + if (tsosDetails.m_detType[index] == 11 ){ // Blayer + trackHitDetails.m_hasSharedIBLHit = true; + } else if ( tsosDetails.m_detType[index] == 1 ){ + trackHitDetails.m_hasSharedPixel = true; // historic definition + } + } // pixel hit + } // if shared - //Keep photon conversions - if ( passPairSelection && // Track pair must be neutral and pass preselection - trackHitDetails.numSCT_Unused >= m_minUniqueSCTHits && trackHitDetails.numPixelHoles + trackHitDetails.numSCTHoles < 2) { // We need to have a good number of unshared SCT hits + if (tsosDetails.m_detType[index] == 11 ){ // Blayer + trackHitDetails.m_thisHasIBLHit = true; + } + if (firstMeasurement && tsosDetails.m_type[index] != OtherTsos){ firstMeasurement = false; } - //Change all shared SCT and Pixel hits to SplitSharedHit - //Need to double check consequence of having split shared SCT hits - ATH_MSG_VERBOSE ("Updating SCT hit information"); - trackHitDetails.numSplitSharedSCT = 0; // reset counter - trackHitDetails.numShared = 0; // reset counter - trackHitDetails.numWeightedShared = 0; // reset counter + } // loop over TSOS + //------------------------------------------------------------------// - trackHitDetails.hassharedblayer = false; - trackHitDetails.hassharedpixel = false; + if (msgLvl(MSG::VERBOSE)){ + trackHitDetails.dumpInfo(); + } + + return; +} // decideWhichHitsToKeep - //Update counts but only allow 1 pixel hit to be updated free of charge - int noUpdatedPixels = 0; +//========================================================================================== - for (unsigned int index(0); index < tsosDetails.nTSoS; ++index ){ - // Dont change blayer only pixel hits -- all other shared hits become splitshared - if ( noUpdatedPixels < 1 && tsosDetails.detType[index]==1 && tsosDetails.type[index] == SharedHit ){ - ++noUpdatedPixels; - tsosDetails.type[index] = SplitSharedHit; - } +// GOAL: Do not kill conversions in the ambi +bool InDet::InDetDenseEnvAmbiTrackSelectionTool::performConversionCheck(const Trk::Track* ptrTrack, + Trk::PRDtoTrackMap &prd_to_track_map, + TrackHitDetails& trackHitDetails, + TSoS_Details& tsosDetails, + CacheEntry* ent) const +{ + ATH_MSG_DEBUG(" Conversion Check "); + + // We need to have a good number of unshared SCT hits + if ( trackHitDetails.m_numSCT_Unused < m_minUniqueSCTHits ) { return false; } + if ( trackHitDetails.m_numPixelHoles + trackHitDetails.m_numSCTHoles >= 2) { return false; } + + //Find the accepted track that shares the most hits our proposed track + const Trk::Track* mostOverlappingTrack(0); + int mostOverlappingNumberOfHits(0); + int indexOfFirstOverlappingHit(0); + for ( std::multimap<const Trk::Track*,int>::iterator it = tsosDetails.m_overlappingTracks.begin(), + end = tsosDetails.m_overlappingTracks.end(); it != end; + it = tsosDetails.m_overlappingTracks.upper_bound(it->first) ) { + int numberOfHitsSharedWithThisTrack = std::distance( it, tsosDetails.m_overlappingTracks.upper_bound(it->first)); + ATH_MSG_DEBUG(it->first <<" shares " << numberOfHitsSharedWithThisTrack << " hits with this track " ); + if (mostOverlappingNumberOfHits < numberOfHitsSharedWithThisTrack){ + mostOverlappingNumberOfHits = numberOfHitsSharedWithThisTrack; + mostOverlappingTrack = it->first; + indexOfFirstOverlappingHit = it->second; + } + } // loop over overlapping tracks - if ( tsosDetails.detType[index]==1 && tsosDetails.type[index] == SplitSharedHit ){ - ++trackHitDetails.numSplitSharedPix; - } + if(!mostOverlappingTrack) { return false; } - if ( tsosDetails.detType[index]==2 && tsosDetails.type[index] == SharedHit ){ - tsosDetails.type[index] = SplitSharedHit; - } + // criteria applied for fitted and pattern tracks + if(mostOverlappingNumberOfHits < 2) { return false; } + if(mostOverlappingNumberOfHits < trackHitDetails.m_numShared) { return false; } - if ( tsosDetails.detType[index]==2 && tsosDetails.type[index] == SplitSharedHit ){ - ++trackHitDetails.numSplitSharedSCT; - } - if (tsosDetails.type[index] == SharedHit){ - trackHitDetails.numShared++; // increase counter - trackHitDetails.numWeightedShared += (tsosDetails.detType[index] % 10 == 1 ? 2 : 1); // increase counter - if (tsosDetails.detType[index] == 11){ - trackHitDetails.hassharedblayer = true; - trackHitDetails.hassharedpixel = true; - } - } - } + //If an overlapping track if found get the track parameters on the first shared surface + auto tpPair = getOverlapTrackParameters(indexOfFirstOverlappingHit, ptrTrack, mostOverlappingTrack, prd_to_track_map, trackHitDetails.m_numSplitSharedPix ); + + // If found track parameters at first overlapping track, check separation + if (tpPair.first && tpPair.second) { + // Check a series of criteria to see if track is a compatible with a photon conversion + // Check if both tracks are above threshold + if(tpPair.first->pT() <= m_minPairTrackPt || tpPair.second->pT() <= m_minPairTrackPt) { + return false; } - } - - if (trackHitDetails.numSCT_Unused < m_minUniqueSCTHits - && trackHitDetails.numSplitSharedSCT > 0){ - ATH_MSG_VERBOSE ("Track has too few unique SCT hits - changing split shared back to shared in SCT"); - for (unsigned int index( tsosDetails.nTSoS - 1 ); index != 0 ; --index ){ - //if ( tsosDetails.detType[index]==2 && tsosDetails.type[index] == SplitSharedHit){ - if ( tsosDetails.detType[index]==2 && tsosDetails.type[index] == SplitSharedHit && tsosDetails.splitProb1[index] < 0.1 ){ //WPM - tsosDetails.type[index] =SharedHit; - --trackHitDetails.numSplitSharedSCT; - ++trackHitDetails.numShared; // increase counter - ++trackHitDetails.numWeightedShared; // increase counter - } - - if ( trackHitDetails.numSplitSharedSCT == 0){ - break; - } + //Check if it is in a ROI, if requested + if(m_useEmClusSeed) { + if(!isEmCaloCompatible( *tpPair.first, ent )) { return false; } } + ATH_MSG_DEBUG ("Possible photon conversion"); } - - // We shared SCT hits when we don't really have enough to share - // Reject SCT shared hits - if ( trackHitDetails.numSCT_Unused != trackHitDetails.numSCTHits && - trackHitDetails.numSCTHits <= m_minUniqueSCTHits ){ - - for (unsigned int index( 0 ); index > tsosDetails.nTSoS; ++index ){ - //if ( tsosDetails.detType[index]==2 && tsosDetails.type[index] == SharedHit){ - if ( tsosDetails.detType[index]==2 && tsosDetails.type[index] == SharedHit && tsosDetails.splitProb1[index] < 0.1 ){ //WPM - tsosDetails.type[index] = RejectedHit; - trackHitDetails.numShared--; // decrease counter - trackHitDetails.numWeightedShared--; // decrease counter - } + // for pattern tracks, cannot get the track parameters at a hit position + // Need an alternate way to find conversion, try to use the accepted track + // Main point is to not kill the pattern track + else if ( trackHitDetails.m_isPatternTrack ) { + if(m_useEmClusSeed && tpPair.second ) { + if(!isEmCaloCompatible( *tpPair.second, ent )) { return false; } } + ATH_MSG_DEBUG ("Possible photon conversion - for pattern track"); } - - // get chi2/NDF, if track is fitted - if ( !trackHitDetails.isPatternTrack ) { - double trackchi2 = 0; - if (ptrTrack->fitQuality() && ptrTrack->fitQuality()->numberDoF()>0 ) { - trackchi2 = ptrTrack->fitQuality()->chiSquared()/ptrTrack->fitQuality()->numberDoF(); + // if cannot find track parameters, and not a pattern track, then failed + else { + return false; + } + + ATH_MSG_DEBUG ("Number of unused SCT hits: " << trackHitDetails.m_numSCT_Unused); + if (msgLvl(MSG::DEBUG)){ + trackHitDetails.dumpInfo(); + } + ATH_MSG_DEBUG ("Track "<< mostOverlappingTrack << " shares " << mostOverlappingNumberOfHits ); + + + //Change all shared SCT to SplitSharedHit + //Change some shared Pix to SplitSharedHit + ATH_MSG_VERBOSE ("Updating SCT hit information"); + trackHitDetails.m_numSplitSharedPix = 0; // reset counter + trackHitDetails.m_numSplitSharedSCT = 0; // reset counter + trackHitDetails.m_numShared = 0; // reset counter + trackHitDetails.m_numSCT_Shared = 0; // reset counter + trackHitDetails.m_numWeightedShared = 0; // reset counter + + trackHitDetails.m_hasSharedIBLHit = false; // reset flag + trackHitDetails.m_hasSharedPixel = false; // reset flag + + //Update counts but only allow 1 pixel hit to be updated free of charge + int noUpdatedPixels = 0; + + for (unsigned int index(0); index < tsosDetails.m_nTSoS; ++index ){ + // Dont change blayer only pixel hits -- all other shared hits become splitshared + if ( noUpdatedPixels < 1 && tsosDetails.m_detType[index]==1 && tsosDetails.m_type[index] == SharedHit ){ + ++noUpdatedPixels; + tsosDetails.m_type[index] = SplitSharedHit; + } + + if ( tsosDetails.m_detType[index]==1 && tsosDetails.m_type[index] == SplitSharedHit ){ + ++trackHitDetails.m_numSplitSharedPix; + } + + if ( tsosDetails.m_detType[index]==2 && tsosDetails.m_type[index] == SharedHit ){ + tsosDetails.m_type[index] = SplitSharedHit; } - // if we have share hits and this is a bad track, we reject it - if ( trackHitDetails.numShared > 0 && trackchi2 > m_minTrackChi2ForSharedHits ) { - ATH_MSG_DEBUG ("Shared hits, we have a bad chi2 track, mark it as bad !"); - // mark track as bad ! - TrkCouldBeAccepted = false; - ATH_MSG_DEBUG ("reject track; Shared hits, we have a bad chi2 track"); + if ( tsosDetails.m_detType[index]==2 && tsosDetails.m_type[index] == SplitSharedHit ){ + ++trackHitDetails.m_numSplitSharedSCT; } - } + // only change shared hits + // m_numUnused and m_numSCT_Unused are not changed from this + if (tsosDetails.m_type[index] != SharedHit){ continue; } - // numTRT cut, special for back tracking - if ( trackHitDetails.numTRT_Unused < nCutTRT) { - ATH_MSG_DEBUG ("Track fails TRT hit cut, mark it as bad !"); - // mark track as bad ! - TrkCouldBeAccepted = false; - ATH_MSG_DEBUG ("reject track; Track fails TRT hit cut, mark it as bad"); - } - - // Check to see if we should reject it on the basis it will mess up another track - if (TrkCouldBeAccepted && trackHitDetails.numWeightedShared > 0){ - ATH_MSG_DEBUG ("Track has shared hits check to if sharing this hit will mess up an accepted track"); - for (unsigned int index(0); index < tsosDetails.nTSoS; ++index ){ - if (tsosDetails.type[index] == SharedHit){ - - int maxiShared = -1; - int maxothernpixel = 0; - bool maxotherhasblayer = false; - bool otherfailsMinUniqueHits = false; - bool isSplitable = tsosDetails.splitProb1[index] >= m_sharedProbCut || tsosDetails.splitProb2[index] >= m_sharedProbCut2; - int numberOfTracksWithThisPrd = checkOtherTracksValidity( tsosDetails.RIO[index], - isSplitable, - splitProbContainer, - prd_to_track_map, - maxiShared, - maxothernpixel, - maxotherhasblayer, - otherfailsMinUniqueHits, - ent); - - if (numberOfTracksWithThisPrd > 0 && ( otherfailsMinUniqueHits || maxiShared >= ent->m_maxShared )){ - TrkCouldBeAccepted = false; - ATH_MSG_DEBUG ("reject track; Tracks shared hits will mess up an accepted track"); - tsosDetails.type[index] = RejectedHit; - trackHitDetails.numShared--; // decrease counter - trackHitDetails.numWeightedShared -= (tsosDetails.detType[index]%10== 1 ? 2 : 1); // increase counter - } - } + increaseSharedHitCounters( trackHitDetails, + (tsosDetails.m_detType[index]%10 == 1), + (tsosDetails.m_detType[index]%10 == 2) ); + + // set flags + if (tsosDetails.m_detType[index] == 11){ + trackHitDetails.m_hasSharedIBLHit = true; + } else if ( tsosDetails.m_detType[index] == 1 ){ + trackHitDetails.m_hasSharedPixel = true; } - } + + } // loop over TSOS - if (msgLvl(MSG::VERBOSE)){ - trackHitDetails.dumpInfo(); - } - - return TrkCouldBeAccepted; -} + return true; +} // performConversionCheck //========================================================================================== @@ -1249,10 +1284,8 @@ Trk::Track* InDet::InDetDenseEnvAmbiTrackSelectionTool::createSubTrack( const st DataVector<const Trk::TrackStateOnSurface>* vecTsos = new DataVector<const Trk::TrackStateOnSurface>(); // loop over TSOS, copy TSOS and push into vector - DataVector<const Trk::TrackStateOnSurface>::const_iterator iTsos = tsos.begin(); - DataVector<const Trk::TrackStateOnSurface>::const_iterator iTsosEnd = tsos.end(); - for ( ; iTsos != iTsosEnd ; ++iTsos) { - const Trk::TrackStateOnSurface* newTsos = new Trk::TrackStateOnSurface(**iTsos); + for (const Trk::TrackStateOnSurface* iTsos : tsos) { + const Trk::TrackStateOnSurface* newTsos = new Trk::TrackStateOnSurface(*iTsos); vecTsos->push_back(newTsos); } @@ -1273,14 +1306,14 @@ void InDet::InDetDenseEnvAmbiTrackSelectionTool::setPixelClusterSplitInformation Trk::ClusterSplitProbabilityContainer &splitProbContainer) const { - for (unsigned int index(0); index < tsosDetails.nTSoS; ++index ){ + for (unsigned int index(0); index < tsosDetails.m_nTSoS; ++index ){ //Only consider split shared hits - if (tsosDetails.type[index] != SplitSharedHit) + if (tsosDetails.m_type[index] != SplitSharedHit) continue; // And the hit is a pixel hit - if (tsosDetails.detType[index]%10 == 1){ - const InDet::PixelCluster* pixelCluster = dynamic_cast<const InDet::PixelCluster*> ( tsosDetails.RIO[index]->prepRawData() ); + if (tsosDetails.m_detType[index]%10 == 1){ + const InDet::PixelCluster* pixelCluster = dynamic_cast<const InDet::PixelCluster*> ( tsosDetails.m_RIO[index]->prepRawData() ); if (pixelCluster){ Trk::ClusterSplitProbabilityContainer::ProbabilityInfo *splitProb = splitProbContainer.getSplitProbability(pixelCluster); if (!splitProb) { @@ -1295,6 +1328,17 @@ void InDet::InDetDenseEnvAmbiTrackSelectionTool::setPixelClusterSplitInformation } +//========================================================================================== +bool InDet::InDetDenseEnvAmbiTrackSelectionTool::inHadronicROI(const Trk::Track* ptrTrack, + CacheEntry* ent) const +{ + + if ( !ptrTrack->trackParameters()->front() ){ return false; } + // above pT for ROI? + if ( ptrTrack->trackParameters()->front()->pT() < m_minPtBjetROI ) { return false; } + + return isHadCaloCompatible(*ptrTrack->trackParameters()->front(), ent); +} //========================================================================================== bool InDet::InDetDenseEnvAmbiTrackSelectionTool::isHadCaloCompatible(const Trk::TrackParameters& Tp, CacheEntry* ent) const { @@ -1375,11 +1419,15 @@ std::pair<const Trk::TrackParameters*, const Trk::TrackParameters*> InDet::InDetDenseEnvAmbiTrackSelectionTool::getOverlapTrackParameters(int index, const Trk::Track* track1, const Trk::Track* track2, const Trk::PRDtoTrackMap &prd_to_track_map, - int SplitSharedPix ) const + int splitSharedPix ) const { auto returnPair = std::make_pair<const Trk::TrackParameters*,const Trk::TrackParameters*>(0,0); + // + // Get the TSOS in question from the candidate track since we know which one it is (index) + // Do some basic checks + // const DataVector<const Trk::TrackStateOnSurface>* track1tsos = track1->trackStateOnSurfaces(); auto firstTsos = track1tsos->begin(); @@ -1402,13 +1450,10 @@ InDet::InDetDenseEnvAmbiTrackSelectionTool::getOverlapTrackParameters(int index, return returnPair; } - if (!(*firstTsos)->trackParameters()){ - ATH_MSG_DEBUG("There are no TrackParameters on this TSOS"); - return returnPair; - } - - returnPair.first = (*firstTsos)->trackParameters(); + // + // now, get TSOS from 2nd track which is the one already accepted + // we know it was fitted so this should be possible const DataVector<const Trk::TrackStateOnSurface>* track2tsos = track2->trackStateOnSurfaces(); auto iTsos = track2tsos->begin(); @@ -1416,7 +1461,8 @@ InDet::InDetDenseEnvAmbiTrackSelectionTool::getOverlapTrackParameters(int index, int measurementsBeforeShared = 0; for (; iTsos != iTsosEnd ; ++iTsos) { - if (measurementsBeforeShared > 1 + SplitSharedPix ){ + // only compare to number of split hits? Why not shared also for NN inefficienicies + if (measurementsBeforeShared > 1 + splitSharedPix ){ ATH_MSG_DEBUG("Too many hits to before shared hit -- unlikely they are from the same thing"); return returnPair; } @@ -1445,49 +1491,106 @@ InDet::InDetDenseEnvAmbiTrackSelectionTool::getOverlapTrackParameters(int index, } returnPair.second = (*iTsos)->trackParameters(); - ATH_MSG_DEBUG("Success! got both track parameters "<< returnPair.first<< " " << returnPair.second ); - return returnPair; + ATH_MSG_DEBUG("Success! track parameters for accepted track " << returnPair.second ); + break; } - - - ATH_MSG_DEBUG("Failed! got both track parameters"); - return returnPair; - -} - - -bool InDet::InDetDenseEnvAmbiTrackSelectionTool::isNearbyTrackCandidate(const Trk::TrackParameters* paraA, const Trk::TrackParameters* paraB ) const -{ - bool pass = true; - - //Only require opposite charge for is using EM clusters -- more photon like - //if (m_useEmClusSeed && paraA->charge() * paraB->charge() > 0 ) - // pass = false; - double dlocalX = paraA->parameters()[Trk::locX] - paraB->parameters()[Trk::locX]; - double dlocalY = paraA->parameters()[Trk::locY] - paraB->parameters()[Trk::locY]; - + // + // Now let's see if we have TPs for the candidate track + // - double dPhi = paraA->parameters()[Trk::phi] - paraB->parameters()[Trk::phi]; - if (dPhi > M_PI) dPhi -= 2* M_PI; - if (dPhi < -M_PI) dPhi += 2* M_PI; - - double dEta = std::fabs(1./std::tan(paraA->parameters()[Trk::theta]) - 1./std::tan(paraB->parameters()[Trk::theta])); - - if (std::fabs(dlocalX) > m_pairDeltaX || std::fabs(dlocalY) > m_pairDeltaY || std::fabs(dPhi) > m_pairDeltaPhi || std::fabs(dEta) > m_pairDeltaEta) - pass = false; + if (!(*firstTsos)->trackParameters()){ + ATH_MSG_DEBUG("There are no TrackParameters on this TSOS"); + return returnPair; + } + returnPair.first = (*firstTsos)->trackParameters(); - //double d_beta = (paraA->momentum().dot(paraB->momentum()))/(paraA->momentum().mag()*paraB->momentum().mag()); - ATH_MSG_DEBUG("Conv? Charge: "<<paraA->charge() * paraB->charge() - <<" dX: " << dlocalX - <<" dy: " << dlocalY - <<" dphi: " << dPhi - <<" dEta: " << dEta - <<" pass: " << pass); + ATH_MSG_DEBUG("Success! track parameters for both tracks " << returnPair.first<< " " << returnPair.second ); - return pass; + return returnPair; + +} + +//============================================================================================ +// +inline bool InDet::InDetDenseEnvAmbiTrackSelectionTool::clusCanBeSplit(float splitProb1, float splitProb2) const +{ + return ( isTwoPartClus(splitProb1, splitProb2) || isMultiPartClus(splitProb2) ); +} +inline bool InDet::InDetDenseEnvAmbiTrackSelectionTool::isTwoPartClus(float splitProb1, float splitProb2) const +{ + return ( (splitProb1 >= m_sharedProbCut) && (splitProb2 < m_sharedProbCut2) ); } +inline bool InDet::InDetDenseEnvAmbiTrackSelectionTool::isMultiPartClus(float splitProb2) const +{ + return ( splitProb2 >= m_sharedProbCut2 ); +} +//============================================================================================ +// +//============================================================================================ +inline void InDet::InDetDenseEnvAmbiTrackSelectionTool::rejectHitOverUse(TrackHitDetails& trackHitDetails, + TSoS_Details& tsosDetails, int index) const { + trackHitDetails.m_trkCouldBeAccepted = false; // we have to remove at least one PRD + tsosDetails.m_type[index] = RejectedHitOverUse; + return; +} +inline void InDet::InDetDenseEnvAmbiTrackSelectionTool::rejectHit(TrackHitDetails& trackHitDetails, + TSoS_Details& tsosDetails, int index) const { + trackHitDetails.m_trkCouldBeAccepted = false; // we have to remove at least one PRD + tsosDetails.m_type[index] = RejectedHit; + return; +} +// used after counters have been set +inline void InDet::InDetDenseEnvAmbiTrackSelectionTool::rejectSharedHit(TrackHitDetails& trackHitDetails, + TSoS_Details& tsosDetails, int index) const { + rejectHit(trackHitDetails, tsosDetails, index); // reject + decreaseSharedHitCounters( trackHitDetails, + (tsosDetails.m_detType[index]%10 == 1), + (tsosDetails.m_detType[index]%10 == 2) ); + return; +} +// used after counters have been set +inline void InDet::InDetDenseEnvAmbiTrackSelectionTool::rejectSharedHitInvalid(TrackHitDetails& trackHitDetails, + TSoS_Details& tsosDetails, int index) const { + trackHitDetails.m_trkCouldBeAccepted = false; + tsosDetails.m_type[index] = RejectedHitInvalid; // do not use rejectHit function since use this flag + decreaseSharedHitCounters( trackHitDetails, + (tsosDetails.m_detType[index]%10 == 1), + (tsosDetails.m_detType[index]%10 == 2) ); + return; +} +// used after counters have been set +inline void InDet::InDetDenseEnvAmbiTrackSelectionTool::sharedToSplitPix(TrackHitDetails& trackHitDetails, + TSoS_Details& tsosDetails, int index) const { + // from shared + decreaseSharedHitCounters( trackHitDetails, true, false ); // isPix=true + // to split + tsosDetails.m_type[index] = SplitSharedHit; + trackHitDetails.m_numSplitSharedPix++; + return; +} +inline void InDet::InDetDenseEnvAmbiTrackSelectionTool::addSharedHit(TrackHitDetails& trackHitDetails, + TSoS_Details& tsosDetails, int index) const { + tsosDetails.m_type[index] = SharedHit; + increaseSharedHitCounters( trackHitDetails, (tsosDetails.m_detType[index]%10 == 1), (tsosDetails.m_detType[index]%10 == 2) ); + return; +} +inline void InDet::InDetDenseEnvAmbiTrackSelectionTool::increaseSharedHitCounters(TrackHitDetails& trackHitDetails, bool isPix, bool isSCT) const { + trackHitDetails.m_numShared++; // increase counter + trackHitDetails.m_numWeightedShared += (isPix ? 2 : 1); // increase counter + // protect from TRT hits (needed?) + if( isSCT ) { trackHitDetails.m_numSCT_Shared++; } + return; +} +inline void InDet::InDetDenseEnvAmbiTrackSelectionTool::decreaseSharedHitCounters(TrackHitDetails& trackHitDetails, bool isPix, bool isSCT) const { + trackHitDetails.m_numShared--; // decrease counter + trackHitDetails.m_numWeightedShared -= (isPix ? 2 : 1); // increase counter + // protect from TRT hits (needed?) + if( isSCT ) { trackHitDetails.m_numSCT_Shared--; } + return; +} +//============================================================================================ diff --git a/Tools/PROCTools/data/master_q221_AOD_digest.ref b/Tools/PROCTools/data/master_q221_AOD_digest.ref index 780afebab35..b3af0f81166 100644 --- a/Tools/PROCTools/data/master_q221_AOD_digest.ref +++ b/Tools/PROCTools/data/master_q221_AOD_digest.ref @@ -1,11 +1,11 @@ run event nTopo nIdTracks nJets nMuons nElec nTrueElec nFakeElec nPhot nTruePhot nFakePhot 284500 87473001 122 131 4 1 8 2 6 7 4 3 284500 87473014 83 80 6 0 10 1 9 7 5 2 - 284500 87473022 38 30 4 0 4 1 3 2 1 1 + 284500 87473022 38 30 4 0 4 1 3 3 2 1 284500 87473032 30 33 4 1 10 4 6 5 2 3 284500 87473037 62 38 7 0 12 2 10 6 4 2 - 284500 87473040 107 97 10 1 17 1 16 10 5 5 - 284500 87473051 140 112 11 1 16 1 15 23 16 7 + 284500 87473040 107 98 10 1 17 1 16 10 5 5 + 284500 87473051 140 113 11 1 16 1 15 23 16 7 284500 87473063 62 76 5 2 7 1 6 6 4 2 284500 87473068 25 34 1 1 0 0 0 0 0 0 284500 87473075 60 87 6 0 5 0 5 7 6 1 @@ -14,10 +14,10 @@ 284500 87473096 66 75 3 2 3 0 3 4 3 1 284500 87473104 64 63 6 0 6 1 5 4 3 1 284500 87473114 89 80 7 2 12 1 11 9 6 3 - 284500 87473121 93 101 6 3 15 3 12 7 6 1 + 284500 87473121 93 102 6 3 15 3 12 7 6 1 284500 87473132 84 58 9 1 12 0 12 3 3 0 284500 87473137 94 71 8 3 15 0 15 8 8 0 - 284500 87473144 78 68 7 1 8 2 6 8 6 2 + 284500 87473144 78 67 7 1 8 2 6 8 6 2 284500 87473154 86 88 7 0 14 3 11 9 4 5 284500 87473162 53 52 4 0 7 0 7 3 2 1 284500 87473167 77 55 6 3 14 3 11 13 8 5 diff --git a/Tools/PROCTools/data/master_q431_AOD_digest.ref b/Tools/PROCTools/data/master_q431_AOD_digest.ref index 75e9c54ec74..8a7784cbb4c 100644 --- a/Tools/PROCTools/data/master_q431_AOD_digest.ref +++ b/Tools/PROCTools/data/master_q431_AOD_digest.ref @@ -1,14 +1,14 @@ run event nTopo nIdTracks nJets nMuons 330470 1183722158 1 0 0 0 - 330470 1183722342 394 413 18 0 - 330470 1183727953 532 578 11 4 - 330470 1183732647 467 464 12 1 - 330470 1183733040 381 285 6 1 + 330470 1183722342 394 412 18 0 + 330470 1183727953 532 581 11 4 + 330470 1183732647 467 465 12 1 + 330470 1183733040 381 286 6 1 330470 1183734651 361 361 14 4 330470 1183735332 406 384 9 1 - 330470 1183736475 741 675 13 2 + 330470 1183736475 741 674 13 2 330470 1183738728 1 0 0 0 - 330470 1183738949 368 429 9 1 + 330470 1183738949 368 430 9 1 330470 1183742489 152 123 2 1 330470 1183743040 285 310 5 0 330470 1183746343 492 462 12 0 @@ -19,8 +19,8 @@ 330470 1183754806 470 406 15 0 330470 1183769295 342 325 8 2 330470 1183769939 348 351 10 3 - 330470 1183773832 307 200 7 0 + 330470 1183773832 307 201 7 0 330470 1183775209 57 0 0 0 - 330470 1183787124 431 361 9 2 + 330470 1183787124 431 362 9 2 330470 1183787946 321 313 5 1 - 330470 1183795329 458 335 18 0 + 330470 1183795329 458 336 18 0 -- GitLab