LDMX Software
StraightTracksDQM.cxx
1#include "Tracking/dqm/StraightTracksDQM.h"
2
3#include <algorithm>
4#include <iostream>
5
6#include "Tracking/Sim/TrackingUtils.h"
7
8namespace tracking::dqm {
9
11 track_collection_ = parameters.getParameter<std::string>(
12 "track_collection", "LinearRecoilTracks");
13 truth_collection_ = parameters.getParameter<std::string>(
14 "truth_collection", "LinearRecoilTruthTracks");
15 title_ = parameters.getParameter<std::string>("title", "recoil_lin_trk_");
16 track_prob_cut_ = parameters.getParameter<double>("trackProb_cut", 0.5);
17 subdetector_ = parameters.getParameter<std::string>("subdetector", "Recoil");
18 measurement_collection_ = parameters.getParameter<std::string>(
19 "measurement_collection", "DigiRecoilSimHits");
20 input_pass_name_ =
21 parameters.getParameter<std::string>("input_pass_name", "");
22
23 ldmx_log(info) << "Track Collection " << track_collection_;
24 ldmx_log(info) << "Truth Collection " << truth_collection_;
25} // configure
26
28 ldmx_log(debug) << "DQM Reading in::" << track_collection_;
29
30 if (!event.exists(track_collection_)) {
31 ldmx_log(error) << "trackCollection " << track_collection_
32 << " not in event";
33 return;
34 }
35
36 const std::vector<ldmx::StraightTrack> tracks =
37 event.getCollection<ldmx::StraightTrack>(track_collection_,
38 input_pass_name_);
39 const std::vector<ldmx::Measurement> measurements =
40 event.getCollection<ldmx::Measurement>(measurement_collection_,
41 input_pass_name_);
42
43 // Get the truth track collection
44 if (event.exists(truth_collection_)) {
45 truth_track_collection_ =
46 std::make_shared<std::vector<ldmx::StraightTrack>>(
47 event.getCollection<ldmx::StraightTrack>(truth_collection_,
48 input_pass_name_));
49 do_truth_comparison_ = true;
50 }
51
52 ldmx_log(debug) << "Do truth comparison::" << do_truth_comparison_;
53
54 if (do_truth_comparison_) {
55 sortTracks(tracks, unique_tracks_, duplicate_tracks_, fake_tracks_);
56 } else {
57 unique_tracks_ = tracks;
58 }
59
60 ldmx_log(debug) << "Filling histograms ";
61
62 // General Plots
63 histograms_.fill(title_ + "N_tracks", tracks.size());
64
65 ldmx_log(debug) << "Track Monitoring on Unique Tracks";
66
67 trackMonitoringUnique(unique_tracks_, measurements, title_, true, true);
68
69 ldmx_log(debug) << "Track Monitoring on duplicates and fakes";
70
71 // Fakes and duplicates
72 trackMonitoring(duplicate_tracks_, measurements, title_ + "dup_", false);
73 trackMonitoring(fake_tracks_, measurements, title_ + "fake_", false);
74
75 // Clear the vectors
76 unique_tracks_.clear();
77 duplicate_tracks_.clear();
78 fake_tracks_.clear();
79} // analyze
80
81void StraightTracksDQM::trackMonitoring(
82 const std::vector<ldmx::StraightTrack>& tracks,
83 const std::vector<ldmx::Measurement>& measurements, const std::string title,
84 const bool& do_detail) {
85 for (auto& track : tracks) {
86 double trk_theta = track.getTheta();
87 double trk_phi = track.getPhi();
88 double track_state_loc0_target = track.getTargetX();
89 double track_state_loc1_target = track.getTargetY();
90 double track_state_loc0_ecal = track.getEcalLayer1X();
91 double track_state_loc1_ecal = track.getEcalLayer1Y();
92 int track_pdgID = track.getPdgID();
93
94 double sigma_phi = phiAngleError(track.getSlopeX(), track.getCov());
95 double sigma_theta =
96 thetaAngleError(track.getSlopeX(), track.getSlopeY(), track.getCov());
97
98 histograms_.fill(title + "phi", trk_phi);
99 histograms_.fill(title + "theta", trk_theta);
100 histograms_.fill(title_ + "trk_target_loc0", track_state_loc0_target);
101 histograms_.fill(title_ + "trk_target_loc1", track_state_loc1_target);
102 histograms_.fill(title_ + "trk_ecal_loc0", track_state_loc0_ecal);
103 histograms_.fill(title_ + "trk_ecal_loc1", track_state_loc1_ecal);
104 histograms_.fill(title + "trk_PID", track_pdgID);
105
106 if (do_detail) {
107 histograms_.fill(title + "nHits", track.getNhits());
108 histograms_.fill(title + "Chi2", track.getChi2());
109 histograms_.fill(title + "ndf", track.getNdf());
110 histograms_.fill(title + "Chi2_per_ndf",
111 track.getChi2() / track.getNdf());
112 histograms_.fill(title + "dRecHit", track.getDistanceToRecHit());
113
114 histograms_.fill(title + "phi_err", sigma_phi);
115 histograms_.fill(title + "theta_err", sigma_theta);
116 } // do detail
117
118 } // for tracks
119} // TrackMonitoring
120
121void StraightTracksDQM::trackMonitoringUnique(
122 const std::vector<ldmx::StraightTrack>& tracks,
123 const std::vector<ldmx::Measurement>& measurements, const std::string title,
124 const bool& do_detail, const bool& do_truth) {
125 for (auto& track : tracks) {
126 double trk_theta = track.getTheta();
127 double trk_phi = track.getPhi();
128 double track_state_loc0_target = track.getTargetX();
129 double track_state_loc1_target = track.getTargetY();
130 double track_state_loc0_ecal = track.getEcalLayer1X();
131 double track_state_loc1_ecal = track.getEcalLayer1Y();
132 int track_pdgID = track.getPdgID();
133
134 double sigma_phi = phiAngleError(track.getSlopeX(), track.getCov());
135 double sigma_theta =
136 thetaAngleError(track.getSlopeX(), track.getSlopeY(), track.getCov());
137 double sigma_loc0_target = std::sqrt(track.getCov()[4]);
138 double sigma_loc1_target = std::sqrt(track.getCov()[9]);
139 double sigma_loc0_ecal =
140 locError(track.getCov()[0], track.getCov()[4], track.getCov()[1],
141 track.getEcalLayer1Z());
142 double sigma_loc1_ecal =
143 locError(track.getCov()[7], track.getCov()[9], track.getCov()[8],
144 track.getEcalLayer1Z());
145
146 histograms_.fill(title + "phi", trk_phi);
147 histograms_.fill(title + "theta", trk_theta);
148 histograms_.fill(title_ + "trk_target_loc0", track_state_loc0_target);
149 histograms_.fill(title_ + "trk_target_loc1", track_state_loc1_target);
150 histograms_.fill(title_ + "trk_ecal_loc0", track_state_loc0_ecal);
151 histograms_.fill(title_ + "trk_ecal_loc1", track_state_loc1_ecal);
152 histograms_.fill(title + "trk_PID", track_pdgID);
153
154 if (do_detail) {
155 histograms_.fill(title + "nHits", track.getNhits());
156 histograms_.fill(title + "Chi2", track.getChi2());
157 histograms_.fill(title + "ndf", track.getNdf());
158 histograms_.fill(title + "Chi2_per_ndf",
159 track.getChi2() / track.getNdf());
160 histograms_.fill(title + "dRecHit", track.getDistanceToRecHit());
161
162 histograms_.fill(title + "phi_err", sigma_phi);
163 histograms_.fill(title + "theta_err", sigma_theta);
164
165 if (do_truth) {
166 // Match to the truth track
167 // TODO: Currently, we assume the truth tracks have no uncertainty, but
168 // the parameters for the truth tracks
169 // TODO: are found from a fitting algorithm, and so have some
170 // uncertainty. Is there a better way to represent
171 // TODO: the truth tracks for a more accurate comparison?
172 ldmx::StraightTrack* truth_trk = nullptr;
173
174 // Only compare truth and reco tracks with same ID
175 auto it = std::find_if(truth_track_collection_->begin(),
176 truth_track_collection_->end(),
177 [&](const ldmx::StraightTrack& tt) {
178 return tt.getTrackID() == track.getTrackID();
179 });
180
181 double track_truth_prob = track.getTruthProb();
182
183 // make sure truth track has good enough truth prob.
184 if (it != truth_track_collection_->end() &&
185 track_truth_prob >= track_prob_cut_) {
186 truth_trk = &(*it);
187 }
188
189 // Found matched track
190 if (truth_trk) {
191 double truth_theta = truth_trk->getTheta();
192 double truth_phi = truth_trk->getPhi();
193 double truth_state_loc0_target = truth_trk->getTargetX();
194 double truth_state_loc1_target = truth_trk->getTargetY();
195 double truth_state_loc0_ecal = truth_trk->getEcalLayer1X();
196 double truth_state_loc1_ecal = truth_trk->getEcalLayer1Y();
197 int truth_pdgID = truth_trk->getPdgID();
198
199 histograms_.fill(title + "truth_phi", truth_phi);
200 histograms_.fill(title + "truth_theta", truth_theta);
201 histograms_.fill(title + "truth_PID", truth_pdgID);
202
203 double res_phi = trk_phi - truth_phi;
204 double res_theta = trk_theta - truth_theta;
205
206 histograms_.fill(title + "res_phi", res_phi);
207 histograms_.fill(title + "res_theta", res_theta);
208
209 double pull_phi = res_phi / sigma_phi;
210 double pull_theta = res_theta / sigma_theta;
211 histograms_.fill(title + "pull_phi", pull_phi);
212 histograms_.fill(title + "pull_theta", pull_theta);
213
214 // TH1F The difference(residual) between end_loc and truth_endloc
215 histograms_.fill(title_ + "trk_target_loc0-truth_target_loc0",
216 track_state_loc0_target - truth_state_loc0_target);
217 histograms_.fill(title_ + "trk_target_loc1-truth_target_loc1",
218 track_state_loc1_target - truth_state_loc1_target);
219 histograms_.fill(title_ + "trk_ecal_loc0-truth_ecal_loc0",
220 track_state_loc0_ecal - truth_state_loc0_ecal);
221 histograms_.fill(title_ + "trk_ecal_loc1-truth_ecal_loc1",
222 track_state_loc1_ecal - truth_state_loc1_ecal);
223
224 // TH1F The pulls of loc0 and loc1
225 histograms_.fill(title_ + "target_Pulls_of_loc0",
226 (track_state_loc0_target - truth_state_loc0_target) /
227 sigma_loc0_target);
228 histograms_.fill(title_ + "target_Pulls_of_loc1",
229 (track_state_loc1_target - truth_state_loc1_target) /
230 sigma_loc1_target);
231 histograms_.fill(title_ + "ecal_Pulls_of_loc0",
232 (track_state_loc0_ecal - truth_state_loc0_ecal) /
233 sigma_loc0_ecal);
234 histograms_.fill(title_ + "ecal_Pulls_of_loc1",
235 (track_state_loc1_ecal - truth_state_loc1_ecal) /
236 sigma_loc1_ecal);
237
238 // TH2F residual vs Nhits
239 histograms_.fill(title_ + "target_res_loc0-vs-N_hits",
240 track.getNhits(),
241 track_state_loc0_target - truth_state_loc0_target);
242 histograms_.fill(title_ + "target_res_loc1-vs-N_hits",
243 track.getNhits(),
244 track_state_loc1_target - truth_state_loc1_target);
245 histograms_.fill(title_ + "ecal_res_loc0-vs-N_hits", track.getNhits(),
246 track_state_loc0_ecal - truth_state_loc0_ecal);
247 histograms_.fill(title_ + "ecal_res_loc1-vs-N_hits", track.getNhits(),
248 track_state_loc1_ecal - truth_state_loc1_ecal);
249
250 // TH2F pulls vs Nhits
251 histograms_.fill(title_ + "target_pulls_loc0-vs-N_hits",
252 track.getNhits(),
253 (track_state_loc0_target - truth_state_loc0_target) /
254 sigma_loc0_target);
255 histograms_.fill(title_ + "target_pulls_loc1-vs-N_hits",
256 track.getNhits(),
257 (track_state_loc1_target - truth_state_loc1_target) /
258 sigma_loc1_target);
259 histograms_.fill(title_ + "ecal_pulls_loc0-vs-N_hits",
260 track.getNhits(),
261 (track_state_loc0_ecal - truth_state_loc0_ecal) /
262 sigma_loc0_ecal);
263 histograms_.fill(title_ + "ecal_pulls_loc1-vs-N_hits",
264 track.getNhits(),
265 (track_state_loc1_ecal - truth_state_loc1_ecal) /
266 sigma_loc1_ecal);
267
268 } // loop on tracks
269
270 } // do truth
271 } // do detail
272
273 } // for tracks
274} // TrackMonitoringUnique
275
276void StraightTracksDQM::sortTracks(
277 const std::vector<ldmx::StraightTrack>& tracks,
278 std::vector<ldmx::StraightTrack>& unique_tracks,
279 std::vector<ldmx::StraightTrack>& duplicate_tracks,
280 std::vector<ldmx::StraightTrack>& fake_tracks) {
281 std::vector<ldmx::StraightTrack> sorted_tracks = tracks;
282
283 // Sort the vector of Track objects based on their trackID member
284 std::sort(sorted_tracks.begin(), sorted_tracks.end(),
286 return trk1.getTrackID() < trk2.getTrackID();
287 });
288
289 // Loop over the sorted vector of Track objects
290 for (size_t i = 0; i < sorted_tracks.size(); i++) {
291 if (sorted_tracks[i].getTruthProb() < track_prob_cut_)
292 fake_tracks.push_back(sorted_tracks[i]);
293 else {
294 // If this is the first Track object with this trackID, add it to the
295 // uniqueTracks vector directly
296 if (unique_tracks.size() == 0 ||
297 sorted_tracks[i].getTrackID() != sorted_tracks[i - 1].getTrackID()) {
298 unique_tracks.push_back(sorted_tracks[i]);
299 }
300
301 // Otherwise, add it to the duplicateTracks vector if its truthProb is
302 // lower than the existing Track object Otherwise, if the truthProbability
303 // is higher than the track stored in uniqueTracks, put it in uniqueTracks
304 // and move the uniqueTracks.back to duplicateTracks.
305 else if (sorted_tracks[i].getTruthProb() >
306 unique_tracks.back().getTruthProb()) {
307 duplicate_tracks.push_back(unique_tracks.back());
308 unique_tracks.back() = sorted_tracks[i];
309 }
310
311 // Otherwise, add it to the duplicateTracks vector
312 else {
313 duplicate_tracks.push_back(sorted_tracks[i]);
314 }
315 } // else (a real track)
316 } // loop on sorted tracks
317
318 // The total number of elements in the uniqueTracks and duplicateTracks
319 // vectors should be equal to the number of elements in the original tracks
320 // vector
321 if ((unique_tracks.size() + duplicate_tracks.size() + fake_tracks.size()) !=
322 tracks.size()) {
323 ldmx_log(error) << "Unique and duplicate track vectors do not add up to "
324 "original tracks vector";
325 return;
326 } // if different tracks don't add up to correct total
327
328 // Iterate through the uniqueTracks vector and duplicateTracks vector
329 ldmx_log(trace) << "Unique tracks:";
330 for (const ldmx::StraightTrack& track : unique_tracks) {
331 ldmx_log(trace) << "Track ID: " << track.getTrackID()
332 << ", Truth Prob: " << track.getTruthProb();
333 }
334 ldmx_log(trace) << "Duplicate tracks:";
335 for (const ldmx::StraightTrack& track : duplicate_tracks) {
336 ldmx_log(trace) << "Track ID: " << track.getTrackID()
337 << ", Truth Prob: " << track.getTruthProb();
338 }
339 ldmx_log(trace) << "Fake tracks:";
340 for (const ldmx::StraightTrack& track : fake_tracks) {
341 ldmx_log(trace) << "Track ID: " << track.getTrackID()
342 << ", Truth Prob: " << track.getTruthProb();
343 }
344
345} // sortTracks
346
347double StraightTracksDQM::thetaAngleError(
348 double m_x, double m_y, const std::vector<double>& covariance_vector) {
349 double sqrt_term = std::sqrt(1 + (m_x * m_x));
350 double sum_term = (1 + (m_x * m_x) + (m_y * m_y));
351
352 double dtheta_dmx = (-m_x * m_y) / (sqrt_term * sum_term);
353 double dtheta_dmy = (sqrt_term / sum_term);
354
355 double sigma_mx2 = covariance_vector[0];
356 double sigma_my2 = covariance_vector[7];
357 double cov_mx_my = covariance_vector[2];
358
359 double sigma_theta2 = (dtheta_dmx * dtheta_dmx * sigma_mx2) +
360 (dtheta_dmy * dtheta_dmy * sigma_my2) +
361 (2 * dtheta_dmx * dtheta_dmy * cov_mx_my);
362
363 return std::sqrt(sigma_theta2);
364} // thetaAngleError
365
366double StraightTracksDQM::phiAngleError(
367 double m_x, const std::vector<double>& covariance_vector) {
368 double sum_term = (1 + (m_x * m_x));
369
370 double sigma_mx = std::sqrt(covariance_vector[0]);
371
372 double sigma_phi = (sigma_mx / sum_term);
373
374 return sigma_phi;
375} // phiAngleError
376
377double StraightTracksDQM::locError(double var_slope, double var_intercept,
378 double cov_slope_intercept, double z_pos) {
379 return std::sqrt((z_pos * z_pos * var_slope) + var_intercept +
380 (2 * z_pos * cov_slope_intercept));
381} // locAngleError
382
383} // namespace tracking::dqm
384
385DECLARE_ANALYZER_NS(tracking::dqm, StraightTracksDQM)
#define DECLARE_ANALYZER_NS(NS, CLASS)
Macro which allows the framework to construct an analyzer given its name during configuration.
HistogramHelper histograms_
Interface class for making and filling histograms.
Implements an event buffer system for storing event data.
Definition Event.h:42
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:92
void fill(const std::string &name, const double &val)
Fill a 1D histogram.
Definition Histograms.h:166
Class encapsulating parameters for configuring a processor.
Definition Parameters.h:29
void configure(framework::config::Parameters &parameters) override
Callback for the EventProcessor to configure itself from the given set of parameters.
void analyze(const framework::Event &event) override
Process the event and make histograms or summaries.