LDMX Software
VisiblesCutflow.cxx
1#include "DQM/VisiblesCutflow.h"
2
3// LDMX
4#include "DetDescr/EcalID.h"
5#include "DetDescr/HcalID.h"
6#include "DetDescr/SimSpecialID.h"
7#include "Ecal/Event/EcalHit.h"
11#include "SimCore/Event/SimParticle.h"
13#include "Tracking/Event/Track.h"
14
15// C++
16#include <algorithm>
17#include <cmath>
18#include <fstream>
19#include <iostream>
20#include <numeric>
21
22namespace dqm {
23
25 rt_ = std::make_unique<ldmx::ort::ONNXRuntime>(
26 parameters.get<std::string>("bdt_file"));
27 feature_list_name_ = parameters.get<std::string>("feature_list_name");
28 bdt_cut_val_ = parameters.get<double>("disc_cut");
29 ecal_bdt_cut_val_ = parameters.get<double>("ecal_disc_cut");
30 all_cuts_ = parameters.get<bool>("all_cuts");
31
32 beam_energy_mev_ = parameters.get<double>("beam_energy");
33
34 // collection names
35 hcal_rec_collection_ = parameters.get<std::string>("hcal_rec_coll_name");
36 hcal_rec_pass_name_ = parameters.get<std::string>("hcal_rec_pass_name");
37
38 ecal_rec_collection_ = parameters.get<std::string>("ecal_rec_coll_name");
39 ecal_rec_pass_name_ = parameters.get<std::string>("ecal_rec_pass_name");
40
41 recoil_from_tracking_ = parameters.get<bool>("recoil_from_tracking");
42 track_collection_ = parameters.get<std::string>("track_collection");
43 track_pass_name_ = parameters.get<std::string>("track_pass_name");
44
45 sp_collection_ = parameters.get<std::string>("sp_coll_name");
46 sp_pass_name_ = parameters.get<std::string>("sp_pass_name");
47
48 sim_particles_coll_name_ =
49 parameters.get<std::string>("sim_particles_coll_name");
50 sim_particles_pass_name_ =
51 parameters.get<std::string>("sim_particles_pass_name");
52
53 ecal_veto_collection_ = parameters.get<std::string>("ecal_veto_coll_name");
54 ecal_veto_pass_ = parameters.get<std::string>("ecal_veto_pass_name");
55}
56
57bool VisiblesCutflow::inList(std::vector<int> parents, int track_id) {
58 return std::find(parents.begin(), parents.end(), track_id) != parents.end();
59}
60
62 std::vector<float> bdt_features;
63
64 double decay_z;
65
66 const auto &particle_map{event.getMap<int, ldmx::SimParticle>(
67 sim_particles_coll_name_, sim_particles_pass_name_)};
68
69 for (auto const &it : particle_map) {
70 std::vector<int> parents = it.second.getParents();
71 for (int track_id : parents) {
72 if (track_id == 0 && it.second.getPdgID() == -11) {
73 decay_z = it.second.getVertex()[2];
74 }
75 }
76 }
77
78 histograms_.fill("total_events", decay_z);
79
80 // Get target scoring plane hits for recoil electron
81 // Use this to calculate the projected photon line vector
82 // This currently uses truth-level information, but it should be replaced
83 // by reconstructed tracker information, when available
84 std::vector<double> gamma_p(3);
85 double gamma_energy = 90000.;
86 std::vector<double> gamma_x0(3);
87
88 std::vector<double> recoil_p(3);
89 bool found_recoil_e = false;
90
91 if (recoil_from_tracking_) {
92 const auto &recoil_tracks{
93 event.getCollection<ldmx::Track>(track_collection_, track_pass_name_)};
94 for (auto &track : recoil_tracks) {
95 // need to figure out how to best isolate candidate electron track
96 auto trk_pos = track.getPositionAtTarget();
97 auto trk_mom = track.getMomentumAtTarget();
98 if (track.getCharge() == 1 && track.getNhits() == 5 &&
99 trk_pos.size() == 3 && trk_mom.size() == 3) {
100 gamma_x0 = trk_pos;
101 gamma_p[0] = -1. * trk_mom[0];
102 gamma_p[1] = -1. * trk_mom[1];
103 gamma_p[2] = 8000. - trk_mom[2];
104 }
105 }
106 } else {
107 if (event.exists(sp_collection_, sp_pass_name_)) {
108 const auto &target_sp_hits = event.getCollection<ldmx::SimTrackerHit>(
109 sp_collection_, sp_pass_name_);
110 bool found_rec = false;
111 for (auto const &it : particle_map) {
112 for (auto const &sphit : target_sp_hits) {
113 if (sphit.getPosition()[2] > 0) {
114 if (it.first == sphit.getTrackID()) {
115 if (it.second.getPdgID() == 622) {
116 std::vector<float> x0_float = sphit.getPosition();
117 std::vector<double> x0_double(x0_float.begin(), x0_float.end());
118 gamma_x0 = x0_double;
119 gamma_p = sphit.getMomentum();
120 gamma_energy = sphit.getEnergy();
121 found_rec = true;
122 }
123 if (it.second.getPdgID() == 11 &&
124 inList(it.second.getParents(), 0)) {
125 if (!found_rec) {
126 std::vector<float> x0_float = sphit.getPosition();
127 std::vector<double> x0_double(x0_float.begin(),
128 x0_float.end());
129 gamma_x0 = x0_double;
130 gamma_p[0] = -1. * sphit.getMomentum()[0];
131 gamma_p[1] = -1. * sphit.getMomentum()[1];
132 gamma_p[2] = beam_energy_mev_ - sphit.getMomentum()[2];
133 gamma_energy = beam_energy_mev_ - sphit.getEnergy();
134 found_rec = true;
135 }
136 recoil_p = sphit.getMomentum();
137 found_recoil_e = true;
138 }
139 }
140 }
141 }
142 }
143 }
144 }
145 histograms_.fill("beam_energy_frac", gamma_energy / 8000.);
146 histograms_.fill("beam_angle",
147 std::acos(gamma_p[2] / std::sqrt(gamma_p[0] * gamma_p[0] +
148 gamma_p[1] * gamma_p[1] +
149 gamma_p[2] * gamma_p[2])));
150
151 double p_mag = 0.;
152 if (found_recoil_e) {
153 p_mag = std::sqrt(recoil_p[0] * recoil_p[0] + recoil_p[1] * recoil_p[1] +
154 recoil_p[2] * recoil_p[2]);
155 }
156
157 if (p_mag < 50. && all_cuts_) {
158 return;
159 }
160 histograms_.fill("pass_acceptance", decay_z);
161
162 // Get EcalRecHits, check that trigger is passed
163 const auto &ecal_rec_hits = event.getCollection<ldmx::EcalHit>(
164 ecal_rec_collection_, ecal_rec_pass_name_);
165 const auto &hcal_rec_hits = event.getCollection<ldmx::HcalHit>(
166 hcal_rec_collection_, hcal_rec_pass_name_);
167
168 double trigger = 0.;
169 double ecal_energy = 0.;
170 double hcal_energy = 0.;
171 bool hcal_containment = true;
172
173 for (const ldmx::EcalHit &hit : ecal_rec_hits) {
174 if (hit.getEnergy() > 0.) {
175 ecal_energy += hit.getEnergy();
176 if (hit.getZPos() <= 541.722) {
177 trigger += hit.getEnergy();
178 }
179 }
180 }
181 for (const ldmx::HcalHit &hit : hcal_rec_hits) {
182 if (hit.getEnergy() > 0.) {
183 ldmx::HcalID det_id(hit.getID());
184 if (det_id.getSection() != 0) {
185 continue;
186 }
187 if (det_id.getLayerID() == 1 && hit.getPE() > 5) {
188 hcal_containment = false;
189 }
190 hcal_energy += 12. * hit.getEnergy();
191 }
192 }
193
194 if (trigger > 3160. && all_cuts_) {
195 return;
196 }
197 histograms_.fill("pass_trigger", decay_z);
198
199 if (ecal_energy > 3160. && all_cuts_) {
200 return;
201 }
202 histograms_.fill("pass_ecal_energy", decay_z);
203
204 if (p_mag > 2400. && all_cuts_) {
205 return;
206 }
207 histograms_.fill("pass_tracker_veto", decay_z);
208
209 const auto &ecal_veto{event.getObject<ldmx::EcalVetoResult>(
210 ecal_veto_collection_, ecal_veto_pass_)};
211 if (ecal_veto.getDisc() < ecal_bdt_cut_val_ && all_cuts_) {
212 return;
213 }
214 histograms_.fill("pass_ecal_bdt", decay_z);
215
216 if (hcal_energy < 4840 && all_cuts_) {
217 return;
218 }
219 histograms_.fill("pass_hcal_energy", decay_z);
220
221 if (!hcal_containment && all_cuts_) {
222 return;
223 }
224 histograms_.fill("pass_hcal_containment", decay_z);
225
226 // initialize all of the features
227 int n_layers_hit = 0;
228 double x_std = 0.;
229 double y_std = 0.;
230 double z_std = 0.;
231 double x_mean = 0.;
232 double y_mean = 0.;
233 double r_mean = 0.;
234 int iso_hits = 0;
235 double iso_energy = 0.;
236 int n_readout_hits = 0;
237 double summed_det = 0.;
238 double r_mean_from_photon_track = 0.;
239
240 double z_mean = 0.; // need this when calculating z_std
241 std::vector<int> layers_hit;
242 for (const ldmx::HcalHit &hit : hcal_rec_hits) {
243 if (hit.getEnergy() > 0.) {
244 ldmx::HcalID det_id(hit.getID());
245 if (det_id.getSection() != 0) { // skip hits that aren't in main Hcal
246 continue;
247 }
248 if (fabs(hit.getXPos()) > 1000 || fabs(hit.getYPos()) > 1000) {
249 continue;
250 }
251 n_readout_hits += 1;
252 double hit_x = hit.getXPos();
253 double hit_y = hit.getYPos();
254 double hit_z = hit.getZPos();
255 double hit_r = sqrt(hit_x * hit_x + hit_y * hit_y);
256
257 summed_det += hit.getEnergy();
258
259 x_mean += hit_x * hit.getEnergy();
260 y_mean += hit_y * hit.getEnergy();
261 z_mean += hit_z * hit.getEnergy();
262 r_mean += hit_r * hit.getEnergy();
263
264 // check if this is a new layer in the collection
265 if (!(std::find(layers_hit.begin(), layers_hit.end(),
266 det_id.getLayerID()) != layers_hit.end())) {
267 layers_hit.push_back(det_id.getLayerID());
268 }
269
270 double proj_x =
271 gamma_x0[0] + (hit_z - gamma_x0[2]) * gamma_p[0] / gamma_p[2];
272 double proj_y =
273 gamma_x0[1] + (hit_z - gamma_x0[2]) * gamma_p[1] / gamma_p[2];
274
275 r_mean_from_photon_track +=
276 hit.getEnergy() * sqrt((hit_x - proj_x) * (hit_x - proj_x) +
277 (hit_y - proj_y) * (hit_y - proj_y));
278
279 // Calculate isolated hits
280 double closest_point = 9999.;
281 for (const ldmx::HcalHit &hit2 : hcal_rec_hits) {
282 if (hit2.getEnergy() > 0.) {
283 ldmx::HcalID det_i_d2(hit2.getID());
284 if (fabs(hit2.getXPos()) > 1000 || fabs(hit2.getYPos()) > 1000) {
285 continue;
286 }
287 if (det_i_d2.getLayerID() == det_id.getLayerID()) {
288 // Determine if a bar is vertical (along y-axis) or horizontal
289 // (along x-axis) Odd layers have horizontal strips Even layers have
290 // vertical strips
291 if (hit.isOrientationX()) {
292 if (fabs(hit2.getYPos() - hit_y) > 0) {
293 if (fabs(hit2.getYPos() - hit_y) < closest_point) {
294 closest_point = abs(hit2.getYPos() - hit_y);
295 }
296 }
297 }
298 if (hit.isOrientationY()) {
299 if (fabs(hit2.getXPos() - hit_x) > 0) {
300 if (fabs(hit2.getXPos() - hit_x) < closest_point) {
301 closest_point = fabs(hit2.getXPos() - hit_x);
302 }
303 }
304 }
305 }
306 }
307 }
308 if (closest_point > 50.) {
309 iso_hits += 1;
310 iso_energy += hit.getEnergy();
311 }
312 }
313 }
314
315 n_layers_hit = layers_hit.size();
316
317 if (summed_det > 0.) {
318 x_mean /= summed_det;
319 y_mean /= summed_det;
320 z_mean /= summed_det;
321 r_mean /= summed_det;
322
323 r_mean_from_photon_track /= summed_det;
324 }
325
326 for (const ldmx::HcalHit &hit : hcal_rec_hits) {
327 if (hit.getEnergy() > 0.) {
328 if (fabs(hit.getXPos()) > 1000 || fabs(hit.getYPos()) > 1000) {
329 continue;
330 }
331 ldmx::HcalID det_id(hit.getID());
332 if (det_id.getSection() == 0) {
333 x_std += hit.getEnergy() * (hit.getXPos() - x_mean) *
334 (hit.getXPos() - x_mean);
335 y_std += hit.getEnergy() * (hit.getYPos() - y_mean) *
336 (hit.getYPos() - y_mean);
337 z_std += hit.getEnergy() * (hit.getZPos() - z_mean) *
338 (hit.getZPos() - z_mean);
339 }
340 }
341 }
342
343 if (summed_det > 0.) {
344 x_std = sqrt(x_std / summed_det);
345 y_std = sqrt(y_std / summed_det);
346 z_std = sqrt(z_std / summed_det);
347 }
348
349 // Fill histograms
350 histograms_.fill("layers_hit", n_layers_hit);
351 histograms_.fill("x_std", x_std);
352 histograms_.fill("y_std", y_std);
353 histograms_.fill("z_std", z_std);
354 histograms_.fill("x_mean", x_mean);
355 histograms_.fill("y_mean", y_mean);
356 histograms_.fill("r_mean", r_mean);
357 histograms_.fill("iso_hits", iso_hits);
358 histograms_.fill("iso_energy", iso_energy);
359 histograms_.fill("n_hits", n_readout_hits);
360 histograms_.fill("total_energy", hcal_energy);
361 histograms_.fill("photon_track", r_mean_from_photon_track);
362
363 bdt_features.push_back(n_layers_hit);
364 bdt_features.push_back(x_std);
365 bdt_features.push_back(y_std);
366 bdt_features.push_back(z_std);
367 bdt_features.push_back(x_mean);
368 bdt_features.push_back(y_mean);
369 bdt_features.push_back(r_mean);
370 bdt_features.push_back(iso_hits);
371 bdt_features.push_back(iso_energy);
372 bdt_features.push_back(n_readout_hits);
373 bdt_features.push_back(hcal_energy);
374 bdt_features.push_back(r_mean_from_photon_track);
375
376 ldmx::ort::FloatArrays inputs({bdt_features});
377 float pred =
378 rt_->run({feature_list_name_}, inputs, {"probabilities"})[0].at(1);
379
380 histograms_.fill("visibles_disc", pred);
381
382 for (int i = 0; i < 10000; i++) {
383 double disc = 0.999 + (double(i) / 10000.) * (1. - 0.999);
384 histograms_.fill("visibles_disc_high_norm",
385 0.999 + ((double(i) + 0.5) / 10000.) * (1. - 0.999));
386 double disc_roc = 0.99 + (double(i) / 10000.) * (1. - 0.99);
387 if (pred >= disc) {
388 histograms_.fill("visibles_disc_high",
389 0.999 + ((double(i) + 0.5) / 10000.) * (1. - 0.999));
390 }
391 if (pred >= disc_roc) {
392 histograms_.fill("roc", disc_roc);
393 }
394 }
395
396 histograms_.fill("ecal_disc_vs_vis_disc", pred, ecal_veto.getDisc());
397
398 if (pred < bdt_cut_val_) {
399 return;
400 }
401 histograms_.fill("pass_visibles_bdt", decay_z);
402
403 return;
404}
405
406} // namespace dqm
407
Class that defines an ECal detector ID with a cell number.
Class used to encapsulate the results obtained from EcalVetoProcessor.
#define DECLARE_ANALYZER(CLASS)
Macro which allows the framework to construct an analyzer given its name during configuration.
Class that stores Stores reconstructed hit information from the HCAL.
Class that defines an HCal sensitive detector.
Class which stores simulated calorimeter hit information.
Class which encapsulates information from a hit in a simulated tracking detector.
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.
HistogramPool histograms_
helper object 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:105
void fill(const std::string &name, const T &val)
Fill a 1D histogram.
Class encapsulating parameters for configuring a processor.
Definition Parameters.h:29
const T & get(const std::string &name) const
Retrieve the parameter of the given name.
Definition Parameters.h:78
Stores reconstructed hit information from the ECAL.
Definition EcalHit.h:19
Stores reconstructed hit information from the HCAL.
Definition HcalHit.h:24
Implements detector ids for HCal subdetector.
Definition HcalID.h:19
unsigned int getLayerID() const
Get the value of the layer field from the ID.
Definition HcalID.h:96
Class representing a simulated particle.
Definition SimParticle.h:24
Represents a simulated tracker hit in the simulation.
Implementation of a track object.
Definition Track.h:53