LDMX Software
ecal::CLUE Class Reference

Classes

struct  Density
 

Public Member Functions

template<typename T >
T dist (T x1, T y1, T x2, T y2)
 Euclidean distance between two points.
 
template<typename T >
T dist (T x1, T y1, T z1, T x2, T y2, T z2)
 
std::vector< std::vector< const ldmx::EcalHit * > > createLayers (const std::vector< const ldmx::EcalHit * > &hits)
 
float roundToDecimal (float x, int num_decimal_precision_digits)
 
std::vector< std::shared_ptr< Density > > setup (const std::vector< const ldmx::EcalHit * > &hits)
 
void electronSeparation (std::vector< ldmx::EcalHit > hits)
 
std::vector< std::vector< const ldmx::EcalHit * > > clustering (std::vector< std::shared_ptr< Density > > &densities, bool connectingLayers, int layerTag=0)
 
std::vector< std::shared_ptr< Density > > setupForClue3D ()
 
void convertToIntermediateClusters (std::vector< std::vector< const ldmx::EcalHit * > > &clusters)
 
void cluster (const std::vector< ldmx::EcalHit > &hits, double dc, double rc, double deltac, double deltao, int nbrOfLayers, bool reclustering)
 
std::vector< double > getCentroidDistances () const
 
int getNLoops () const
 
int getInitialClusterNbr () const
 
std::vector< IntermediateCluster > getClusters () const
 
std::vector< IntermediateCluster > getFirstLayerCentroids () const
 

Private Member Functions

 enableLogging ("CLUE")
 

Private Attributes

int clustering_loops_
 
bool reclustering_
 
double dc_
 
double rhoc_
 
double deltac_
 
double deltao_
 
double dm_
 
int max_layers_ {32}
 
int nbr_of_layers_
 
std::vector< double > layer_rho_c_
 
std::vector< double > layer_delta_c_
 
std::vector< double > radius_
 
std::vector< double > centroid_distances_
 
IntermediateCluster event_centroid_
 
std::vector< IntermediateCluster > first_layer_centroids_
 
int seed_index_ {0}
 
std::vector< std::vector< std::shared_ptr< Density > > > seeds_
 
int initial_cluster_nbr_ {-1}
 
std::vector< IntermediateCluster > final_clusters_
 
std::vector< std::pair< double, double > > layer_centroid_separations_
 

Detailed Description

Definition at line 21 of file CLUE.h.

Member Function Documentation

◆ cluster()

void ecal::CLUE::cluster ( const std::vector< ldmx::EcalHit > & hits,
double dc,
double rc,
double deltac,
double deltao,
int nbrOfLayers,
bool reclustering )

Definition at line 590 of file CLUE.cxx.

592 {
593 ldmx_log(info) << "Starting CLUE clustering with parameters:" << "dc " << dc
594 << ", rc " << rc << ", delta_c " << delta_c << ", delta_o "
595 << delta_o << ", nbr_of_layers " << nbr_of_layers
596 << ", reclustering " << reclustering;
597 // cutoff distance for local density
598 dc_ = dc;
599 // min density to promote as seed/max density to demote as outlier
600 rhoc_ = rc;
601 // min separation distance for seeds
602 deltac_ = delta_c;
603 // min separation distance for outliers
604 deltao_ = delta_o;
605 // max distance to parent for both seeds and followers
606 dm_ = std::max(delta_c, delta_o);
607
608 // Recluster merged clusters or not
609 reclustering_ = reclustering;
610 nbr_of_layers_ = nbr_of_layers;
611
612 if (nbr_of_layers_ < 1) {
613 // anything below 1 => include all layers
614 nbr_of_layers_ = max_layers_;
615 } else if (nbr_of_layers_ > max_layers_) {
616 ldmx_log(warn) << "nbr_of_layers_ " << nbr_of_layers_
617 << " exceeds max layers " << max_layers_
618 << ", setting to max layers";
619 nbr_of_layers_ = max_layers_;
620 }
621
622 // first copy *addresses* so we are only ever passing around pointers
623 std::vector<const ldmx::EcalHit*> hits;
624 hits.reserve(unsorted_hits.size());
625 ldmx_log(debug) << "Clustering " << unsorted_hits.size() << " hits";
626 for (const auto& unsorted_hit : unsorted_hits) {
627 hits.push_back(&unsorted_hit);
628 }
629 // sort hits by Z position
630 ldmx_log(debug) << "Sorting hits by Z position";
631 std::sort(hits.begin(), hits.end(),
632 [](const ldmx::EcalHit* a, const ldmx::EcalHit* b) {
633 return a->getZPos() < b->getZPos();
634 });
635
636 seeds_.resize(nbr_of_layers_);
637
638 if (nbr_of_layers_ > 1) {
639 ldmx_log(debug) << "Creating layers";
640 // returns a vector of layers, with each layer having a vector of hits
641 const auto layers = createLayers(hits);
642 ldmx_log(debug) << "Doing layer-wise clustering on " << layers.size()
643 << " layers";
644 for (int i = 0; i < layers.size(); i++) {
645 ldmx_log(trace) << "--- LAYER " << i + 1 << " ---";
646 auto densities = setup(layers[i]);
647 auto clusters = clustering(densities, false, i);
648 convertToIntermediateClusters(clusters);
649 // clustering without 3D
650 }
651 // Below for CLUE3D, comment for just layer clustering
652 // This does not work properly yet
653 // auto densities = setupForClue3D();
654 // auto clusters = clustering(densities, true);
655 // convertToIntermediateClusters(clusters);
656 } else {
657 ldmx_log(debug) << "Only one layer, doing 2D clustering";
658 auto densities = setup(hits);
659 auto clusters = clustering(densities, false);
660 convertToIntermediateClusters(clusters);
661 }
662}
Stores reconstructed hit information from the ECAL.
Definition EcalHit.h:19

