18void EcalPnetVetoProcessor::configure(
20 disc_cut_ = parameters.
get<
double>(
"disc_cut");
21 rt_ = std::make_unique<ldmx::ort::ONNXRuntime>(
22 parameters.
get<std::string>(
"model_path"));
25 collection_name_ = parameters.
get<std::string>(
"collection_name");
27 rec_coll_name_ = parameters.
get<std::string>(
"rec_coll_name");
28 ecal_rec_hits_passname_ =
29 parameters.
get<std::string>(
"ecal_rec_hits_passname");
30 ecal_sp_hits_passname_ = parameters.
get<std::string>(
"ecal_sp_hits_passname");
31 track_pass_name_ = parameters.
get<std::string>(
"track_pass_name",
"");
32 track_collection_ = parameters.
get<std::string>(
"track_collection");
33 recoil_from_tracking_ = parameters.
get<
bool>(
"recoil_from_tracking");
39 const auto& ecal_geometry = getCondition<ldmx::EcalGeometry>(
40 ldmx::EcalGeometry::CONDITIONS_OBJECT_NAME);
43 const auto ecal_rec_hits =
event.getCollection<
ldmx::EcalHit>(
44 rec_coll_name_, ecal_rec_hits_passname_);
45 auto nhits = std::count_if(
46 ecal_rec_hits.begin(), ecal_rec_hits.end(),
47 [](
const ldmx::EcalHit& hit) { return hit.getEnergy() > 0; });
50 ldmx_log(debug) <<
"nhits = " << nhits <<
" MAX_NUM_HITS = " << MAX_NUM_HITS;
51 if (nhits < MAX_NUM_HITS) {
52 std::array<double, 3> etraj = {-999., -999., -999.};
53 std::array<double, 3> enorm = {-999., -999., -999.};
57 if (!recoil_from_tracking_ &&
58 event.
exists(
"EcalScoringPlaneHits", ecal_sp_hits_passname_)) {
60 "EcalScoringPlaneHits", ecal_sp_hits_passname_);
61 double electron_pz_max = -1.0;
62 for (
auto const& hit : ecal_sp_hits) {
64 if (hit.getPdgID() != 11)
continue;
65 double electron_z = hit.getPosition()[2];
67 if (electron_z <= 239.0 || electron_z >= 240.0)
continue;
68 double electron_pz = hit.getMomentum()[2];
70 if (electron_pz > electron_pz_max) {
71 electron_pz_max = electron_pz;
78 ldmx_log(debug) <<
"Electron Found in the Ecal SP!";
81 ldmx_log(debug) <<
"ECAL SP pos_=(" << pos[0] <<
"," << pos[1] <<
","
83 ldmx_log(debug) <<
"ECAL SP mom=(" << mom[0] <<
"," << mom[1] <<
","
85 etraj = {pos[0], pos[1], pos[2]};
89 enorm = {mom[0] / pz, mom[1] / pz, 1.0};
92 }
else if (recoil_from_tracking_) {
94 auto recoil_tracks{
event.getCollection<
ldmx::Track>(track_collection_,
96 ldmx::TrackStateType ts_at_ecal = ldmx::TrackStateType::AtECAL;
97 auto recoil_track_states_ecal =
99 if (!recoil_track_states_ecal.empty()) {
100 std::array<double, 3> pos = {recoil_track_states_ecal[0],
101 recoil_track_states_ecal[1],
102 recoil_track_states_ecal[2]};
103 std::array<double, 3> mom = {(recoil_track_states_ecal[3]),
104 (recoil_track_states_ecal[4]),
105 (recoil_track_states_ecal[5])};
106 ldmx_log(debug) <<
"Electron track pos_=(" << pos[0] <<
"," << pos[1]
107 <<
"," << pos[2] <<
")";
108 ldmx_log(debug) <<
"Electron track mom=(" << mom[0] <<
"," << mom[1]
109 <<
"," << mom[2] <<
")";
113 enorm = {mom[0] / pz, mom[1] / pz, 1.0};
116 ldmx_log(info) <<
" No recoil track at ECAL";
119 ldmx_log(fatal) <<
" No electron hit at scoring plane or no tracking";
123 makeInputs(ecal_geometry, ecal_rec_hits, etraj, enorm);
125 auto logits = rt_->run(INPUT_NAMES, data_)[0];
128 auto prob = std::exp((logSoftmax(logits)[1]));
129 result.setDiscValue(prob);
131 result.setDiscValue(-99);
134 ldmx_log(debug) <<
"ParticleNet disc value = " << result.getDisc();
136 result.setVetoResult(result.getDisc() > disc_cut_);
145 event.add(collection_name_, result);
148void EcalPnetVetoProcessor::makeInputs(
150 const std::vector<ldmx::EcalHit>& ecal_rec_hits,
151 std::array<double, 3> etraj, std::array<double, 3> enorm) {
153 for (
auto& v : data_) {
154 std::fill(v.begin(), v.end(), 0);
159 for (
const auto& hit : ecal_rec_hits) {
160 if (hit.getEnergy() <= 0) {
162 <<
"Hit with zero energy found, should not happen, skipping it.";
168 double delta_z = hit_z - etraj[2];
169 double etraj_x = etraj[0] + enorm[0] * delta_z;
170 double etraj_y = etraj[1] + enorm[1] * delta_z;
171 data_[0].at(COORDINATE_X_OFFSET + idx) = hit_x - etraj_x;
172 data_[0].at(COORDINATE_Y_OFFSET + idx) = hit_y - etraj_y;
173 data_[0].at(COORDINATE_Z_OFFSET + idx) = hit_z;
175 data_[1].at(FEATURE_X_OFFSET + idx) = hit_x - etraj_x;
176 data_[1].at(FEATURE_Y_OFFSET + idx) = hit_y - etraj_y;
177 data_[1].at(FEATURE_Z_OFFSET + idx) = hit_z;
178 data_[1].at(FEATURE_LAYER_ID_OFFSET + idx) =
id.layer();
179 data_[1].at(FEATURE_ENERGY_OFFSET + idx) = std::log(hit.getEnergy());
184 std::stringstream ss;
185 for (
unsigned iname = 0; iname < INPUT_NAMES.size(); ++iname) {
186 ss <<
"=== " << INPUT_NAMES[iname] <<
" ===";
187 for (
unsigned i = 0; i < INPUT_SIZES[iname]; ++i) {
188 ss << data_[iname].at(i) <<
", ";
189 if ((i + 1) % MAX_NUM_HITS == 0) {
194 ldmx_log(trace) << ss.str();
197std::vector<float> EcalPnetVetoProcessor::logSoftmax(
198 const std::vector<float>& logits) {
200 auto max_val = *std::max_element(logits.begin(), logits.end());
203 std::vector<float> exp_vals(logits.size());
204 for (
size_t i = 0; i < logits.size(); ++i) {
205 exp_vals[i] = std::exp(logits[i] - max_val);
208 float sum_exp = std::accumulate(exp_vals.begin(), exp_vals.end(), 0.0);
209 float log_sum_exp = max_val + std::log(sum_exp);
212 std::vector<float> result(logits.size());
213 for (
size_t i = 0; i < logits.size(); ++i) {
214 result[i] = logits[i] - log_sum_exp;