Warning, file /EICrecon/src/algorithms/reco/MatchClusters.cc was not indexed
or was modified since last indexation (in which case cross-reference links may be missing, inaccurate or erroneous).
0001
0002
0003
0004
0005
0006
0007
0008 #include <algorithms/logger.h>
0009 #include <edm4eic/ClusterCollection.h>
0010 #include <edm4eic/EDM4eicVersion.h>
0011 #include <edm4eic/MCRecoClusterParticleAssociationCollection.h>
0012 #include <edm4eic/MCRecoParticleAssociationCollection.h>
0013 #include <edm4eic/ReconstructedParticleCollection.h>
0014 #include <edm4hep/MCParticleCollection.h>
0015 #include <edm4hep/Vector3f.h>
0016 #include <edm4hep/utils/vector_utils.h>
0017 #include <podio/ObjectID.h>
0018 #include <podio/detail/Link.h>
0019 #include <podio/detail/LinkCollectionImpl.h>
0020 #include <cmath>
0021 #include <iterator>
0022 #include <map>
0023 #include <memory>
0024 #include <tuple>
0025 #include <utility>
0026
0027 #include "MatchClusters.h"
0028
0029 namespace eicrecon {
0030
0031 void MatchClusters::process(const MatchClusters::Input& input,
0032 const MatchClusters::Output& output) const {
0033
0034 const auto [mcparticles, inparts, inpartsassoc, clusters, clustersassoc] = input;
0035 #if EDM4EIC_BUILD_VERSION >= EDM4EIC_VERSION(8, 7, 0)
0036 auto [outparts, outlinks, outpartsassoc] = output;
0037 #else
0038 auto [outparts, outpartsassoc] = output;
0039 #endif
0040
0041 debug("Processing cluster info for new event");
0042
0043 debug("Step 0/2: Getting indexed list of clusters...");
0044
0045
0046 auto clusterMap = indexedClusters(clusters, clustersassoc);
0047
0048
0049
0050 debug("Step 1/2: Matching clusters to charged particles...");
0051
0052 for (const auto inpart : *inparts) {
0053 debug(" --> Processing charged particle {}, PDG {}, energy {}", inpart.getObjectID().index,
0054 inpart.getPDG(), inpart.getEnergy());
0055
0056 auto outpart = inpart.clone();
0057 outparts->push_back(outpart);
0058
0059
0060 int bestMcID = -1;
0061 double bestWeight = -1.;
0062
0063 for (const auto& assoc : *inpartsassoc) {
0064 if (assoc.getRec().getObjectID() == inpart.getObjectID()) {
0065 const double w = assoc.getWeight();
0066 if (w > bestWeight) {
0067 bestWeight = w;
0068 bestMcID = assoc.getSim().getObjectID().index;
0069 }
0070 }
0071 }
0072
0073 trace(" --> Found particle with best mcID {} weight {}", bestMcID, bestWeight);
0074
0075 if (bestMcID < 0) {
0076 debug(" --> cannot match track without associated mcID");
0077 } else if (clusterMap.contains(bestMcID)) {
0078 const auto& clus = clusterMap[bestMcID];
0079 debug(" --> found matching cluster with energy: {}", clus.getEnergy());
0080 debug(" --> adding cluster to reconstructed particle");
0081 outpart.addToClusters(clus);
0082 clusterMap.erase(bestMcID);
0083 }
0084
0085
0086 for (const auto& assoc : *inpartsassoc) {
0087 if (assoc.getRec().getObjectID() == inpart.getObjectID()) {
0088 #if EDM4EIC_BUILD_VERSION >= EDM4EIC_VERSION(8, 7, 0)
0089 auto link = outlinks->create();
0090 link.setWeight(assoc.getWeight());
0091 link.setFrom(outpart);
0092 link.setTo(assoc.getSim());
0093 #endif
0094 auto outassoc = outpartsassoc->create();
0095 outassoc.setWeight(assoc.getWeight());
0096 outassoc.setRec(outpart);
0097 outassoc.setSim(assoc.getSim());
0098 }
0099 }
0100 }
0101
0102
0103
0104 debug("Step 2/2: Creating neutrals for remaining clusters...");
0105 for (const auto& [mcID, clus] : clusterMap) {
0106 debug(" --> Processing unmatched cluster with energy: {}", clus.getEnergy());
0107
0108
0109 const auto mc = (*mcparticles)[mcID];
0110 const double mass = 0.;
0111 const int32_t pdg = 0;
0112 if (level() <= algorithms::LogLevel::kDebug) {
0113 if (mc.getCharge() != 0.0F) {
0114 debug(" --> associated mcparticle is not a neutral (PDG: {}), "
0115 "setting the reconstructed particle ID to 0 (unidentified)",
0116 mc.getPDG());
0117 }
0118 debug(" --> found matching associated mcparticle with PDG: {}, energy: {}", pdg,
0119 mc.getEnergy());
0120 }
0121
0122
0123 const auto outpart = reconstruct_neutral(&clus, mass, pdg);
0124 debug(" --> Reconstructed neutral particle with PDG: {}, energy: {}", outpart.getPDG(),
0125 outpart.getEnergy());
0126
0127 outparts->push_back(outpart);
0128
0129
0130 #if EDM4EIC_BUILD_VERSION >= EDM4EIC_VERSION(8, 7, 0)
0131 auto link = outlinks->create();
0132 link.setWeight(1.0);
0133 link.setFrom(outpart);
0134 link.setTo((*mcparticles)[mcID]);
0135 #endif
0136 auto assoc = outpartsassoc->create();
0137 assoc.setWeight(1.0);
0138 assoc.setRec(outpart);
0139 assoc.setSim((*mcparticles)[mcID]);
0140 }
0141 }
0142
0143
0144
0145
0146 std::map<int, edm4eic::Cluster> MatchClusters::indexedClusters(
0147 const edm4eic::ClusterCollection* clusters,
0148 const edm4eic::MCRecoClusterParticleAssociationCollection* associations) const {
0149
0150
0151 std::map<int, std::pair<edm4eic::Cluster, float>> bestForMc;
0152
0153
0154 for (const auto cluster : *clusters) {
0155
0156 int bestMcID = -1;
0157 float bestWeight = -1.F;
0158
0159
0160 for (const auto assoc : *associations) {
0161 if (assoc.getRec() == cluster) {
0162 const int candMcID = assoc.getSim().getObjectID().index;
0163 const float w = assoc.getWeight();
0164 if (w > bestWeight) {
0165 bestWeight = w;
0166 bestMcID = candMcID;
0167 }
0168 }
0169 }
0170
0171 trace(" --> Found cluster with best mcID {} weight {} and energy {}", bestMcID, bestWeight,
0172 cluster.getEnergy());
0173
0174 if (bestMcID < 0) {
0175 trace(" --> WARNING: no valid MC truth link found, skipping cluster...");
0176 continue;
0177 }
0178
0179
0180 auto it = bestForMc.find(bestMcID);
0181 if (it == bestForMc.end()) {
0182 bestForMc.emplace(bestMcID, std::make_pair(cluster, bestWeight));
0183 } else {
0184 const float existingWeight = it->second.second;
0185 if (bestWeight > existingWeight ||
0186 (bestWeight == existingWeight && cluster.getEnergy() > it->second.first.getEnergy())) {
0187 it->second = std::make_pair(cluster, bestWeight);
0188 }
0189 }
0190 }
0191
0192
0193 std::map<int, edm4eic::Cluster> matched;
0194 for (const auto& kv : bestForMc) {
0195 matched.emplace(kv.first, kv.second.first);
0196 }
0197
0198 return matched;
0199 }
0200
0201
0202
0203 edm4eic::MutableReconstructedParticle
0204 MatchClusters::reconstruct_neutral(const edm4eic::Cluster* cluster, const double mass,
0205 const int32_t pdg) {
0206
0207 const float energy = cluster->getEnergy();
0208 const float p = energy < mass ? 0 : std::sqrt(energy * energy - mass * mass);
0209 const auto position = cluster->getPosition();
0210 const auto momentum = p * (position / edm4hep::utils::magnitude(position));
0211
0212 edm4eic::MutableReconstructedParticle part;
0213 part.setMomentum(momentum);
0214 part.setPDG(pdg);
0215 part.setCharge(0);
0216 part.setEnergy(energy);
0217 part.setMass(mass);
0218 part.addToClusters(*cluster);
0219 return part;
0220 }
0221
0222 }