◆ clustering()

std::vector< std::vector< const ldmx::EcalHit * > > ecal::CLUE::clustering ( std::vector< std::shared_ptr< Density > > & densities,
bool connectingLayers,
int layerTag = 0 )

Definition at line 262 of file CLUE.cxx.

264 {
265 ldmx_log(trace) << "--- CLUSTERING ---";
266 ldmx_log(trace) << "Number of densities: " << densities.size()
267 << "; connecting_layers: " << connecting_layers
268 << "; layer_index: " << layer_index;
269 if (!connecting_layers && nbr_of_layers_ > 1) {
270 // if layerwise clustering override rhoc_ and deltac_ with per-layer values
271 rhoc_ = layer_rho_c_[layer_index];
272 ldmx_log(trace) << "Setting rho_c on layer " << layer_index << " to "
273 << rhoc_;
274 if (layer_index * 2 - 1 < radius_.size()) {
275 deltac_ = radius_[layer_index * 2 - 1];
276 ldmx_log(trace) << "Setting delta_c on layer " << layer_index << " to "
277 << deltac_;
278 }
279 } else if (connecting_layers) {
280 // if doing 3D clustering, override deltac_ and rhoc_ with other values
281 // NOT IMPLEMENTED YET
282 // if currently doing 3D clustering
283 // IF 3D clustering
284 // deltao_ = 200.;
285 // deltac_ = 100.;
286 // rhoc_ = 1000.;
287 }
288
289 bool energy_overload = false;
290 double max_energy = 10000.;
291 clustering_loops_ = 0;
292 double delta_c_mod = deltac_;
293 double centroid_radius = 10.;
294
295 // stores seeds of this layer
296 std::vector<std::shared_ptr<Density>>& layer_seeds = seeds_[layer_index];
297
298 // stores hits in cluster
299 std::vector<std::vector<const ldmx::EcalHit*>> clusters;
300 // keeps track of which densities have merged; only used if reclustering
301 std::vector<bool> merged_densities; // index_= cluster id
302 merged_densities.resize(densities.size());
303 // keeps track of cluster energies
304 std::vector<double> cluster_energies;
305 do {
306 // while no cluster has merged
307 if (energy_overload) {
308 // makes delta_c smaller if clusters have merged
309 delta_c_mod = delta_c_mod / 1.1;
310 ldmx_log(trace) << "Energy overload, new delta_cmod: " << delta_c_mod;
311 energy_overload = false;
312 }
313
314 clustering_loops_++;
315 ldmx_log(trace) << "Clustering loop " << clustering_loops_;
316
317 // cluster index
318 int k = 0;
319
320 layer_seeds.clear();
321 layer_seeds.reserve(densities.size());
322 clusters.clear();
323 clusters.reserve(densities.size());
324 cluster_energies.clear();
325 cluster_energies.reserve(densities.size());
326
327 std::stack<int> cluster_stack;
328 // stores followers of densities at corr index_
329 std::vector<std::vector<int>> followers;
330 followers.resize(densities.size());
331
332 // Mark as seed, follower, or outlier
333 for (auto& density : densities) {
334 // funky line to generalize this function for both 2D and 3D case
335 ldmx_log(trace) << " Index: " << density->index_
336 << "; x: " << density->x_ << "; y: " << density->y_
337 << "; Energy: " << density->total_energy_
338 << " Parent ID: " << density->follower_of_
339 << "; Delta: " << density->delta_;
340
341 bool is_seed;
342 if (delta_c_mod != deltac_ && density->cluster_id_ >= 0 &&
343 merged_densities[density->cluster_id_] &&
344 dist(density->x_, density->y_, event_centroid_.centroidX(),
345 event_centroid_.centroidY()) < centroid_radius) {
346 // if energy has been overloaded and this density belongs to cluster
347 // that was overloaded and this density is close enough to event
348 // centroid use modded delta c
349 is_seed =
350 density->total_energy_ > rhoc_ && density->delta_ > delta_c_mod;
351 } else {
352 is_seed = density->total_energy_ > rhoc_ && density->delta_ > deltac_;
353 if (is_seed) {
354 ldmx_log(trace) << " Distance to event centroid: "
355 << dist(density->x_, density->y_,
356 event_centroid_.centroidX(),
357 event_centroid_.centroidY());
358 }
359 }
360 bool is_outlier =
361 (density->total_energy_ < rhoc_) && (density->delta_ > deltao_);
362 density->cluster_id_ = -1;
363 if (is_seed) {
364 ldmx_log(trace) << " This is a Seed";
365 ldmx_log(trace) << " Distance to centroid: "
366 << dist(density->x_, density->y_,
367 event_centroid_.centroidX(),
368 event_centroid_.centroidY())
369 << "; with delta " << density->delta_;
370 ldmx_log(trace) << " Setting cluster ID to " << k;
371 density->cluster_id_ = k;
372 k++;
373 // get the index of the seed density
374 cluster_stack.push(density->index_);
375 clusters.push_back(density->hits_);
376 cluster_energies.push_back(density->total_energy_);
377 layer_seeds.push_back(density);
378 } else if (!is_outlier) {
379 ldmx_log(trace) << " This is a Follower";
380 int& parent_index = density->follower_of_;
381 if (parent_index != -1)
382 followers[parent_index].push_back(density->index_);
383 else
384 ldmx_log(error)
385 << " Somehow found a follower with parent index -1: id = "
386 << density->index_;
387 } else {
388 ldmx_log(trace) << " This is an Outlier";
389 }
390 }
391
392 merged_densities.clear();
393 merged_densities.resize(densities.size());
394
395 // Go through all seeds and add followers, then follower's followers, etc.
396 while (cluster_stack.size() > 0) {
397 auto& d = densities[cluster_stack.top()];
398 cluster_stack.pop();
399 auto& cid = d->cluster_id_;
400 // for indices of followers of dp
401 for (const auto follower_index : followers[d->index_]) {
402 auto& follower = densities[follower_index];
403 // Set cluster index of the follower to the cluster index of `d`
404 follower->cluster_id_ = cid;
405 cluster_energies[cid] += follower->total_energy_;
406
407 if (reclustering_ && cluster_energies[cid] > max_energy &&
408 delta_c_mod > 0.5 && clustering_loops_ < 100) {
409 // If reclustering is on and cluster energy is too high,
410 // delta_c_mod is not too low, and we haven't tried for too long
411 merged_densities[cid] = true;
412 if (!energy_overload && clustering_loops_ == 99) {
413 ldmx_log(warn) << "Merging clusters, max cluster loops hit";
414 }
415 energy_overload = true;
416 if (clustering_loops_ != 1) {
417 goto endwhile; // Don't break on the first loop to save the initial
418 // cluster number
419 }
420 }
421
422 clusters[cid].insert(std::end(clusters[cid]),
423 std::begin(follower->hits_),
424 std::end(follower->hits_));
425 // Add follower to the stack so its followers can also get the correct
426 // cluster index
427 cluster_stack.push(follower_index);
428 }
429 }
430 // for first clusteringloop, we want to save number of clusters before
431 // reclustering
432 if (clustering_loops_ == 1 && energy_overload)
433 initial_cluster_nbr_ = clusters.size();
434 endwhile:;
435 } while (energy_overload);
436 // if we have more than one layer and we are not currently doing CLUE3D
437 if (!connecting_layers && nbr_of_layers_ > 1) {
438 // Overwrite seed densities' properties with cluster properties
439 // Might be cleaner to just create new densities for cluster seeds
440 for (auto& seed : layer_seeds) {
441 seed->delta_ = std::numeric_limits<float>::max();
442 seed->hits_ = clusters[seed->cluster_id_];
443 seed->total_energy_ = cluster_energies[seed->cluster_id_];
444 seed->index_ = seed_index_;
445 seed_index_++;
446 }
447 // Sort seeds in layer based on energy
448 std::sort(layer_seeds.begin(), layer_seeds.end(),
449 [](const std::shared_ptr<Density>& a,
450 const std::shared_ptr<Density>& b) {
451 return a->total_energy_ > b->total_energy_;
452 });
453 }
454 return clusters;
455} // end of clustering
T dist(T x1, T y1, T x2, T y2)
Euclidean distance between two points.
Definition CLUE.cxx:22
double centroidY() const
Get the centroid Y position (energy-weighted).
double centroidX() const
Get the centroid X position (energy-weighted).

