Skip to content

Commit f46fc94

Browse files
qunibpre-commit-ci[bot]github-actions[bot]wdconinc
authored
Fix missing photon reconstruction caused by charged track overlap in MatchClusters.cc (#2154)
Previously, some photons that overlapped with charged tracks were being incorrectly discarded, leading to reduced reconstruction efficiency. This change adjusts the matching logic to retain valid photons without affecting charged particle suppression. ### Briefly, what does this PR introduce? This PR improves the cluster-to-MC association logic in MatchClusters by selecting the best MC particle per cluster based on association weight, instead of taking the first match found. Default behavior is slightly changed for clusters with multiple MC associations; otherwise, results are identical. No API or function signature changes are required for users. This code change : 1. Builds a map keyed by cluster object index, storing the best-associated MC id and its weight. 2. When matching charged tracks, it only removes a cluster if that cluster's best association is to that charged MC particle (and chooses the best cluster for that MC by highest association weight if multiple clusters claim the same MC). Remaining clusters are treated as neutrals. ### What kind of change does this PR introduce? - [ ] Bug fix (issue #__) - [ ] New feature (issue #__) - [ ] Documentation update - [ ] Other: __ ### Please check if this PR fulfills the following: - [ ] Tests for the changes have been added - [ ] Documentation has been added / updated - [ ] Changes have been communicated to collaborators ### Does this PR introduce breaking changes? What changes might users need to make to their code? ### Does this PR change default behavior? --------- Co-authored-by: pre-commit-ci[bot] <66853113+pre-commit-ci[bot]@users.noreply.github.com> Co-authored-by: github-actions[bot] <41898282+github-actions[bot]@users.noreply.github.com> Co-authored-by: Wouter Deconinck <[email protected]>
1 parent 65ca478 commit f46fc94

File tree

1 file changed

+35
-16
lines changed

1 file changed

+35
-16
lines changed

src/algorithms/reco/MatchClusters.cc

Lines changed: 35 additions & 16 deletions
Original file line numberDiff line numberDiff line change
@@ -17,7 +17,9 @@
1717
#include <podio/ObjectID.h>
1818
#include <cmath>
1919
#include <gsl/pointers>
20+
#include <iterator>
2021
#include <map>
22+
#include <utility>
2123

2224
#include "MatchClusters.h"
2325

@@ -119,43 +121,60 @@ void MatchClusters::process(const MatchClusters::Input& input,
119121
}
120122

121123
// get a map of mcID --> cluster
122-
// input: clusters --> all clusters
124+
// For each cluster, pick the best associated MC particle by association weight.
125+
// Returns a map keyed by mcID and valued with the selected cluster.
123126
std::map<int, edm4eic::Cluster> MatchClusters::indexedClusters(
124127
const edm4eic::ClusterCollection* clusters,
125128
const edm4eic::MCRecoClusterParticleAssociationCollection* associations) const {
126129

127-
std::map<int, edm4eic::Cluster> matched = {};
130+
// temporary map: mcID -> (cluster, weight) so we can choose the cluster with highest weight per mcID
131+
std::map<int, std::pair<edm4eic::Cluster, float>> bestForMc;
128132

129-
// loop over clusters
133+
// loop over clusters and pick their best MC association by weight
130134
for (const auto cluster : *clusters) {
131135

132-
int mcID = -1;
136+
int bestMcID = -1;
137+
float bestWeight = -1.F;
133138

134-
// find associated particle
139+
// find best associated MC particle for this cluster (largest association weight)
135140
for (const auto assoc : *associations) {
136141
if (assoc.getRec() == cluster) {
137-
mcID = assoc.getSim().getObjectID().index;
138-
break;
142+
const int candMcID = assoc.getSim().getObjectID().index;
143+
const float w = assoc.getWeight();
144+
if (w > bestWeight) {
145+
bestWeight = w;
146+
bestMcID = candMcID;
147+
}
139148
}
140149
}
141150

142-
trace(" --> Found cluster with mcID {} and energy {}", mcID, cluster.getEnergy());
151+
trace(" --> Found cluster with best mcID {} weight {} and energy {}", bestMcID, bestWeight,
152+
cluster.getEnergy());
143153

144-
if (mcID < 0) {
154+
if (bestMcID < 0) {
145155
trace(" --> WARNING: no valid MC truth link found, skipping cluster...");
146156
continue;
147157
}
148158

149-
const bool duplicate = matched.contains(mcID);
150-
if (duplicate) {
151-
trace(" --> WARNING: this is a duplicate mcID, keeping the higher energy cluster");
152-
153-
if (cluster.getEnergy() < matched[mcID].getEnergy()) {
154-
continue;
159+
// For this mcID, keep the cluster with the highest association weight (tie-break by energy).
160+
auto it = bestForMc.find(bestMcID);
161+
if (it == bestForMc.end()) {
162+
bestForMc.emplace(bestMcID, std::make_pair(cluster, bestWeight));
163+
} else {
164+
const float existingWeight = it->second.second;
165+
if (bestWeight > existingWeight ||
166+
(bestWeight == existingWeight && cluster.getEnergy() > it->second.first.getEnergy())) {
167+
it->second = std::make_pair(cluster, bestWeight);
155168
}
156169
}
157-
matched[mcID] = cluster;
158170
}
171+
172+
// Convert to the old API: map<int, edm4eic::Cluster>
173+
std::map<int, edm4eic::Cluster> matched;
174+
for (const auto& kv : bestForMc) {
175+
matched.emplace(kv.first, kv.second.first);
176+
}
177+
159178
return matched;
160179
}
161180

0 commit comments

Comments
 (0)