LDMX Software
TrackingRecoDQM.cxx
1#include "Tracking/dqm/TrackingRecoDQM.h"
2
3#include <algorithm>
4#include <iostream>
5
6#include "Tracking/Sim/TrackingUtils.h"
7
8namespace tracking::dqm {
9
11 track_collection_ = parameters.get<std::string>("track_collection");
12 truth_collection_ = parameters.get<std::string>("truth_collection");
13 measurement_collection_ =
14 parameters.get<std::string>("measurement_collection");
15 measurement_passname_ = parameters.get<std::string>("measurement_passname");
16
17 ecal_sp_coll_name_ = parameters.get<std::string>("ecal_sp_coll_name");
18 ecal_sp_passname_ = parameters.get<std::string>("ecal_sp_passname");
19 target_sp_coll_name_ = parameters.get<std::string>("target_sp_coll_name");
20 target_sp_passname_ = parameters.get<std::string>("target_sp_passname");
21 truth_passname_ = parameters.get<std::string>("truth_passname");
22 truth_events_passname_ = parameters.get<std::string>("truth_events_passname");
23 track_passname_ = parameters.get<std::string>("track_passname");
24 track_collection_events_passname_ =
25 parameters.get<std::string>("track_collection_events_passname");
26
27 title_ = parameters.get<std::string>("title", "tagger_trk_");
28 track_prob_cut_ = parameters.get<double>("trackProb_cut", 0.5);
29 subdetector_ = parameters.get<std::string>("subdetector", "Tagger");
30 track_states_ = parameters.get<std::vector<std::string>>("track_states", {});
31
32 pidmap_[-321] = PIDBins::kminus;
33 pidmap_[321] = PIDBins::kplus;
34 pidmap_[-211] = PIDBins::piminus;
35 pidmap_[211] = PIDBins::piplus;
36 pidmap_[11] = PIDBins::electron;
37 pidmap_[-11] = PIDBins::positron;
38 pidmap_[2212] = PIDBins::proton;
39 pidmap_[-2212] = PIDBins::antiproton;
40}
41
43 ldmx_log(trace) << "DQM Reading in:" << track_collection_;
44
45 if (!event.exists(track_collection_, track_collection_events_passname_)) {
46 ldmx_log(error) << "TrackCollection " << track_collection_
47 << " with pass = " << track_collection_events_passname_
48 << " not in event";
49 return;
50 }
51
52 auto tracks{
53 event.getCollection<ldmx::Track>(track_collection_, track_passname_)};
54
55 if (!event.exists(measurement_collection_, measurement_passname_)) {
56 ldmx_log(error) << "Measurement collection " << measurement_collection_
57 << " with pass = " << measurement_passname_
58 << " not in event";
59 return;
60 }
61
62 auto measurements{event.getCollection<ldmx::Measurement>(
63 measurement_collection_, measurement_passname_)};
64
65 // The truth track collection
66 if (event.exists(truth_collection_, truth_events_passname_)) {
67 truth_track_collection_ = std::make_shared<std::vector<ldmx::Track>>(
68 event.getCollection<ldmx::Track>(truth_collection_, truth_passname_));
69 do_truth_comparison_ = true;
70 }
71
72 // The scoring plane hits_
73 if (event.exists(ecal_sp_coll_name_, ecal_sp_passname_)) {
74 ecal_scoring_hits_ = std::make_shared<std::vector<ldmx::SimTrackerHit>>(
75 event.getCollection<ldmx::SimTrackerHit>(ecal_sp_coll_name_,
76 ecal_sp_passname_));
77 }
78
79 if (event.exists(target_sp_coll_name_, target_sp_passname_)) {
80 target_scoring_hits_ = std::make_shared<std::vector<ldmx::SimTrackerHit>>(
81 event.getCollection<ldmx::SimTrackerHit>(target_sp_coll_name_,
82 target_sp_passname_));
83 }
84
85 ldmx_log(debug) << "Do truth comparison::" << do_truth_comparison_;
86
87 if (do_truth_comparison_) {
88 sortTracks(tracks, unique_tracks_, duplicate_tracks_, fake_tracks_);
89 } else {
90 unique_tracks_ = tracks;
91 }
92
93 ldmx_log(debug) << "Filling histograms for " << tracks.size() << " tracks";
94
95 // General Plots
96 histograms_.fill(title_ + "N_tracks", tracks.size());
97
98 if (!unique_tracks_.empty()) {
99 ldmx_log(debug) << "Track Monitoring on " << unique_tracks_.size()
100 << " Unique Tracks";
101 trackMonitoring(unique_tracks_, measurements, title_, true,
102 do_truth_comparison_);
103 }
104
105 // Fakes and duplicates
106 if (!duplicate_tracks_.empty()) {
107 ldmx_log(debug) << "Track Monitoring on " << duplicate_tracks_.size()
108 << " duplicates";
109 trackMonitoring(duplicate_tracks_, measurements, title_ + "dup_", false,
110 false);
111 }
112 if (!fake_tracks_.empty()) {
113 ldmx_log(debug) << "Track Monitoring on " << fake_tracks_.size()
114 << " fakes";
115 trackMonitoring(fake_tracks_, measurements, title_ + "fake_", false, false);
116 }
117
118 // Track Extrapolation to Ecal Monitoring
119 // trackStateMonitoring requires truth_track_collection_ to be available
120 ldmx_log(trace) << "Track Extrapolation to Ecal Monitoring";
121 if (do_truth_comparison_) {
122 if (std::find(track_states_.begin(), track_states_.end(), "target") !=
123 track_states_.end()) {
124 trackStateMonitoring(tracks, ldmx::AtTarget, "target");
125 }
126
127 if (std::find(track_states_.begin(), track_states_.end(), "ecal") !=
128 track_states_.end()) {
129 trackStateMonitoring(tracks, ldmx::AtECAL, "ecal");
130 }
131
132 if (std::find(track_states_.begin(), track_states_.end(), "beamOrigin") !=
133 track_states_.end()) {
134 trackStateMonitoring(tracks, ldmx::AtBeamOrigin, "beamOrigin");
135 }
136 }
137
138 // Technical Efficiency plots
139 if (do_truth_comparison_) {
140 ldmx_log(trace) << "Technical Efficiency plots";
141 efficiencyPlots(tracks, measurements, title_);
142 }
143
144 // Tagger Recoil Matching
145
146 // Clear the vectors
147 ldmx_log(trace) << "Clear the vectors";
148 unique_tracks_.clear();
149 duplicate_tracks_.clear();
150 fake_tracks_.clear();
151}
152
154 // Produce the efficiency plots. (TODO::Switch to TEfficiency instead)
155}
156
157void TrackingRecoDQM::efficiencyPlots(
158 const std::vector<ldmx::Track>& tracks,
159 const std::vector<ldmx::Measurement>& measurements,
160 const std::string& title) {
161 // Do all truth track plots - denominator
162
163 histograms_.fill(title + "truth_N_tracks", truth_track_collection_->size());
164 for (auto& truth_trk : *(truth_track_collection_)) {
165 auto truth_phi = truth_trk.getPhi();
166 auto truth_d0 = truth_trk.getD0();
167 auto truth_z0 = truth_trk.getZ0();
168 auto truth_theta = truth_trk.getTheta();
169 auto truth_qop = truth_trk.getQoP();
170 auto truth_p = 1000. / abs(truth_trk.getQoP()); // MeV
171 auto truth_n_hits = truth_trk.getNhits();
172
173 auto truth_mom = truth_trk.getMomentumAtTarget();
174 double truth_pt_beam{0.}, truth_beam_angle{0.};
175 if (truth_mom.size() == 3) {
176 truth_pt_beam =
177 std::sqrt(truth_mom[0] * truth_mom[0] + truth_mom[1] * truth_mom[1]);
178 truth_beam_angle = std::atan2(truth_pt_beam, truth_mom[2]);
179 }
180
181 histograms_.fill(title + "truth_nHits", truth_n_hits);
182 histograms_.fill(title + "truth_d0", truth_d0);
183 histograms_.fill(title + "truth_z0", truth_z0);
184 histograms_.fill(title + "truth_phi", truth_phi);
185 histograms_.fill(title + "truth_theta", truth_theta);
186 histograms_.fill(title + "truth_qop", truth_qop);
187 histograms_.fill(title + "truth_p", truth_p);
188 histograms_.fill(title + "truth_beam_angle", truth_beam_angle);
189
190 if (pidmap_.count(truth_trk.getPdgID()) != 0) {
191 histograms_.fill(title + "truth_PID", pidmap_[truth_trk.getPdgID()]);
192
193 // TODO do this properly.
194
195 if (pidmap_[truth_trk.getPdgID()] == PIDBins::kminus) {
196 histograms_.fill(title + "truth_kminus_p", truth_p);
197 }
198
199 if (pidmap_[truth_trk.getPdgID()] == PIDBins::kplus) {
200 histograms_.fill(title + "truth_kplus_p", truth_p);
201 }
202
203 if (pidmap_[truth_trk.getPdgID()] == PIDBins::piminus) {
204 histograms_.fill(title + "truth_piminus_p", truth_p);
205 }
206
207 if (pidmap_[truth_trk.getPdgID()] == PIDBins::piplus) {
208 histograms_.fill(title + "truth_piplus_p", truth_p);
209 }
210
211 if (pidmap_[truth_trk.getPdgID()] == PIDBins::electron) {
212 histograms_.fill(title + "truth_electron_p", truth_p);
213 }
214
215 if (pidmap_[truth_trk.getPdgID()] == PIDBins::positron) {
216 histograms_.fill(title + "truth_positron_p", truth_p);
217 }
218
219 if (pidmap_[truth_trk.getPdgID()] == PIDBins::proton) {
220 histograms_.fill(title + "truth_proton_p", truth_p);
221 }
222 }
223
224 } // loop on truth tracks
225
226 for (auto& track : tracks) {
227 // Match the tracks to truth
228 ldmx::Track* truth_trk = nullptr;
229
230 auto it = std::find_if(truth_track_collection_->begin(),
231 truth_track_collection_->end(),
232 [&](const ldmx::Track& tt) {
233 return tt.getTrackID() == track.getTrackID();
234 });
235
236 double track_truth_prob = track.getTruthProb();
237
238 if (it != truth_track_collection_->end() &&
239 track_truth_prob >= track_prob_cut_)
240 truth_trk = &(*it);
241
242 // Match not found, go to next track
243 if (!truth_trk) continue;
244
245 auto truth_phi = truth_trk->getPhi();
246 auto truth_d0 = truth_trk->getD0();
247 auto truth_z0 = truth_trk->getZ0();
248 auto truth_theta = truth_trk->getTheta();
249 auto truth_qop = truth_trk->getQoP();
250 auto truth_p = 1000. / abs(truth_trk->getQoP()); // MeV
251
252 auto truth_mom = truth_trk->getMomentumAtTarget();
253 double truth_pt_beam{0.}, truth_beam_angle{0.};
254 if (truth_mom.size() == 3) {
255 truth_pt_beam =
256 std::sqrt(truth_mom[0] * truth_mom[0] + truth_mom[1] * truth_mom[1]);
257 truth_beam_angle = std::atan2(truth_pt_beam, truth_mom[2]);
258 }
259
260 // Fill reco plots for efficiencies - numerator. The quantities are truth
261 histograms_.fill(title + "match_prob", track_truth_prob);
262 histograms_.fill(title + "match_d0", truth_d0);
263 histograms_.fill(title + "match_z0", truth_z0);
264 histograms_.fill(title + "match_phi", truth_phi);
265 histograms_.fill(title + "match_theta", truth_theta);
266 histograms_.fill(title + "match_p", truth_p);
267 histograms_.fill(title + "match_qop", truth_qop);
268 histograms_.fill(title + "match_beam_angle", truth_beam_angle);
269 histograms_.fill(title + "match_nHits", measurements.size());
270 auto dedx_measurements = track.getDedxMeasurements();
271 auto measurement_idxs = track.getMeasurementsIdxs();
272 for (size_t i = 0; i < measurement_idxs.size(); ++i) {
273 histograms_.fill(title + "match_layers_hit",
274 measurements.at(measurement_idxs[i]).getLayer());
275 // Add histogram of the measurement dE/dx
276 if (i < dedx_measurements.size()) {
277 histograms_.fill(title + "match_measurement_dedx",
278 dedx_measurements[i]);
279 }
280 }
281
282 // For some particles
283
284 if (pidmap_.count(truth_trk->getPdgID()) != 0) {
285 histograms_.fill(title + "match_PID", pidmap_[truth_trk->getPdgID()]);
286
287 // TODO do this properly.
288
289 if (pidmap_[truth_trk->getPdgID()] == PIDBins::kminus) {
290 histograms_.fill(title + "match_kminus_p", truth_p);
291 }
292
293 if (pidmap_[truth_trk->getPdgID()] == PIDBins::kplus) {
294 histograms_.fill(title + "match_kplus_p", truth_p);
295 }
296
297 if (pidmap_[truth_trk->getPdgID()] == PIDBins::piminus) {
298 histograms_.fill(title + "match_piminus_p", truth_p);
299 }
300
301 if (pidmap_[truth_trk->getPdgID()] == PIDBins::piplus) {
302 histograms_.fill(title + "match_piplus_p", truth_p);
303 }
304
305 if (pidmap_[truth_trk->getPdgID()] == PIDBins::electron) {
306 histograms_.fill(title + "match_electron_p", truth_p);
307 }
308
309 if (pidmap_[truth_trk->getPdgID()] == PIDBins::positron) {
310 histograms_.fill(title + "match_positron_p", truth_p);
311 }
312
313 if (pidmap_[truth_trk->getPdgID()] == PIDBins::proton) {
314 histograms_.fill(title + "match_proton_p", truth_p);
315 }
316 }
317 } // Loop on tracks
318
319} // Efficiency plots
320
321void TrackingRecoDQM::trackMonitoring(
322 const std::vector<ldmx::Track>& tracks,
323 const std::vector<ldmx::Measurement>& measurements, const std::string title,
324 const bool& doDetail, const bool& doTruth) {
325 for (auto& track : tracks) {
326 // Perigee track parameters
327 auto trk_d0 = track.getD0();
328 auto trk_z0 = track.getZ0();
329 auto trk_qop = track.getQoP();
330 auto trk_theta = track.getTheta();
331 auto trk_phi = track.getPhi();
332 auto trk_p = 1000. / abs(trk_qop); // MeV
333 auto dedx_measurements = track.getDedxMeasurements();
334 auto measurement_idxs = track.getMeasurementsIdxs();
335 for (size_t i = 0; i < measurement_idxs.size(); ++i) {
336 histograms_.fill(title + "layers_hit",
337 measurements.at(measurement_idxs[i]).getLayer());
338 // Add histogram of the measurement dE/dx
339 if (i < dedx_measurements.size()) {
340 histograms_.fill(title + "measurement_dedx", dedx_measurements[i]);
341 }
342 }
343
344 // Per-layer unbiased U-residuals — only filled for the main unique-track
345 // call (title == title_). Fakes/duplicates use a different title prefix
346 // and do not have these histograms declared.
347 //
348 // Algebraic leave-one-out unbiasing (NIM A 262, 444, 1987):
349 // r_smooth = m - x_smooth
350 // denom = V - C (V = cov_uu, C = smoothed cov[loc0,loc0])
351 // r_ubs = V / denom * r_smooth
352 // pull = r_smooth / sqrt(denom)
353 if (title == title_) {
354 const auto& sm_loc0 = track.getSmoothedLoc0();
355 const auto& sm_cov = track.getSmoothedCovLoc0();
356 for (size_t i = 0; i < measurement_idxs.size(); ++i) {
357 if (i >= sm_loc0.size()) break;
358 const auto& meas = measurements.at(measurement_idxs[i]);
359 int layer = meas.getLayer();
360 float meas_u = meas.getLocalPosition()[0];
361 float v = meas.getLocalCovariance()[0]; // cov_uu
362 float c = sm_cov[i]; // smoothed cov[loc0, loc0]
363 float denom = v - c;
364 if (denom <= 0.f) continue; // degenerate — skip
365 float r_smooth = meas_u - sm_loc0[i];
366 float res_ubs = r_smooth * v / denom;
367 float pull_ubs = r_smooth / std::sqrt(denom);
368 histograms_.fill(title_ + "unbiased_res_u_l" + std::to_string(layer),
369 res_ubs);
370 histograms_.fill(title_ + "unbiased_pull_u_l" + std::to_string(layer),
371 pull_ubs);
372 }
373 }
374
375 auto trk_mom = track.getMomentumAtTarget();
376 // getMomentumAtTarget() returns MeV (LDMX convention)
377 double px_ldmx{0.}, py_ldmx{0.}, pz_ldmx{0.};
378 double pt_bending{0.}, pt_beam{0.};
379 if (trk_mom.size() == 3) {
380 px_ldmx = trk_mom[0]; // MeV
381 py_ldmx = trk_mom[1];
382 pz_ldmx = trk_mom[2];
383 // Bending-plane pT: horizontal (x_ldmx) + downstream (z_ldmx)
384 pt_bending = std::sqrt(px_ldmx * px_ldmx + pz_ldmx * pz_ldmx);
385 // Transverse pT perpendicular to beam: horizontal + vertical
386 pt_beam = std::sqrt(px_ldmx * px_ldmx + py_ldmx * py_ldmx);
387 }
388
389 // Covariance matrix
390 Acts::BoundMatrix cov =
391 tracking::sim::utils::unpackCov(track.getPerigeeCov());
392
393 double sigmad0 = sqrt(
394 cov(Acts::BoundIndices::eBoundLoc0, Acts::BoundIndices::eBoundLoc0));
395 double sigmaz0 = sqrt(
396 cov(Acts::BoundIndices::eBoundLoc1, Acts::BoundIndices::eBoundLoc1));
397 double sigmaphi =
398 sqrt(cov(Acts::BoundIndices::eBoundPhi, Acts::BoundIndices::eBoundPhi));
399 double sigmatheta = sqrt(
400 cov(Acts::BoundIndices::eBoundTheta, Acts::BoundIndices::eBoundTheta));
401 double sigmaqop = sqrt(cov(Acts::BoundIndices::eBoundQOverP,
402 Acts::BoundIndices::eBoundQOverP));
403 double sigmap =
404 (1000. / trk_qop) * (1000. / trk_qop) * sigmaqop / 1000.; // MeV
405
406 histograms_.fill(title + "d0", trk_d0);
407 histograms_.fill(title + "z0", trk_z0);
408 histograms_.fill(title + "qop", trk_qop);
409 histograms_.fill(title + "phi", trk_phi);
410 histograms_.fill(title + "theta", trk_theta);
411 histograms_.fill(title + "p", trk_p);
412
413 if (doDetail) {
414 histograms_.fill(title + "px", px_ldmx);
415 histograms_.fill(title + "py", py_ldmx);
416 histograms_.fill(title + "pz", pz_ldmx);
417
418 histograms_.fill(title + "pt_bending", pt_bending);
419 histograms_.fill(title + "pt_beam", pt_beam);
420
421 histograms_.fill(title + "nHits", track.getNhits());
422 histograms_.fill(title + "Chi2", track.getChi2());
423 histograms_.fill(title + "ndf", track.getNdf());
424 histograms_.fill(title + "Chi2_per_ndf",
425 track.getChi2() / track.getNdf());
426 histograms_.fill(title + "nShared", track.getNsharedHits());
427
428 histograms_.fill(title + "d0_err", sigmad0);
429 histograms_.fill(title + "z0_err", sigmaz0);
430 histograms_.fill(title + "phi_err", sigmaphi);
431 histograms_.fill(title + "theta_err", sigmatheta);
432 histograms_.fill(title + "qop_err", sigmaqop);
433 histograms_.fill(title + "p_err", sigmap);
434
435 // 2D Error plots (p in MeV)
436 histograms_.fill(title + "d0_err_vs_p", trk_p, sigmad0);
437 histograms_.fill(title + "z0_err_vs_p", trk_p, sigmaz0);
438 histograms_.fill(title + "p_err_vs_p", trk_p, sigmap);
439
440 if (track.getNhits() == 8)
441 histograms_.fill(title + "p_err_vs_p_8hits", trk_p, sigmap);
442 else if (track.getNhits() == 9)
443 histograms_.fill(title + "p_err_vs_p_9hits", trk_p, sigmap);
444 else if (track.getNhits() == 10)
445 histograms_.fill(title + "p_err_vs_p_10hits", trk_p, sigmap);
446 }
447
448 if (doTruth) {
449 // Match to the truth track
450 ldmx::Track* truth_trk = nullptr;
451
452 auto it = std::find_if(truth_track_collection_->begin(),
453 truth_track_collection_->end(),
454 [&](const ldmx::Track& tt) {
455 return tt.getTrackID() == track.getTrackID();
456 });
457
458 double track_truth_prob = track.getTruthProb();
459
460 if (it != truth_track_collection_->end() &&
461 track_truth_prob >= track_prob_cut_)
462 truth_trk = &(*it);
463
464 // Found matched track
465 if (truth_trk) {
466 auto truth_d0 = truth_trk->getD0();
467 auto truth_z0 = truth_trk->getZ0();
468 auto truth_phi = truth_trk->getPhi();
469 auto truth_theta = truth_trk->getTheta();
470 auto truth_qop = truth_trk->getQoP();
471 auto truth_p = 1000. / abs(truth_trk->getQoP()); // MeV
472 auto truth_mom = truth_trk->getMomentumAtTarget();
473 // getMomentumAtTarget() returns MeV (LDMX convention)
474 double truth_pt_beam{0.};
475 if (truth_mom.size() == 3) {
476 truth_pt_beam = std::sqrt(truth_mom[0] * truth_mom[0] +
477 truth_mom[1] * truth_mom[1]);
478 }
479
480 // histograms_.fill(title+"truth_d0", truth_d0);
481 // histograms_.fill(title+"truth_z0", truth_z0);
482 // histograms_.fill(title+"truth_phi", truth_phi);
483 // histograms_.fill(title+"truth_theta",truth_theta);
484 // histograms_.fill(title+"truth_qop", truth_qop);
485 // histograms_.fill(title+"truth_p", truth_p);
486
487 double res_d0 = trk_d0 - truth_d0;
488 double res_z0 = trk_z0 - truth_z0;
489 double res_phi = trk_phi - truth_phi;
490 double res_theta = trk_theta - truth_theta;
491 double res_qop = trk_qop - truth_qop;
492 double res_p = trk_p - truth_p;
493 double res_pt_beam = pt_beam - truth_pt_beam;
494
495 histograms_.fill(title + "res_d0", res_d0);
496 histograms_.fill(title + "res_z0", res_z0);
497 histograms_.fill(title + "res_phi", res_phi);
498 histograms_.fill(title + "res_theta", res_theta);
499 histograms_.fill(title + "res_qop", res_qop);
500 histograms_.fill(title + "res_p", res_p);
501 histograms_.fill(title + "res_pt_beam", res_pt_beam);
502
503 double pull_d0 = res_d0 / sigmad0;
504 double pull_z0 = res_z0 / sigmaz0;
505 double pull_phi = res_phi / sigmaphi;
506 double pull_theta = res_theta / sigmatheta;
507 double pull_qop = res_qop / sigmaqop;
508 double pull_p = res_p / sigmap;
509
510 histograms_.fill(title + "pull_d0", pull_d0);
511 histograms_.fill(title + "pull_z0", pull_z0);
512 histograms_.fill(title + "pull_phi", pull_phi);
513 histograms_.fill(title + "pull_theta", pull_theta);
514 histograms_.fill(title + "pull_qop", pull_qop);
515 histograms_.fill(title + "pull_p", pull_p);
516
517 // Error plots from residuals
518
519 histograms_.fill(title + "res_p_vs_p", truth_p, res_p);
520
521 histograms_.fill(title + "res_qop_vs_p", truth_p, res_qop);
522 histograms_.fill(title + "res_d0_vs_p", truth_p, res_d0);
523 histograms_.fill(title + "res_z0_vs_p", truth_p, res_z0);
524 histograms_.fill(title + "res_phi_vs_p", truth_p, res_phi);
525 histograms_.fill(title + "res_theta_vs_p", truth_p, res_theta);
526
527 histograms_.fill(title + "pull_qop_vs_p", truth_p, pull_qop);
528 histograms_.fill(title + "pull_d0_vs_p", truth_p, pull_d0);
529 histograms_.fill(title + "pull_z0_vs_p", truth_p, pull_z0);
530 histograms_.fill(title + "pull_phi_vs_p", truth_p, pull_phi);
531 histograms_.fill(title + "pull_theta_vs_p", truth_p, pull_theta);
532
533 if (track.getNhits() == 8)
534 histograms_.fill(title + "res_p_vs_p_8hits", truth_p, res_p);
535 else if (track.getNhits() == 9)
536 histograms_.fill(title + "res_p_vs_p_9hits", truth_p, res_p);
537 else if (track.getNhits() == 10)
538 histograms_.fill(title + "res_p_vs_p_10hits", truth_p, res_p);
539
540 histograms_.fill(title + "res_pt_beam_vs_p", truth_pt_beam,
541 res_pt_beam);
542
543 } // found matched track
544 } // do TruthComparison
545 } // loop on tracks
546
547} // Track Monitoring
548
550 const std::vector<ldmx::Track>& tracks, ldmx::TrackStateType ts_type,
551 const std::string& ts_title) {
552 for (auto& track : tracks) {
553 // Match the tracks to truth
554 ldmx::Track* truth_trk = nullptr;
555
556 auto it = std::find_if(truth_track_collection_->begin(),
557 truth_track_collection_->end(),
558 [&](const ldmx::Track& tt) {
559 return tt.getTrackID() == track.getTrackID();
560 });
561
562 double track_truth_prob = track.getTruthProb();
563
564 if (it != truth_track_collection_->end() &&
565 track_truth_prob >= track_prob_cut_)
566 truth_trk = &(*it);
567
568 // Match not found, skip track
569 if (!truth_trk) continue;
570
571 auto trk_ts = track.getTrackState(ts_type);
572 auto truth_ts = truth_trk->getTrackState(ts_type);
573
574 if (!trk_ts.has_value()) continue;
575 if (!truth_ts.has_value()) continue;
576
577 const ldmx::Track::TrackState& target_state = trk_ts.value();
578 const ldmx::Track::TrackState& truth_target_state = truth_ts.value();
579
580 // Check that the covariance is filled
581 if (target_state.pos_mom_cov_.size() < 21) continue;
582
583 // Sigma from Cartesian position covariance (LDMX frame):
584 // pos_mom_cov_ upper-triangle layout: xx=0, yy=6
585 double sigmaloc0 = std::sqrt(target_state.pos_mom_cov_[0]); // sigma_x
586 double sigmaloc1 = std::sqrt(target_state.pos_mom_cov_[6]); // sigma_y
587
588 double trk_qop = track.getQoP();
589 double trk_p = 1000. / abs(trk_qop); // MeV
590
591 // loc0/loc1 = x/y position at the surface in LDMX global frame
592 double track_state_loc0 = target_state.pos_[0];
593 double track_state_loc1 = target_state.pos_[1];
594
595 double truth_state_loc0 = truth_target_state.pos_[0];
596 double truth_state_loc1 = truth_target_state.pos_[1];
597
598 histograms_.fill(title_ + "trk_" + ts_title + "_loc0", track_state_loc0);
599 histograms_.fill(title_ + "trk_" + ts_title + "_loc1", track_state_loc1);
600 histograms_.fill(title_ + ts_title + "_truth_loc0", truth_state_loc0);
601 histograms_.fill(title_ + ts_title + "_truth_loc1", truth_state_loc1);
602
603 // TH1F residuals
605 title_ + "trk_" + ts_title + "_loc0-truth_" + ts_title + "_loc0",
606 track_state_loc0 - truth_state_loc0);
608 title_ + "trk_" + ts_title + "_loc1-truth_" + ts_title + "_loc1",
609 track_state_loc1 - truth_state_loc1);
610
611 // TH1F The pulls of loc0 and loc1
612 histograms_.fill(title_ + ts_title + "_Pulls_of_loc0",
613 (track_state_loc0 - truth_state_loc0) / sigmaloc0);
614 histograms_.fill(title_ + ts_title + "_Pulls_of_loc1",
615 (track_state_loc1 - truth_state_loc1) / sigmaloc1);
616
617 // TODO:: TH1F The pulls of phi, theta, qop
618
619 // TH2F residual vs Nhits
620 histograms_.fill(title_ + ts_title + "_res_loc0-vs-N_hits",
621 track.getNhits(), track_state_loc0 - truth_state_loc0);
622 histograms_.fill(title_ + ts_title + "_res_loc1-vs-N_hits",
623 track.getNhits(), track_state_loc1 - truth_state_loc1);
624
625 // TH2F pulls vs Nhits
626 histograms_.fill(title_ + ts_title + "_pulls_loc0-vs-N_hits",
627 track.getNhits(),
628 (track_state_loc0 - truth_state_loc0) / sigmaloc0);
629 histograms_.fill(title_ + ts_title + "_pulls_loc1-vs-N_hits",
630 track.getNhits(),
631 (track_state_loc1 - truth_state_loc1) / sigmaloc1);
632
633 // TH2F residual vs trk_p
634 histograms_.fill(title_ + ts_title + "_res_loc0-vs-trk_p", trk_p,
635 track_state_loc0 - truth_state_loc0);
636 histograms_.fill(title_ + ts_title + "_res_loc1-vs-trk_p", trk_p,
637 track_state_loc1 - truth_state_loc1);
638
639 // TH2F pulls vs trk_p
640 histograms_.fill(title_ + ts_title + "_pulls_loc0-vs-trk_p", trk_p,
641 (track_state_loc0 - truth_state_loc0) / sigmaloc0);
642 histograms_.fill(title_ + ts_title + "_pulls_loc1-vs-trk_p", trk_p,
643 (track_state_loc1 - truth_state_loc1) / sigmaloc1);
644
645 } // loop on tracks
646}
647
648void TrackingRecoDQM::sortTracks(const std::vector<ldmx::Track>& tracks,
649 std::vector<ldmx::Track>& uniqueTracks,
650 std::vector<ldmx::Track>& duplicateTracks,
651 std::vector<ldmx::Track>& fakeTracks) {
652 // Create a copy of the const vector so we can sort it
653 std::vector<ldmx::Track> sorted_tracks = tracks;
654
655 // Sort the vector of Track objects based on their trackID member
656 std::sort(sorted_tracks.begin(), sorted_tracks.end(),
657 [](ldmx::Track& t1, ldmx::Track& t2) {
658 return t1.getTrackID() < t2.getTrackID();
659 });
660
661 // Loop over the sorted vector of Track objects
662 for (size_t i = 0; i < sorted_tracks.size(); i++) {
663 if (sorted_tracks[i].getTruthProb() < track_prob_cut_)
664 fakeTracks.push_back(sorted_tracks[i]);
665 else { // not a fake track
666 // If this is the first Track object with this trackID, add it to the
667 // uniqueTracks vector directly
668 if (uniqueTracks.size() == 0 ||
669 sorted_tracks[i].getTrackID() != sorted_tracks[i - 1].getTrackID()) {
670 uniqueTracks.push_back(sorted_tracks[i]);
671 }
672 // Otherwise, add it to the duplicateTracks vector if its truthProb is
673 // lower than the existing Track object Otherwise, if the truthProbability
674 // is higher than the track stored in uniqueTracks, put it in uniqueTracks
675 // and move the uniqueTracks.back to duplicateTracks.
676 else if (sorted_tracks[i].getTruthProb() >
677 uniqueTracks.back().getTruthProb()) {
678 duplicateTracks.push_back(uniqueTracks.back());
679 uniqueTracks.back() = sorted_tracks[i];
680 }
681 // Otherwise, add it to the duplicateTracks vector
682 else {
683 duplicateTracks.push_back(sorted_tracks[i]);
684 }
685 } // a real track
686 } // loop on sorted tracks
687 // The total number of elements in the uniqueTracks and duplicateTracks
688 // vectors should be equal to the number of elements in the original tracks
689 // vector
690 if (uniqueTracks.size() + duplicateTracks.size() + fakeTracks.size() !=
691 tracks.size()) {
692 std::cerr << "Error: unique and duplicate tracks vectors do not add up to "
693 "original tracks vector";
694 return;
695 }
696
697 // Iterate through the uniqueTracks vector and duplicateTracks vector
698 ldmx_log(trace) << "Unique tracks:";
699 for (const ldmx::Track& track : uniqueTracks) {
700 ldmx_log(trace) << "\tTrack ID: " << track.getTrackID()
701 << ", Truth Prob: " << track.getTruthProb();
702 }
703 ldmx_log(trace) << "Duplicate tracks:";
704 for (const ldmx::Track& track : duplicateTracks) {
705 ldmx_log(trace) << "\tTrack ID: " << track.getTrackID()
706 << ", Truth Prob: " << track.getTruthProb();
707 }
708 ldmx_log(trace) << "Fake tracks:";
709 for (const ldmx::Track& track : fakeTracks) {
710 ldmx_log(trace) << "\tTrack ID: " << track.getTrackID()
711 << ", Truth Prob: " << track.getTruthProb();
712 }
713}
714} // namespace tracking::dqm
715
#define DECLARE_ANALYZER(CLASS)
Macro which allows the framework to construct an analyzer given its name during configuration.
HistogramPool histograms_
helper object for making and filling histograms
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
void fill(const std::string &name, const T &val)
Fill a 1D histogram.
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
Represents a simulated tracker hit in the simulation.
Implementation of a track object.
Definition Track.h:54
std::vector< double > getMomentumAtTarget() const
Returns the momentum (px, py, pz) in MeV in the LDMX global frame from the AtTarget TrackState.
Definition Track.h:220
void trackStateMonitoring(const std::vector< ldmx::Track > &tracks, ldmx::TrackStateType ts_type, const std::string &ts_title)
Monitoring plots for tracks extrapolated to the ECAL Scoring plane.
void onProcessEnd() override
Callback for the EventProcessor to take any necessary action when the processing of events finishes,...
void configure(framework::config::Parameters &parameters) override
Configure the analyzer using the given user specified parameters.
void analyze(const framework::Event &event) override
Process the event and make histograms or summaries.