◆ convertToIntermediateClusters()

void ecal::CLUE::convertToIntermediateClusters ( std::vector< std::vector< const ldmx::EcalHit * > > & clusters)

Definition at line 560 of file CLUE.cxx.

561 {
562 // Convert to workingecalclusters to ensure compatibility with
563 // EcalClusterProducer
564 for (const auto& cluster : clusters) {
565 IntermediateCluster intermediate_cluster{},
566 intermediate_cluster_first_layer{};
567
568 for (const auto& hit : cluster) {
569 intermediate_cluster.add(hit);
570 // if hit is in first layer, add to first layer cluster
571 ldmx::EcalID ecal_id(hit->getID());
572 auto layer = ecal_id.layer();
573 intermediate_cluster.setLayer(layer);
574 if (layer == 0) {
575 intermediate_cluster_first_layer.add(hit);
576 intermediate_cluster_first_layer.setLayer(layer);
577 }
578 }
579 final_clusters_.push_back(intermediate_cluster);
580 first_layer_centroids_.push_back(intermediate_cluster_first_layer);
581 auto cent_x = intermediate_cluster.centroidX();
582 auto cent_y = intermediate_cluster.centroidY();
583 auto event_cent_x = event_centroid_.centroidX();
584 auto event_cent_y = event_centroid_.centroidY();
585 const auto& distance = dist(cent_x, cent_y, event_cent_x, event_cent_y);
586 centroid_distances_.push_back(distance);
587 }
588}
recon::WorkingCluster< ldmx::EcalHit > IntermediateCluster
Type alias for WorkingCluster specialized for EcalHit.
Extension of DetectorID providing access to ECal layers and cell numbers in a hex grid.
Definition EcalID.h:20

