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