LDMX Software
trigger::IdealClusterBuilder Class Reference

Public Member Functions

void addHit (Hit h)
 
std::vector< Cluster > getClusters ()
 
void setClusterGeo (ClusterGeometry *g)
 
virtual void buildClusters ()
 
std::vector< Cluster > build2dClustersLayer (std::vector< Hit > hits)
 
void build2dClusters ()
 
void build3dClusters ()
 
void fit (Cluster &c3)
 

Public Attributes

std::vector< Hit > all_hits_ {}
 
std::vector< Cluster > all_clusters_ {}
 
ClusterGeometry * g_
 
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
 
const int DEPTH_GOOD = 5
 
bool debug_ = false
 

Detailed Description

Definition at line 136 of file IdealClusterBuilder.h.

Member Function Documentation

◆ addHit()

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

Definition at line 160 of file IdealClusterBuilder.h.

160 {
161 if (h.layer_ >= LAYER_MAX) return;
162 auto p = std::make_pair(h.cell_id_, h.module_id_);
163 h.id_ = g_->reverse_id_map_[p];
164 all_hits_.push_back(h);
165 }

◆ build2dClusters()

void trigger::IdealClusterBuilder::build2dClusters ( )

Definition at line 198 of file IdealClusterBuilder.cxx.

198 {
199 // first partition hits by layer
200 std::map<int, std::vector<Hit> > layer_hits; // id(xy) to Hit
201 for (const auto hit : all_hits_) {
202 layer_hits[hit.layer_].push_back(hit);
203 }
204
205 // run clustering in each layer and add to the list
206 for (auto& pair : layer_hits) {
207 if (debug_) {
208 cout << "Found " << pair.second.size() << " hits in layer " << pair.first
209 << endl;
210 }
211 auto clus = build2dClustersLayer(pair.second);
212 all_clusters_.insert(all_clusters_.end(), clus.begin(), clus.end());
213 }
214}

◆ build2dClustersLayer()

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

Definition at line 54 of file IdealClusterBuilder.cxx.

