234 const std::vector<ldmx::EcalHit>& hits) {
237 layer_of_.assign(hits.size(), 0);
238 std::map<int, std::vector<int>> by_layer;
239 for (std::size_t i = 0; i < hits.size(); i++) {
240 if (hits[i].getEnergy() <= p_.hit_ecut_ || hits[i].getEnergy() <= 0)
243 by_layer[layer_of_[i]].push_back(i);
245 for (
const auto& [layer, idx] : by_layer) cluster2D(idx);
249 core_.assign(hits.size(), 0);
250 for (
const auto& lc : lcs_)
252 for (
int h : lc.hits_) core_[h] = 1;
256 for (
const auto& lc : lcs_) ncl = std::max(ncl, lc.cid_ + 1);
257 std::vector<std::vector<int>> members(ncl);
258 for (
const auto& lc : lcs_)
260 members[lc.cid_].insert(members[lc.cid_].end(), lc.hits_.begin(),
262 auto fit_all = [&](std::vector<Cluster>& cls,
263 const std::vector<std::vector<int>>& mem) {
264 cls.assign(mem.size(),
Cluster{});
265 for (std::size_t k = 0; k < mem.size(); k++)
266 fitAxis(cls[k], mem[k], std::vector<double>(mem[k].size(), 1.));
268 std::vector<Cluster> cls;
269 fit_all(cls, members);
272 for (
const auto& lc : lcs_) {
273 if (lc.cid_ >= 0)
continue;
275 double best_d = p_.attach_radius_;
276 for (std::size_t k = 0; k < cls.size(); k++) {
277 double d = dist(lc.x_, lc.y_, cls[k].axisX(lc.z_), cls[k].axisY(lc.z_));
284 members[best].insert(members[best].end(), lc.hits_.begin(),
287 members.push_back(lc.hits_);
288 for (
int h : lc.hits_) core_[h] = 1;
291 fit_all(cls, members);
295 std::vector<int> order(cls.size());
296 std::iota(order.begin(), order.end(), 0);
297 std::sort(order.begin(), order.end(),
298 [&](
int a,
int b) { return cls[a].e_ < cls[b].e_; });
299 std::vector<double> esum(cls.size());
300 std::vector<int> nlay(cls.size());
301 for (std::size_t k = 0; k < cls.size(); k++) {
304 for (
int h : members[k]) ls.push_back(layer_of_[h]);
305 std::sort(ls.begin(), ls.end());
306 nlay[k] = std::unique(ls.begin(), ls.end()) - ls.begin();
308 for (
int sat : order) {
310 double best_d = p_.sc_radius_;
311 bool short_sat = nlay[sat] < p_.sc_min_layers_;
312 for (std::size_t k = 0; k < cls.size(); k++) {
314 if (
static_cast<int>(k) == sat || members[k].empty() ||
315 esum[k] <= esum[sat] || nlay[k] < p_.sc_min_layers_ ||
316 (!short_sat && esum[sat] >= p_.sc_ratio_ * esum[k]))
318 double d = dist(cls[sat].x_, cls[sat].y_, cls[k].axisX(cls[sat].z_),
319 cls[k].axisY(cls[sat].z_));
325 if (best < 0)
continue;
326 members[best].insert(members[best].end(), members[sat].begin(),
328 for (
int h : members[sat]) core_[h] = 0;
329 esum[best] += esum[sat];
330 members[sat].clear();
332 std::vector<std::vector<int>> left;
333 for (
auto& m : members)
334 if (!m.empty()) left.push_back(std::move(m));
335 members = std::move(left);
336 fit_all(cls, members);
340 std::vector<std::vector<int>> kept;
341 for (std::size_t k = 0; k < cls.size(); k++)
342 if (cls[k].e_ >= p_.min_cluster_energy_) kept.push_back(members[k]);
343 members = std::move(kept);
344 fit_all(cls, members);
345 std::vector<std::vector<double>> fracs(members.size());
346 for (std::size_t k = 0; k < members.size(); k++)
347 fracs[k].assign(members[k].size(), 1.);
350 std::vector<int> big;
351 for (std::size_t k = 0; k < cls.size(); k++)
352 if (cls[k].e_ >= p_.share_min_energy_) big.push_back(k);
353 if (p_.share_ && big.size() > 1) {
354 std::vector<int> shared_hits;
356 shared_hits.insert(shared_hits.end(), members[k].begin(),
358 std::vector<std::vector<int>> mem(big.size());
359 std::vector<std::vector<double>> fr(big.size());
360 for (
int it = 0; it < p_.share_iters_; it++) {
361 for (
auto& v : mem) v.clear();
362 for (
auto& v : fr) v.clear();
363 for (
int h : shared_hits) {
364 double hz = hits[h].getZPos();
365 double lam =
lambda(layer_of_[h]);
366 std::vector<double> w(big.size());
368 for (std::size_t b = 0; b < big.size(); b++) {
369 const auto& c = cls[big[b]];
370 double d = dist(hits[h].getXPos(), hits[h].getYPos(), c.axisX(hz),
372 w[b] = c.e_ * std::exp(-d / lam);
378 double dmin = std::numeric_limits<double>::max();
379 for (std::size_t b = 0; b < big.size(); b++) {
380 const auto& c = cls[big[b]];
381 double d = dist(hits[h].getXPos(), hits[h].getYPos(), c.axisX(hz),
388 w.assign(big.size(), 0.);
391 for (std::size_t b = 0; b < big.size(); b++) {
392 double f = w[b] / sw;
393 if (f < 1e-4)
continue;
398 for (std::size_t b = 0; b < big.size(); b++) {
399 fitAxis(cls[big[b]], mem[b], fr[b]);
402 for (std::size_t b = 0; b < big.size(); b++) {
403 members[big[b]] = mem[b];
404 fracs[big[b]] = fr[b];
407 for (std::size_t i = 0; i < big.size(); i++) {
408 for (std::size_t j = i + 1; j < big.size(); j++) {
409 auto& a = cls[big[i]];
410 auto& b = cls[big[j]];
411 if (members[big[i]].empty() || members[big[j]].empty())
continue;
412 double zz = a.e_ < b.e_ ? a.z_ : b.z_;
413 double d = dist(a.axisX(zz), a.axisY(zz), b.axisX(zz), b.axisY(zz));
416 d < p_.ghost_dist_ &&
417 std::min(a.e_, b.e_) < p_.ghost_ratio_ * std::max(a.e_, b.e_);
418 if (d > p_.coincide_dist_ && !ghost)
continue;
419 std::map<int, double> f;
420 for (std::size_t k = 0; k < members[big[i]].size(); k++)
421 f[members[big[i]][k]] += fracs[big[i]][k];
422 for (std::size_t k = 0; k < members[big[j]].size(); k++)
423 f[members[big[j]][k]] += fracs[big[j]][k];
424 members[big[i]].clear();
425 fracs[big[i]].clear();
426 for (
auto& [h, v] : f) {
427 members[big[i]].push_back(h);
428 fracs[big[i]].push_back(v);
430 members[big[j]].clear();
431 fracs[big[j]].clear();
432 fitAxis(a, members[big[i]], fracs[big[i]]);
438 std::vector<Cluster> out;
439 for (std::size_t k = 0; k < members.size(); k++) {
441 fitAxis(c, members[k], fracs[k]);
442 if (c.e_ < p_.min_cluster_energy_)
continue;
443 c.hits_ = members[k];
445 double sxx{0}, syy{0}, szz{0}, sx{0}, sy{0}, e0{0};
446 for (std::size_t i = 0; i < c.hits_.size(); i++) {
447 const auto& h = hits[c.hits_[i]];
448 double e = c.frac_[i] * h.getEnergy();
449 sx += e * h.getXPos();
450 sy += e * h.getYPos();
451 sxx += e * h.getXPos() * h.getXPos();
452 syy += e * h.getYPos() * h.getYPos();
453 szz += e * (h.getZPos() - c.z_) * (h.getZPos() - c.z_);
454 if (layer_of_[c.hits_[i]] == 0) {
455 c.x0_ += e * h.getXPos();
456 c.y0_ += e * h.getYPos();
463 c.rms_x_ = std::sqrt(std::max(0., sxx / c.e_ - sx * sx));
464 c.rms_y_ = std::sqrt(std::max(0., syy / c.e_ - sy * sy));
465 c.rms_z_ = std::sqrt(szz / c.e_);
470 out.push_back(std::move(c));
472 std::sort(out.begin(), out.end(),