◆ createLayers()

std::vector< std::vector< const ldmx::EcalHit * > > ecal::CLUE::createLayers ( const std::vector< const ldmx::EcalHit * > & hits)

Definition at line 108 of file CLUE.cxx.

109 {
110 ldmx_log(trace) << "--- LAYER CREATION ---";
111 ldmx_log(trace) << "Number of layers: " << nbr_of_layers_;
112
113 // vector of layers, each layer having a vector of hits
114 // initialize with nbr_of_layers_ empty vectors
115 std::vector<std::vector<const ldmx::EcalHit*>> hits_per_layer(nbr_of_layers_);
116
117 // Track highest energy per layer for proper rho_c calculation
118 std::vector<double> layer_max_energies(nbr_of_layers_, 0.0);
119
120 // Clear any existing layer_rho_c_ values
121 layer_rho_c_.clear();
122
123 // This is rather ad-hoc, but this way it's still tunable via rhoc_ parameter
124 double rhoc_factor = rhoc_ / 250.;
125
126 for (const auto& hit : hits) {
127 ldmx::EcalID ecal_id(hit->getID());
128 // layer number from EcalID, starting at 0
129 int layer = ecal_id.layer();
130
131 if (layer >= nbr_of_layers_) {
132 ldmx_log(trace) << "Skipping hit in layer " << layer
133 << " (beyond nbr_of_layers_ = " << nbr_of_layers_ << ")";
134 continue;
135 }
136
137 // Track the highest energy in this specific layer
138 if (hit->getEnergy() > layer_max_energies[layer]) {
139 layer_max_energies[layer] = hit->getEnergy();
140 }
141
142 ldmx_log(trace) << " Adding hit with energy " << hit->getEnergy()
143 << " to layer " << layer;
144 hits_per_layer[layer].push_back(hit);
145 } // end of loop over hits
146
147 // Calculate rhoc for each layer based on that layer's maximum energy
148 for (int i = 0; i < nbr_of_layers_; i++) {
149 double rho_c = layer_max_energies[i] / rhoc_factor;
150 layer_rho_c_.push_back(rho_c);
151 ldmx_log(trace) << "Layer " << i << " has " << hits_per_layer[i].size()
152 << " hits, max energy " << layer_max_energies[i]
153 << ", rho_c " << rho_c;
154 }
155
156 ldmx_log(trace) << "Created " << hits_per_layer.size() << " layers";
157 return hits_per_layer;
158} // end of createLayers

◆ dist() [1/2]

template<typename T >
T ecal::CLUE::dist ( T x1,
T y1,
T x2,
T y2 )

Euclidean distance between two points.

Euclidean distance between two points Using x*x and std::sqrt since they are more specialized and faster than std::pow.

Template Parameters
Tfloating point type

Definition at line 22 of file CLUE.cxx.

