File indexing completed on 2025-12-16 09:27:56
0001
0002
0003
0004 #include "algorithms/calorimetry/EnergyPositionClusterMerger.h"
0005
0006 #include <edm4hep/MCParticle.h>
0007 #include <edm4hep/Vector3f.h>
0008 #include <edm4hep/utils/vector_utils.h>
0009 #include <fmt/core.h>
0010 #include <podio/ObjectID.h>
0011 #include <cmath>
0012 #include <cstddef>
0013 #include <gsl/pointers>
0014 #include <limits>
0015 #include <vector>
0016
0017 #include "algorithms/calorimetry/EnergyPositionClusterMergerConfig.h"
0018
0019 namespace eicrecon {
0020
0021 void EnergyPositionClusterMerger::process(const Input& input, const Output& output) const {
0022
0023 const auto [energy_clus, energy_assoc, pos_clus, pos_assoc] = input;
0024 auto [merged_clus, merged_assoc] = output;
0025
0026 debug("Merging energy and position clusters for new event");
0027
0028 if (energy_clus->empty() && pos_clus->empty()) {
0029 debug("Nothing to do for this event, returning...");
0030 return;
0031 }
0032
0033 std::vector<bool> consumed(energy_clus->size(), false);
0034
0035
0036 for (const auto& pc : *pos_clus) {
0037
0038 trace(" --> Processing position cluster {}, energy: {}", pc.getObjectID().index,
0039 pc.getEnergy());
0040
0041
0042 int best_match = -1;
0043 double best_delta = std::numeric_limits<double>::max();
0044 for (std::size_t ie = 0; ie < energy_clus->size(); ++ie) {
0045 if (consumed[ie]) {
0046 continue;
0047 }
0048
0049 const auto& ec = (*energy_clus)[ie];
0050
0051 trace(" --> Evaluating energy cluster {}, energy: {}", ec.getObjectID().index,
0052 ec.getEnergy());
0053
0054
0055
0056 const double de_rel = std::abs((pc.getEnergy() - ec.getEnergy()) / ec.getEnergy());
0057 const double deta =
0058 std::abs(edm4hep::utils::eta(pc.getPosition()) - edm4hep::utils::eta(ec.getPosition()));
0059
0060
0061 const double dphi = edm4hep::utils::angleAzimuthal(pc.getPosition()) -
0062 edm4hep::utils::angleAzimuthal(ec.getPosition());
0063 const double dsphi = std::abs(sin(0.5 * dphi));
0064 if ((m_cfg.energyRelTolerance > 0 && de_rel > m_cfg.energyRelTolerance) ||
0065 (m_cfg.etaTolerance > 0 && deta > m_cfg.etaTolerance) ||
0066 (m_cfg.phiTolerance > 0 && dsphi > sin(0.5 * m_cfg.phiTolerance))) {
0067 continue;
0068 }
0069
0070
0071
0072
0073 const double delta = std::abs(pc.getEnergy() - ec.getEnergy());
0074 if (delta < best_delta) {
0075 best_delta = delta;
0076 best_match = ie;
0077 }
0078 }
0079
0080
0081 if (best_match >= 0) {
0082
0083 const auto& ec = (*energy_clus)[best_match];
0084
0085 auto new_clus = merged_clus->create();
0086 new_clus.setEnergy(ec.getEnergy());
0087 new_clus.setEnergyError(ec.getEnergyError());
0088 new_clus.setTime(pc.getTime());
0089 new_clus.setNhits(pc.getNhits() + ec.getNhits());
0090 new_clus.setPosition(pc.getPosition());
0091 new_clus.setPositionError(pc.getPositionError());
0092 new_clus.addToClusters(pc);
0093 new_clus.addToClusters(ec);
0094
0095 trace(" --> Found matching energy cluster {}, energy: {}", ec.getObjectID().index,
0096 ec.getEnergy());
0097 trace(" --> Created a new combined cluster {}, energy: {}", new_clus.getObjectID().index,
0098 new_clus.getEnergy());
0099
0100
0101 auto ea = energy_assoc->begin();
0102 for (; ea != energy_assoc->end(); ++ea) {
0103 if (ea->getRec() == ec) {
0104 break;
0105 }
0106 }
0107
0108 auto pa = pos_assoc->begin();
0109 for (; pa != pos_assoc->end(); ++pa) {
0110 if (pa->getRec() == pc) {
0111 break;
0112 }
0113 }
0114 if (ea != energy_assoc->end() || pa != pos_assoc->end()) {
0115
0116 if (ea != energy_assoc->end() && pa != pos_assoc->end()) {
0117
0118 if (pa->getSimID() == ea->getSimID()) {
0119
0120 auto clusterassoc = merged_assoc->create();
0121 clusterassoc.setRecID(new_clus.getObjectID().index);
0122 clusterassoc.setSimID(ea->getSimID());
0123 clusterassoc.setWeight(1.0);
0124 clusterassoc.setRec(new_clus);
0125 clusterassoc.setSim(ea->getSim());
0126 } else {
0127
0128 debug(" --> Two associations added to {} and {}", ea->getSimID(), pa->getSimID());
0129 auto clusterassoc1 = merged_assoc->create();
0130 clusterassoc1.setRecID(new_clus.getObjectID().index);
0131 clusterassoc1.setSimID(ea->getSimID());
0132 clusterassoc1.setWeight(0.5);
0133 clusterassoc1.setRec(new_clus);
0134 clusterassoc1.setSim(ea->getSim());
0135 auto clusterassoc2 = merged_assoc->create();
0136 clusterassoc2.setRecID(new_clus.getObjectID().index);
0137 clusterassoc2.setSimID(pa->getSimID());
0138 clusterassoc2.setWeight(0.5);
0139 clusterassoc2.setRec(new_clus);
0140 clusterassoc2.setSim(pa->getSim());
0141 }
0142 } else if (ea != energy_assoc->end()) {
0143
0144 debug(" --> Only added energy cluster association to {}", ea->getSimID());
0145 auto clusterassoc = merged_assoc->create();
0146 clusterassoc.setRecID(new_clus.getObjectID().index);
0147 clusterassoc.setSimID(ea->getSimID());
0148 clusterassoc.setWeight(1.0);
0149 clusterassoc.setRec(new_clus);
0150 clusterassoc.setSim(ea->getSim());
0151 } else if (pa != pos_assoc->end()) {
0152
0153 debug(" --> Only added position cluster association to {}", pa->getSimID());
0154 auto clusterassoc = merged_assoc->create();
0155 clusterassoc.setRecID(new_clus.getObjectID().index);
0156 clusterassoc.setSimID(pa->getSimID());
0157 clusterassoc.setWeight(1.0);
0158 clusterassoc.setRec(new_clus);
0159 clusterassoc.setSim(pa->getSim());
0160 }
0161 }
0162
0163
0164 consumed[best_match] = true;
0165
0166 debug(" Matched position cluster {} with energy cluster {}", pc.getObjectID().index,
0167 ec.getObjectID().index);
0168 debug(" - Position cluster: (E: {}, phi: {}, z: {})", pc.getEnergy(),
0169 edm4hep::utils::angleAzimuthal(pc.getPosition()), pc.getPosition().z);
0170 debug(" - Energy cluster: (E: {}, phi: {}, z: {})", ec.getEnergy(),
0171 edm4hep::utils::angleAzimuthal(ec.getPosition()), ec.getPosition().z);
0172 debug(" ---> Merged cluster: (E: {}, phi: {}, z: {})", new_clus.getEnergy(),
0173 edm4hep::utils::angleAzimuthal(new_clus.getPosition()), new_clus.getPosition().z);
0174
0175 } else {
0176
0177 debug(" Unmatched position cluster {}", pc.getObjectID().index);
0178 }
0179 }
0180 }
0181
0182 }