LDMX Software
IdealClusterBuilder.cxx
1#include "Trigger/IdealClusterBuilder.h"
2
3namespace trigger {
4
5void ClusterGeometry::addTp(int tid, int cell_id, int module_id, float x,
6 float y) {
7 id_map_[tid] = std::make_pair(cell_id, module_id);
8 reverse_id_map_[std::make_pair(cell_id, module_id)] = tid;
9 positions_[tid] = std::make_pair(x, y);
10}
11void ClusterGeometry::addNeighbor(int id1, int id2) {
12 if (neighbors_.count(id1))
13 neighbors_[id1].push_back(id2);
14 else
15 neighbors_[id1] = {id2};
16 if (neighbors_.count(id2))
17 neighbors_[id2].push_back(id1);
18 else
19 neighbors_[id2] = {id1};
20 // cout << "Nbs: " << id1 << " " << id2 << endl;
21}
22bool ClusterGeometry::checkNeighbor(int id1, int id2) {
23 // true if neighbors
24 auto &ns = neighbors_[id1];
25 return std::find(ns.begin(), ns.end(), id2) != ns.end();
26}
27void ClusterGeometry::initialize() {
28 // calculate pairwise distances
29 distances_.clear();
30 for (auto pair1 = id_map_.begin(); pair1 != id_map_.end(); pair1++) {
31 for (auto pair2 = pair1; pair2 != id_map_.end(); pair2++) {
32 if (pair1 == pair2) continue;
33 auto &id1 = pair1->first;
34 auto &id2 = pair2->first;
35 auto &xy1 = positions_[id1];
36 auto &xy2 = positions_[id2];
37 float d =
38 sqrt(pow(xy1.first - xy2.first, 2) + pow(xy1.second - xy2.second, 2));
39 distances_[std::make_pair(id1, id2)] = d;
40 distances_[std::make_pair(id2, id1)] = d;
41 }
42 }
43 // find neighbors
44 float n_dist = 1.8 * getDist(getId(0, 0), getId(1, 0));
45 for (auto pair1 = id_map_.begin(); pair1 != id_map_.end(); pair1++) {
46 for (auto pair2 = pair1; pair2 != id_map_.end(); pair2++) {
47 if (pair1 == pair2) continue;
48 if (getDist(pair1->first, pair2->first) < n_dist)
49 addNeighbor(pair1->first, pair2->first);
50 }
51 }
52 is_initialized_ = true;
53}
54
55std::vector<Cluster> IdealClusterBuilder::build2dClustersLayer(
56 std::vector<Hit> hits) {
57 // Re-index by id
58 std::map<int, Hit> hits_by_id;
59 for (auto &hit : hits) hits_by_id[hit.id_] = hit;
60
61 if (debug_) {
62 cout << "--------\nBuild2dClustersLayer Input Hits" << endl;
63 for (auto &hitpair : hits_by_id) hitpair.second.print();
64 }
65
66 // Find seeds
67 std::vector<Cluster> clusters;
68 for (auto &hitpair : hits_by_id) {
69 auto &hit = hitpair.second;
70 bool is_local_max = true;
71 for (auto n : g_->neighbors_[hit.id_]) {
72 if (hits_by_id.count(n) && hits_by_id[n].e_ > hit.e_)
73 is_local_max = false;
74 }
75 if (is_local_max && (hit.e_ > seed_thresh_)) {
76 hit.used_ = true;
77 Cluster c;
78 c.hits_.push_back(hit);
79 c.e_ = hit.e_;
80 c.x_ = hit.x_;
81 c.y_ = hit.y_;
82 c.z_ = hit.z_;
83 c.seed_ = hit.id_;
84 c.module_ = g_->id_map_[hit.id_].second;
85 c.layer_ = hit.layer_;
86 clusters.push_back(c);
87 }
88 }
89
90 if (debug_) {
91 cout << "--------\nAfter seed-finding" << endl;
92 for (auto &hitpair : hits_by_id) hitpair.second.print();
93 for (auto &c : clusters) c.print();
94 }
95
96 // Add neighbors up to the specified limit
97 int i_neighbor = 0;
98 while (i_neighbor < n_neighbors_) {
99 // find (unused) neighbors for all clusters
100 std::map<int, std::vector<int> > assoc_clus2hit_i_ds;
101 for (int iclus = 0; iclus < clusters.size(); iclus++) {
102 auto &clus = clusters[iclus];
103 std::vector<int> neighbors;
104 for (const auto &hit : clus.hits_) {
105 for (auto n : g_->neighbors_[hit.id_]) {
106 if (hits_by_id.count(n) && !hits_by_id[n].used_ &&
107 hits_by_id[n].e_ > neighb_thresh_) {
108 neighbors.push_back(n);
109 }
110 }
111 }
112 assoc_clus2hit_i_ds[iclus] = neighbors;
113 }
114
115 // check how many clusters to which each hit is assoc
116 std::map<int, std::vector<int> > assoc_hit_i_d2clusters;
117 for (auto clus2hit_id : assoc_clus2hit_i_ds) {
118 auto iclus = clus2hit_id.first;
119 auto &hit_i_ds = clus2hit_id.second;
120 for (const auto &hit_id : hit_i_ds) {
121 if (assoc_hit_i_d2clusters.count(hit_id))
122 assoc_hit_i_d2clusters[hit_id].push_back(iclus);
123 else
124 assoc_hit_i_d2clusters[hit_id] = {iclus};
125 }
126 }
127
128 // add associated hits to clusters
129 // (w/ optional e-splitting)
130 for (auto hit_i_d2clusters : assoc_hit_i_d2clusters) {
131 auto hit_id = hit_i_d2clusters.first;
132 auto iclusters = hit_i_d2clusters.second;
133 if (iclusters.size() == 1) {
134 // simply add cell to the cluster
135 auto &hit = hits_by_id[hit_id];
136 auto iclus = iclusters[0];
137 hit.used_ = true;
138 clusters[iclus].hits_.push_back(hit);
139 clusters[iclus].e_ += hit.e_;
140 } else {
141 auto &hit = hits_by_id[hit_id];
142 hit.used_ = true;
143 float esum = 0;
144 for (auto iclus : iclusters) {
145 esum += clusters[iclus].e_;
146 }
147 for (auto iclus : iclusters) {
148 Hit new_hit = hit;
149 if (split_energy_) new_hit.e_ = hit.e_ * clusters[iclus].e_ / esum;
150 clusters[iclus].hits_.push_back(new_hit);
151 clusters[iclus].e_ += new_hit.e_;
152 }
153 }
154 }
155
156 // rebuild the clusters and return
157 for (auto &c : clusters) {
158 c.e_ = 0;
159 c.x_ = 0;
160 c.y_ = 0;
161 c.z_ = 0;
162 c.xx_ = 0;
163 c.yy_ = 0;
164 c.zz_ = 0;
165 float sumw = 0;
166 for (auto hit : c.hits_) {
167 // if(debug_) cout << hit.x << " " << hit.y << " " << hit.z << endl;
168 c.e_ += hit.e_;
169 // cout << "2d: " << h.e << " " << log(h.e/MIN_TP_ENERGY) << endl;
170 float w = std::max(0., log(hit.e_ / MIN_TP_ENERGY)); // use log-e wgt
171 c.x_ += hit.x_ * w;
172 c.y_ += hit.y_ * w;
173 c.z_ += hit.z_ * w;
174 c.xx_ += hit.x_ * hit.x_ * w;
175 c.yy_ += hit.y_ * hit.y_ * w;
176 c.zz_ += hit.z_ * hit.z_ * w;
177 sumw += w;
178 }
179 c.x_ /= sumw;
180 c.y_ /= sumw;
181 c.z_ /= sumw;
182 c.xx_ /= sumw; // now is <x^2>
183 c.yy_ /= sumw;
184 c.zz_ /= sumw;
185 c.xx_ = sqrt(c.xx_ - c.x_ * c.x_); // now is sqrt(<x^2>-<x>^2)
186 c.yy_ = sqrt(c.yy_ - c.y_ * c.y_);
187 c.zz_ = sqrt(c.zz_ - c.z_ * c.z_);
188 }
189
190 i_neighbor++;
191
192 if (debug_) {
193 cout << "--------\nAfter " << i_neighbor << " neighbors" << endl;
194 for (auto &hitpair : hits_by_id) hitpair.second.print();
195 for (auto &c : clusters) c.print();
196 }
197 }
198
199 return clusters;
200}
201
202void IdealClusterBuilder::build2dClusters() {
203 // first partition hits by layer
204 std::map<int, std::vector<Hit> > layer_hits; // id(xy) to Hit
205 for (const auto hit : all_hits_) {
206 layer_hits[hit.layer_].push_back(hit);
207 }
208
209 // run clustering in each layer and add to the list
210 for (auto &pair : layer_hits) {
211 if (debug_) {
212 cout << "Found " << pair.second.size() << " hits in layer " << pair.first
213 << endl;
214 }
215 auto clus = build2dClustersLayer(pair.second);
216 all_clusters_.insert(all_clusters_.end(), clus.begin(), clus.end());
217 }
218}
219
220void IdealClusterBuilder::build3dClusters() {
221 if (debug_) {
222 cout << "--------\nBuilding 3d clusters" << endl;
223 }
224
225 // first partition 2d clusters by layer
226 std::vector<std::vector<Cluster> > layer_clusters;
227 layer_clusters.resize(LAYER_MAX); // first 20 layers
228 for (auto &clus : all_clusters_) {
229 layer_clusters[clus.layer_].push_back(clus);
230 }
231
232 // sort by layer
233 for (auto &clusters : layer_clusters) eSort(clusters);
234
235 if (debug_) {
236 cout << "--------\n3d: sorted 2d inputs" << endl;
237 for (auto &clusters : layer_clusters)
238 for (auto &c : clusters) c.print(g_);
239 }
240
241 // Pass through clusters from layer 0 to last,
242 // starting with highest energy
243 bool building = true;
244 std::vector<Cluster> clusters3d;
245 while (building) {
246 // find the seed cluster
247 Cluster cluster3d;
248 cluster3d.is_2d_ = false;
249 cluster3d.first_layer_ = LAYER_SHOWERMAX;
250 cluster3d.last_layer_ = LAYER_SHOWERMAX;
251 int test_layer;
252 for (int ilayer = 0; ilayer < LAYER_MAX; ilayer++) {
253 if (LAYER_SHOWERMAX + ilayer < LAYER_MAX) {
254 // walk to back of ECal from shower max
255 test_layer = LAYER_SHOWERMAX + ilayer; // 7,8,9,...19
256 } else {
257 // then to front of ECal
258 test_layer = LAYER_MAX - ilayer - 1; // 20-13-1=6,5,4,...
259 }
260
261 auto &clusters2d = layer_clusters[test_layer];
262
263 // still must find the 3d seed
264 if (cluster3d.depth_ == 0) {
265 // only seed from the middle layers
266 if (test_layer > LAYER_SEEDMAX || test_layer < LAYER_SEEDMIN) continue;
267 if (clusters2d.size()) {
268 if (debug_) {
269 cout << " 3d seed: ";
270 clusters2d[0].print(g_);
271 }
272 // cout << "got seed" << endl;
273 // found seed
274 cluster3d.clusters2d_ = {clusters2d[0]};
275 cluster3d.first_layer_ = test_layer;
276 cluster3d.last_layer_ = test_layer;
277 cluster3d.depth_ = 1;
278 // remove (first) 2d cluster from list
279 clusters2d.erase(clusters2d.begin());
280 }
281 } else {
282 // looking to extend the 3d seed
283 // grow if 2d seed is a neighbor
284 // auto &last_seed2d = clusters3d.back().seed_;
285 auto &last_seed2d = cluster3d.clusters2d_.back().seed_;
286 // case where we begin extending cluster backward->forward
287 if (test_layer == LAYER_SHOWERMAX - 1)
288 last_seed2d = cluster3d.clusters2d_.front().seed_;
289 if (debug_) {
290 // cout << cluster3d.clusters2d.size() << endl;
291 // cluster3d.clusters2d.back().print();
292 cout << " check 3d w/ seed id " << last_seed2d << endl;
293 // cout << " from #cands: " << clusters2d.size() << endl;
294 }
295 for (int iclus2d = 0; iclus2d < clusters2d.size(); iclus2d++) {
296 if (debug_) {
297 cout << " -- " << iclus2d << endl;
298 // clusters2d[iclus2d].print(g_);
299 // cout << " check ext " << seed2d << endl;
300 }
301 auto &seed2d = clusters2d[iclus2d].seed_;
302 if (last_seed2d == seed2d || g_->checkNeighbor(last_seed2d, seed2d)) {
303 // if(debug_){
304 // cout << " extend: ";
305 // clusters2d[iclus2d].print(g_);
306 // }
307 // add to 3d cluster
308 cluster3d.clusters2d_.push_back(clusters2d[iclus2d]);
309 cluster3d.depth_++;
310 if (test_layer < cluster3d.first_layer_)
311 cluster3d.first_layer_ = test_layer;
312 if (test_layer > cluster3d.last_layer_)
313 cluster3d.last_layer_ = test_layer;
314 // remove from list
315 clusters2d.erase(clusters2d.begin() + iclus2d);
316 // proceed to next layer
317 break;
318 }
319 }
320 }
321 }
322 // done with all layers. finish or store cluster
323 if (cluster3d.depth_ == 0) {
324 building = false;
325 } else {
326 // cout << "storing 3d cluster" << endl;
327 if (cluster3d.depth_ >= DEPTH_GOOD) clusters3d.push_back(cluster3d);
328 }
329 }
330
331 // post-process 3d clusters here
332 for (auto &c : clusters3d) {
333 c.e_ = 0;
334 c.x_ = 0;
335 c.y_ = 0;
336 c.z_ = 0;
337 c.xx_ = 0;
338 c.yy_ = 0;
339 c.zz_ = 0;
340 float sumw = 0;
341 for (auto &c2 : c.clusters2d_) {
342 c.e_ += c2.e_;
343 // cout << "3d: " << c2.e << " " << log(c2.e/MIN_TP_ENERGY) << endl;
344 float w = std::max(0., log(c2.e_ / MIN_TP_ENERGY)); // use log-e wgt
345 c.x_ += c2.x_ * w;
346 c.y_ += c2.y_ * w;
347 c.z_ += c2.z_ * w;
348 c.xx_ += c2.x_ * c2.x_ * w;
349 c.yy_ += c2.y_ * c2.y_ * w;
350 c.zz_ += c2.z_ * c2.z_ * w;
351 sumw += w;
352 }
353 // cout << "sum: " << sumw << endl;
354 // cout << "x: " << c.x << endl;
355 c.x_ /= sumw;
356 // cout << "x: " << c.x << endl;
357 c.y_ /= sumw;
358 c.z_ /= sumw;
359 c.xx_ /= sumw; // now is <x^2>
360 c.yy_ /= sumw;
361 c.zz_ /= sumw;
362 c.xx_ = sqrt(c.xx_ - c.x_ * c.x_); // now is sqrt(<x^2>-<x>^2)
363 c.yy_ = sqrt(c.yy_ - c.y_ * c.y_);
364 c.zz_ = sqrt(c.zz_ - c.z_ * c.z_);
365 fit(c); // calc dx/dz, dy/dz
366 }
367
368 if (debug_) {
369 cout << "--------\nFound 3d clusters" << endl;
370 for (auto &c : clusters3d) c.print3d();
371 }
372
373 // std::map<int, std::vector<Cluster> > layer_clusters; // id(xy) to Hit
374 // for(const auto clus : all_clusters_){
375 // auto l = clus.layer;
376 // if (layer_clusters.count(l)){
377 // layer_clusters[l].push_back(clus);
378 // } else {
379 // layer_clusters[l]={clus};
380 // }
381 // }
382 // // sort by layer
383 // for(auto &pair : layer_clusters){
384 // auto &clusters = pair.second;
385
386 // if(debug_ && clusters.size()>2){
387 // cout << "--------\nBefore sort " << endl;
388 // for(auto &c : clusters) c.print();
389 // }
390 // eSort(clusters);
391 // if(debug_ && clusters.size()>2){
392 // cout << "-- After sort " << endl;
393 // for(auto &c : clusters) c.print();
394 // }
395 // }
396
397 all_clusters_.clear();
398 all_clusters_.insert(all_clusters_.begin(), clusters3d.begin(),
399 clusters3d.end());
400}
401
402void IdealClusterBuilder::buildClusters() {
403 if (debug_) {
404 cout << "--------\nAll hits" << endl;
405 for (auto &hit : all_hits_) hit.print();
406 }
407
408 if (use_towers_) {
409 // project hits in z to form towers
410 std::map<int, Hit> towers; // id(xy) to Hit
411 for (const auto hit : all_hits_) {
412 if (towers.count(hit.id_)) {
413 towers[hit.id_].e_ += hit.e_;
414 towers[hit.id_].n_sub_hit_++;
415 } else {
416 towers[hit.id_] = hit;
417 towers[hit.id_].layer_ = 0;
418 towers[hit.id_].z_ = 0;
419 towers[hit.id_].n_sub_hit_ = 1;
420 }
421 }
422 all_hits_.clear();
423 for (const auto t : towers) all_hits_.push_back(t.second);
424
425 if (debug_) {
426 cout << "--------\nHits after towers" << endl;
427 for (auto &hit : all_hits_) hit.print();
428 }
429 }
430
431 // Cluster the hits in each plane
432 build2dClusters();
433
434 if (!use_towers_) {
435 build3dClusters();
436 }
437 eSort(all_clusters_);
438};
439
440void IdealClusterBuilder::fit(Cluster &c3) {
441 // TODO: think about whether to incorporate uncertainties
442 // into the fit (RMSs), or weight each layer in the fit.
443
444 // skip short clusters
445 if (c3.clusters2d_.size() < 4) return;
446
447 // std::vector logE;
448 std::vector<float> x;
449 std::vector<float> y;
450 std::vector<float> z;
451 for (const auto &c2 : c3.clusters2d_) {
452 // logE.push_back( log(c2.e) );
453 x.push_back(c2.x_);
454 y.push_back(c2.y_);
455 z.push_back(c2.z_);
456 }
457 TGraph gxz(z.size(), z.data(), x.data());
458 auto r_xz = gxz.Fit("pol1", "SQ"); // p0 + x*p1
459 c3.dxdz_ = r_xz->Value(1);
460 c3.dxdze_ = r_xz->ParError(1);
461
462 TGraph gyz(z.size(), z.data(), y.data());
463 auto r_yz = gyz.Fit("pol1", "SQ"); // p0 + x*p1
464 c3.dydz_ = r_yz->Value(1);
465 c3.dydze_ = r_yz->ParError(1);
466}
467
468} // namespace trigger
Definition objdef.h:49