LDMX Software
Public Member Functions | Public Attributes | List of all members
trigger::IdealClusterBuilder Class Reference

Public Member Functions

void AddHit (Hit h)
 
std::vector< ClusterGetClusters ()
 
void SetClusterGeo (ClusterGeometry *_g)
 
virtual void BuildClusters ()
 
std::vector< ClusterBuild2dClustersLayer (std::vector< Hit > hits)
 
void Build2dClusters ()
 
void Build3dClusters ()
 
void Fit (Cluster &c3)
 

Public Attributes

std::vector< Hitall_hits {}
 
std::vector< Clusterall_clusters {}
 
ClusterGeometryg
 
float seed_thresh = 0
 
float neighb_thresh = 0
 
int n_neighbors = 1
 
bool split_energy = true
 
bool use_towers = false
 
const int LAYER_MAX = 35
 
const int LAYER_SHOWERMAX = 7
 
const int LAYER_SEEDMIN = 3
 
const int LAYER_SEEDMAX = 15
 
const float MIN_TP_ENERGY = 0.5
 
int DEPTH_GOOD = 5
 
bool debug = false
 

Detailed Description

Definition at line 142 of file IdealClusterBuilder.h.

Member Function Documentation

◆ AddHit()

void trigger::IdealClusterBuilder::AddHit ( Hit  h)
inline

Definition at line 166 of file IdealClusterBuilder.h.

166 {
167 if (h.layer >= LAYER_MAX) return;
168 auto p = std::make_pair(h.cell_id, h.module_id);
169 h.id = g->reverse_id_map[p];
170 all_hits.push_back(h);
171 }

◆ Build2dClusters()

void trigger::IdealClusterBuilder::Build2dClusters ( )

Definition at line 207 of file IdealClusterBuilder.cxx.

207 {
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}

◆ Build2dClustersLayer()

std::vector< Cluster > trigger::IdealClusterBuilder::Build2dClustersLayer ( std::vector< Hit hits)

Definition at line 58 of file IdealClusterBuilder.cxx.

59 {
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}
Definition objdef.h:49

◆ Build3dClusters()

void trigger::IdealClusterBuilder::Build3dClusters ( )

Definition at line 230 of file IdealClusterBuilder.cxx.

230 {
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}

◆ BuildClusters()

void trigger::IdealClusterBuilder::BuildClusters ( )
virtual

Definition at line 412 of file IdealClusterBuilder.cxx.

412 {
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};

◆ Fit()

void trigger::IdealClusterBuilder::Fit ( Cluster c3)

Definition at line 450 of file IdealClusterBuilder.cxx.

450 {
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}

◆ GetClusters()

std::vector< Cluster > trigger::IdealClusterBuilder::GetClusters ( )
inline

Definition at line 172 of file IdealClusterBuilder.h.

172{ return all_clusters; }

◆ SetClusterGeo()

void trigger::IdealClusterBuilder::SetClusterGeo ( ClusterGeometry _g)
inline

Definition at line 173 of file IdealClusterBuilder.h.

173{ g = _g; }

Member Data Documentation

◆ all_clusters

std::vector<Cluster> trigger::IdealClusterBuilder::all_clusters {}

Definition at line 146 of file IdealClusterBuilder.h.

146{};

◆ all_hits

std::vector<Hit> trigger::IdealClusterBuilder::all_hits {}

Definition at line 145 of file IdealClusterBuilder.h.

145{};

◆ debug

bool trigger::IdealClusterBuilder::debug = false

Definition at line 164 of file IdealClusterBuilder.h.

◆ DEPTH_GOOD

int trigger::IdealClusterBuilder::DEPTH_GOOD = 5

Definition at line 160 of file IdealClusterBuilder.h.

◆ g

ClusterGeometry* trigger::IdealClusterBuilder::g

Definition at line 147 of file IdealClusterBuilder.h.

◆ LAYER_MAX

const int trigger::IdealClusterBuilder::LAYER_MAX = 35

Definition at line 155 of file IdealClusterBuilder.h.

◆ LAYER_SEEDMAX

const int trigger::IdealClusterBuilder::LAYER_SEEDMAX = 15

Definition at line 158 of file IdealClusterBuilder.h.

◆ LAYER_SEEDMIN

const int trigger::IdealClusterBuilder::LAYER_SEEDMIN = 3

Definition at line 157 of file IdealClusterBuilder.h.

◆ LAYER_SHOWERMAX

const int trigger::IdealClusterBuilder::LAYER_SHOWERMAX = 7

Definition at line 156 of file IdealClusterBuilder.h.

◆ MIN_TP_ENERGY

const float trigger::IdealClusterBuilder::MIN_TP_ENERGY = 0.5

Definition at line 159 of file IdealClusterBuilder.h.

◆ n_neighbors

int trigger::IdealClusterBuilder::n_neighbors = 1

Definition at line 151 of file IdealClusterBuilder.h.

◆ neighb_thresh

float trigger::IdealClusterBuilder::neighb_thresh = 0

Definition at line 150 of file IdealClusterBuilder.h.

◆ seed_thresh

float trigger::IdealClusterBuilder::seed_thresh = 0

Definition at line 149 of file IdealClusterBuilder.h.

◆ split_energy

bool trigger::IdealClusterBuilder::split_energy = true

Definition at line 152 of file IdealClusterBuilder.h.

◆ use_towers

bool trigger::IdealClusterBuilder::use_towers = false

Definition at line 154 of file IdealClusterBuilder.h.


The documentation for this class was generated from the following files: