LDMX Software
LinearTrackFinder.cxx
1#include "Tracking/Reco/LinearTrackFinder.h"
2
3//--- C++ StdLib ---//
4#include <algorithm>
5#include <iostream>
6#include <map>
7
8// eN files
9
10namespace tracking {
11namespace reco {
12
14 framework::Process& process)
15 : TrackingGeometryUser(name, process) {}
16
18 // seeds from the event
19 seed_collection_ =
20 parameters.get<std::string>("seed_collection", "LinearRecoilSeedTracks");
21 // output track collection
22 out_trk_collection_ =
23 parameters.get<std::string>("out_trk_collection", "LinearRecoilTracks");
24
25 input_pass_name_ = parameters.get<std::string>("input_pass_name");
26
27} // configure
28
30 std::vector<ldmx::StraightTrack> straight_tracks;
31
32 auto start = std::chrono::high_resolution_clock::now();
33
34 n_events_++;
35 if (n_events_ % 1000 == 0) ldmx_log(info) << "events processed:" << n_events_;
36
37 ldmx_log(debug) << "Retrieve the seeds::" << seed_collection_;
38
39 const auto& seed_tracks = event.getCollection<ldmx::StraightTrack>(
40 seed_collection_, input_pass_name_);
41
42 n_seeds_ = seed_tracks.size();
43 ldmx_log(debug) << "Number of seeds::" << n_seeds_;
44
45 if (n_seeds_ > 0) {
46 straight_tracks = findTracks(seed_tracks);
47 }
48
49 n_tracks_ += straight_tracks.size();
50
51 // Add the tracks to the event
52 event.add(out_trk_collection_, straight_tracks);
53
54 auto end = std::chrono::high_resolution_clock::now();
55 auto diff = end - start;
56 processing_time_ += std::chrono::duration<double, std::milli>(diff).count();
57
58 straight_tracks.clear();
59} // produce
60
62 ldmx_log(info) << "found " << n_tracks_ << " tracks / " << n_events_
63 << " events.";
64 ldmx_log(info) << "AVG Time/Event: " << std::fixed << std::setprecision(1)
65 << processing_time_ / n_events_ << " ms";
66} // onProcessEnd
67
68std::vector<ldmx::StraightTrack> LinearTrackFinder::findTracks(
69 const std::vector<ldmx::StraightTrack>& track_seeds) {
70 std::vector<ldmx::StraightTrack> best_tracks;
71 std::map<std::array<double, 3>, std::vector<ldmx::StraightTrack>>
72 seeds_by_rec_hit;
73
74 // Group seeds by their EcalRecHit point
75 for (const auto& seed : track_seeds) {
76 auto rec_hit_point = seed.getFirstLayerEcalRecHit();
77 seeds_by_rec_hit[rec_hit_point].push_back(seed);
78 }
79
80 // Track used sensor positions
81 std::set<std::tuple<float, float, float>> used_sensor_positions;
82
83 // Find the best seed for each RecHit
84 // numTracks <= number of RecHits
85 for (auto& entry : seeds_by_rec_hit) {
86 const auto& rec_hit_point = entry.first;
87 auto& seeds_with_same_rec_hit = entry.second;
88
89 ldmx_log(debug) << "Processing RecHit at: (" << rec_hit_point[0] << ", "
90 << rec_hit_point[1] << ", " << rec_hit_point[2] << ")\n";
91
92 // Main function to remove seeds with overlapping sensor positions
93 seeds_with_same_rec_hit.erase(
94 std::remove_if(
95 seeds_with_same_rec_hit.begin(), seeds_with_same_rec_hit.end(),
96 [&](const ldmx::StraightTrack& seed) {
97 for (const auto& measurement : seed.getAllSensorPoints()) {
98 // Check if this sensor's position is already used
99 if (isPositionUsed(measurement, used_sensor_positions)) {
100 // Mark this seed for removal
101 return true;
102 } // ifPositionUsed
103 } // for measurement
104 // Keep the seed if no position overlap
105 return false;
106 }),
107 seeds_with_same_rec_hit.end());
108
109 // If no valid seeds remain after filtering, skip to next RecHit
110 if (seeds_with_same_rec_hit.empty()) continue;
111
112 // Find the seed with the lowest chi2 for this RecHit, this is "best" seed
113 auto best_seed_it = std::min_element(
114 seeds_with_same_rec_hit.begin(), seeds_with_same_rec_hit.end(),
115 [](const ldmx::StraightTrack& trk_a, const ldmx::StraightTrack& trk_b) {
116 return trk_a.getChi2() < trk_b.getChi2();
117 });
118
119 // Store the best seed for this RecHit
120 ldmx::StraightTrack best_seed = *best_seed_it;
121 best_tracks.push_back(best_seed);
122
123 ldmx_log(debug) << "For RecHit at: (" << rec_hit_point[0] << ", "
124 << rec_hit_point[1] << ", " << rec_hit_point[2] << ")\n";
125
126 // Add best seed's sensor position to the global used positions set
127 auto best_seed_measurement = best_seed.getAllSensorPoints();
128
129 for (auto& position_object : best_seed_measurement) {
130 used_sensor_positions.insert(
131 std::make_tuple(position_object.getGlobalPosition()[0],
132 position_object.getGlobalPosition()[1],
133 position_object.getGlobalPosition()[2]));
134 ldmx_log(debug) << "We used the following point: ("
135 << position_object.getGlobalPosition()[0] << ", "
136 << position_object.getGlobalPosition()[1] << ", "
137 << position_object.getGlobalPosition()[2] << ")\n";
138 ldmx_log(debug) << "Which gave a track a distance: "
139 << best_seed.getDistanceToRecHit()
140 << " to the closest ECalRecHit\n";
141 } // for sensor points in "best" seed
142
143 } // for entry loop, everytime we loop onto a new RecHit, we will have fewer
144 // points to check
145
146 return best_tracks;
147
148} // findTracks
149
150bool LinearTrackFinder::isPositionUsed(
151 const ldmx::Measurement& measurement,
152 const std::set<std::tuple<float, float, float>>& used_sensor_positions) {
153 const auto& position = std::make_tuple(measurement.getGlobalPosition()[0],
154 measurement.getGlobalPosition()[1],
155 measurement.getGlobalPosition()[2]);
156
157 return used_sensor_positions.find(position) != used_sensor_positions.end();
158
159} // isPositionUsed
160
161} // namespace reco
162} // namespace tracking
163
#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
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
std::array< float, 3 > getGlobalPosition() const
Definition Measurement.h:50
void onProcessEnd() override
Output event statistics.
LinearTrackFinder(const std::string &name, framework::Process &process)
Constructor.
void configure(framework::config::Parameters &parameters) override
Configure the processor using the given user specified parameters.
void produce(framework::Event &event) override
Run the processor.
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...