LDMX Software
DBScanClusterBuilder.cxx
1// #include "DetDescr/EcalGeometry.h"
2// #include "Recon/Event/HgcrocDigiCollection.h"
4
5#include <set>
6
7#include "TFitResult.h"
8#include "TGraph.h"
9
10namespace recon {
11
12DBScanClusterBuilder::DBScanClusterBuilder() {
13 min_hit_energy_ = 0;
14 cluster_hit_dist_ = 100;
15 cluster_z_bias_ = 1; // defaults to 1
16 min_cluster_hit_mult_ = 2;
17}
18
19DBScanClusterBuilder::DBScanClusterBuilder(float minHitEnergy,
20 float clusterHitDist,
21 float clusterZBias,
22 float minClusterHitMult) {
23 min_hit_energy_ = minHitEnergy;
24 cluster_hit_dist_ = clusterHitDist;
25 cluster_z_bias_ = clusterZBias; // clustering bias in the z_ direction
26 min_cluster_hit_mult_ = minClusterHitMult;
27}
28
29std::vector<std::vector<const ldmx::CalorimeterHit*> >
30DBScanClusterBuilder::runDBSCAN(
31 const std::vector<const ldmx::CalorimeterHit*>& hits_) {
32 const int n = hits_.size();
33 std::vector<std::vector<const ldmx::CalorimeterHit*> > idx_clusters;
34 std::vector<unsigned int> tried;
35 tried.reserve(n);
36 std::vector<unsigned int> used;
37 used.reserve(n);
38 for (unsigned int i = 0; i < n; i++) {
39 if (isIn(i, tried)) continue;
40 tried.push_back(i);
41 ldmx_log(debug) << "trying " << i;
42 if (hits_[i]->getEnergy() < min_hit_energy_) continue;
43 std::set<unsigned int> neighbors;
44 unsigned int n_nearby = 1;
45 // find neighbors
46 for (unsigned int j = 0; j < n; j++) {
47 if (i != j &&
48 dist(hits_[i], hits_[j]) < cluster_hit_dist_) { // pair-wise distance
49 neighbors.insert(j);
50 if (hits_[j]->getEnergy() >= min_hit_energy_) n_nearby++;
51 }
52 }
53 if (n_nearby >= min_cluster_hit_mult_) {
54 std::vector<const ldmx::CalorimeterHit*> idx_cluster{
55 hits_[i]}; // start a cluster
56 used.push_back(i);
57 ldmx_log(debug) << "- starting a cluster from " << i;
58 for (unsigned int j : neighbors) {
59 if (!isIn(j, tried)) {
60 tried.push_back(j);
61 ldmx_log(debug) << "== tried " << j;
62 std::vector<unsigned int> neighbors2;
63 for (unsigned int k = 0; k < n; k++) {
64 if (dist(hits_[k], hits_[j]) < cluster_hit_dist_) {
65 neighbors2.push_back(k);
66 }
67 }
68 for (unsigned int k : neighbors2) neighbors.insert(k);
69 }
70 if (!isIn(j, used)) {
71 ldmx_log(debug) << "== used " << j;
72 used.push_back(j);
73 idx_cluster.push_back(hits_[j]);
74 }
75 }
76 idx_clusters.push_back(idx_cluster);
77 }
78 }
79 ldmx_log(debug) << "done. writing this many clusters out: "
80 << idx_clusters.size();
81 return idx_clusters;
82}
83
84void DBScanClusterBuilder::fillClusterInfoFromHits(
85 ldmx::CaloCluster* cl, std::vector<const ldmx::CalorimeterHit*> hits_,
86 bool logEnergyWeight, bool saveHitContribs) {
87 float e(0), x(0), y(0), z(0), xx(0), yy(0), zz(0), n(0);
88 float w = 1; // weight
89 float sumw = 0;
90 std::vector<float> raw_xvals{};
91 std::vector<float> raw_yvals{};
92 std::vector<float> raw_zvals{};
93 std::vector<float> raw_evals{};
94 std::vector<const ldmx::CalorimeterHit*> constituent_hits;
95
96 for (const ldmx::CalorimeterHit* h : hits_) {
97 if (h->getEnergy() < min_hit_energy_) continue;
98 if (logEnergyWeight) w = log(h->getEnergy()) - log(min_hit_energy_);
99 e += h->getEnergy();
100 x += w * h->getXPos();
101 y += w * h->getYPos();
102 z += w * h->getZPos();
103 xx += w * h->getXPos() * h->getXPos();
104 yy += w * h->getYPos() * h->getYPos();
105 zz += w * h->getZPos() * h->getZPos();
106 n += 1;
107 sumw += w;
108 if (saveHitContribs) {
109 raw_xvals.push_back(h->getXPos());
110 raw_yvals.push_back(h->getYPos());
111 raw_zvals.push_back(h->getZPos());
112 raw_evals.push_back(h->getEnergy());
113 constituent_hits.emplace_back(h);
114 }
115 } // over hits_
116 x /= sumw; // now is <x_>
117 y /= sumw;
118 z /= sumw;
119 xx /= sumw; // now is <x_^2>
120 yy /= sumw;
121 zz /= sumw;
122 xx = sqrt(xx - x * x); // now is sqrt(<x_^2>-<x_>^2)
123 yy = sqrt(yy - y * y);
124 zz = sqrt(zz - z * z);
125 cl->setEnergy(e);
126 cl->setNHits(n);
127 cl->setCentroidXYZ(x, y, z);
128 cl->setRMSXYZ(xx, yy, zz);
129 if (saveHitContribs) {
130 cl->setHitValsX(raw_xvals);
131 cl->setHitValsY(raw_yvals);
132 cl->setHitValsZ(raw_zvals);
133 cl->setHitValsE(raw_evals);
134 cl->addHits(constituent_hits); // associate used hits_ to cluster
135 }
136
137 if (raw_xvals.size() > 2) {
138 // skip fits for 'vertical' clusters
139 std::vector<float> sorted_z = raw_zvals;
140 std::sort(sorted_z.begin(), sorted_z.end());
141 if ((sorted_z.size() > 2) and (sorted_z.back() - sorted_z.front() > 1e3)) {
142 for (int i = 0; i < raw_xvals.size(); i++) { // mean subtract
143 raw_xvals[i] = raw_xvals[i] - x;
144 raw_yvals[i] = raw_yvals[i] - y;
145 raw_zvals[i] = raw_zvals[i] - z;
146 }
147
148 TGraph gxz(raw_zvals.size(), raw_zvals.data(), raw_xvals.data());
149 auto r_xz = gxz.Fit("pol1", "SQ"); // p0 + x_*p1
150 cl->setDXDZ(r_xz->Value(1));
151 cl->setEDXDZ(r_xz->ParError(1));
152
153 TGraph gyz(raw_zvals.size(), raw_zvals.data(), raw_yvals.data());
154 auto r_yz = gyz.Fit("pol1", "SQ"); // p0 + x_*p1
155 cl->setDYDZ(r_yz->Value(1));
156 cl->setEDYDZ(r_yz->ParError(1));
157 }
158 }
159 return;
160}
161
162} // namespace recon
Implementation of DBSCAN clustering algo.
Stores cluster information from the ECal.
Definition CaloCluster.h:25
void setNHits(int nHits)
Sets total number of hits in the cluster.
Definition CaloCluster.h:64
void addHits(const std::vector< const ldmx::CalorimeterHit * > hitsVec)
Take in the hits that make up the cluster.
void setCentroidXYZ(double centroid_x, double centroid_y, double centroid_z)
Sets the three coordinates of the cluster centroid.
Definition CaloCluster.h:84
void setEnergy(double energy)
Sets total energy for the cluster.
Definition CaloCluster.h:58
Represents a reconstructed hit in a calorimeter cell within the detector.