22 {
23 auto delta_x = x1 - x2;
24 auto delta_y = y1 - y2;
25 auto r_square = delta_x * delta_x + delta_y * delta_y;
26 return std::sqrt(r_square);
27}

◆ dist() [2/2]

template<typename T >
T ecal::CLUE::dist ( T x1,
T y1,
T z1,
T x2,
T y2,
T z2 )

Definition at line 31 of file CLUE.cxx.

31 {
32 auto delta_x = x1 - x2;
33 auto delta_y = y1 - y2;
34 auto delta_z = z1 - z2;
35 auto r_square = delta_x * delta_x + delta_y * delta_y + delta_z * delta_z;
36 return std::sqrt(r_square);
37}

◆ electronSeparation()

void ecal::CLUE::electronSeparation ( std::vector< ldmx::EcalHit > hits)

Definition at line 44 of file CLUE.cxx.

44 {
45 std::vector<double> layer_thickness = {2., 3.5, 5.3, 5.3, 5.3, 5.3,
46 5.3, 5.3, 5.3, 5.3, 5.3, 10.5,
47 10.5, 10.5, 10.5, 10.5};
48 double air = 10.;
49 // sort hits in z
50 std::sort(hits.begin(), hits.end(),
51 [](const ldmx::EcalHit& a, const ldmx::EcalHit& b) {
52 return a.getZPos() < b.getZPos();
53 });
54
55 std::vector<ldmx::EcalHit> first_layers;
56 std::vector<IntermediateCluster> first_layer_clusters;
57 int layer_tag = 0;
58 double layer_z = hits[0].getZPos();
59 for (const auto& hit : hits) {
60 if (hit.getZPos() > layer_z + layer_thickness[layer_tag] + air) {
61 layer_tag++;
62 // if (layerTag > limit) break;
63 break;
64 }
65 first_layers.push_back(hit);
66 IntermediateCluster cluster(hit);
67 cluster.setLayer(layer_tag);
68 first_layer_clusters.push_back(cluster);
69 }
70 bool merge = false;
71 do {
72 merge = false;
73 for (int i = 0; i < first_layer_clusters.size(); i++) {
74 if (first_layer_clusters[i].empty()) continue;
75 // if (firstLayerClusters[i].energy() >= seedThreshold_) {
76 for (int j = i + 1; j < first_layer_clusters.size(); j++) {
77 if (first_layer_clusters[j].empty()) continue;
78 if (dist(first_layer_clusters[i].centroidX(),
79 first_layer_clusters[i].centroidY(),
80 first_layer_clusters[j].centroidX(),
81 first_layer_clusters[j].centroidY()) < 8.) {
82 first_layer_clusters[i].add(first_layer_clusters[j]);
83 first_layer_clusters[j].clear();
84 merge = true;
85 }
86 }
87 // } else break;
88 }
89 } while (merge);
90 ldmx_log(trace) << "--- ELECTRON SEPARATION ---";
91 for (int i = 0; i < first_layer_clusters.size(); i++) {
92 if (first_layer_clusters[i].empty()) continue;
93 ldmx_log(trace) << " Cluster " << i
94 << " x: " << first_layer_clusters[i].centroidX()
95 << " y: " << first_layer_clusters[i].centroidY();
96 for (int j = i + 1; j < first_layer_clusters.size(); j++) {
97 if (first_layer_clusters[j].empty()) continue;
98 auto d = dist(first_layer_clusters[i].centroidX(),
99 first_layer_clusters[i].centroidY(),
100 first_layer_clusters[j].centroidX(),
101 first_layer_clusters[j].centroidY());
102 ldmx_log(trace) << "Dist to cluster " << j << ": " << d;
103 }
104 }
105}

◆ getCentroidDistances()

std::vector< double > ecal::CLUE::getCentroidDistances ( ) const
inline

Definition at line 95 of file CLUE.h.

95 {
96 return centroid_distances_;
97 }

◆ getClusters()

std::vector< IntermediateCluster > ecal::CLUE::getClusters ( ) const
inline

Definition at line 103 of file CLUE.h.

103 {
104 return final_clusters_;
105 }

◆ getFirstLayerCentroids()

std::vector< IntermediateCluster > ecal::CLUE::getFirstLayerCentroids ( ) const
inline

Definition at line 109 of file CLUE.h.

109 {
110 return first_layer_centroids_;
111 }

◆ getInitialClusterNbr()

int ecal::CLUE::getInitialClusterNbr ( ) const
inline

Definition at line 101 of file CLUE.h.

101{ return initial_cluster_nbr_; }

◆ getNLoops()

int ecal::CLUE::getNLoops ( ) const
inline

Definition at line 99 of file CLUE.h.

99{ return clustering_loops_; }

◆ roundToDecimal()

