LDMX Software
VisiblesFeatureProducer.cxx
1#include "DQM/VisiblesFeatureProducer.h"
2
3// LDMX
4#include "DetDescr/HcalID.h"
5#include "DetDescr/SimSpecialID.h"
6#include "Ecal/Event/EcalHit.h"
9#include "SimCore/Event/SimParticle.h"
11#include "Tracking/Event/Track.h"
12
13// C++
14#include <algorithm>
15#include <cmath>
16#include <fstream>
17#include <iostream>
18#include <numeric>
19
20namespace dqm {
21
24 training_ = parameters.get<bool>("training");
25 training_file_ = parameters.get<std::string>("training_file");
26
27 beam_energy_mev_ = parameters.get<double>("beam_energy");
28
29 // collection names
30 hcal_rec_collection_ = parameters.get<std::string>("hcal_rec_coll_name");
31 hcal_rec_pass_name_ = parameters.get<std::string>("hcal_rec_pass_name");
32
33 ecal_rec_collection_ = parameters.get<std::string>("ecal_rec_coll_name");
34 ecal_rec_pass_name_ = parameters.get<std::string>("ecal_rec_pass_name");
35
36 recoil_from_tracking_ = parameters.get<bool>("recoil_from_tracking");
37 track_collection_ = parameters.get<std::string>("track_collection");
38 track_pass_name_ = parameters.get<std::string>("track_pass_name");
39
40 sp_collection_ = parameters.get<std::string>("sp_coll_name");
41 sp_pass_name_ = parameters.get<std::string>("sp_pass_name");
42
43 sim_particles_coll_name_ =
44 parameters.get<std::string>("sim_particles_coll_name");
45 sim_particles_pass_name_ =
46 parameters.get<std::string>("sim_particles_pass_name");
47}
48
49bool VisiblesFeatureProducer::inList(std::vector<int> parents, int track_id) {
50 return std::find(parents.begin(), parents.end(), track_id) != parents.end();
51}
52
54 std::vector<double> bdt_features;
55
56 const auto &particle_map{event.getMap<int, ldmx::SimParticle>(
57 sim_particles_coll_name_, sim_particles_pass_name_)};
58
59 // Get target scoring plane hits for recoil electron
60 // Use this to calculate the projected photon line vector
61 // This currently uses truth-level information, but it should be replaced
62 // by reconstructed tracker information, when available
63 std::vector<double> gamma_p(3);
64 std::vector<double> gamma_x0(3);
65
66 std::vector<double> recoil_p(3);
67 bool found_recoil_e = false;
68
69 if (recoil_from_tracking_) {
70 const auto &recoil_tracks{
71 event.getCollection<ldmx::Track>(track_collection_, track_pass_name_)};
72 // Fill this in later when you know how to use it
73 for (auto &track : recoil_tracks) {
74 // need to figure out how to best isolate candidate electron track
75 if (track.q() == 1 && track.getNhits() == 5) {
76 gamma_x0 = track.getPosition();
77 gamma_p[0] = -1. * track.getMomentum()[0];
78 gamma_p[1] = -1. * track.getMomentum()[1];
79 gamma_p[2] = beam_energy_mev_ - track.getMomentum()[2];
80 }
81 }
82 } else {
83 if (event.exists(sp_collection_, sp_pass_name_)) {
84 const auto &target_sp_hits = event.getCollection<ldmx::SimTrackerHit>(
85 sp_collection_, sp_pass_name_);
86 bool found_rec = false;
87 for (auto const &it : particle_map) {
88 for (auto const &sphit : target_sp_hits) {
89 if (sphit.getPosition()[2] > 0) {
90 if (it.first == sphit.getTrackID()) {
91 if (it.second.getPdgID() == 622) {
92 std::vector<float> x0_float = sphit.getPosition();
93 std::vector<double> x0_double(x0_float.begin(), x0_float.end());
94 gamma_x0 = x0_double;
95 gamma_p = sphit.getMomentum();
96 found_rec = true;
97 }
98 if (it.second.getPdgID() == 11 &&
99 inList(it.second.getParents(), 0)) {
100 if (!found_rec) {
101 std::vector<float> x0_float = sphit.getPosition();
102 std::vector<double> x0_double(x0_float.begin(),
103 x0_float.end());
104 gamma_x0 = x0_double;
105 gamma_p[0] = -1. * sphit.getMomentum()[0];
106 gamma_p[1] = -1. * sphit.getMomentum()[1];
107 gamma_p[2] = beam_energy_mev_ - sphit.getMomentum()[2];
108 found_rec = true;
109 }
110 recoil_p = sphit.getMomentum();
111 found_recoil_e = true;
112 }
113 }
114 }
115 }
116 }
117 }
118 }
119
120 double p_mag = 0.;
121 if (found_recoil_e) {
122 p_mag = std::sqrt(recoil_p[0] * recoil_p[0] + recoil_p[1] * recoil_p[1] +
123 recoil_p[2] * recoil_p[2]);
124 }
125
126 const auto &ecal_rec_hits = event.getCollection<ldmx::EcalHit>(
127 ecal_rec_collection_, ecal_rec_pass_name_);
128 const auto &hcal_rec_hits = event.getCollection<ldmx::HcalHit>(
129 hcal_rec_collection_, hcal_rec_pass_name_);
130
131 double ecal_energy = 0.;
132 double hcal_energy = 0.;
133 bool hcal_containment = true;
134
135 for (const ldmx::EcalHit &hit : ecal_rec_hits) {
136 if (hit.getEnergy() > 0.) {
137 ecal_energy += hit.getEnergy();
138 }
139 }
140 for (const ldmx::HcalHit &hit : hcal_rec_hits) {
141 if (hit.getEnergy() > 0.) {
142 ldmx::HcalID det_id(hit.getID());
143 if (det_id.getSection() != 0) {
144 continue;
145 }
146 if (det_id.getLayerID() == 1 && hit.getPE() > 5) {
147 hcal_containment = false;
148 }
149 hcal_energy += 12. * hit.getEnergy();
150 }
151 }
152
153 if (ecal_energy < 3160 && hcal_energy > 4840 && hcal_containment &&
154 p_mag < 2400) {
155 // initialize all of the features
156 int n_layers_hit = 0;
157 double x_std = 0.;
158 double y_std = 0.;
159 double z_std = 0.;
160 double x_mean = 0.;
161 double y_mean = 0.;
162 double r_mean = 0.;
163 int iso_hits = 0;
164 double iso_energy = 0.;
165 int n_readout_hits = 0;
166 double summed_det = 0.;
167 double r_mean_from_photon_track = 0.;
168
169 double z_mean = 0.; // need this when calculating z_std
170 std::vector<int> layers_hit;
171
172 for (const ldmx::HcalHit &hit : hcal_rec_hits) {
173 if (hit.getEnergy() > 0.) {
174 ldmx::HcalID det_id(hit.getID());
175 if (det_id.getSection() != 0) { // skip hits that aren't in main Hcal
176 continue;
177 }
178 if (fabs(hit.getXPos()) > 1000 || fabs(hit.getYPos()) > 1000) {
179 continue;
180 }
181
182 n_readout_hits += 1;
183 double hit_x = hit.getXPos();
184 double hit_y = hit.getYPos();
185 double hit_z = hit.getZPos();
186 double hit_r = sqrt(hit_x * hit_x + hit_y * hit_y);
187
188 summed_det += hit.getEnergy();
189
190 x_mean += hit_x * hit.getEnergy();
191 y_mean += hit_y * hit.getEnergy();
192 z_mean += hit_z * hit.getEnergy();
193 r_mean += hit_r * hit.getEnergy();
194
195 // check if this is a new layer in the collection
196 if (!(std::find(layers_hit.begin(), layers_hit.end(),
197 det_id.getLayerID()) != layers_hit.end())) {
198 layers_hit.push_back(det_id.getLayerID());
199 }
200
201 double proj_x =
202 gamma_x0[0] + (hit_z - gamma_x0[2]) * gamma_p[0] / gamma_p[2];
203 double proj_y =
204 gamma_x0[1] + (hit_z - gamma_x0[2]) * gamma_p[1] / gamma_p[2];
205
206 r_mean_from_photon_track +=
207 hit.getEnergy() * sqrt((hit_x - proj_x) * (hit_x - proj_x) +
208 (hit_y - proj_y) * (hit_y - proj_y));
209
210 // Calculate isolated hits
211 double closest_point = 9999.;
212 for (const ldmx::HcalHit &hit2 : hcal_rec_hits) {
213 if (hit2.getEnergy() > 0.) {
214 ldmx::HcalID det_i_d2(hit2.getID());
215 if (fabs(hit2.getXPos()) > 1000 || fabs(hit2.getYPos()) > 1000) {
216 continue;
217 }
218 if (det_i_d2.getLayerID() == det_id.getLayerID()) {
219 // Determine if a bar is vertical (along y-axis) or horizontal
220 // (along x-axis) Odd layers have horizontal strips Even layers
221 // have vertical strips
222 if (hit.isOrientationX()) {
223 if (fabs(hit2.getYPos() - hit_y) > 0) {
224 if (fabs(hit2.getYPos() - hit_y) < closest_point) {
225 closest_point = fabs(hit2.getYPos() - hit_y);
226 }
227 }
228 }
229 if (hit.isOrientationY()) {
230 if (fabs(hit2.getXPos() - hit_x) > 0) {
231 if (fabs(hit2.getXPos() - hit_x) < closest_point) {
232 closest_point = fabs(hit2.getXPos() - hit_x);
233 }
234 }
235 }
236 }
237 }
238 }
239 if (closest_point > 50.) {
240 iso_hits += 1;
241 iso_energy += hit.getEnergy();
242 }
243 }
244 }
245
246 n_layers_hit = layers_hit.size();
247
248 if (summed_det > 0.) {
249 x_mean /= summed_det;
250 y_mean /= summed_det;
251 z_mean /= summed_det;
252 r_mean /= summed_det;
253
254 r_mean_from_photon_track /= summed_det;
255 }
256
257 for (const ldmx::HcalHit &hit : hcal_rec_hits) {
258 if (hit.getEnergy() > 0.) {
259 if (fabs(hit.getXPos()) > 1000 || fabs(hit.getYPos()) > 1000) {
260 continue;
261 }
262 ldmx::HcalID det_id(hit.getID());
263 if (det_id.getSection() == 0) {
264 x_std += hit.getEnergy() * (hit.getXPos() - x_mean) *
265 (hit.getXPos() - x_mean);
266 y_std += hit.getEnergy() * (hit.getYPos() - y_mean) *
267 (hit.getYPos() - y_mean);
268 z_std += hit.getEnergy() * (hit.getZPos() - z_mean) *
269 (hit.getZPos() - z_mean);
270 }
271 }
272 }
273
274 if (summed_det > 0.) {
275 x_std = sqrt(x_std / summed_det);
276 y_std = sqrt(y_std / summed_det);
277 z_std = sqrt(z_std / summed_det);
278 }
279
280 // Fill histograms
281 histograms_.fill("layers_hit", n_layers_hit);
282 histograms_.fill("x_std", x_std);
283 histograms_.fill("y_std", y_std);
284 histograms_.fill("z_std", z_std);
285 histograms_.fill("x_mean", x_mean);
286 histograms_.fill("y_mean", y_mean);
287 histograms_.fill("r_mean", r_mean);
288 histograms_.fill("iso_hits", iso_hits);
289 histograms_.fill("iso_energy", iso_energy);
290 histograms_.fill("n_hits", n_readout_hits);
291 histograms_.fill("total_energy", hcal_energy);
292 histograms_.fill("photon_track", r_mean_from_photon_track);
293
294 bdt_features.push_back(n_layers_hit);
295 bdt_features.push_back(x_std);
296 bdt_features.push_back(y_std);
297 bdt_features.push_back(z_std);
298 bdt_features.push_back(x_mean);
299 bdt_features.push_back(y_mean);
300 bdt_features.push_back(r_mean);
301 bdt_features.push_back(iso_hits);
302 bdt_features.push_back(iso_energy);
303 bdt_features.push_back(n_readout_hits);
304 bdt_features.push_back(hcal_energy);
305 bdt_features.push_back(r_mean_from_photon_track);
306
307 if (training_) {
308 std::ofstream file(training_file_, std::ios::app);
309 if (!file.is_open()) {
310 ldmx_log(fatal) << "Error: Could not open file " << training_file_;
311 return;
312 }
313 for (int i = 0; i < bdt_features.size(); ++i) {
314 file << bdt_features[i] << (i + 1 == bdt_features.size() ? "\n" : ", ");
315 }
316 }
317 }
318
319 return;
320}
321
322} // namespace dqm
323
#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:92
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:23
Represents a simulated tracker hit in the simulation.
Implementation of a track object.
Definition Track.h:53