File indexing completed on 2026-07-08 07:40:56
0001
0002
0003
0004 #include <edm4eic/Track.h>
0005 #include <edm4eic/TrackPoint.h>
0006 #include <edm4hep/utils/vector_utils.h>
0007 #include <podio/ObjectID.h>
0008 #include <podio/RelationRange.h>
0009 #include <podio/detail/Link.h>
0010 #include <podio/detail/LinkCollectionImpl.h>
0011 #include <cmath>
0012 #include <cstdint>
0013 #include <limits>
0014 #include <map>
0015 #include <memory>
0016 #include <tuple>
0017 #include <utility>
0018 #include <vector>
0019
0020 #include "TrackClusterSubtractor.h"
0021 #include "algorithms/interfaces/CompareObjectID.h"
0022 #include "algorithms/particle_flow/TrackClusterSubtractorConfig.h"
0023
0024 namespace eicrecon {
0025
0026
0027
0028
0029
0030
0031
0032
0033
0034
0035
0036
0037
0038
0039
0040 void TrackClusterSubtractor::process(const TrackClusterSubtractor::Input& input,
0041 const TrackClusterSubtractor::Output& output) const {
0042
0043
0044 const auto [in_matches, in_clusters, in_projections] = input;
0045 #if EDM4EIC_BUILD_VERSION >= EDM4EIC_VERSION(8, 7, 0)
0046 auto [out_remnants, out_expectants, out_links, out_matches] = output;
0047 #else
0048 auto [out_remnants, out_expectants, out_matches] = output;
0049 #endif
0050
0051
0052 if (in_clusters->size() == 0) {
0053 debug("No clusters in collection");
0054 return;
0055 }
0056
0057
0058 if (in_matches->size() == 0) {
0059 debug("No matched tracks in collection.");
0060 }
0061
0062
0063
0064
0065 std::map<edm4eic::Cluster, segment_vector, CompareObjectID<edm4eic::Cluster>>
0066 mapClusterToProjections;
0067 for (const auto& match : *in_matches) {
0068 for (const auto& project : *in_projections) {
0069
0070
0071 if (match.getTrack() != project.getTrack()) {
0072 continue;
0073 } else {
0074 mapClusterToProjections[match.getCluster()].push_back(project);
0075 }
0076
0077 }
0078 }
0079 debug("Built map of clusters-onto-tracks, size = {}", mapClusterToProjections.size());
0080
0081
0082
0083
0084 for (const auto& cluster : *in_clusters) {
0085 if (mapClusterToProjections.count(cluster) == 0) {
0086 auto remain_cluster = cluster.clone();
0087 out_remnants->push_back(remain_cluster);
0088 }
0089 }
0090 debug("Finished copying unmatched clusters to remnants, {} remnant clusters",
0091 out_remnants->size());
0092
0093
0094
0095
0096 for (const auto& [cluster, projections] : mapClusterToProjections) {
0097
0098
0099 const double eTrackSum = sum_track_energy(projections);
0100 const double eToSubtract = m_cfg.energyFractionToSubtract * eTrackSum;
0101 const double eSubtracted = cluster.getEnergy() - eToSubtract;
0102 trace("Subtracted {} GeV from cluster with {} GeV", eToSubtract, cluster.getEnergy());
0103
0104
0105
0106 const bool isGreaterThan = is_track_energy_greater_than_calo(eSubtracted);
0107 const double eSubtractedToUse = isGreaterThan ? 0. : eSubtracted;
0108
0109
0110
0111
0112 if (!isGreaterThan) {
0113 auto remain_cluster = cluster.clone();
0114 remain_cluster.setEnergy(eSubtractedToUse);
0115 out_remnants->push_back(remain_cluster);
0116 trace("Created remnant cluster with {} GeV", remain_cluster.getEnergy());
0117 }
0118
0119
0120
0121
0122 auto expect_cluster = cluster.clone();
0123 expect_cluster.setEnergy(cluster.getEnergy() - eSubtractedToUse);
0124 out_expectants->push_back(expect_cluster);
0125 trace("Created expected cluster with {} GeV (originally {} GeV)", expect_cluster.getEnergy(),
0126 cluster.getEnergy());
0127
0128
0129 for (const auto& project : projections) {
0130 #if EDM4EIC_BUILD_VERSION >= EDM4EIC_VERSION(8, 7, 0)
0131 edm4eic::MutableTrackClusterLink link = out_links->create();
0132 link.setFrom(expect_cluster);
0133 link.setTo(project.getTrack());
0134 link.setWeight(1.0);
0135 #endif
0136
0137 edm4eic::MutableTrackClusterMatch match = out_matches->create();
0138 match.setCluster(expect_cluster);
0139 match.setTrack(project.getTrack());
0140 match.setWeight(1.0);
0141 trace("Matched expected cluster {} to track {}", expect_cluster.getObjectID().index,
0142 project.getTrack().getObjectID().index);
0143 }
0144 }
0145 debug("Finished subtraction, {} remnant clusters and {} expected clusters", out_remnants->size(),
0146 out_expectants->size());
0147
0148 }
0149
0150
0151
0152
0153
0154
0155
0156
0157
0158
0159 double TrackClusterSubtractor::sum_track_energy(const segment_vector& projections) const {
0160
0161 double energySum = 0.0;
0162 for (const auto& project : projections) {
0163
0164
0165 double momentum = 0.0;
0166 bool momentum_valid = false;
0167 for (const auto& point : project.getPoints()) {
0168 if (point.surface != m_cfg.surfaceToUse) {
0169 continue;
0170 } else {
0171 momentum = edm4hep::utils::magnitude(point.momentum);
0172 momentum_valid = true;
0173 break;
0174 }
0175 }
0176 if (!momentum_valid) {
0177 continue;
0178 }
0179
0180
0181 int pdgToUse = project.getTrack().getPdg();
0182 if (pdgToUse == 0) {
0183 pdgToUse = m_cfg.defaultPDG;
0184 }
0185 const double mass = m_parSvc.particle(pdgToUse).mass;
0186
0187
0188 energySum += std::sqrt((momentum * momentum) + (mass * mass));
0189 }
0190
0191 trace("Sum of track energy = {} GeV", energySum);
0192 return energySum;
0193
0194 }
0195
0196
0197
0198
0199
0200
0201
0202
0203
0204
0205
0206
0207
0208 bool TrackClusterSubtractor::is_track_energy_greater_than_calo(const double difference) const {
0209
0210
0211 if (difference < 0) {
0212 return true;
0213 }
0214
0215
0216 bool isGreaterThan = false;
0217 if (m_cfg.doNSigmaCut) {
0218
0219
0220 const double totalVariance = (m_cfg.trackResolution * m_cfg.trackResolution) +
0221 (m_cfg.calorimeterResolution * m_cfg.calorimeterResolution);
0222 const uint32_t nSigma2 =
0223 static_cast<uint32_t>(std::floor((difference * difference) / totalVariance));
0224 const uint32_t nSigmaMax2 = m_cfg.nSigmaMax * m_cfg.nSigmaMax;
0225
0226 isGreaterThan = (nSigma2 < nSigmaMax2);
0227 if (isGreaterThan) {
0228 trace(
0229 "Within {} NSigma^2, track energy sum greater than calorimeter cluster: difference = {} "
0230 "GeV, nSigma^2 = {}",
0231 nSigmaMax2, difference, nSigma2);
0232 }
0233 } else {
0234 isGreaterThan = difference < std::numeric_limits<double>::epsilon();
0235 if (isGreaterThan) {
0236 trace("Track energy sum greater than calorimeter cluster: difference = {} GeV", difference);
0237 }
0238 }
0239 return isGreaterThan;
0240
0241 }
0242 }