float ecal::CLUE::roundToDecimal ( float x,
int num_decimal_precision_digits )

Definition at line 160 of file CLUE.cxx.

160 {
161 float power_of_10 = std::pow(10, num_decimal_precision_digits);
162 return std::round(x_ * power_of_10) / power_of_10;
163}

◆ setup()

std::vector< std::shared_ptr< CLUE::Density > > ecal::CLUE::setup ( const std::vector< const ldmx::EcalHit * > & hits)

Definition at line 165 of file CLUE.cxx.

166 {
167 std::vector<std::shared_ptr<Density>> densities;
168 std::map<std::pair<float, float>, std::shared_ptr<Density>> density_map;
169 event_centroid_ = IntermediateCluster();
170 ldmx_log(trace) << "--- SETUP ---";
171 ldmx_log(trace) << "Building densities";
172 for (const auto& hit : hits) {
173 // collapse z dimension
174 float x = roundToDecimal(hit->getXPos(), 4);
175 float y = roundToDecimal(hit->getYPos(), 4);
176 float z = roundToDecimal(hit->getZPos(), 4);
177 ldmx_log(trace) << " New hit { x: " << x << " y: " << y << "}"
178 << " (and z: " << z << ")";
179 std::pair<float, float> coords;
180 if (dc_ != 0 && nbr_of_layers_ > 1) {
181 // if more than one layer, divide hit into densities with side dc
182 double i = std::ceil(std::abs(x) / dc_);
183 double j = std::ceil(std::abs(y) / dc_);
184 if (x < 0) {
185 i = -i;
186 x = (i + 0.5) * dc_;
187 } else {
188 x = (i - 0.5) * dc_;
189 }
190 if (y < 0) {
191 j = -j;
192 y = (j + 0.5) * dc_;
193 } else {
194 y = (j - 0.5) * dc_;
195 }
196 coords = {i, j};
197 ldmx_log(trace) << " Index " << i << ", " << j << "; x: " << x
198 << " y: " << y;
199 } else {
200 // if just one layer, have all densities with the same x,y be in same
201 // density
202 coords = {x, y};
203 }
204
205 if (density_map.find(coords) == density_map.end()) {
206 density_map.emplace(coords, std::make_shared<CLUE::Density>(x, y));
207 ldmx_log(trace) << " * New density created";
208 } else {
209 ldmx_log(trace) << " --> Found density with x: "
210 << density_map[coords]->x_
211 << " y: " << density_map[coords]->y_;
212 }
213 density_map[coords]->hits_.push_back(hit);
214 density_map[coords]->total_energy_ += hit->getEnergy();
215 density_map[coords]->z_ += hit->getZPos();
216
217 event_centroid_.add(hit);
218 } // end of loop over hits
219
220 densities.reserve(density_map.size());
221 for (const auto& entry : density_map) {
222 densities.push_back(std::move(entry.second));
223 }
224 // sort according to energy
225 std::sort(densities.begin(), densities.end(),
226 [](const std::shared_ptr<CLUE::Density>& a,
227 const std::shared_ptr<CLUE::Density>& b) {
228 return a->total_energy_ > b->total_energy_;
229 });
230
231 ldmx_log(trace) << "Decide parents";
232
233 // decide delta_ and follower_of_
234 for (int i = 0; i < densities.size(); i++) {
235 densities[i]->index_ = i;
236 // avg z position
237 densities[i]->z_ = densities[i]->z_ / densities[i]->hits_.size();
238 ldmx_log(trace) << " Index: " << i << "; x: " << densities[i]->x_
239 << "; y: " << densities[i]->y_
240 << "; Energy: " << densities[i]->total_energy_;
241 // loop through all higher energy densities
242 for (int j = 0; j < i; j++) {
243 float distance_2d = dist(densities[i]->x_, densities[i]->y_,
244 densities[j]->x_, densities[j]->y_);
245 // condition energyJ > energyI but this should be baked in as we sorted
246 // according to energy
247 if ((distance_2d < dm_) && (distance_2d < densities[i]->delta_)) {
248 densities[i]->delta_ = distance_2d;
249 densities[i]->follower_of_ = j;
250 ldmx_log(trace) << " New parent, index " << j
251 << "; delta_2d: " << std::setprecision(4)
252 << distance_2d;
253 }
254 }
255 }
256 return densities;
257} // end of setup
void add(const HitType *hit)
Add a hit to the cluster using its stored position.

◆ setupForClue3D()

std::vector< std::shared_ptr< CLUE::Density > > ecal::CLUE::setupForClue3D ( )

Definition at line 459 of file CLUE.cxx.

