2020#include < numeric>
2121#include < stdexcept>
2222
23+ #include < boost/container/flat_map.hpp>
24+ #include < boost/container/flat_set.hpp>
25+
2326ActsExamples::AmbiguityResolutionAlgorithm::AmbiguityResolutionAlgorithm (
2427 ActsExamples::AmbiguityResolutionAlgorithm::Config cfg,
2528 Acts::Logging::Level lvl)
2629 : ActsExamples::IAlgorithm(" AmbiguityResolutionAlgorithm" , lvl),
2730 m_cfg(std::move(cfg)) {
28- if (m_cfg.inputSourceLinks .empty ()) {
29- throw std::invalid_argument (" Missing source links input collection" );
30- }
3131 if (m_cfg.inputTrajectories .empty ()) {
3232 throw std::invalid_argument (" Missing trajectories input collection" );
3333 }
@@ -38,148 +38,145 @@ ActsExamples::AmbiguityResolutionAlgorithm::AmbiguityResolutionAlgorithm(
3838
3939namespace {
4040
41- // TODO this is somewhat duplicated in TrackFindingAlgorithm.hpp
42- // TODO we should make a common implementation in the core at some point
43- std::vector<std::size_t > computeSharedHits (
44- const ActsExamples::IndexSourceLinkContainer& sourceLinks,
41+ struct State {
42+ std::size_t numberOfTracks{};
43+
44+ std::vector<std::pair<std::size_t , std::size_t >> trackTips;
45+ std::vector<float > trackChi2;
46+ std::vector<ActsExamples::TrackParameters> trackParameters;
47+ std::vector<std::vector<std::size_t >> measurementsPerTrack;
48+
49+ boost::container::flat_map<std::size_t ,
50+ boost::container::flat_set<std::size_t >>
51+ tracksPerMeasurement;
52+ std::vector<std::size_t > sharedMeasurementsPerTrack;
53+
54+ boost::container::flat_set<std::size_t > selectedTracks;
55+ };
56+
57+ State computeInitialState (
4558 const ActsExamples::TrajectoriesContainer& trajectories,
46- const std::vector<uint32_t >& trackIndices,
47- const std::vector<std::pair<size_t , size_t >>& trackTips) {
48- std::vector<std::size_t > hitCountPerMeasurement (sourceLinks.size (), 0 );
59+ std::size_t nMeasurementsMin) {
60+ State state;
4961
50- for (auto indexTrack : trackIndices) {
51- const auto [indexTraj, tip] = trackTips[indexTrack];
52- const auto & traj = trajectories[indexTraj];
62+ for (std::size_t iTrack = 0 , iTraj = 0 ; iTraj < trajectories.size ();
63+ ++iTraj) {
64+ const auto & traj = trajectories[iTraj];
65+ for (auto tip : traj.tips ()) {
66+ if (!traj.hasTrackParameters (tip)) {
67+ continue ;
68+ }
5369
54- traj.multiTrajectory ().visitBackwards (tip, [&](const auto & state) {
55- if (!state.typeFlags ().test (Acts::TrackStateFlag::MeasurementFlag)) {
56- return true ;
70+ auto trajState = Acts::MultiTrajectoryHelpers::trajectoryState (
71+ traj.multiTrajectory (), tip);
72+ if (trajState.nMeasurements < nMeasurementsMin) {
73+ continue ;
5774 }
5875
59- const std::size_t indexHit =
60- state.getUncalibratedSourceLink ()
61- .template get <ActsExamples::IndexSourceLink>()
62- .index ();
76+ std::vector<std::size_t > measurements;
77+ traj.multiTrajectory ().visitBackwards (tip, [&](const auto & hit) {
78+ if (hit.typeFlags ().test (Acts::TrackStateFlag::MeasurementFlag)) {
79+ std::size_t iMeasurement =
80+ hit.getUncalibratedSourceLink ()
81+ .template get <ActsExamples::IndexSourceLink>()
82+ .index ();
83+ measurements.push_back (iMeasurement);
84+ }
85+ return true ;
86+ });
6387
64- ++hitCountPerMeasurement[indexHit] ;
88+ ++state. numberOfTracks ;
6589
66- return true ;
67- });
68- }
90+ state.trackTips .emplace_back (iTraj, tip);
91+ state.trackChi2 .push_back (trajState.chi2Sum / trajState.NDF );
92+ state.trackParameters .push_back (traj.trackParameters (tip));
93+ state.measurementsPerTrack .push_back (std::move (measurements));
6994
70- std::vector<std:: size_t > sharedHitCountPerTrack (trackIndices. size (), 0 );
95+ state. selectedTracks . insert (iTrack );
7196
72- for (std::size_t i = 0 ; i < trackIndices.size (); ++i) {
73- const auto indexTrack = trackIndices[i];
74- const auto [indexTraj, tip] = trackTips[indexTrack];
75- const auto & traj = trajectories[indexTraj];
97+ ++iTrack;
98+ }
99+ }
76100
77- traj.multiTrajectory ().visitBackwards (tip, [&](const auto & state) {
78- if (!state.typeFlags ().test (Acts::TrackStateFlag::MeasurementFlag)) {
79- return true ;
80- }
101+ for (std::size_t iTrack = 0 ; iTrack < state.numberOfTracks ; ++iTrack) {
102+ for (auto iMeasurement : state.measurementsPerTrack [iTrack]) {
103+ state.tracksPerMeasurement [iMeasurement].insert (iTrack);
104+ }
105+ }
81106
82- const std::size_t indexHit =
83- state.getUncalibratedSourceLink ()
84- .template get <ActsExamples::IndexSourceLink>()
85- .index ();
107+ state.sharedMeasurementsPerTrack =
108+ std::vector<std::size_t >(state.trackTips .size (), 0 );
86109
87- if (hitCountPerMeasurement[indexHit] > 1 ) {
88- ++sharedHitCountPerTrack[i];
110+ for (std::size_t iTrack = 0 ; iTrack < state.numberOfTracks ; ++iTrack) {
111+ for (auto iMeasurement : state.measurementsPerTrack [iTrack]) {
112+ if (state.tracksPerMeasurement [iMeasurement].size () > 1 ) {
113+ ++state.sharedMeasurementsPerTrack [iTrack];
89114 }
90-
91- return true ;
92- });
115+ }
93116 }
94117
95- return sharedHitCountPerTrack ;
118+ return state ;
96119}
97120
98- std::size_t computeTrackHits (
99- const Acts::ConstVectorMultiTrajectory& multiTrajectory,
100- const std::size_t tip) {
101- std::size_t result = 0 ;
121+ void removeTrack (State& state, std::size_t iTrack) {
122+ for (auto iMeasurement : state.measurementsPerTrack [iTrack]) {
123+ state.tracksPerMeasurement [iMeasurement].erase (iTrack);
102124
103- multiTrajectory.visitBackwards (tip, [&](const auto &) { ++result; });
125+ if (state.tracksPerMeasurement [iMeasurement].size () == 1 ) {
126+ auto jTrack = *std::begin (state.tracksPerMeasurement [iMeasurement]);
127+ --state.sharedMeasurementsPerTrack [jTrack];
128+ }
129+ }
104130
105- return result ;
131+ state. selectedTracks . erase (iTrack) ;
106132}
107133
108134} // namespace
109135
110136ActsExamples::ProcessCode ActsExamples::AmbiguityResolutionAlgorithm::execute (
111137 const AlgorithmContext& ctx) const {
112- // Read input data
113- const auto & sourceLinks =
114- ctx.eventStore .get <IndexSourceLinkContainer>(m_cfg.inputSourceLinks );
115138 const auto & trajectories =
116139 ctx.eventStore .get <TrajectoriesContainer>(m_cfg.inputTrajectories );
117140
118- TrackParametersContainer trackParameters;
119- std::vector<std::pair<size_t , size_t >> trackTips;
141+ auto state = computeInitialState (trajectories, m_cfg.nMeasurementsMin );
120142
121- for (std::size_t iTraj = 0 ; iTraj < trajectories.size (); ++iTraj) {
122- const auto & traj = trajectories[iTraj];
123- for (auto tip : traj.tips ()) {
124- if (!traj.hasTrackParameters (tip)) {
125- continue ;
126- }
127- auto trajState = Acts::MultiTrajectoryHelpers::trajectoryState (
128- traj.multiTrajectory (), tip);
129- if (trajState.nMeasurements < m_cfg.nMeasurementsMin ) {
130- continue ;
131- }
132- trackParameters.push_back (traj.trackParameters (tip));
133- trackTips.emplace_back (iTraj, tip);
134- }
135- }
143+ auto sharedMeasurementsComperator = [&state](std::size_t a, std::size_t b) {
144+ return state.sharedMeasurementsPerTrack [a] <
145+ state.sharedMeasurementsPerTrack [b];
146+ };
147+ auto badTrackComperator = [&state](std::size_t a, std::size_t b) {
148+ auto relativeSharedMeasurements = [&state](std::size_t i) {
149+ return 1.0 * state.sharedMeasurementsPerTrack [i] /
150+ state.measurementsPerTrack [i].size ();
151+ };
136152
137- std::vector<uint32_t > hitCount (trackParameters.size (), 0 );
138- for (std::size_t i = 0 ; i < trackParameters.size (); ++i) {
139- const auto [iTraj, tip] = trackTips[i];
140- const auto & traj = trajectories[iTraj];
141- hitCount[i] = computeTrackHits (traj.multiTrajectory (), tip);
142- }
143-
144- std::vector<uint32_t > trackIndices (trackParameters.size ());
145- std::iota (std::begin (trackIndices), std::end (trackIndices), 0 );
146-
147- while (true ) {
148- const auto sharedHits =
149- computeSharedHits (sourceLinks, trajectories, trackIndices, trackTips);
150-
151- if (sharedHits.empty () ||
152- *std::max_element (std::begin (sharedHits), std::end (sharedHits)) <
153- m_cfg.maximumSharedHits ) {
154- break ;
153+ if (relativeSharedMeasurements (a) != relativeSharedMeasurements (b)) {
154+ return relativeSharedMeasurements (a) < relativeSharedMeasurements (b);
155155 }
156-
157- std::vector<float > relativeSharedHits (trackIndices.size (), 0 );
158- for (std::size_t i = 0 ; i < trackIndices.size (); ++i) {
159- const auto indexTrack = trackIndices[i];
160- relativeSharedHits[i] = 1 .0f * sharedHits[i] / hitCount[indexTrack];
156+ return state.trackChi2 [a] < state.trackChi2 [b];
157+ };
158+
159+ for (std::size_t i = 0 ; i < m_cfg.maximumIterations ; ++i) {
160+ auto maximumSharedMeasurements = *std::max_element (
161+ state.selectedTracks .begin (), state.selectedTracks .end (),
162+ sharedMeasurementsComperator);
163+ ACTS_VERBOSE (
164+ " maximum shared measurements "
165+ << state.sharedMeasurementsPerTrack [maximumSharedMeasurements]);
166+ if (state.sharedMeasurementsPerTrack [maximumSharedMeasurements] <
167+ m_cfg.maximumSharedHits ) {
168+ break ;
161169 }
162170
163- const auto maxRelativeSharedHits = std::max_element (
164- std::begin (relativeSharedHits), std::end (relativeSharedHits));
165- const auto index =
166- std::distance (std::begin (relativeSharedHits), maxRelativeSharedHits);
167- trackIndices.erase (std::begin (trackIndices) + index);
168- }
169-
170- if (trackIndices.size () == trackParameters.size ()) {
171- const auto sharedHits =
172- computeSharedHits (sourceLinks, trajectories, trackIndices, trackTips);
173-
174- std::vector<float > relativeSharedHits (trackIndices.size (), 0 );
175- for (std::size_t i = 0 ; i < trackIndices.size (); ++i) {
176- const auto indexTrack = trackIndices[i];
177- relativeSharedHits[i] = 1 .0f * sharedHits[i] / hitCount[indexTrack];
178- }
171+ auto badTrack =
172+ *std::max_element (state.selectedTracks .begin (),
173+ state.selectedTracks .end (), badTrackComperator);
174+ ACTS_VERBOSE (" remove track " << badTrack);
175+ removeTrack (state, badTrack);
179176 }
180177
181- ACTS_INFO (" Resolved to " << trackIndices .size () << " tracks from "
182- << trackParameters .size ());
178+ ACTS_INFO (" Resolved to " << state. selectedTracks .size () << " tracks from "
179+ << state. trackTips .size ());
183180
184181 TrajectoriesContainer outputTrajectories;
185182 outputTrajectories.reserve (trajectories.size ());
@@ -189,13 +186,13 @@ ActsExamples::ProcessCode ActsExamples::AmbiguityResolutionAlgorithm::execute(
189186 std::vector<Acts::MultiTrajectoryTraits::IndexType> tips;
190187 Trajectories::IndexedParameters parameters;
191188
192- for (auto iTrack : trackIndices ) {
193- if (trackTips[iTrack].first != iTraj) {
189+ for (auto iTrack : state. selectedTracks ) {
190+ if (state. trackTips [iTrack].first != iTraj) {
194191 continue ;
195192 }
196- const auto tip = trackTips[iTrack].second ;
193+ const auto tip = state. trackTips [iTrack].second ;
197194 tips.push_back (tip);
198- parameters.emplace (tip, trackParameters[iTrack]);
195+ parameters.emplace (tip, state. trackParameters [iTrack]);
199196 }
200197 if (!tips.empty ()) {
201198 outputTrajectories.emplace_back (traj.multiTrajectory (), tips, parameters);
0 commit comments