File indexing completed on 2025-02-22 09:55:37
0001
0002
0003
0004 #include <limits>
0005 #include <numbers>
0006
0007 #include <fmt/format.h>
0008
0009 #include "Gaudi/Property.h"
0010 #include "GaudiAlg/GaudiAlgorithm.h"
0011 #include "GaudiAlg/GaudiTool.h"
0012 #include "GaudiAlg/Transformer.h"
0013 #include "GaudiKernel/PhysicalConstants.h"
0014
0015 #include "JugBase/DataHandle.h"
0016
0017
0018 #include "edm4hep/MCParticleCollection.h"
0019 #include "edm4eic/ClusterCollection.h"
0020 #include "edm4eic/MCRecoClusterParticleAssociationCollection.h"
0021 #include <edm4hep/utils/vector_utils.h>
0022
0023 using namespace Gaudi::Units;
0024
0025 namespace Jug::Fast {
0026
0027
0028
0029
0030
0031
0032
0033
0034
0035 class TruthEnergyPositionClusterMerger : public GaudiAlgorithm {
0036 private:
0037
0038 DataHandle<edm4hep::MCParticleCollection> m_inputMCParticles{"MCParticles", Gaudi::DataHandle::Reader, this};
0039 DataHandle<edm4eic::ClusterCollection> m_energyClusters{"EnergyClusters", Gaudi::DataHandle::Reader, this};
0040 DataHandle<edm4eic::MCRecoClusterParticleAssociationCollection> m_energyAssociations{"EnergyAssociations", Gaudi::DataHandle::Reader, this};
0041 DataHandle<edm4eic::ClusterCollection> m_positionClusters{"PositionClusters", Gaudi::DataHandle::Reader, this};
0042 DataHandle<edm4eic::MCRecoClusterParticleAssociationCollection> m_positionAssociations{"PositionAssociations", Gaudi::DataHandle::Reader, this};
0043
0044 DataHandle<edm4eic::ClusterCollection> m_outputClusters{"OutputClusters", Gaudi::DataHandle::Writer, this};
0045 DataHandle<edm4eic::MCRecoClusterParticleAssociationCollection> m_outputAssociations{"OutputAssociations", Gaudi::DataHandle::Writer, this};
0046
0047 public:
0048 TruthEnergyPositionClusterMerger(const std::string& name, ISvcLocator* svcLoc)
0049 : GaudiAlgorithm(name, svcLoc) {
0050 declareProperty("inputMCParticles", m_inputMCParticles, "MCParticles");
0051 declareProperty("inputEnergyClusters", m_energyClusters, "Cluster collection with good energy precision");
0052 declareProperty("inputEnergyAssociations", m_energyAssociations, "Cluster association with good energy precision");
0053 declareProperty("inputPositionClusters", m_positionClusters, "Cluster collection with good position precision");
0054 declareProperty("inputPositionAssociations", m_positionAssociations, "Cluster association with good position precision");
0055 declareProperty("outputClusters", m_outputClusters, "Cluster collection with good energy precision");
0056 declareProperty("outputAssociations", m_outputAssociations, "Cluster association with good energy precision");
0057 }
0058
0059 StatusCode initialize() override { return StatusCode::SUCCESS; }
0060
0061 StatusCode execute() override {
0062 if (msgLevel(MSG::DEBUG)) {
0063 debug() << "Merging energy and position clusters for new event" << endmsg;
0064 }
0065
0066 const auto& mcparticles = *(m_inputMCParticles.get());
0067 const auto& energy_clus = *(m_energyClusters.get());
0068 const auto& energy_assoc = *(m_energyAssociations.get());
0069 const auto& pos_clus = *(m_positionClusters.get());
0070 const auto& pos_assoc = *(m_positionAssociations.get());
0071
0072 auto& merged_clus = *(m_outputClusters.createAndPut());
0073 auto& merged_assoc = *(m_outputAssociations.createAndPut());
0074
0075 if (!energy_clus.size() && !pos_clus.size()) {
0076 if (msgLevel(MSG::DEBUG)) {
0077 debug() << "Nothing to do for this event, returning..." << endmsg;
0078 }
0079 return StatusCode::SUCCESS;
0080 }
0081
0082 if (msgLevel(MSG::DEBUG)) {
0083 debug() << "Step 0/2: Getting indexed list of clusters..." << endmsg;
0084 }
0085
0086 auto energyMap = indexedClusters(energy_clus, energy_assoc);
0087 auto posMap = indexedClusters(pos_clus, pos_assoc);
0088
0089
0090 if (msgLevel(MSG::DEBUG)) {
0091 debug() << "Step 1/2: Matching all position clusters to the available energy clusters..." << endmsg;
0092 }
0093 for (const auto& [mcID, pclus] : posMap) {
0094 if (msgLevel(MSG::DEBUG)) {
0095 debug() << " --> Processing position cluster " << pclus.id() << ", mcID: " << mcID << ", energy: " << pclus.getEnergy()
0096 << endmsg;
0097 }
0098 if (energyMap.count(mcID)) {
0099 const auto& eclus = energyMap[mcID];
0100 auto new_clus = merged_clus.create();
0101 new_clus.setEnergy(eclus.getEnergy());
0102 new_clus.setEnergyError(eclus.getEnergyError());
0103 new_clus.setTime(pclus.getTime());
0104 new_clus.setNhits(pclus.getNhits() + eclus.getNhits());
0105 new_clus.setPosition(pclus.getPosition());
0106 new_clus.setPositionError(pclus.getPositionError());
0107 new_clus.addToClusters(pclus);
0108 new_clus.addToClusters(eclus);
0109 for (const auto& cl : {pclus, eclus}) {
0110 for (const auto& hit : cl.getHits()) {
0111 new_clus.addToHits(hit);
0112 }
0113 new_clus.addToSubdetectorEnergies(cl.getEnergy());
0114 }
0115 for (const auto& param : pclus.getShapeParameters()) {
0116 new_clus.addToShapeParameters(param);
0117 }
0118 if (msgLevel(MSG::DEBUG)) {
0119 debug() << " --> Found matching energy cluster " << eclus.id() << ", energy: " << eclus.getEnergy() << endmsg;
0120 debug() << " --> Created new combined cluster " << new_clus.id() << ", energy: " << new_clus.getEnergy() << endmsg;
0121 }
0122
0123
0124 edm4eic::MutableMCRecoClusterParticleAssociation clusterassoc;
0125 clusterassoc.setRecID(new_clus.getObjectID().index);
0126 clusterassoc.setSimID(mcID);
0127 clusterassoc.setWeight(1.0);
0128 clusterassoc.setRec(new_clus);
0129
0130 merged_assoc.push_back(clusterassoc);
0131
0132
0133
0134 energyMap.erase(mcID);
0135 } else {
0136 if (msgLevel(MSG::DEBUG)) {
0137 debug() << " --> No matching energy cluster found, copying over position cluster" << endmsg;
0138 }
0139 auto new_clus = pclus.clone();
0140 new_clus.addToClusters(pclus);
0141 merged_clus.push_back(new_clus);
0142
0143
0144 edm4eic::MutableMCRecoClusterParticleAssociation clusterassoc;
0145 clusterassoc.setRecID(new_clus.getObjectID().index);
0146 clusterassoc.setSimID(mcID);
0147 clusterassoc.setWeight(1.0);
0148 clusterassoc.setRec(new_clus);
0149
0150 merged_assoc.push_back(clusterassoc);
0151 }
0152 }
0153
0154
0155
0156 if (msgLevel(MSG::DEBUG)) {
0157 debug() << "Step 2/2: Collecting remaining energy clusters..." << endmsg;
0158 }
0159 for (const auto& [mcID, eclus] : energyMap) {
0160 const auto& mc = mcparticles[mcID];
0161 const auto& p = mc.getMomentum();
0162 const auto phi = std::atan2(p.y, p.x);
0163 const auto theta = std::atan2(std::hypot(p.x, p.y), p.z);
0164 auto new_clus = merged_clus.create();
0165 new_clus.setEnergy(eclus.getEnergy());
0166 new_clus.setEnergyError(eclus.getEnergyError());
0167 new_clus.setTime(eclus.getTime());
0168 new_clus.setNhits(eclus.getNhits());
0169
0170 new_clus.setPosition(edm4hep::utils::sphericalToVector(110.*cm, theta, phi));
0171 new_clus.addToClusters(eclus);
0172 if (msgLevel(MSG::DEBUG)) {
0173 debug() << " --> Processing energy cluster " << eclus.id() << ", mcID: " << mcID << ", energy: " << eclus.getEnergy()
0174 << endmsg;
0175 debug() << " --> Created new 'combined' cluster " << new_clus.id() << ", energy: " << new_clus.getEnergy() << endmsg;
0176 }
0177
0178
0179 edm4eic::MutableMCRecoClusterParticleAssociation clusterassoc;
0180 clusterassoc.setRecID(new_clus.getObjectID().index);
0181 clusterassoc.setSimID(mcID);
0182 clusterassoc.setWeight(1.0);
0183 clusterassoc.setRec(new_clus);
0184
0185 merged_assoc.push_back(clusterassoc);
0186 }
0187
0188
0189 return StatusCode::SUCCESS;
0190 }
0191
0192
0193
0194 std::map<int, edm4eic::Cluster> indexedClusters(
0195 const edm4eic::ClusterCollection& clusters,
0196 const edm4eic::MCRecoClusterParticleAssociationCollection& associations
0197 ) const {
0198
0199 std::map<int, edm4eic::Cluster> matched = {};
0200
0201 for (const auto& cluster : clusters) {
0202 int mcID = -1;
0203
0204
0205 for (const auto& assoc : associations) {
0206 if (assoc.getRec() == cluster) {
0207 mcID = assoc.getSimID();
0208 break;
0209 }
0210 }
0211
0212 if (msgLevel(MSG::VERBOSE)) {
0213 verbose() << " --> Found cluster: " << cluster.getObjectID().index << " with mcID " << mcID << " and energy "
0214 << cluster.getEnergy() << endmsg;
0215 }
0216
0217 if (mcID < 0) {
0218 if (msgLevel(MSG::VERBOSE)) {
0219 verbose() << " --> WARNING: no valid MC truth link found, skipping cluster..." << endmsg;
0220 }
0221 continue;
0222 }
0223
0224 const bool duplicate = matched.count(mcID);
0225 if (duplicate) {
0226 if (msgLevel(MSG::VERBOSE)) {
0227 verbose() << " --> WARNING: this is a duplicate mcID, keeping the higher energy cluster" << endmsg;
0228 }
0229 if (cluster.getEnergy() < matched[mcID].getEnergy()) {
0230 continue;
0231 }
0232 }
0233
0234 matched[mcID] = cluster;
0235 }
0236 return matched;
0237 }
0238 };
0239
0240
0241 DECLARE_COMPONENT(TruthEnergyPositionClusterMerger)
0242
0243 }