459 {
460 ldmx_log(trace) << "--- LAYER SETUP ---";
461 std::vector<std::shared_ptr<CLUE::Density>> densities;
462 layer_rho_c_.clear();
463 for (int layer = 0; layer < nbr_of_layers_; layer++) {
464 ldmx_log(trace) << " LAYER " << layer << " with " << seeds_[layer].size()
465 << " seeds";
466 auto& seeds_in_current_layer = seeds_[layer];
467 double highest_energy = 0.;
468 for (const auto& current_seed : seeds_in_current_layer) {
469 // for each seed in layer
470 current_seed->layer_ = layer;
471 if (current_seed->total_energy_ > highest_energy)
472 highest_energy = current_seed->total_energy_;
473 ldmx_log(trace) << " Density with index " << current_seed->index_
474 << ", energy: " << current_seed->total_energy_
475 << " position (x,y)= {" << current_seed->x_ << ","
476 << current_seed->y_ << ")";
477 int depth = 1;
478 // decide delta_ and followerof from seeds in previous and next layer_
479 // do {
480 // depth++;
481 if ((layer - depth >= 0) && (layer - depth < seeds_.size())) {
482 ldmx_log(trace) << " Looking at pre-layer: " << layer - depth;
483 // look at previous layer
484 ldmx_log(trace) << " In previous layer... ";
485 auto& previous_layer = seeds_[layer - depth];
486 ldmx_log(trace) << " Got " << previous_layer.size() << " seeds";
487 for (const auto& prev_seed : previous_layer) {
488 // for each seed in previous layer
489 auto distance_2d_prev = dist(current_seed->x_, current_seed->y_,
490 prev_seed->x_, prev_seed->y_);
491 auto dz_prev = std::abs(current_seed->z_ - prev_seed->z_);
492 ldmx_log(trace) << " DeltaXY to index " << prev_seed->index_
493 << ": " << std::setprecision(4) << distance_2d_prev;
494 ldmx_log(trace) << " DeltaZ to index " << prev_seed->index_
495 << ": " << std::setprecision(4) << dz_prev;
496 if (prev_seed->total_energy_ > current_seed->total_energy_ &&
497 distance_2d_prev < current_seed->delta_ &&
498 dz_prev < current_seed->z_delta_) {
499 ldmx_log(trace) << " New parent: index " << prev_seed->index_
500 << " on layer " << layer - depth << "; energy "
501 << prev_seed->total_energy_;
502 ldmx_log(trace) << " New 2D distance to prev-layer: "
503 << std::setprecision(4) << distance_2d_prev;
504 ldmx_log(trace)
505 << " New delta Z: " << std::setprecision(4) << dz_prev;
506 current_seed->delta_ = distance_2d_prev;
507 current_seed->z_delta_ = dz_prev;
508 current_seed->follower_of_ = prev_seed->index_;
509 } else if (prev_seed->total_energy_ < current_seed->total_energy_) {
510 ldmx_log(trace) << " Breaking on index " << prev_seed->index_
511 << " with energy " << prev_seed->total_energy_;
512 break;
513 }
514 }
515 }
516
517 if (layer + depth < nbr_of_layers_ && layer + depth < seeds_.size()) {
518 ldmx_log(trace) << " Looking at post-layer: " << layer + depth;
519 auto& next_layer = seeds_[layer + depth];
520 ldmx_log(trace) << " Got " << next_layer.size() << " seeds";
521 for (const auto& next_seed : next_layer) {
522 auto distance_2d_next = dist(current_seed->x_, current_seed->y_,
523 next_seed->x_, next_seed->y_);
524 auto dz_next = std::abs(current_seed->z_ - next_seed->z_);
525 ldmx_log(trace) << " DeltaXY to index " << next_seed->index_
526 << ": " << std::setprecision(4) << distance_2d_next;
527 ldmx_log(trace) << " DeltaZ to index_" << next_seed->index_
528 << ": " << std::setprecision(4) << dz_next;
529 if (next_seed->total_energy_ > current_seed->total_energy_ &&
530 distance_2d_next < current_seed->delta_ &&
531 dz_next < current_seed->z_delta_) {
532 ldmx_log(trace) << " New parent: index_" << next_seed->index_
533 << " on layer " << layer + depth << "; energy "
534 << next_seed->total_energy_;
535 ldmx_log(trace) << " New 2D distance to next-layer: "
536 << std::setprecision(4) << distance_2d_next;
537 ldmx_log(trace)
538 << " New delta_Z: " << std::setprecision(4) << dz_next;
539 current_seed->delta_ = distance_2d_next;
540 current_seed->z_delta_ = dz_next;
541 current_seed->follower_of_ = next_seed->index_;
542 } else if (next_seed->total_energy_ < current_seed->total_energy_) {
543 ldmx_log(trace) << " Breaking on index_" << next_seed->index_
544 << " with energy " << next_seed->total_energy_;
545 break;
546 }
547 } // end loop on seeds in next layer
548 } // end of looking at next layer
549 // } while (currentLayer[i]->layerFollowerOf == -1 && (layer - depth >=
550 // 0 || layer + depth < nbr_of_layers_));
551 ldmx_log(trace) << " Done setting parents.";
552 densities.push_back(current_seed);
553 }
554 // TODO: This 2 needs to be configurable
555 layer_rho_c_.push_back(highest_energy / 2);
556 } // end loop over layers
557 return densities;
558} // end of setupForClue3D

