LDMX Software
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
 
const int DEPTH_GOOD = 5
 
bool debug_ = false
 

Detailed Description

Definition at line 140 of file IdealClusterBuilder.h.

Member Function Documentation

◆ addHit()

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

Definition at line 164 of file IdealClusterBuilder.h.

164 {
165 if (h.layer_ >= LAYER_MAX) return;
166 auto p = std::make_pair(h.cell_id_, h.module_id_);
167 h.id_ = g_->reverse_id_map_[p];
168 all_hits_.push_back(h);
169 }

◆ build2dClusters()

void trigger::IdealClusterBuilder::build2dClusters ( )

Definition at line 193 of file IdealClusterBuilder.cxx.

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

◆ build2dClustersLayer()

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

Definition at line 49 of file IdealClusterBuilder.cxx.

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

◆ build3dClusters()

void trigger::IdealClusterBuilder::build3dClusters ( )

Definition at line 211 of file IdealClusterBuilder.cxx.

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

◆ buildClusters()

void trigger::IdealClusterBuilder::buildClusters ( )
virtual

Definition at line 394 of file IdealClusterBuilder.cxx.

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

◆ fit()

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

Definition at line 432 of file IdealClusterBuilder.cxx.

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

◆ getClusters()

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

Definition at line 170 of file IdealClusterBuilder.h.

170{ return all_clusters_; }

◆ setClusterGeo()

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

Definition at line 171 of file IdealClusterBuilder.h.

171{ g_ = g; }

Member Data Documentation

◆ all_clusters_

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

Definition at line 144 of file IdealClusterBuilder.h.

144{};

◆ all_hits_

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

Definition at line 143 of file IdealClusterBuilder.h.

143{};

◆ debug_

bool trigger::IdealClusterBuilder::debug_ = false

Definition at line 162 of file IdealClusterBuilder.h.

◆ DEPTH_GOOD

const int trigger::IdealClusterBuilder::DEPTH_GOOD = 5

Definition at line 158 of file IdealClusterBuilder.h.

◆ g_

ClusterGeometry* trigger::IdealClusterBuilder::g_

Definition at line 145 of file IdealClusterBuilder.h.

◆ LAYER_MAX

const int trigger::IdealClusterBuilder::LAYER_MAX = 35

Definition at line 153 of file IdealClusterBuilder.h.

◆ LAYER_SEEDMAX

const int trigger::IdealClusterBuilder::LAYER_SEEDMAX = 15

Definition at line 156 of file IdealClusterBuilder.h.

◆ LAYER_SEEDMIN

const int trigger::IdealClusterBuilder::LAYER_SEEDMIN = 3

Definition at line 155 of file IdealClusterBuilder.h.

◆ LAYER_SHOWERMAX

const int trigger::IdealClusterBuilder::LAYER_SHOWERMAX = 7

Definition at line 154 of file IdealClusterBuilder.h.

◆ MIN_TP_ENERGY

const float trigger::IdealClusterBuilder::MIN_TP_ENERGY = 0.5

Definition at line 157 of file IdealClusterBuilder.h.

◆ n_neighbors_

int trigger::IdealClusterBuilder::n_neighbors_ = 1

Definition at line 149 of file IdealClusterBuilder.h.

◆ neighb_thresh_

float trigger::IdealClusterBuilder::neighb_thresh_ = 0

Definition at line 148 of file IdealClusterBuilder.h.

◆ seed_thresh_

float trigger::IdealClusterBuilder::seed_thresh_ = 0

Definition at line 147 of file IdealClusterBuilder.h.

◆ split_energy_

bool trigger::IdealClusterBuilder::split_energy_ = true

Definition at line 150 of file IdealClusterBuilder.h.

◆ use_towers_

bool trigger::IdealClusterBuilder::use_towers_ = false

Definition at line 152 of file IdealClusterBuilder.h.


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