41 rec_hit_coll_name_, rec_hit_pass_name_)};
43 ecal_sim_hit_coll_, ecal_sim_hit_pass_)};
45 cluster_coll_name_, cluster_pass_name_)};
49 int nbr_of_electrons{
event.getElectronCount()};
55 std::map<int, int> layer_cluster_count;
56 for (
const auto& cluster : ecal_clusters) {
57 auto layer = cluster.getLayer();
58 layer_cluster_count[layer]++;
61 int total_clusters = 0;
62 for (
const auto& [layer, count] : layer_cluster_count) {
63 total_clusters += count;
66 int n_ecal_clusters = 0;
67 if (layer_cluster_count.size() != 0) {
68 n_ecal_clusters =
static_cast<int>(std::round(
69 static_cast<double>(total_clusters) / layer_cluster_count.size()));
72 ldmx_log(info) <<
"Avg number of clusters per layer: " << n_ecal_clusters;
76 histograms_.
fill(
"number_of_clusters_first_layer", layer_cluster_count[0]);
79 if (n_ecal_clusters == nbr_of_electrons) {
82 }
else if (n_ecal_clusters < nbr_of_electrons) {
85 }
else if (n_ecal_clusters > nbr_of_electrons) {
90 std::unordered_map<int, std::pair<int, std::vector<double>>> hit_info;
91 hit_info.reserve(ecal_rec_hits.size());
94 std::vector<std::vector<float>> sp_electron_positions;
96 ecal_sp_hits_coll_name_, ecal_sp_hits_pass_name_)};
98 std::vector<ldmx::SimTrackerHit> sorted_sp_hits = ecal_sp_hits;
99 std::sort(sorted_sp_hits.begin(), sorted_sp_hits.end(),
101 return a.getTrackID() < b.getTrackID();
104 ldmx_log(trace) <<
"Number of ECal Scoring Plane Hits: "
105 << sorted_sp_hits.size();
109 unsigned int n_filled = 0;
111 if (sp_hit.getPdgID() != 11)
continue;
112 if (sp_hit.getMomentum()[2] <= 0)
continue;
115 if (hit_id.
plane() != 31)
continue;
116 if (n_filled < nbr_of_electrons) {
117 ldmx_log(trace) <<
"\tSP Hit to be added with Track ID : "
118 << sp_hit.getTrackID() <<
", SP Hit Position ("
119 << sp_hit.getPosition()[0] <<
", "
120 << sp_hit.getPosition()[1] <<
", "
121 << sp_hit.getPosition()[2] <<
") mm";
122 sp_electron_positions.push_back(sp_hit.getPosition());
127 ldmx_log(info) <<
"Number of ECal CLUE clusters: " << n_ecal_clusters
128 <<
", TS counted electrons: " << nbr_of_electrons
129 <<
", SP electrons: " << sp_electron_positions.size();
131 std::map<int, float> true_energy;
132 std::map<int, float> delta_energy;
133 double sp_ele_dist{9999.};
134 if (nbr_of_electrons == 2 && sp_electron_positions.size() > 1) {
137 std::vector<float> pos1;
138 std::vector<float> pos2;
139 pos1 = sp_electron_positions[0];
140 pos2 = sp_electron_positions[1];
141 sp_ele_dist = std::sqrt((pos1[0] - pos2[0]) * (pos1[0] - pos2[0]) +
142 (pos1[1] - pos2[1]) * (pos1[1] - pos2[1]));
148 ldmx_log(trace) <<
"Distance between the two e- in the ECal scoring plane: "
149 << sp_ele_dist <<
" mm";
151 double tot_event_energy = 0;
152 std::vector<double> tot_origin_edep;
157 ldmx_log(trace) <<
"Loop over the rechits and find the matching simhits";
158 for (
const auto& hit : ecal_rec_hits) {
159 auto it = std::find_if(
160 ecal_sim_hits.begin(), ecal_sim_hits.end(),
161 [&hit](
const auto& sim_hit) { return sim_hit.getID() == hit.getID(); });
162 if (it != ecal_sim_hits.end()) {
164 ldmx_log(trace) <<
"\tFound simhit matching rechit with ID"
167 int prev_ancestor = 0;
170 std::vector<double> edep;
173 ldmx_log(trace) <<
"\t\tIt has " << it->getNumberOfContribs()
175 for (
int i = 0; i < it->getNumberOfContribs(); i++) {
177 const auto& contrib = it->getContrib(i);
179 ancestor = contrib.origin_id_;
180 ldmx_log(trace) <<
"\t\t\tAncestor ID " << ancestor <<
" with edep "
182 tot_event_energy += contrib.edep_;
184 if (ancestor <= nbr_of_electrons) {
185 edep[ancestor] += contrib.edep_;
186 tot_origin_edep[ancestor] += contrib.edep_;
187 e_tot += contrib.edep_;
189 if (!tagged && i != 0 && prev_ancestor != ancestor) {
194 ldmx_log(trace) <<
"\t\t\t\tMixed hit! Ancestor ID changed to "
197 prev_ancestor = ancestor;
203 if (edep[i] / e_tot >
204 1 - mixed_hit_cutoff_) {
209 distance(edep.begin(), max_element(edep.begin(), edep.end()));
211 <<
"\t\t\t\tUndid mixed hit tagging, now ancestor = "
224 hit_info.insert({hit.getID(), std::make_pair(tag, edep)});
229 int clustered_hits = 0;
230 ldmx_log(trace) <<
"Loop over the clusters, N = " << n_ecal_clusters;
232 (
float)n_mixed / ecal_rec_hits.size());
233 ldmx_log(debug) <<
"Got " << n_mixed <<
" mixed hits, a fraction of "
234 << (float)n_mixed / ecal_rec_hits.size();
236 if (ecal_clusters.size() >= 2) {
238 ecal_clusters[0].getCentroidX() - ecal_clusters[1].getCentroidX();
240 ecal_clusters[0].getCentroidY() - ecal_clusters[1].getCentroidY();
241 float d_r = std::sqrt(d_x * d_x + d_y * d_y);
243 ldmx_log(trace) <<
"Gt cluster distance (0,1) = " << d_r;
246 for (
const auto& cl : ecal_clusters) {
247 auto layer = cl.getLayer();
248 ldmx_log(trace) <<
"Cluster in layer " << layer
249 <<
", energy: " << cl.getEnergy()
250 <<
", number of hits: " << cl.getHitIDs().size();
251 auto cluster_centroid_x = cl.getCentroidX();
252 auto cluster_centroid_y = cl.getCentroidY();
253 auto cluster_rms_x = cl.getRMSX();
254 auto cluster_rms_y = cl.getRMSY();
257 double min_distance = 9999.;
258 double sp_clue_x_residuals = 9999.;
259 double sp_clue_y_residuals = 9999.;
260 for (
const auto& sp_pos : sp_electron_positions) {
261 double distance = std::sqrt(
262 (sp_pos[0] - cluster_centroid_x) * (sp_pos[0] - cluster_centroid_x) +
263 (sp_pos[1] - cluster_centroid_y) * (sp_pos[1] - cluster_centroid_y));
264 if (distance < min_distance) {
265 min_distance = distance;
266 sp_clue_x_residuals = sp_pos[0] - cluster_centroid_x;
267 sp_clue_y_residuals = sp_pos[1] - cluster_centroid_y;
271 ldmx_log(trace) <<
"\tCluster centroid: (" << cluster_centroid_x <<
" +/- "
272 << cluster_rms_x <<
", " << cluster_centroid_y <<
" +/- "
274 <<
" mm; min distance to SP electron: " << min_distance
285 std::vector<double> n_hits_from_electron;
286 n_hits_from_electron.resize(nbr_of_electrons + 2);
288 std::vector<double> energy_from_electron;
289 energy_from_electron.resize(nbr_of_electrons + 2);
290 double energy_sum = 0.;
292 ldmx_log(trace) <<
"Looping over hits in the cluster";
293 const auto& hit_ids = cl.getHitIDs();
294 for (
const auto&
id : hit_ids) {
296 auto it = hit_info.find(
id);
297 if (it != hit_info.end()) {
300 auto id_electron = t.first;
302 auto energies = t.second;
304 n_hits_from_electron[id_electron]++;
307 double hit_energy_sum = 0.;
308 for (
int i = 1; i < nbr_of_electrons + 1; i++) {
310 if (energies[i] > 0.) {
311 energy_sum += energies[i];
314 energy_from_electron[i] += energies[i];
319 if (id_electron == 0) energy_from_electron[0] += hit_energy_sum;
320 energy_sum += hit_energy_sum;
326 if (energy_sum > 0) {
328 double max_energy_contribution = *max_element(
329 energy_from_electron.begin(), energy_from_electron.end());
331 for (
auto nb : energy_from_electron)
332 to_log.append(std::to_string(nb) +
" ");
333 ldmx_log(debug) <<
"Energies vector is " << to_log;
337 100. * (max_energy_contribution / energy_sum));
338 if (energy_from_electron[0] > 0.)
340 100. * (energy_from_electron[0] / energy_sum));
343 cl.getHitIDs().size());
345 100. * (max_energy_contribution / energy_sum));
347 if (nbr_of_electrons == 2) {
349 100. * (max_energy_contribution / energy_sum));
353 double n_max = *max_element(n_hits_from_electron.begin(),
354 n_hits_from_electron.end());
359 energy_from_electron.begin(),
360 max_element(energy_from_electron.begin(), energy_from_electron.end()));
361 ldmx_log(debug) <<
"Found that the maximum contributing trackID is " << elt;
362 delta_energy[elt] = cl.getEnergy() - true_energy[elt];
366 std::string more_log;
367 for (
auto nb : tot_origin_edep) more_log.append(std::to_string(nb) +
" ");
368 ldmx_log(debug) <<
"Edep per ancestor in event is " << more_log;
369 ldmx_log(debug) <<
"Total energy deposited in event: " << tot_event_energy;
372 histograms_.
fill(
"unclustered_hits", (ecal_rec_hits.size() - clustered_hits));
375 "unclustered_hits_percentage",
376 100. * (ecal_rec_hits.size() - clustered_hits) / ecal_rec_hits.size());
380 if (n_ecal_clusters > n_ecal_clusters_min_) {
387 if (n_ecal_clusters > n_ecal_clusters_min_) {