12 double cluster_threshold,
double noise_sigma_adc,
13 double mean_time_ns,
double time_window_ns,
14 double neighbor_delta_t_ns,
double max_chi2_ndf)
15 : seed_threshold_(seed_threshold),
16 neighbor_threshold_(neighbor_threshold),
17 cluster_threshold_(cluster_threshold),
18 noise_sigma_adc_(noise_sigma_adc),
19 mean_time_ns_(mean_time_ns),
20 time_window_ns_(time_window_ns),
21 neighbor_delta_t_ns_(neighbor_delta_t_ns),
22 max_chi2_ndf_(max_chi2_ndf) {}
51 const std::vector<ldmx::FittedSiStripHit>& hits)
const {
56 std::map<int, const ldmx::FittedSiStripHit*> channel_map;
57 for (
const auto& h : hits) {
58 const int ch = h.getStripID();
59 auto it = channel_map.find(ch);
60 if (it == channel_map.end()) {
64 if (std::abs(h.
getT0() - mean_time_ns_) <
65 std::abs(it->second->getT0() - mean_time_ns_)) {
80 std::set<int> clusterable_set;
81 std::vector<int> seed_channels;
83 for (
const auto& [ch, hp] : channel_map) {
84 const double amp = hp->getAmplitude();
86 if (amp >= neighbor_threshold_ * noise) {
87 clusterable_set.insert(ch);
89 if (amp >= seed_threshold_ * noise && passesSeedCuts(*hp)) {
90 seed_channels.push_back(ch);
95 std::sort(seed_channels.begin(), seed_channels.end(), [&](
int a,
int b) {
96 return channel_map.at(a)->getAmplitude() >
97 channel_map.at(b)->getAmplitude();
103 std::vector<ClusterCandidate> clusters;
105 for (
int seed_ch : seed_channels) {
107 if (clusterable_set.find(seed_ch) == clusterable_set.end())
continue;
110 double cluster_weighted_t = 0.0;
111 double cluster_total_amp = 0.0;
112 double cluster_noise_sq = 0.0;
114 std::deque<int> unchecked;
115 unchecked.push_back(seed_ch);
116 clusterable_set.erase(seed_ch);
118 while (!unchecked.empty()) {
119 const int cur_ch = unchecked.front();
120 unchecked.pop_front();
127 cand.strip_ids.push_back(cur_ch);
128 cluster_total_amp += amp;
129 cluster_weighted_t += amp * hit.
getT0();
130 cluster_noise_sq += noise * noise;
133 for (
int delta : {-1, +1}) {
134 const int nb_ch = cur_ch + delta;
135 if (clusterable_set.find(nb_ch) == clusterable_set.end())
continue;
138 if (!passesNeighborCuts(*channel_map.at(nb_ch), cluster_weighted_t,
139 cluster_total_amp)) {
143 unchecked.push_back(nb_ch);
144 clusterable_set.erase(nb_ch);
149 if (cluster_noise_sq <= 0.0)
continue;
150 if (cluster_total_amp / std::sqrt(cluster_noise_sq) < cluster_threshold_) {
157 double sum_amp_strip = 0.0;
158 for (
int ch : cand.strip_ids) {
159 sum_amp_strip += channel_map.at(ch)->getAmplitude() * ch;
164 cand.
time_ns = cluster_weighted_t / cluster_total_amp;
165 cand.n_strips =
static_cast<int>(cand.strip_ids.size());
172 double sum_amp_dsq = 0.0;
173 for (
int ch : cand.strip_ids) {
175 sum_amp_dsq += channel_map.at(ch)->getAmplitude() * d * d;
177 constexpr double k_single_strip_sigma = 1.0 / 3.4641;
178 const double rms = std::sqrt(sum_amp_dsq / cluster_total_amp);
179 cand.
sigma_strip = (rms > 0.0) ? rms : k_single_strip_sigma;
180 cand.layer_id = channel_map.at(seed_ch)->getLayerID();
182 clusters.push_back(std::move(cand));
StripClusterer(double seed_threshold=4.0, double neighbor_threshold=3.0, double cluster_threshold=4.0, double noise_sigma_adc=5.0, double mean_time_ns=0.0, double time_window_ns=-1.0, double neighbor_delta_t_ns=-1.0, double max_chi2_ndf=-1.0)