55 {
56 // Re-index by id
57 std::map<int, Hit> hits_by_id;
58 for (auto& hit : hits) hits_by_id[hit.id_] = hit;
59
60 if (debug_) {
61 cout << "--------\nBuild2dClustersLayer Input Hits" << endl;
62 for (auto& hitpair : hits_by_id) hitpair.second.print();
63 }
64
65 // Find seeds
66 std::vector<Cluster> clusters;
67 for (auto& hitpair : hits_by_id) {
68 auto& hit = hitpair.second;
69 bool is_local_max = true;
70 for (auto n : g_->neighbors_[hit.id_]) {
71 if (hits_by_id.count(n) && hits_by_id[n].e_ > hit.e_)
72 is_local_max = false;
73 }
74 if (is_local_max && (hit.e_ > seed_thresh_)) {
75 hit.used_ = true;
76 Cluster c;
77 c.hits_.push_back(hit);
78 c.e_ = hit.e_;
79 c.x_ = hit.x_;
80 c.y_ = hit.y_;
81 c.z_ = hit.z_;
82 c.seed_ = hit.id_;
83 c.module_ = g_->id_map_[hit.id_].second;
84 c.layer_ = hit.layer_;
85 clusters.push_back(c);
86 }
87 }
88
89 if (debug_) {
90 cout << "--------\nAfter seed-finding" << endl;
91 for (auto& hitpair : hits_by_id) hitpair.second.print();
92 for (auto& c : clusters) c.print();
93 }
94
95 // Add neighbors up to the specified limit
96 int i_neighbor = 0;
97 while (i_neighbor < n_neighbors_) {
98 // find (unused) neighbors for all clusters
99 std::map<int, std::vector<int> > assoc_clus2hit_i_ds;
100 for (int iclus = 0; iclus < clusters.size(); iclus++) {
101 auto& clus = clusters[iclus];
102 std::vector<int> neighbors;
103 for (const auto& hit : clus.hits_) {
104 for (auto n : g_->neighbors_[hit.id_]) {
105 if (hits_by_id.count(n) && !hits_by_id[n].used_ &&
106 hits_by_id[n].e_ > neighb_thresh_) {
107 neighbors.push_back(n);
108 }
109 }
110 }
111 assoc_clus2hit_i_ds[iclus] = neighbors;
112 }
113
114 // check how many clusters to which each hit is assoc
115 std::map<int, std::vector<int> > assoc_hit_i_d2clusters;
116 for (auto clus2hit_id : assoc_clus2hit_i_ds) {
117 auto iclus = clus2hit_id.first;
118 auto& hit_i_ds = clus2hit_id.second;
119 for (const auto& hit_id : hit_i_ds) {
120 assoc_hit_i_d2clusters[hit_id].push_back(iclus);
121 }
122 }
123
124 // add associated hits to clusters
125 // (w/ optional e-splitting)
126 for (auto hit_i_d2clusters : assoc_hit_i_d2clusters) {
127 auto hit_id = hit_i_d2clusters.first;
128 auto iclusters = hit_i_d2clusters.second;
129 if (iclusters.size() == 1) {
130 // simply add cell to the cluster
131 auto& hit = hits_by_id[hit_id];
132 auto iclus = iclusters[0];
133 hit.used_ = true;
134 clusters[iclus].hits_.push_back(hit);
135 clusters[iclus].e_ += hit.e_;
136 } else {
137 auto& hit = hits_by_id[hit_id];
138 hit.used_ = true;
139 float esum = 0;
140 for (auto iclus : iclusters) {
141 esum += clusters[iclus].e_;
142 }
143 for (auto iclus : iclusters) {
144 Hit new_hit = hit;
145 if (split_energy_) new_hit.e_ = hit.e_ * clusters[iclus].e_ / esum;
146 clusters[iclus].hits_.push_back(new_hit);
147 clusters[iclus].e_ += new_hit.e_;
148 }
149 }
150 }
151
152 // rebuild the clusters and return
153 for (auto& c : clusters) {
154 c.e_ = 0;
155 c.x_ = 0;
156 c.y_ = 0;
157 c.z_ = 0;
158 c.xx_ = 0;
159 c.yy_ = 0;
160 c.zz_ = 0;
161 float sumw = 0;
162 for (auto hit : c.hits_) {
163 // if(debug_) cout << hit.x << " " << hit.y << " " << hit.z << endl;
164 c.e_ += hit.e_;
165 // cout << "2d: " << h.e << " " << log(h.e/MIN_TP_ENERGY) << endl;
166 float w = std::max(0., log(hit.e_ / MIN_TP_ENERGY)); // use log-e wgt
167 c.x_ += hit.x_ * w;
168 c.y_ += hit.y_ * w;
169 c.z_ += hit.z_ * w;
170 c.xx_ += hit.x_ * hit.x_ * w;
171 c.yy_ += hit.y_ * hit.y_ * w;
172 c.zz_ += hit.z_ * hit.z_ * w;
173 sumw += w;
174 }
175 c.x_ /= sumw;
176 c.y_ /= sumw;
177 c.z_ /= sumw;
178 c.xx_ /= sumw; // now is <x^2>
179 c.yy_ /= sumw;
180 c.zz_ /= sumw;
181 c.xx_ = sqrt(c.xx_ - c.x_ * c.x_); // now is sqrt(<x^2>-<x>^2)
182 c.yy_ = sqrt(c.yy_ - c.y_ * c.y_);
183 c.zz_ = sqrt(c.zz_ - c.z_ * c.z_);
184 }
185
186 i_neighbor++;
187
188 if (debug_) {
189 cout << "--------\nAfter " << i_neighbor << " neighbors" << endl;
190 for (auto& hitpair : hits_by_id) hitpair.second.print();
191 for (auto& c : clusters) c.print();
192 }
193 }
194
195 return clusters;
196}
Definition objdef.h:49

◆ build3dClusters()

void trigger::IdealClusterBuilder::build3dClusters ( )

Definition at line 216 of file IdealClusterBuilder.cxx.