Member Data Documentation

◆ centroid_distances_

std::vector<double> ecal::CLUE::centroid_distances_
private

Definition at line 143 of file CLUE.h.

◆ clustering_loops_

int ecal::CLUE::clustering_loops_
private

Definition at line 114 of file CLUE.h.

◆ dc_

double ecal::CLUE::dc_
private

Definition at line 118 of file CLUE.h.

◆ deltac_

double ecal::CLUE::deltac_
private

Definition at line 120 of file CLUE.h.

◆ deltao_

double ecal::CLUE::deltao_
private

Definition at line 121 of file CLUE.h.

◆ dm_

double ecal::CLUE::dm_
private

Definition at line 122 of file CLUE.h.

◆ event_centroid_

IntermediateCluster ecal::CLUE::event_centroid_
private

Definition at line 144 of file CLUE.h.

◆ final_clusters_

std::vector<IntermediateCluster> ecal::CLUE::final_clusters_
private

Definition at line 152 of file CLUE.h.

◆ first_layer_centroids_

std::vector<IntermediateCluster> ecal::CLUE::first_layer_centroids_
private

Definition at line 146 of file CLUE.h.

◆ initial_cluster_nbr_

int ecal::CLUE::initial_cluster_nbr_ {-1}
private

Definition at line 151 of file CLUE.h.

151{-1};

◆ layer_centroid_separations_

std::vector<std::pair<double, double> > ecal::CLUE::layer_centroid_separations_
private

Definition at line 153 of file CLUE.h.

◆ layer_delta_c_

std::vector<double> ecal::CLUE::layer_delta_c_
private

Definition at line 129 of file CLUE.h.

◆ layer_rho_c_

std::vector<double> ecal::CLUE::layer_rho_c_
private

Definition at line 128 of file CLUE.h.

◆ max_layers_

int ecal::CLUE::max_layers_ {32}
private

Definition at line 125 of file CLUE.h.

125{32};

◆ nbr_of_layers_

int ecal::CLUE::nbr_of_layers_
private

Definition at line 126 of file CLUE.h.

◆ radius_

std::vector<double> ecal::CLUE::radius_
private
Initial value:
{
5.723387467629167, 5.190678018534044, 5.927290663506518,
6.182560329200212, 7.907549398117859, 8.606100542857211,
10.93381822596916, 12.043201938160239, 14.784548371508041,
16.102403056546482, 18.986402399412817, 20.224453740305716,
23.048820910305643, 24.11202594672678, 26.765135236851666,
27.78700483852502, 30.291794353801293, 31.409870873194464,
33.91006482486666, 35.173073672355926, 38.172422630271,
40.880288341493205, 44.696485719120005, 49.23802839743545,
53.789910813378675, 60.87843355562641, 66.32931132415688,
75.78117972604727, 86.04697356716805, 96.90360704034346}

Definition at line 131 of file CLUE.h.

131 {
132 5.723387467629167, 5.190678018534044, 5.927290663506518,
133 6.182560329200212, 7.907549398117859, 8.606100542857211,
134 10.93381822596916, 12.043201938160239, 14.784548371508041,
135 16.102403056546482, 18.986402399412817, 20.224453740305716,
136 23.048820910305643, 24.11202594672678, 26.765135236851666,
137 27.78700483852502, 30.291794353801293, 31.409870873194464,
138 33.91006482486666, 35.173073672355926, 38.172422630271,
139 40.880288341493205, 44.696485719120005, 49.23802839743545,
140 53.789910813378675, 60.87843355562641, 66.32931132415688,
141 75.78117972604727, 86.04697356716805, 96.90360704034346};

◆ reclustering_

bool ecal::CLUE::reclustering_
private

Definition at line 116 of file CLUE.h.

◆ rhoc_

double ecal::CLUE::rhoc_
private

Definition at line 119 of file CLUE.h.

◆ seed_index_

int ecal::CLUE::seed_index_ {0}
private

Definition at line 148 of file CLUE.h.

148{0};

◆ seeds_

std::vector<std::vector<std::shared_ptr<Density> > > ecal::CLUE::seeds_
private

Definition at line 149 of file CLUE.h.


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