File indexing completed on 2025-07-06 07:55:44
0001
0002
0003
0004 #include "MergeParticleID.h"
0005
0006 #include <algorithms/logger.h>
0007 #include <edm4eic/CherenkovParticleIDHypothesis.h>
0008 #include <edm4eic/TrackSegmentCollection.h>
0009 #include <edm4hep/Vector2f.h>
0010 #include <fmt/core.h>
0011 #include <podio/ObjectID.h>
0012 #include <podio/RelationRange.h>
0013 #include <cstddef>
0014 #include <gsl/pointers>
0015 #include <stdexcept>
0016 #include <unordered_map>
0017 #include <utility>
0018
0019 #include "algorithms/pid/MergeParticleIDConfig.h"
0020 #include "algorithms/pid/Tools.h"
0021
0022 namespace eicrecon {
0023
0024 void MergeParticleID::init() { debug() << m_cfg << endmsg; }
0025
0026 void MergeParticleID::process(const MergeParticleID::Input& input,
0027 const MergeParticleID::Output& output) const {
0028
0029 const auto [in_pid_collections_list] = input;
0030 auto [out_pids] = output;
0031
0032
0033
0034
0035
0036
0037
0038
0039
0040
0041
0042
0043
0044
0045
0046
0047
0048
0049
0050
0051
0052
0053
0054
0055
0056
0057
0058
0059
0060
0061
0062
0063
0064
0065 std::unordered_map<decltype(podio::ObjectID::index),
0066 std::vector<std::pair<std::size_t, std::size_t>>>
0067 particle_pids;
0068 trace("{:-<70}", "Build `particle_pids` indexing data structure ");
0069
0070
0071 for (std::size_t idx_coll = 0; idx_coll < in_pid_collections_list.size(); idx_coll++) {
0072 const auto& in_pid_collection = in_pid_collections_list.at(idx_coll);
0073 trace("idx_col={}", idx_coll);
0074
0075
0076 for (std::size_t idx_pid = 0; idx_pid < in_pid_collection->size(); idx_pid++) {
0077
0078 const auto& in_pid = in_pid_collection->at(idx_pid);
0079 const auto& charged_particle_track_segment = in_pid.getChargedParticle();
0080 if (!charged_particle_track_segment.isAvailable()) {
0081 error("PID object found with no charged particle");
0082 continue;
0083 }
0084 auto id_particle = charged_particle_track_segment.getObjectID().index;
0085 auto idx_paired = std::make_pair(idx_coll, idx_pid);
0086 trace(" idx_pid={} id_particle={}", idx_pid, id_particle);
0087
0088
0089 auto it = particle_pids.find(id_particle);
0090 if (it == particle_pids.end()) {
0091 particle_pids.insert({id_particle, {idx_paired}});
0092 } else {
0093 it->second.push_back(idx_paired);
0094 }
0095 }
0096 }
0097
0098
0099 if (level() <= algorithms::LogLevel::kTrace) {
0100 trace("{:-<70}", "Resulting `particle_pids` ");
0101 for (auto& [id_particle, idx_paired_list] : particle_pids) {
0102 trace("id_particle={}", id_particle);
0103 for (auto& [idx_coll, idx_pid] : idx_paired_list) {
0104 trace(" (idx_coll, idx_pid) = ({}, {})", idx_coll, idx_pid);
0105 }
0106 }
0107 }
0108
0109
0110
0111
0112
0113 trace("{:-<70}", "Begin Merging PID Objects ");
0114 for (auto& [id_particle, idx_paired_list] : particle_pids) {
0115
0116
0117 trace("Charged Particle:");
0118 trace(" id = {}", id_particle);
0119 trace(" PID Hypotheses:");
0120
0121
0122 auto out_pid = out_pids->create();
0123 decltype(edm4eic::CherenkovParticleIDData::npe) out_npe = 0.0;
0124 decltype(edm4eic::CherenkovParticleIDData::refractiveIndex) out_refractiveIndex = 0.0;
0125 decltype(edm4eic::CherenkovParticleIDData::photonEnergy) out_photonEnergy = 0.0;
0126
0127
0128 std::unordered_map<decltype(edm4eic::CherenkovParticleIDHypothesis::PDG),
0129 edm4eic::CherenkovParticleIDHypothesis>
0130 pdg_2_out_hyp;
0131
0132
0133 for (auto& [idx_coll, idx_pid] : idx_paired_list) {
0134 const auto& in_pid = in_pid_collections_list.at(idx_coll)->at(idx_pid);
0135
0136
0137 trace(" Hypotheses for PID result (idx_coll, idx_pid) = ({}, {}):", idx_coll, idx_pid);
0138 trace(Tools::HypothesisTableHead(6));
0139
0140
0141 out_npe += in_pid.getNpe();
0142 out_refractiveIndex += in_pid.getNpe() * in_pid.getRefractiveIndex();
0143 out_photonEnergy += in_pid.getNpe() * in_pid.getPhotonEnergy();
0144
0145
0146 for (auto in_photon_vec : in_pid.getThetaPhiPhotons()) {
0147 out_pid.addToThetaPhiPhotons(in_photon_vec);
0148 }
0149
0150
0151 if (!out_pid.getChargedParticle().isAvailable()) {
0152 out_pid.setChargedParticle(in_pid.getChargedParticle());
0153 }
0154
0155
0156 for (auto in_hyp : in_pid.getHypotheses()) {
0157 trace(Tools::HypothesisTableLine(in_hyp, 6));
0158 auto out_hyp_it = pdg_2_out_hyp.find(in_hyp.PDG);
0159 if (out_hyp_it == pdg_2_out_hyp.end()) {
0160 edm4eic::CherenkovParticleIDHypothesis out_hyp;
0161 out_hyp.PDG = in_hyp.PDG;
0162 out_hyp.npe = in_hyp.npe;
0163 out_hyp.weight = in_hyp.weight;
0164 pdg_2_out_hyp.insert({out_hyp.PDG, out_hyp});
0165 } else {
0166 auto& out_hyp = out_hyp_it->second;
0167 out_hyp.npe += in_hyp.npe;
0168
0169 switch (m_cfg.mergeMode) {
0170 case MergeParticleIDConfig::kAddWeights:
0171 out_hyp.weight += in_hyp.weight;
0172 break;
0173 case MergeParticleIDConfig::kMultiplyWeights:
0174 out_hyp.weight *= in_hyp.weight;
0175 break;
0176 default:
0177 throw std::runtime_error(
0178 "unknown MergeParticleIDConfig::mergeMode setting; weights not combined");
0179 }
0180 }
0181 }
0182
0183 }
0184
0185
0186 out_pid.setNpe(out_npe);
0187 if (out_npe > 0) {
0188 out_pid.setRefractiveIndex(out_refractiveIndex / out_npe);
0189 out_pid.setPhotonEnergy(out_photonEnergy / out_npe);
0190 }
0191
0192
0193 for (auto [pdg, out_hyp] : pdg_2_out_hyp) {
0194 out_pid.addToHypotheses(out_hyp);
0195 }
0196
0197
0198 trace(" => merged hypothesis weights:");
0199 trace(Tools::HypothesisTableHead(6));
0200 for (auto out_hyp : out_pid.getHypotheses()) {
0201 trace(Tools::HypothesisTableLine(out_hyp, 6));
0202 }
0203
0204 }
0205 }
0206
0207 }