216 {
217 if (debug_) {
218 cout << "--------\nBuilding 3d clusters" << endl;
219 }
220
221 // first partition 2d clusters by layer
222 std::vector<std::vector<Cluster> > layer_clusters;
223 layer_clusters.resize(LAYER_MAX); // first 20 layers
224 for (auto& clus : all_clusters_) {
225 layer_clusters[clus.layer_].push_back(clus);
226 }
227
228 // sort by layer
229 for (auto& clusters : layer_clusters) eSort(clusters);
230
231 if (debug_) {
232 cout << "--------\n3d: sorted 2d inputs" << endl;
233 for (auto& clusters : layer_clusters)
234 for (auto& c : clusters) c.print(g_);
235 }
236
237 // Pass through clusters from layer 0 to last,
238 // starting with highest energy
239 bool building = true;
240 std::vector<Cluster> clusters3d;
241 while (building) {
242 // find the seed cluster
243 Cluster cluster3d;
244 cluster3d.is_2d_ = false;
245 cluster3d.first_layer_ = LAYER_SHOWERMAX;
246 cluster3d.last_layer_ = LAYER_SHOWERMAX;
247 int test_layer;
248 for (int ilayer = 0; ilayer < LAYER_MAX; ilayer++) {
249 if (LAYER_SHOWERMAX + ilayer < LAYER_MAX) {
250 // walk to back of ECal from shower max
251 test_layer = LAYER_SHOWERMAX + ilayer; // 7,8,9,...19
252 } else {
253 // then to front of ECal
254 test_layer = LAYER_MAX - ilayer - 1; // 20-13-1=6,5,4,...
255 }
256
257 auto& clusters2d = layer_clusters[test_layer];
258
259 // still must find the 3d seed
260 if (cluster3d.depth_ == 0) {
261 // only seed from the middle layers
262 if (test_layer > LAYER_SEEDMAX || test_layer < LAYER_SEEDMIN) continue;
263 if (clusters2d.size()) {
264 if (debug_) {
265 cout << " 3d seed: ";
266 clusters2d[0].print(g_);
267 }
268 // cout << "got seed" << endl;
269 // found seed
270 cluster3d.clusters2d_.clear();
271 cluster3d.clusters2d_.push_back(clusters2d[0]);
272 cluster3d.first_layer_ = test_layer;
273 cluster3d.last_layer_ = test_layer;
274 cluster3d.depth_ = 1;
275 // remove (first) 2d cluster from list
276 clusters2d.erase(clusters2d.begin());
277 }
278 } else {
279 // looking to extend the 3d seed
280 // grow if 2d seed is a neighbor
281 // auto &last_seed2d = clusters3d.back().seed_;
282 auto& last_seed2d = cluster3d.clusters2d_.back().seed_;
283 // case where we begin extending cluster backward->forward
284 if (test_layer == LAYER_SHOWERMAX - 1)
285 last_seed2d = cluster3d.clusters2d_.front().seed_;
286 if (debug_) {
287 // cout << cluster3d.clusters2d.size() << endl;
288 // cluster3d.clusters2d.back().print();
289 cout << " check 3d w/ seed id " << last_seed2d << endl;
290 // cout << " from #cands: " << clusters2d.size() << endl;
291 }
292 for (int iclus2d = 0; iclus2d < clusters2d.size(); iclus2d++) {
293 if (debug_) {
294 cout << " -- " << iclus2d << endl;
295 // clusters2d[iclus2d].print(g_);
296 // cout << " check ext " << seed2d << endl;
297 }
298 auto& seed2d = clusters2d[iclus2d].seed_;
299 if (last_seed2d == seed2d || g_->checkNeighbor(last_seed2d, seed2d)) {
300 // if(debug_){
301 // cout << " extend: ";
302 // clusters2d[iclus2d].print(g_);
303 // }
304 // add to 3d cluster
305 cluster3d.clusters2d_.push_back(clusters2d[iclus2d]);
306 cluster3d.depth_++;
307 if (test_layer < cluster3d.first_layer_)
308 cluster3d.first_layer_ = test_layer;
309 if (test_layer > cluster3d.last_layer_)
310 cluster3d.last_layer_ = test_layer;
311 // remove from list
312 clusters2d.erase(clusters2d.begin() + iclus2d);
313 // proceed to next layer
314 break;
315 }
316 }
317 }
318 }
319 // done with all layers. finish or store cluster
320 if (cluster3d.depth_ == 0) {
321 building = false;
322 } else {
323 // cout << "storing 3d cluster" << endl;
324 if (cluster3d.depth_ >= DEPTH_GOOD) clusters3d.push_back(cluster3d);
325 }
326 }
327
328 // post-process 3d clusters here
329 for (auto& c : clusters3d) {
330 c.e_ = 0;
331 c.x_ = 0;
332 c.y_ = 0;
333 c.z_ = 0;
334 c.xx_ = 0;
335 c.yy_ = 0;
336 c.zz_ = 0;
337 float sumw = 0;
338 for (auto& c2 : c.clusters2d_) {
339 c.e_ += c2.e_;
340 // cout << "3d: " << c2.e << " " << log(c2.e/MIN_TP_ENERGY) << endl;
341 float w = std::max(0., log(c2.e_ / MIN_TP_ENERGY)); // use log-e wgt
342 c.x_ += c2.x_ * w;
343 c.y_ += c2.y_ * w;
344 c.z_ += c2.z_ * w;
345 c.xx_ += c2.x_ * c2.x_ * w;
346 c.yy_ += c2.y_ * c2.y_ * w;
347 c.zz_ += c2.z_ * c2.z_ * w;
348 sumw += w;
349 }
350 // cout << "sum: " << sumw << endl;
351 // cout << "x: " << c.x << endl;
352 c.x_ /= sumw;
353 // cout << "x: " << c.x << endl;
354 c.y_ /= sumw;
355 c.z_ /= sumw;
356 c.xx_ /= sumw; // now is <x^2>
357 c.yy_ /= sumw;
358 c.zz_ /= sumw;
359 c.xx_ = sqrt(c.xx_ - c.x_ * c.x_); // now is sqrt(<x^2>-<x>^2)
360 c.yy_ = sqrt(c.yy_ - c.y_ * c.y_);
361 c.zz_ = sqrt(c.zz_ - c.z_ * c.z_);
362 fit(c); // calc dx/dz, dy/dz
363 }
364
365 if (debug_) {
366 cout << "--------\nFound 3d clusters" << endl;
367 for (auto& c : clusters3d) c.print3d();
368 }
369
370 // std::map<int, std::vector<Cluster> > layer_clusters; // id(xy) to Hit
371 // for(const auto clus : all_clusters_){
372 // auto l = clus.layer;
373 // if (layer_clusters.count(l)){
374 // layer_clusters[l].push_back(clus);
375 // } else {
376 // layer_clusters[l]={clus};
377 // }
378 // }
379 // // sort by layer
380 // for(auto &pair : layer_clusters){
381 // auto &clusters = pair.second;
382
383 // if(debug_ && clusters.size()>2){
384 // cout << "--------\nBefore sort " << endl;
385 // for(auto &c : clusters) c.print();
386 // }
387 // eSort(clusters);
388 // if(debug_ && clusters.size()>2){
389 // cout << "-- After sort " << endl;
390 // for(auto &c : clusters) c.print();
391 // }
392 // }
393
394 all_clusters_.clear();
395 all_clusters_.insert(all_clusters_.begin(), clusters3d.begin(),
396 clusters3d.end());
397}

