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