2 Copyright (C) 2002-2026 CERN for the benefit of the ATLAS collaboration
5#include "src/detail/AtlasUncalibSourceLinkAccessor.h"
6#include "ActsCalibrators/xAODUncalibMeasCalibrator.h"
9namespace ActsTrk::detail {
11template <Acts::TrackContainerFrontend track_container_t>
12inline auto SharedHitCounter::computeSharedHits(typename track_container_t::TrackProxy &track,
13 track_container_t &tracks,
14 const MeasurementIndex &measurementIndex,
15 bool removeSharedHits) -> ReturnSharedAndBad {
16 return computeSharedHits(track, tracks, measurementIndex.size(), [&measurementIndex](const xAOD::UncalibratedMeasurement &hit) -> std::size_t {
17 return measurementIndex.index(hit);
21template <Acts::TrackContainerFrontend track_container_t>
22inline auto SharedHitCounter::computeSharedHitsDynamic(typename track_container_t::TrackProxy &track,
23 track_container_t &tracks,
24 MeasurementIndex &measurementIndex,
25 bool removeSharedHits) -> ReturnSharedAndBad {
26 return computeSharedHits(track, tracks, measurementIndex.size(), [this, &measurementIndex](const xAOD::UncalibratedMeasurement &hit) -> std::size_t {
27 auto [index, newContainer] = measurementIndex.newMeasurementIndex(hit);
29 m_firstTrackStateOnTheHit.resize(measurementIndex.size(), s_noTrackState);
36 track : the track under investigation and that will be updated with the shared hit information
37 tracks : the track container. Used to check what hits are used. Both tracks that share hits will get the shared states set and nShared hits updated
38 indexSize : the size of measurements to be used fo shared hit counting
39 indexFun : template param to get the index from the hit
40 removeSharedHits : if true this function will remove the shared hits from the track and the matching tracks and reset the states sharedHit flag.
42template <Acts::TrackContainerFrontend track_container_t, typename IndexFun>
43inline auto SharedHitCounter::computeSharedHits(typename track_container_t::TrackProxy &track,
44 track_container_t &tracks,
45 std::size_t indexSize,
47 bool removeSharedHits) -> ReturnSharedAndBad {
48 // Based on ActsExamples::TrackFindingAlgorithm::computeSharedHits().
49 // Finds shared hits in the reconstructed track and updates SharedHitFlag in both tracks.
50 // Uses measurementIndex to convert hit to hitIndex, and then m_firstTrackStateOnTheHit[] to convert hitIndex -> TrackStateIndex
51 // Returns stats: nShared and nBadTrackMeasurements
53 if (m_firstTrackStateOnTheHit.size() < indexSize)
54 m_firstTrackStateOnTheHit.resize(indexSize, s_noTrackState);
56 std::size_t nShared = 0;
57 std::size_t nBadTrackMeasurements = 0;
58 for (auto state : track.trackStatesReversed()) {
59 // filter for state that is a measurement (not hole, outlier etc):
60 if (!state.typeFlags().isMeasurement())
63 if (!state.hasUncalibratedSourceLink())
66 if (removeSharedHits and !state.typeFlags().isSharedHit())
69 auto hit = detail::xAODUncalibMeasCalibrator::unpack(state.getUncalibratedSourceLink());
73 std::size_t hitIndex = indexFun(*hit);
74 if (!(hitIndex < m_firstTrackStateOnTheHit.size())) {
75 state.typeFlags().setIsSharedHit(false);
76 // Save ATH_MSG_ERROR() for the caller, since for simplicity and efficiency this class doesn't have access to AthMsgStream.
77 //std::cout << "ERROR hit index " << hitIndex << " past end of " << m_firstTrackStateOnTheHit.size() << " hit indices\n";
78 ++nBadTrackMeasurements;
82 // Check if hit not already used
83 if (m_firstTrackStateOnTheHit[hitIndex].trackIndex == s_noTrackState.trackIndex) {
84 state.typeFlags().setIsSharedHit(false);
85 m_firstTrackStateOnTheHit[hitIndex] = {track.index(), state.index()};
89 // if already used, control if first track state has been marked as shared
90 const TrackStateIndex& indexFirstTrackState = m_firstTrackStateOnTheHit[hitIndex];
91 if (!(indexFirstTrackState.trackIndex < tracks.size())) {
92 state.typeFlags().setIsSharedHit(false);
93 //std::cout << "ERROR track index " << indexFirstTrackState.trackIndex << " past end of " << tracks.size() << " tracks in container\n";
94 ++nBadTrackMeasurements;
98 auto firstTrack = tracks.getTrack(indexFirstTrackState.trackIndex);
99 auto& firstStateContainer = firstTrack.container().trackStateContainer();
101 if (!(indexFirstTrackState.stateIndex < firstStateContainer.size())) {
102 state.typeFlags().setIsSharedHit(false);
103 //std::cout << "ERROR track state index " << indexFirstTrackState.stateIndex << " past end of " << firstStateContainer.size() << " track states in container\n";
104 ++nBadTrackMeasurements;
108 auto firstState = firstStateContainer.getTrackState(indexFirstTrackState.stateIndex);
110 // if removeSharedHits is false, this is the nominal behaviour
111 if (!removeSharedHits) {
112 // Only count shared hits if neither track uses the cluster as a split hit.
113 // The split decision can depend on the track (e.g. the NN calibrator uses
114 // the track angles), so check both states. A split hit and a shared hit
115 // exclude each other, and setIsSharedHit() clears the split flag.
116 if (!firstState.typeFlags().isSplitHit() && !state.typeFlags().isSplitHit()) {
117 if (!firstState.typeFlags().isSharedHit()) {
118 firstState.typeFlags().setIsSharedHit();
119 firstTrack.nSharedHits()++;
122 // Decorate this track state
123 state.typeFlags().setIsSharedHit();
124 track.nSharedHits()++;
127 // Do nothing for split hits
128 state.typeFlags().setIsSharedHit(false);
131 } else { // remove shared hits mode
132 if (firstState.typeFlags().isSharedHit()) {
133 firstState.typeFlags().setIsSharedHit(false);
135 //We should not find more shared measurements than initially attached to the track
136 if (firstTrack.nSharedHits() == 0) {
137 //std::cout << "ERROR inconsistency in removing shared hits for firstTrack " <<std::endl;
138 ++nBadTrackMeasurements;
141 firstTrack.nSharedHits()--;
145 // reset the flag for this track state
146 state.typeFlags().setIsSharedHit(false);
147 track.nSharedHits()--;
150 // clear up the firstTrackStateOnTheHit vector from the update
151 if (m_firstTrackStateOnTheHit[hitIndex].trackIndex == track.index() && m_firstTrackStateOnTheHit[hitIndex].stateIndex == state.index())
152 m_firstTrackStateOnTheHit[hitIndex] = s_noTrackState;
155 } // loop on the track states
157 return {nShared, nBadTrackMeasurements};
160} // namespace ActsTrk::detail