◆ buildClusters()

void trigger::IdealClusterBuilder::buildClusters ( )
virtual

Definition at line 399 of file IdealClusterBuilder.cxx.

399 {
400 if (debug_) {
401 cout << "--------\nAll hits" << endl;
402 for (auto& hit : all_hits_) hit.print();
403 }
404
405 if (use_towers_) {
406 // project hits in z to form towers
407 std::map<int, Hit> towers; // id(xy) to Hit
408 for (const auto hit : all_hits_) {
409 if (towers.count(hit.id_)) {
410 towers[hit.id_].e_ += hit.e_;
411 towers[hit.id_].n_sub_hit_++;
412 } else {
413 towers[hit.id_] = hit;
414 towers[hit.id_].layer_ = 0;
415 towers[hit.id_].z_ = 0;
416 towers[hit.id_].n_sub_hit_ = 1;
417 }
418 }
419 all_hits_.clear();
420 for (const auto t : towers) all_hits_.push_back(t.second);
421
422 if (debug_) {
423 cout << "--------\nHits after towers" << endl;
424 for (auto& hit : all_hits_) hit.print();
425 }
426 }
427
428 // Cluster the hits in each plane
429 build2dClusters();
430
431 if (!use_towers_) {
432 build3dClusters();
433 }
434 eSort(all_clusters_);
435};

