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 // float n_dist = 1.2*GetDist(GetID(0,0), GetID(1,0));
46 for (auto pair1 = id_map.begin(); pair1 != id_map.end(); pair1++) {
47 for (auto pair2 = pair1; pair2 != id_map.end(); pair2++) {
48 if (pair1 == pair2) continue;
49 if (GetDist(pair1->first, pair2->first) < n_dist)
50 AddNeighbor(pair1->first, pair2->first);
51 }
52 }
53 is_initialized = true;
54}
55
56/* std::vector<Cluster> */
57/* IdealClusterBuilder::Build2dClustersLayer(std::vector<Hit> hits){ */
58std::vector<Cluster> IdealClusterBuilder::Build2dClustersLayer(
59 std::vector<Hit> hits) {
60 // Re-index by id
61 std::map<int, Hit> hits_by_id;
62 for (auto &hit : hits) hits_by_id[hit.id] = hit;
63
64 if (debug) {
65 cout << "--------\nBuild2dClustersLayer Input Hits" << endl;
66 for (auto &hitpair : hits_by_id) hitpair.second.Print();
67 }
68
69 // Find seeds
70 std::vector<Cluster> clusters;
71 for (auto &hitpair : hits_by_id) {
72 auto &hit = hitpair.second;
73 bool isLocalMax = true;
74 for (auto n : g->neighbors[hit.id]) {
75 // cout << " checking " << n << endl;
76 if (hits_by_id.count(n) && hits_by_id[n].e > hit.e) isLocalMax = false;
77 }
78 // if(debug) cout << hit.e << " " << hit.id << " "
79 // << hit.layer << " isMax=" << isLocalMax << endl;
80 if (isLocalMax && (hit.e > seed_thresh)) {
81 hit.used = true;
82 Cluster c;
83 c.hits.push_back(hit);
84 c.e = hit.e;
85 c.x = hit.x;
86 c.y = hit.y;
87 c.z = hit.z;
88 c.seed = hit.id;
89 c.module = g->id_map[hit.id].second;
90 c.layer = hit.layer;
91 clusters.push_back(c);
92 }
93 }
94
95 if (debug) {
96 cout << "--------\nAfter seed-finding" << endl;
97 for (auto &hitpair : hits_by_id) hitpair.second.Print();
98 for (auto &c : clusters) c.Print();
99 }
100
101 // Add neighbors up to the specified limit
102 int i_neighbor = 0;
103 while (i_neighbor < n_neighbors) {
104 // find (unused) neighbors for all clusters
105 std::map<int, std::vector<int> > assoc_clus2hitIDs;
106 for (int iclus = 0; iclus < clusters.size(); iclus++) {
107 auto &clus = clusters[iclus];
108 std::vector<int> neighbors;
109 for (const auto &hit : clus.hits) {
110 for (auto n : g->neighbors[hit.id]) {
111 if (hits_by_id.count(n) && !hits_by_id[n].used &&
112 hits_by_id[n].e > neighb_thresh) {
113 neighbors.push_back(n);
114 }
115 }
116 }
117 assoc_clus2hitIDs[iclus] = neighbors;
118 }
119
120 // check how many clusters to which each hit is assoc
121 std::map<int, std::vector<int> > assoc_hitID2clusters;
122 for (auto clus2hitID : assoc_clus2hitIDs) {
123 auto iclus = clus2hitID.first;
124 auto &hitIDs = clus2hitID.second;
125 for (const auto &hitID : hitIDs) {
126 if (assoc_hitID2clusters.count(hitID))
127 assoc_hitID2clusters[hitID].push_back(iclus);
128 else
129 assoc_hitID2clusters[hitID] = {iclus};
130 }
131 }
132
133 // add associated hits to clusters
134 // (w/ optional e-splitting)
135 for (auto hitID2clusters : assoc_hitID2clusters) {
136 auto hitID = hitID2clusters.first;
137 auto iclusters = hitID2clusters.second;
138 if (iclusters.size() == 1) {
139 // simply add cell to the cluster
140 auto &hit = hits_by_id[hitID];
141 auto iclus = iclusters[0];
142 hit.used = true;
143 clusters[iclus].hits.push_back(hit);
144 clusters[iclus].e += hit.e;
145 } else {
146 auto &hit = hits_by_id[hitID];
147 hit.used = true;
148 float esum = 0;
149 for (auto iclus : iclusters) {
150 esum += clusters[iclus].e;
151 }
152 for (auto iclus : iclusters) {
153 Hit newHit = hit;
154 if (split_energy) newHit.e = hit.e * clusters[iclus].e / esum;
155 clusters[iclus].hits.push_back(newHit);
156 clusters[iclus].e += newHit.e;
157 }
158 }
159 }
160
161 // rebuild the clusters and return
162 for (auto &c : clusters) {
163 c.e = 0;
164 c.x = 0;
165 c.y = 0;
166 c.z = 0;
167 c.xx = 0;
168 c.yy = 0;
169 c.zz = 0;
170 float sumw = 0;
171 for (auto hit : c.hits) {
172 // if(debug) cout << hit.x << " " << hit.y << " " << hit.z << endl;
173 c.e += hit.e;
174 // cout << "2d: " << h.e << " " << log(h.e/MIN_TP_ENERGY) << endl;
175 float w = std::max(0., log(hit.e / MIN_TP_ENERGY)); // use log-e wgt
176 c.x += hit.x * w;
177 c.y += hit.y * w;
178 c.z += hit.z * w;
179 c.xx += hit.x * hit.x * w;
180 c.yy += hit.y * hit.y * w;
181 c.zz += hit.z * hit.z * w;
182 sumw += w;
183 }
184 c.x /= sumw;
185 c.y /= sumw;
186 c.z /= sumw;
187 c.xx /= sumw; // now is <x^2>
188 c.yy /= sumw;
189 c.zz /= sumw;
190 c.xx = sqrt(c.xx - c.x * c.x); // now is sqrt(<x^2>-<x>^2)
191 c.yy = sqrt(c.yy - c.y * c.y);
192 c.zz = sqrt(c.zz - c.z * c.z);
193 }
194
195 i_neighbor++;
196
197 if (debug) {
198 cout << "--------\nAfter " << i_neighbor << " neighbors" << endl;
199 for (auto &hitpair : hits_by_id) hitpair.second.Print();
200 for (auto &c : clusters) c.Print();
201 }
202 }
203
204 return clusters;
205}
206
207void IdealClusterBuilder::Build2dClusters() {
208 // first partition hits by layer
209 std::map<int, std::vector<Hit> > layer_hits; // id(xy) to Hit
210 for (const auto hit : all_hits) {
211 auto l = hit.layer;
212 if (layer_hits.count(l)) {
213 layer_hits[l].push_back(hit);
214 } else {
215 layer_hits[l] = {hit};
216 }
217 }
218
219 // run clustering in each layer and add to the list
220 for (auto &pair : layer_hits) {
221 if (debug) {
222 cout << "Found " << pair.second.size() << " hits in layer " << pair.first
223 << endl;
224 }
225 auto clus = Build2dClustersLayer(pair.second);
226 all_clusters.insert(all_clusters.end(), clus.begin(), clus.end());
227 }
228}
229
230void IdealClusterBuilder::Build3dClusters() {
231 if (debug) {
232 cout << "--------\nBuilding 3d clusters" << endl;
233 }
234
235 // first partition 2d clusters by layer
236 std::vector<std::vector<Cluster> > layer_clusters;
237 layer_clusters.resize(LAYER_MAX); // first 20 layers
238 for (auto &clus : all_clusters) {
239 layer_clusters[clus.layer].push_back(clus);
240 }
241
242 // sort by layer
243 for (auto &clusters : layer_clusters) ESort(clusters);
244
245 if (debug) {
246 cout << "--------\n3d: sorted 2d inputs" << endl;
247 for (auto &clusters : layer_clusters)
248 for (auto &c : clusters) c.Print(g);
249 }
250
251 // Pass through clusters from layer 0 to last,
252 // starting with highest energy
253 bool building = true;
254 std::vector<Cluster> clusters3d;
255 while (building) {
256 // find the seed cluster
257 Cluster cluster3d;
258 cluster3d.is2D = false;
259 cluster3d.first_layer = LAYER_SHOWERMAX;
260 cluster3d.last_layer = LAYER_SHOWERMAX;
261 int test_layer;
262 for (int ilayer = 0; ilayer < LAYER_MAX; ilayer++) {
263 if (LAYER_SHOWERMAX + ilayer < LAYER_MAX) {
264 // walk to back of ECal from shower max
265 test_layer = LAYER_SHOWERMAX + ilayer; // 7,8,9,...19
266 } else {
267 // then to front of ECal
268 test_layer = LAYER_MAX - ilayer - 1; // 20-13-1=6,5,4,...
269 }
270
271 auto &clusters2d = layer_clusters[test_layer];
272
273 // still must find the 3d seed
274 if (cluster3d.depth == 0) {
275 // only seed from the middle layers
276 if (test_layer > LAYER_SEEDMAX || test_layer < LAYER_SEEDMIN) continue;
277 if (clusters2d.size()) {
278 if (debug) {
279 cout << " 3d seed: ";
280 clusters2d[0].Print(g);
281 }
282 // cout << "got seed" << endl;
283 // found seed
284 cluster3d.clusters2d = {clusters2d[0]};
285 cluster3d.first_layer = test_layer;
286 cluster3d.last_layer = test_layer;
287 cluster3d.depth = 1;
288 // remove (first) 2d cluster from list
289 clusters2d.erase(clusters2d.begin());
290 }
291 } else {
292 // looking to extend the 3d seed
293 // grow if 2d seed is a neighbor
294 // auto &last_seed2d = clusters3d.back().seed;
295 auto &last_seed2d = cluster3d.clusters2d.back().seed;
296 // case where we begin extending cluster backward->forward
297 if (test_layer == LAYER_SHOWERMAX - 1)
298 last_seed2d = cluster3d.clusters2d.front().seed;
299 if (debug) {
300 // cout << cluster3d.clusters2d.size() << endl;
301 // cluster3d.clusters2d.back().Print();
302 cout << " check 3d w/ seed id " << last_seed2d << endl;
303 // cout << " from #cands: " << clusters2d.size() << endl;
304 }
305 for (int iclus2d = 0; iclus2d < clusters2d.size(); iclus2d++) {
306 if (debug) {
307 cout << " -- " << iclus2d << endl;
308 // clusters2d[iclus2d].Print(g);
309 // cout << " check ext " << seed2d << endl;
310 }
311 auto &seed2d = clusters2d[iclus2d].seed;
312 if (last_seed2d == seed2d || g->CheckNeighbor(last_seed2d, seed2d)) {
313 // if(debug){
314 // cout << " extend: ";
315 // clusters2d[iclus2d].Print(g);
316 // }
317 // add to 3d cluster
318 cluster3d.clusters2d.push_back(clusters2d[iclus2d]);
319 cluster3d.depth++;
320 if (test_layer < cluster3d.first_layer)
321 cluster3d.first_layer = test_layer;
322 if (test_layer > cluster3d.last_layer)
323 cluster3d.last_layer = test_layer;
324 // remove from list
325 clusters2d.erase(clusters2d.begin() + iclus2d);
326 // proceed to next layer
327 break;
328 }
329 }
330 }
331 }
332 // done with all layers. finish or store cluster
333 if (cluster3d.depth == 0) {
334 building = false;
335 } else {
336 // cout << "storing 3d cluster" << endl;
337 if (cluster3d.depth >= DEPTH_GOOD) clusters3d.push_back(cluster3d);
338 }
339 }
340
341 // post-process 3d clusters here
342 for (auto &c : clusters3d) {
343 c.e = 0;
344 c.x = 0;
345 c.y = 0;
346 c.z = 0;
347 c.xx = 0;
348 c.yy = 0;
349 c.zz = 0;
350 float sumw = 0;
351 for (auto &c2 : c.clusters2d) {
352 c.e += c2.e;
353 // cout << "3d: " << c2.e << " " << log(c2.e/MIN_TP_ENERGY) << endl;
354 float w = std::max(0., log(c2.e / MIN_TP_ENERGY)); // use log-e wgt
355 c.x += c2.x * w;
356 c.y += c2.y * w;
357 c.z += c2.z * w;
358 c.xx += c2.x * c2.x * w;
359 c.yy += c2.y * c2.y * w;
360 c.zz += c2.z * c2.z * w;
361 sumw += w;
362 }
363 // cout << "sum: " << sumw << endl;
364 // cout << "x: " << c.x << endl;
365 c.x /= sumw;
366 // cout << "x: " << c.x << endl;
367 c.y /= sumw;
368 c.z /= sumw;
369 c.xx /= sumw; // now is <x^2>
370 c.yy /= sumw;
371 c.zz /= sumw;
372 c.xx = sqrt(c.xx - c.x * c.x); // now is sqrt(<x^2>-<x>^2)
373 c.yy = sqrt(c.yy - c.y * c.y);
374 c.zz = sqrt(c.zz - c.z * c.z);
375 Fit(c); // calc dx/dz, dy/dz
376 }
377
378 if (debug) {
379 cout << "--------\nFound 3d clusters" << endl;
380 for (auto &c : clusters3d) c.Print3d();
381 }
382
383 // std::map<int, std::vector<Cluster> > layer_clusters; // id(xy) to Hit
384 // for(const auto clus : all_clusters){
385 // auto l = clus.layer;
386 // if (layer_clusters.count(l)){
387 // layer_clusters[l].push_back(clus);
388 // } else {
389 // layer_clusters[l]={clus};
390 // }
391 // }
392 // // sort by layer
393 // for(auto &pair : layer_clusters){
394 // auto &clusters = pair.second;
395
396 // if(debug && clusters.size()>2){
397 // cout << "--------\nBefore sort " << endl;
398 // for(auto &c : clusters) c.Print();
399 // }
400 // ESort(clusters);
401 // if(debug && clusters.size()>2){
402 // cout << "-- After sort " << endl;
403 // for(auto &c : clusters) c.Print();
404 // }
405 // }
406
407 all_clusters.clear();
408 all_clusters.insert(all_clusters.begin(), clusters3d.begin(),
409 clusters3d.end());
410}
411
412void IdealClusterBuilder::BuildClusters() {
413 if (debug) {
414 cout << "--------\nAll hits" << endl;
415 for (auto &hit : all_hits) hit.Print();
416 }
417
418 if (use_towers) {
419 // project hits in z to form towers
420 std::map<int, Hit> towers; // id(xy) to Hit
421 for (const auto hit : all_hits) {
422 if (towers.count(hit.id)) {
423 towers[hit.id].e += hit.e;
424 towers[hit.id].nSubHit++;
425 } else {
426 towers[hit.id] = hit;
427 towers[hit.id].layer = 0;
428 towers[hit.id].z = 0;
429 towers[hit.id].nSubHit = 1;
430 }
431 }
432 all_hits.clear();
433 for (const auto t : towers) all_hits.push_back(t.second);
434
435 if (debug) {
436 cout << "--------\nHits after towers" << endl;
437 for (auto &hit : all_hits) hit.Print();
438 }
439 }
440
441 // Cluster the hits in each plane
442 Build2dClusters();
443
444 if (!use_towers) {
445 Build3dClusters();
446 }
447 ESort(all_clusters);
448};
449
450void IdealClusterBuilder::Fit(Cluster &c3) {
451 // TODO: think about whether to incorporate uncertainties
452 // into the fit (RMSs), or weight each layer in the fit.
453
454 // skip short clusters
455 if (c3.clusters2d.size() < 4) return;
456
457 // std::vector logE;
458 std::vector<float> x;
459 std::vector<float> y;
460 std::vector<float> z;
461 for (const auto &c2 : c3.clusters2d) {
462 // logE.push_back( log(c2.e) );
463 x.push_back(c2.x);
464 y.push_back(c2.y);
465 z.push_back(c2.z);
466 }
467 TGraph gxz(z.size(), z.data(), x.data());
468 auto r_xz = gxz.Fit("pol1", "SQ"); // p0 + x*p1
469 c3.dxdz = r_xz->Value(1);
470 c3.dxdze = r_xz->ParError(1);
471
472 TGraph gyz(z.size(), z.data(), y.data());
473 auto r_yz = gyz.Fit("pol1", "SQ"); // p0 + x*p1
474 c3.dydz = r_yz->Value(1);
475 c3.dydze = r_yz->ParError(1);
476}
477
478} // namespace trigger
Definition objdef.h:49