LDMX Software
VisiblesVetoProcessor.cxx
1#include "Hcal/VisiblesVetoProcessor.h"
2
3// LDMX
4#include "DetDescr/HcalID.h"
5#include "DetDescr/SimSpecialID.h"
7#include "SimCore/Event/SimParticle.h"
9
10// C++
11#include <algorithm>
12#include <cmath>
13#include <fstream>
14#include <iostream>
15#include <numeric>
16
17namespace hcal {
18void VisiblesVetoProcessor::buildBDTFeatureVector(
19 const ldmx::VisiblesVetoResult &result) {
20 bdt_features_.push_back(result.getNLayersHit());
21 bdt_features_.push_back(result.getXStd());
22 bdt_features_.push_back(result.getYStd());
23 bdt_features_.push_back(result.getZStd());
24 bdt_features_.push_back(result.getXMean());
25 bdt_features_.push_back(result.getYMean());
26 bdt_features_.push_back(result.getRMean());
27 bdt_features_.push_back(result.getIsoHits());
28 bdt_features_.push_back(result.getIsoEnergy());
29 bdt_features_.push_back(result.getNReadoutHits());
30 bdt_features_.push_back(result.getSummedDet());
31 bdt_features_.push_back(result.getDistFromPhotonTrack());
32}
33
36 feature_list_name_ = parameters.get<std::string>("feature_list_name");
37 // Load BDT ONNX file
38 rt_ = std::make_unique<ldmx::ort::ONNXRuntime>(
39 parameters.get<std::string>("bdt_file"));
40
41 bdt_cut_val_ = parameters.get<double>("disc_cut");
42
43 beam_energy_mev_ = parameters.get<double>("beam_energy");
44
45 // collection and pass names
46 collection_name_ = parameters.get<std::string>("collection_name");
47 rec_pass_name_ = parameters.get<std::string>("rec_pass_name");
48 rec_coll_name_ = parameters.get<std::string>("rec_coll_name");
49
50 recoil_from_tracking_ = parameters.get<bool>("recoil_from_tracking");
51 track_collection_ = parameters.get<std::string>("track_collection");
52 track_pass_name_ = parameters.get<std::string>("track_pass_name");
53
54 sp_collection_ = parameters.get<std::string>("sp_coll_name");
55 sp_pass_name_ = parameters.get<std::string>("sp_pass_name");
56 sim_particles_pass_name_ =
57 parameters.get<std::string>("sim_particles_pass_name");
58}
59
60bool VisiblesVetoProcessor::inList(std::vector<int> parents, int track_id) {
61 return std::find(parents.begin(), parents.end(), track_id) != parents.end();
62}
63
64void VisiblesVetoProcessor::clearProcessor() {
65 bdt_features_.clear();
66
67 n_layers_hit_ = 0;
68 x_std_ = 0.;
69 y_std_ = 0.;
70 z_std_ = 0.;
71 x_mean_ = 0.;
72 y_mean_ = 0.;
73 r_mean_ = 0.;
74 iso_hits_ = 0;
75 iso_energy_ = 0.;
76 n_readout_hits_ = 0;
77 summed_det_ = 0.;
78 r_mean_from_photon_track_ = 0.;
79}
80
83
84 clearProcessor();
85
86 const auto &particle_map{event.getMap<int, ldmx::SimParticle>(
87 "SimParticles", sim_particles_pass_name_)};
88
89 // Get target scoring plane hits for recoil electron
90 // Use this to calculate the projected photon line vector
91 // This currently uses truth-level information, but it should be replaced
92 // by reconstructed tracker information, when available
93 std::vector<double> gamma_p(3);
94 std::vector<double> gamma_x0(3);
95 if (recoil_from_tracking_) {
96 const auto &recoil_tracks{
97 event.getCollection<ldmx::Track>(track_collection_, track_pass_name_)};
98 // Fill this in later when you know how to use it
99 for (auto &track : recoil_tracks) {
100 // need to figure out how to best isolate candidate electron track
101 auto trk_pos = track.getPositionAtTarget();
102 auto trk_mom = track.getMomentumAtTarget();
103 if (track.getCharge() == 1 && track.getNhits() == 5 &&
104 trk_pos.size() == 3 && trk_mom.size() == 3) {
105 gamma_x0 = trk_pos;
106 gamma_p[0] = -1. * trk_mom[0];
107 gamma_p[1] = -1. * trk_mom[1];
108 gamma_p[2] = beam_energy_mev_ - trk_mom[2];
109 }
110 }
111 } else {
112 if (event.exists(sp_collection_, sp_pass_name_)) {
113 const auto &target_sp_hits = event.getCollection<ldmx::SimTrackerHit>(
114 sp_collection_, sp_pass_name_);
115 for (auto const &it : particle_map) {
116 for (auto const &sphit : target_sp_hits) {
117 if (sphit.getPosition()[2] > 0) {
118 if (it.first == sphit.getTrackID()) {
119 if (it.second.getPdgID() == 11 &&
120 inList(it.second.getParents(), 0)) {
121 /* Since SP hit positions are stored as floats and gamma_x0 is
122 a double vector, the conversion here is a little convolcuted.
123 */
124 std::vector<float> x0_float = sphit.getPosition();
125 std::vector<double> x0_double(x0_float.begin(), x0_float.end());
126 gamma_x0 = x0_double;
127 gamma_p[0] = -1. * sphit.getMomentum()[0];
128 gamma_p[1] = -1. * sphit.getMomentum()[1];
129 gamma_p[2] = beam_energy_mev_ - sphit.getMomentum()[2];
130 }
131 }
132 }
133 }
134 }
135 }
136 }
137
138 // Get Hcal reconstructed hits and loop through them to build features
139 const auto &hcal_rec_hits =
140 event.getCollection<ldmx::HcalHit>(rec_coll_name_, rec_pass_name_);
141
142 double z_mean = 0.; // need this when calculating z_std_
143 std::vector<int> layers_hit;
144 for (const ldmx::HcalHit &hit : hcal_rec_hits) {
145 if (hit.getEnergy() > 0.) {
146 ldmx::HcalID det_id(hit.getID());
147 if (det_id.getSection() != 0) { // skip hits that aren't in main Hcal
148 continue;
149 }
150 n_readout_hits_ += 1;
151 double hit_x = hit.getXPos();
152 double hit_y = hit.getYPos();
153 double hit_z = hit.getZPos();
154 double hit_r = sqrt(hit_x * hit_x + hit_y * hit_y);
155
156 summed_det_ += hit.getEnergy();
157
158 x_mean_ += hit_x * hit.getEnergy();
159 y_mean_ += hit_y * hit.getEnergy();
160 z_mean += hit_z * hit.getEnergy();
161 r_mean_ += hit_r * hit.getEnergy();
162
163 // check if this is a new layer in the collection
164 if (!(std::find(layers_hit.begin(), layers_hit.end(),
165 det_id.getLayerID()) != layers_hit.end())) {
166 layers_hit.push_back(det_id.getLayerID());
167 }
168
169 double proj_x =
170 gamma_x0[0] + (hit_z - gamma_x0[2]) * gamma_p[0] / gamma_p[2];
171 double proj_y =
172 gamma_x0[1] + (hit_z - gamma_x0[2]) * gamma_p[1] / gamma_p[2];
173
174 r_mean_from_photon_track_ +=
175 hit.getEnergy() * sqrt((hit_x - proj_x) * (hit_x - proj_x) +
176 (hit_y - proj_y) * (hit_y - proj_y));
177
178 // Calculate isolated hits
179 double closest_point = 9999.;
180 for (const ldmx::HcalHit &hit2 : hcal_rec_hits) {
181 if (hit2.getEnergy() > 0.) {
182 ldmx::HcalID det_i_d2(hit2.getID());
183 if (det_i_d2.getLayerID() == det_id.getLayerID()) {
184 // Determine if a bar is vertical (along y-axis) or horizontal
185 // (along x-axis) Odd layers have horizontal strips Even layers have
186 // vertical strips
187 if (hit.isOrientationX()) {
188 if (abs(hit2.getYPos() - hit_y) > 0) {
189 if (abs(hit2.getYPos() - hit_y) < closest_point) {
190 closest_point = abs(hit2.getYPos() - hit_y);
191 }
192 }
193 }
194 if (hit.isOrientationY()) {
195 if (abs(hit2.getXPos() - hit_x) > 0) {
196 if (abs(hit2.getXPos() - hit_x) < closest_point) {
197 closest_point = abs(hit2.getXPos() - hit_x);
198 }
199 }
200 }
201 }
202 }
203 }
204 if (closest_point > 50.) {
205 iso_hits_ += 1;
206 iso_energy_ += hit.getEnergy();
207 }
208 }
209 }
210
211 n_layers_hit_ = layers_hit.size();
212
213 if (summed_det_ > 0.) {
214 x_mean_ /= summed_det_;
215 y_mean_ /= summed_det_;
216 z_mean /= summed_det_;
217 r_mean_ /= summed_det_;
218
219 r_mean_from_photon_track_ /= summed_det_;
220 }
221
222 for (const ldmx::HcalHit &hit : hcal_rec_hits) {
223 if (hit.getEnergy() > 0.) {
224 ldmx::HcalID det_id(hit.getID());
225 if (det_id.getSection() == 0) {
226 x_std_ += hit.getEnergy() * (hit.getXPos() - x_mean_) *
227 (hit.getXPos() - x_mean_);
228 y_std_ += hit.getEnergy() * (hit.getYPos() - y_mean_) *
229 (hit.getYPos() - y_mean_);
230 z_std_ += hit.getEnergy() * (hit.getZPos() - z_mean) *
231 (hit.getZPos() - z_mean);
232 }
233 }
234 }
235
236 if (summed_det_ > 0.) {
237 x_std_ = sqrt(x_std_ / summed_det_);
238 y_std_ = sqrt(y_std_ / summed_det_);
239 z_std_ = sqrt(z_std_ / summed_det_);
240 }
241
242 result.setVariables(n_layers_hit_, x_std_, y_std_, z_std_, x_mean_, y_mean_,
243 r_mean_, iso_hits_, iso_energy_, n_readout_hits_,
244 summed_det_, r_mean_from_photon_track_);
245
246 buildBDTFeatureVector(result);
247
248 ldmx::ort::FloatArrays inputs({bdt_features_});
249 float pred =
250 rt_->run({feature_list_name_}, inputs, {"probabilities"})[0].at(1);
251 ldmx_log(info) << " Visibles BDT was ran, score is " << pred;
252
253 event.add(collection_name_, result);
254}
255
256} // namespace hcal
257
#define DECLARE_PRODUCER(CLASS)
Macro which allows the framework to construct a producer given its name during configuration.
Class that stores Stores reconstructed hit information from the HCAL.
Class that defines an HCal sensitive detector.
Class which encapsulates information from a hit in a simulated tracking detector.
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
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
void produce(framework::Event &event) override
Process the event and put new data products into it.
void configure(framework::config::Parameters &parameters) override
Callback for the EventProcessor to configure itself from the given set of parameters.
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