Process the event and make histograms or summaries.
30 {
32 rec_hit_coll_name_, rec_hit_pass_name_)};
34 ecal_sim_hit_coll_, ecal_sim_hit_pass_)};
36 cluster_coll_name_, cluster_pass_name_)};
37
38
39
40 int nbr_of_electrons{event.getElectronCount()};
41
44 }
45
46 std::map<int, int> layer_cluster_count;
47 for (const auto& cluster : ecal_clusters) {
48 auto layer = cluster.getLayer();
49 layer_cluster_count[layer]++;
50 }
51
52 int total_clusters = 0;
53 for (const auto& [layer, count] : layer_cluster_count) {
54 total_clusters += count;
55 }
56
57 int n_ecal_clusters = 0;
58 if (layer_cluster_count.size() != 0) {
59 n_ecal_clusters = static_cast<int>(std::round(
60 static_cast<double>(total_clusters) / layer_cluster_count.size()));
61 }
62
63 ldmx_log(info) << "Avg number of clusters per layer: " << n_ecal_clusters;
64
67 histograms_.
fill(
"number_of_clusters_first_layer", layer_cluster_count[0]);
68
69
70 if (n_ecal_clusters == nbr_of_electrons) {
71
73 } else if (n_ecal_clusters < nbr_of_electrons) {
74
76 } else if (n_ecal_clusters > nbr_of_electrons) {
77
79 }
80
81 std::unordered_map<int, std::pair<int, std::vector<double>>> hit_info;
82 hit_info.reserve(ecal_rec_hits.size());
83
84
85 std::vector<std::vector<float>> sp_electron_positions;
87 "EcalScoringPlaneHits", ecal_sp_hits_pass_name_)};
88
89 std::vector<ldmx::SimTrackerHit> sorted_sp_hits = ecal_sp_hits;
90 std::sort(sorted_sp_hits.begin(), sorted_sp_hits.end(),
92 return a.getTrackID() < b.getTrackID();
93 });
94
95 ldmx_log(trace) << "Number of ECal Scoring Plane Hits: "
96 << sorted_sp_hits.size();
97
98
99
100 unsigned int n_filled = 0;
102 if (sp_hit.getPdgID() != 11) continue;
103 if (sp_hit.getMomentum()[2] <= 0) continue;
105
106 if (hit_id.plane() != 31) continue;
107 if (n_filled < nbr_of_electrons) {
108 ldmx_log(trace) << "\tSP Hit to be added with Track ID : "
109 << sp_hit.getTrackID() << ", SP Hit Position ("
110 << sp_hit.getPosition()[0] << ", "
111 << sp_hit.getPosition()[1] << ", "
112 << sp_hit.getPosition()[2] << ") mm";
113 sp_electron_positions.push_back(sp_hit.getPosition());
114 n_filled++;
115 }
116 }
117
118 ldmx_log(info) << "Number of ECal CLUE clusters: " << n_ecal_clusters
119 << ", TS counted electrons: " << nbr_of_electrons
120 << ", SP electrons: " << sp_electron_positions.size();
121
122 std::map<int, float> true_energy;
123 std::map<int, float> delta_energy;
124 double sp_ele_dist{9999.};
125 if (nbr_of_electrons == 2 && sp_electron_positions.size() > 1) {
126
127
128 std::vector<float> pos1;
129 std::vector<float> pos2;
130 pos1 = sp_electron_positions[0];
131 pos2 = sp_electron_positions[1];
132 sp_ele_dist = std::sqrt((pos1[0] - pos2[0]) * (pos1[0] - pos2[0]) +
133 (pos1[1] - pos2[1]) * (pos1[1] - pos2[1]));
134
136
137 }
138
139 ldmx_log(trace) << "Distance between the two e- in the ECal scoring plane: "
140 << sp_ele_dist << " mm";
141
142 double tot_event_energy = 0;
143 std::vector<double> tot_origin_edep;
145 int n_mixed = 0;
146
147
148 ldmx_log(trace) << "Loop over the rechits and find the matching simhits";
149 for (const auto& hit : ecal_rec_hits) {
150 auto it = std::find_if(
151 ecal_sim_hits.begin(), ecal_sim_hits.end(),
152 [&hit](const auto& sim_hit) { return sim_hit.getID() == hit.getID(); });
153 if (it != ecal_sim_hits.end()) {
154
155 ldmx_log(trace) << "\tFound simhit matching rechit with ID"
156 << hit.getID();
157 int ancestor = 0;
158 int prev_ancestor = 0;
159 bool tagged = false;
160 int tag = 0;
161 std::vector<double> edep;
163 double e_tot = 0;
164 ldmx_log(trace) << "\t\tIt has " << it->getNumberOfContribs()
165 << " contribs. ";
166 for (int i = 0; i < it->getNumberOfContribs(); i++) {
167
168 const auto& contrib = it->getContrib(i);
169
170 ancestor = contrib.origin_id_;
171 ldmx_log(trace) << "\t\t\tAncestor ID " << ancestor << " with edep "
172 << contrib.edep_;
173 tot_event_energy += contrib.edep_;
174
175 if (ancestor <= nbr_of_electrons) {
176 edep[ancestor] += contrib.edep_;
177 tot_origin_edep[ancestor] += contrib.edep_;
178 e_tot += contrib.edep_;
179 }
180 if (!tagged && i != 0 && prev_ancestor != ancestor) {
181
182
183 tag = 0;
184 tagged = true;
185 ldmx_log(trace) << "\t\t\t\tMixed hit! Ancestor ID changed to "
186 << ancestor;
187 }
188 prev_ancestor = ancestor;
189 }
190
191
192 if (tagged) {
194 if (edep[i] / e_tot >
195 1 - mixed_hit_cutoff_) {
196
197
198 tagged = false;
199 ancestor =
200 distance(edep.begin(), max_element(edep.begin(), edep.end()));
201 ldmx_log(trace)
202 << "\t\t\t\tUndid mixed hit tagging, now ancestor = "
203 << ancestor;
204 break;
205 }
206 }
207 }
208 if (!tagged) {
209
210
211 tag = ancestor;
212 } else
213 n_mixed++;
215 hit_info.insert({hit.getID(), std::make_pair(tag, edep)});
216 }
217 }
218
219
220 int clustered_hits = 0;
221 ldmx_log(trace) << "Loop over the clusters, N = " << n_ecal_clusters;
223 (float)n_mixed / ecal_rec_hits.size());
224 ldmx_log(debug) << "Got " << n_mixed << " mixed hits, a fraction of "
225 << (float)n_mixed / ecal_rec_hits.size();
226
227 if (ecal_clusters.size() >= 2) {
228 float d_x =
229 ecal_clusters[0].getCentroidX() - ecal_clusters[1].getCentroidX();
230 float d_y =
231 ecal_clusters[0].getCentroidY() - ecal_clusters[1].getCentroidY();
232 float d_r = std::sqrt(d_x * d_x + d_y * d_y);
234 ldmx_log(trace) << "Gt cluster distance (0,1) = " << d_r;
235 }
236
237 for (const auto& cl : ecal_clusters) {
238 auto layer = cl.getLayer();
239 ldmx_log(trace) << "Cluster in layer " << layer
240 << ", energy: " << cl.getEnergy()
241 << ", number of hits: " << cl.getHitIDs().size();
242 auto cluster_centroid_x = cl.getCentroidX();
243 auto cluster_centroid_y = cl.getCentroidY();
244 auto cluster_rms_x = cl.getRMSX();
245 auto cluster_rms_y = cl.getRMSY();
246
247
248 double min_distance = 9999.;
249 double sp_clue_x_residuals = 9999.;
250 double sp_clue_y_residuals = 9999.;
251 for (const auto& sp_pos : sp_electron_positions) {
252 double distance = std::sqrt(
253 (sp_pos[0] - cluster_centroid_x) * (sp_pos[0] - cluster_centroid_x) +
254 (sp_pos[1] - cluster_centroid_y) * (sp_pos[1] - cluster_centroid_y));
255 if (distance < min_distance) {
256 min_distance = distance;
257 sp_clue_x_residuals = sp_pos[0] - cluster_centroid_x;
258 sp_clue_y_residuals = sp_pos[1] - cluster_centroid_y;
259 }
260 }
261
262 ldmx_log(trace) << "\tCluster centroid: (" << cluster_centroid_x << " +/- "
263 << cluster_rms_x << ", " << cluster_centroid_y << " +/- "
264 << cluster_rms_y
265 << " mm; min distance to SP electron: " << min_distance
266 << " mm";
267 if (layer == 0) {
271 }
273
274
275
276 std::vector<double> n_hits_from_electron;
277 n_hits_from_electron.resize(nbr_of_electrons + 2);
278
279 std::vector<double> energy_from_electron;
280 energy_from_electron.resize(nbr_of_electrons + 2);
281 double energy_sum = 0.;
282 double n_sum = 0.;
283 ldmx_log(trace) << "Looping over hits in the cluster";
284 const auto& hit_ids = cl.getHitIDs();
285 for (const auto& id : hit_ids) {
286
287 auto it = hit_info.find(id);
288 if (it != hit_info.end()) {
289 auto t = it->second;
290
291 auto id_electron = t.first;
292
293 auto energies = t.second;
294
295 n_hits_from_electron[id_electron]++;
296 n_sum++;
297
298 double hit_energy_sum = 0.;
299 for (int i = 1; i < nbr_of_electrons + 1; i++) {
300
301 if (energies[i] > 0.) {
302 energy_sum += energies[i];
303
304
305 energy_from_electron[i] += energies[i];
306 }
307 }
308
309
310 if (id_electron == 0) energy_from_electron[0] += hit_energy_sum;
311 energy_sum += hit_energy_sum;
312
313 clustered_hits++;
314 }
315 }
316
317 if (energy_sum > 0) {
318
319 double max_energy_contribution = *max_element(
320 energy_from_electron.begin(), energy_from_electron.end());
321 std::string to_log;
322 for (auto nb : energy_from_electron)
323 to_log.append(std::to_string(nb) + " ");
324 ldmx_log(debug) << "Energies vector is " << to_log;
325
326
328 100. * (max_energy_contribution / energy_sum));
329 if (energy_from_electron[0] > 0.)
331 100. * (energy_from_electron[0] / energy_sum));
332
334 cl.getHitIDs().size());
336 100. * (max_energy_contribution / energy_sum));
337
338 if (nbr_of_electrons == 2) {
340 100. * (max_energy_contribution / energy_sum));
341 }
342 }
343 if (n_sum > 0) {
344 double n_max = *max_element(n_hits_from_electron.begin(),
345 n_hits_from_electron.end());
347 }
348
349 auto elt = distance(
350 energy_from_electron.begin(),
351 max_element(energy_from_electron.begin(), energy_from_electron.end()));
352 ldmx_log(debug) << "Found that the maximum contributing trackID is " << elt;
353 delta_energy[elt] = cl.getEnergy() - true_energy[elt];
354
356 }
357 std::string more_log;
358 for (auto nb : tot_origin_edep) more_log.append(std::to_string(nb) + " ");
359 ldmx_log(debug) << "Edep per ancestor in event is " << more_log;
360 ldmx_log(debug) << "Total energy deposited in event: " << tot_event_energy;
361
363 histograms_.
fill(
"unclustered_hits", (ecal_rec_hits.size() - clustered_hits));
366 "unclustered_hits_percentage",
367 100. * (ecal_rec_hits.size() - clustered_hits) / ecal_rec_hits.size());
368
369 if (inverse_skim_) {
370
371 if (n_ecal_clusters > n_ecal_clusters_min_) {
373 } else {
375 }
376 } else {
377
378 if (n_ecal_clusters > n_ecal_clusters_min_) {
380 } else {
382 }
383 }
384}
int nbr_of_electrons_
What is the number of electrons in the event?
bool use_simulated_electron_number_
Use the number of simulated electrons instead of the number of determined by the TS track counting.
HistogramPool histograms_
helper object for making and filling histograms
void setStorageHint(framework::StorageControl::Hint hint)
Mark the current event as having the given storage control hint from this module_.
void fill(const std::string &name, const T &val)
Fill a 1D histogram.
Stores cluster information from the ECal.
Stores reconstructed hit information from the ECAL.
Stores simulated calorimeter hit information.
Implements detector ids for special simulation-derived hits like scoring planes.
Represents a simulated tracker hit in the simulation.
constexpr StorageControl::Hint HINT_SHOULD_DROP
storage control hint alias for backwards compatibility
constexpr StorageControl::Hint HINT_SHOULD_KEEP
storage control hint alias for backwards compatibility