◆ fit()

void trigger::IdealClusterBuilder::fit ( Cluster & c3)

Definition at line 437 of file IdealClusterBuilder.cxx.

437 {
438 // TODO: think about whether to incorporate uncertainties
439 // into the fit (RMSs), or weight each layer in the fit.
440
441 // skip short clusters
442 if (c3.clusters2d_.size() < 4) return;
443
444 // std::vector logE;
445 std::vector<float> x;
446 std::vector<float> y;
447 std::vector<float> z;
448 for (const auto& c2 : c3.clusters2d_) {
449 // logE.push_back( log(c2.e) );
450 x.push_back(c2.x_);
451 y.push_back(c2.y_);
452 z.push_back(c2.z_);
453 }
454 TGraph gxz(z.size(), z.data(), x.data());
455 auto r_xz = gxz.Fit("pol1", "SQ"); // p0 + x*p1
456 c3.dxdz_ = r_xz->Value(1);
457 c3.dxdze_ = r_xz->ParError(1);
458
459 TGraph gyz(z.size(), z.data(), y.data());
460 auto r_yz = gyz.Fit("pol1", "SQ"); // p0 + x*p1
461 c3.dydz_ = r_yz->Value(1);
462 c3.dydze_ = r_yz->ParError(1);
463}

◆ getClusters()

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

Definition at line 166 of file IdealClusterBuilder.h.

166{ return all_clusters_; }

◆ setClusterGeo()

void trigger::IdealClusterBuilder::setClusterGeo ( ClusterGeometry * g)
inline

Definition at line 167 of file IdealClusterBuilder.h.

167{ g_ = g; }

Member Data Documentation

◆ all_clusters_

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

Definition at line 140 of file IdealClusterBuilder.h.

140{};

◆ all_hits_

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

Definition at line 139 of file IdealClusterBuilder.h.

139{};

◆ debug_

bool trigger::IdealClusterBuilder::debug_ = false

Definition at line 158 of file IdealClusterBuilder.h.

◆ DEPTH_GOOD

const int trigger::IdealClusterBuilder::DEPTH_GOOD = 5

Definition at line 154 of file IdealClusterBuilder.h.

◆ g_

ClusterGeometry* trigger::IdealClusterBuilder::g_

Definition at line 141 of file IdealClusterBuilder.h.

◆ LAYER_MAX

const int trigger::IdealClusterBuilder::LAYER_MAX = 35

Definition at line 149 of file IdealClusterBuilder.h.

◆ LAYER_SEEDMAX

const int trigger::IdealClusterBuilder::LAYER_SEEDMAX = 15

Definition at line 152 of file IdealClusterBuilder.h.

◆ LAYER_SEEDMIN

const int trigger::IdealClusterBuilder::LAYER_SEEDMIN = 3

Definition at line 151 of file IdealClusterBuilder.h.

◆ LAYER_SHOWERMAX

const int trigger::IdealClusterBuilder::LAYER_SHOWERMAX = 7

Definition at line 150 of file IdealClusterBuilder.h.

◆ MIN_TP_ENERGY

const float trigger::IdealClusterBuilder::MIN_TP_ENERGY = 0.5

Definition at line 153 of file IdealClusterBuilder.h.

◆ n_neighbors_

int trigger::IdealClusterBuilder::n_neighbors_ = 1

Definition at line 145 of file IdealClusterBuilder.h.

◆ neighb_thresh_

float trigger::IdealClusterBuilder::neighb_thresh_ = 0

Definition at line 144 of file IdealClusterBuilder.h.

◆ seed_thresh_

float trigger::IdealClusterBuilder::seed_thresh_ = 0

Definition at line 143 of file IdealClusterBuilder.h.

◆ split_energy_

bool trigger::IdealClusterBuilder::split_energy_ = true

Definition at line 146 of file IdealClusterBuilder.h.

◆ use_towers_

bool trigger::IdealClusterBuilder::use_towers_ = false

Definition at line 148 of file IdealClusterBuilder.h.


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