LDMX Software
GreedyAmbiguitySolver.cxx
1#include "Tracking/Reco/GreedyAmbiguitySolver.h"
2
3#include <Acts/Geometry/TrackingGeometry.hpp>
4#include <algorithm>
5#include <chrono>
6#include <iomanip>
7
8#include "Acts/EventData/SourceLink.hpp"
9#include "Acts/Geometry/GeometryIdentifier.hpp"
10#include "Tracking/Sim/IndexSourceLink.h"
11#include "Tracking/Sim/TrackingUtils.h"
12
13namespace tracking {
14namespace reco {
15
17 framework::Process& process)
18 : TrackingGeometryUser(name, process) {}
19
20// Helper Functions
21
22/*
23std::size_t GreedyAmbiguitySolver::sourceLinkHash(const Acts::SourceLink& a) {
24 return static_cast<std::size_t>(
25 a.get<ActsExamples::IndexSourceLink>().index());
26 }
27
28bool GreedyAmbiguitySolver::sourceLinkEquality(const Acts::SourceLink& a, const
29Acts::SourceLink& b) { return a.get<ActsExamples::IndexSourceLink>().index() ==
30 b.get<ActsExamples::IndexSourceLink>().index();
31}
32*/
33
35 std::size_t iTrack) const {
36 for (auto i_measurement : state.measurements_per_track_[iTrack]) {
37 state.tracks_per_measurement_[i_measurement].erase(iTrack);
38 if (state.tracks_per_measurement_[i_measurement].size() == 1) {
39 auto j_track = *state.tracks_per_measurement_[i_measurement].begin();
40 --state.shared_measurements_per_track_[j_track];
41 }
42 }
43 state.selected_tracks_.erase(iTrack);
44}
45
46template <typename geometry_t, typename source_link_hash_t,
47 typename source_link_equality_t>
49 std::vector<ldmx::Track> tracks, std::vector<ldmx::Measurement> meas_coll,
50 State& state, geometry_t& tg, source_link_hash_t&& sourceLinkHash,
51 source_link_equality_t&& sourceLinkEquality) const {
52 auto measurement_index_map =
53 std::unordered_map<Acts::SourceLink, std::size_t, source_link_hash_t,
54 source_link_equality_t>(0, sourceLinkHash,
55 sourceLinkEquality);
56
57 // auto tg{geometry()};
58 // Iterate through all input tracks, collect their properties like measurement
59 // count and chi2 and fill the measurement map in order to relate tracks to
60 // each other if they have shared hits_.
61 state.number_of_tracks_ = 0;
62 for (const auto& track : tracks) {
63 // Kick out tracks that do not fulfill our initial requirements
64 if (track.getNhits() < n_meas_min_) {
65 continue;
66 }
67
68 std::vector<std::size_t> measurements;
69 for (auto imeas : track.getMeasurementsIdxs()) {
70 auto meas = meas_coll.at(imeas);
71 const Acts::Surface* hit_surface = tg.getSurface(meas.getLayerID());
72 // Store the index_ source link
73 acts_examples::IndexSourceLink idx_sl(hit_surface->geometryId(), imeas);
74 Acts::SourceLink source_link = Acts::SourceLink(idx_sl);
75
76 auto emplace = measurement_index_map.try_emplace(
77 source_link, measurement_index_map.size());
78 measurements.push_back(emplace.first->second);
79 }
80
81 state.track_tips_.push_back(state.number_of_tracks_);
82 state.track_chi2_.push_back(track.getChi2() / track.getNdf());
83 state.measurements_per_track_.push_back(std::move(measurements));
84 state.selected_tracks_.insert(state.number_of_tracks_);
85
86 ++state.number_of_tracks_;
87 }
88
89 // Now we relate measurements to tracks
90 for (std::size_t i_track = 0; i_track < state.number_of_tracks_; ++i_track) {
91 for (auto i_measurement : state.measurements_per_track_[i_track]) {
92 state.tracks_per_measurement_[i_measurement].insert(i_track);
93 }
94 }
95
96 // Finally, we can accumulate the number of shared measurements per track
97 state.shared_measurements_per_track_ =
98 std::vector<std::size_t>(state.track_tips_.size(), 0);
99 for (std::size_t i_track = 0; i_track < state.number_of_tracks_; ++i_track) {
100 for (auto i_measurement : state.measurements_per_track_[i_track]) {
101 if (state.tracks_per_measurement_[i_measurement].size() > 1) {
102 ++state.shared_measurements_per_track_[i_track];
103 }
104 }
105 }
106}
107
111 auto shared_measurements_comperator = [&state](std::size_t a, std::size_t b) {
112 return state.shared_measurements_per_track_[a] <
113 state.shared_measurements_per_track_[b];
114 };
115
119 auto track_comperator = [&state](std::size_t a, std::size_t b) {
121 auto relative_shared_measurements = [&state](std::size_t i) {
122 return 1.0 * state.shared_measurements_per_track_[i] /
123 state.measurements_per_track_[i].size();
124 };
125
126 if (relative_shared_measurements(a) != relative_shared_measurements(b)) {
127 return relative_shared_measurements(a) < relative_shared_measurements(b);
128 }
129 return state.track_chi2_[a] < state.track_chi2_[b];
130 };
131
132 for (std::size_t i = 0; i < maximum_iterations_; ++i) {
133 // Lazy out if there is nothing to filter on.
134 if (state.selected_tracks_.empty()) {
135 ldmx_log(trace) << "No tracks left - exit loop";
136 break;
137 }
138
139 // Find the maximum amount of shared measurements per track to decide if we
140 // are done or not.
141 auto maximum_shared_measurements = *std::max_element(
142 state.selected_tracks_.begin(), state.selected_tracks_.end(),
143 shared_measurements_comperator);
144 // ldmx_log(debug) <<
145 // "maximum shared measurements "
146 // << state.sharedMeasurementsPerTrack[maximumSharedMeasurements];
147 if (state.shared_measurements_per_track_[maximum_shared_measurements] <
149 break;
150 }
151
152 // Find the "worst" track by comparing them to each other
153 auto bad_track =
154 *std::max_element(state.selected_tracks_.begin(),
155 state.selected_tracks_.end(), track_comperator);
156 ldmx_log(trace) << "Remove track " << bad_track << ", nMeas = "
157 << state.measurements_per_track_[bad_track].size()
158 << ", nShared = "
159 << state.shared_measurements_per_track_[bad_track]
160 << ", chi2 =" << state.track_chi2_[bad_track];
161 removeTrack(state, bad_track);
162 }
163}
164
165// Processor Functions
166
168
170 framework::config::Parameters& parameters) {
171 out_trk_collection_ =
172 parameters.get<std::string>("out_trk_collection", "TaggerTracksClean");
173
174 track_collection_ =
175 parameters.get<std::string>("track_collection", "TaggerTracks");
176
177 meas_collection_ =
178 parameters.get<std::string>("meas_collection", "DigiTaggerSimHits");
179 input_pass_name_ = parameters.get<std::string>("input_pass_name");
180 n_meas_min_ = parameters.get<int>("n_measurements_min", 5);
181 maximum_shared_hits_ = parameters.get<int>("maximum_shared_hits", 1);
182}
183
185 auto t_start = std::chrono::high_resolution_clock::now();
186
188 std::vector<ldmx::Track> out_tracks;
189
190 auto tg{geometry()};
191
192 if (!event.exists(track_collection_, input_pass_name_)) {
193 ldmx_log(debug) << "Track collection not found, exiting";
194 ++nevents_;
195 return;
196 }
197 const auto& tracks =
198 event.getCollection<ldmx::Track>(track_collection_, input_pass_name_);
199
200 if (!event.exists(meas_collection_, input_pass_name_)) {
201 ldmx_log(debug) << "Measurement collection not found, exiting";
202 ++nevents_;
203 return;
204 }
205 const auto& measurements = event.getCollection<ldmx::Measurement>(
206 meas_collection_, input_pass_name_);
207
208 n_input_tracks_ += static_cast<int>(tracks.size());
209
210 computeInitialState(tracks, measurements, state, tg,
211 tracking::sim::utils::sourceLinkHash,
212 tracking::sim::utils::sourceLinkEquality);
213 resolve(state);
214
215 for (auto i_track : state.selected_tracks_) {
216 auto clean_trk = tracks[state.track_tips_.at(i_track)];
217 if ((clean_trk.getNhits() > n_meas_min_) &&
218 (std::abs(1. / clean_trk.getQoP()) > 0.05)) {
219 out_tracks.push_back(clean_trk);
220 }
221 }
222
223 n_output_tracks_ += static_cast<int>(out_tracks.size());
224
225 event.add(out_trk_collection_, out_tracks);
226
227 auto t_end = std::chrono::high_resolution_clock::now();
228 processing_time_ +=
229 std::chrono::duration<double, std::milli>(t_end - t_start).count();
230 ++nevents_;
231}
232
234 double avg_in =
235 nevents_ > 0 ? static_cast<double>(n_input_tracks_) / nevents_ : 0.;
236 double avg_out =
237 nevents_ > 0 ? static_cast<double>(n_output_tracks_) / nevents_ : 0.;
238 double retention =
239 n_input_tracks_ > 0 ? 100.0 * n_output_tracks_ / n_input_tracks_ : 0.;
240 ldmx_log(info) << "--------------------------------- ";
241 ldmx_log(info) << "GAS: " << n_output_tracks_ << " output tracks / "
242 << n_input_tracks_ << " input tracks";
243 ldmx_log(info) << "AVG Time/Event: " << std::fixed << std::setprecision(1)
244 << processing_time_ / nevents_ << " ms";
245 ldmx_log(info) << "AVG tracks in/event: " << std::fixed
246 << std::setprecision(1) << avg_in;
247 ldmx_log(info) << "AVG tracks out/event: " << std::fixed
248 << std::setprecision(1) << avg_out << " (" << std::fixed
249 << std::setprecision(1) << retention << "% retained)";
250}
251
252} // namespace reco
253} // namespace tracking
254
#define DECLARE_PRODUCER(CLASS)
Macro which allows the framework to construct a producer given its name during configuration.
Implements an event buffer system for storing event data.
Definition Event.h:40
bool exists(const std::string &name, const std::string &passName, bool unique=true) const
Check for the existence of an object or collection with the given name and pass name in the event.
Definition Event.cxx:107
Class which represents the process under execution.
Definition Process.h:34
Class encapsulating parameters for configuring a processor.
Definition Parameters.h:26
const T & get(const std::string &name) const
Retrieve the parameter of the given name.
Definition Parameters.h:75
Run-specific configuration and data stored in its own output TTree alongside the event TTree in the o...
Definition RunHeader.h:68
Implementation of a track object.
Definition Track.h:54
Minimal example of a processor.
GreedyAmbiguitySolver(const std::string &name, framework::Process &process)
Constructor.
std::size_t n_meas_min_
Minimum number of measurement to form a track.
void removeTrack(State &state, std::size_t iTrack) const
void configure(framework::config::Parameters &parameters) override
Configure the processor using the given user specified parameters.
void computeInitialState(std::vector< ldmx::Track > tracks, std::vector< ldmx::Measurement > measurements, State &state, geometry_t &tg, source_link_hash_t &&sourceLinkHash, source_link_equality_t &&sourceLinkEquality) const
void resolve(State &state)
Updates the state iteratively by evicting one track after the other until the final state conditions ...
void onNewRun(const ldmx::RunHeader &rh) override
onNewRun is the first function called for each processor after the conditions are fully configured an...
void produce(framework::Event &event) override
Process the event and put new data products into it.
std::uint32_t maximum_iterations_
Maximum number of iterations.
void onProcessEnd() override
Callback for the EventProcessor to take any necessary action when the processing of events finishes,...
std::uint32_t maximum_shared_hits_
Maximum amount of shared hits per track.
a helper base class providing some methods to shorten access to common conditions used within the tra...
The measurement calibrator can be a function or a class/struct able to retrieve the sim hits containe...