File indexing completed on 2025-05-12 08:02:27
0001
0002
0003
0004
0005
0006 #include <DD4hep/Detector.h>
0007 #include <DD4hep/IDDescriptor.h>
0008 #include <DD4hep/Readout.h>
0009 #include <DDSegmentation/BitFieldCoder.h>
0010 #include <algorithms/geo.h>
0011 #include <edm4hep/MCParticle.h>
0012 #include <edm4hep/SimCalorimeterHit.h>
0013 #include <edm4hep/SimTrackerHit.h>
0014 #include <edm4hep/Vector3f.h>
0015 #include <fmt/core.h>
0016 #include <podio/RelationRange.h>
0017 #include <algorithm>
0018 #include <cmath>
0019 #include <gsl/pointers>
0020 #include <map>
0021 #include <numeric>
0022 #include <stdexcept>
0023 #include <utility>
0024 #include <vector>
0025
0026 #include "PulseCombiner.h"
0027
0028 namespace eicrecon {
0029
0030 void PulseCombiner::init() {
0031
0032
0033 if (!(m_cfg.readout.empty() && m_cfg.combine_field.empty())) {
0034 try {
0035 auto detector = algorithms::GeoSvc::instance().detector();
0036 auto id_spec = detector->readout(m_cfg.readout).idSpec();
0037 m_detector_bitmask = 0;
0038
0039 for (auto& field : id_spec.fields()) {
0040
0041 std::string field_name = field.first;
0042
0043 m_detector_bitmask |= id_spec.field(field_name)->mask();
0044 if (field_name == m_cfg.combine_field) {
0045 break;
0046 }
0047 }
0048
0049 } catch (...) {
0050 error("Failed set bitshift for detector {} with segmentation id {}", m_cfg.readout,
0051 m_cfg.combine_field);
0052 throw std::runtime_error("Failed to load ID decoder");
0053 }
0054 }
0055 }
0056
0057 void PulseCombiner::process(const PulseCombiner::Input& input,
0058 const PulseCombiner::Output& output) const {
0059 const auto [inPulses] = input;
0060 auto [outPulses] = output;
0061
0062
0063 std::map<uint64_t, std::vector<PulseType>> cell_pulses;
0064 for (const PulseType& pulse : *inPulses) {
0065 uint64_t shiftedCellID = pulse.getCellID() & m_detector_bitmask;
0066 cell_pulses[shiftedCellID].push_back(pulse);
0067 }
0068
0069
0070 for (const auto& [cellID, pulses] : cell_pulses) {
0071 if (pulses.size() == 1) {
0072 outPulses->push_back(pulses.at(0).clone());
0073 debug("CellID {} has only one pulse, no combination needed", cellID);
0074 } else {
0075 std::vector<std::vector<PulseType>> clusters = clusterPulses(pulses);
0076 for (auto cluster : clusters) {
0077
0078 auto sum_pulse = outPulses->create();
0079 sum_pulse.setCellID(cluster[0].getCellID());
0080 sum_pulse.setInterval(cluster[0].getInterval());
0081 sum_pulse.setTime(cluster[0].getTime());
0082
0083 auto newPulse = sumPulses(cluster);
0084 for (auto pulse : newPulse) {
0085 sum_pulse.addToAmplitude(pulse);
0086 }
0087
0088 #if EDM4EIC_VERSION_MAJOR > 8 || (EDM4EIC_VERSION_MAJOR == 8 && EDM4EIC_VERSION_MINOR >= 1)
0089
0090 float integral = std::accumulate(newPulse.begin(), newPulse.end(), 0.0f);
0091 sum_pulse.setIntegral(integral);
0092 sum_pulse.setPosition(edm4hep::Vector3f(
0093 cluster[0].getPosition().x, cluster[0].getPosition().y, cluster[0].getPosition().z));
0094 for (auto pulse : cluster) {
0095 sum_pulse.addToPulses(pulse);
0096 for (auto particle : pulse.getParticles()) {
0097 sum_pulse.addToParticles(particle);
0098 }
0099 for (auto hit : pulse.getTrackerHits()) {
0100 sum_pulse.addToTrackerHits(hit);
0101 }
0102 for (auto hit : pulse.getCalorimeterHits()) {
0103 sum_pulse.addToCalorimeterHits(hit);
0104 }
0105 }
0106 #endif
0107 }
0108 debug("CellID {} has {} pulses, combined into {} clusters", cellID, pulses.size(),
0109 clusters.size());
0110 }
0111 }
0112
0113 }
0114
0115 std::vector<std::vector<PulseType>>
0116 PulseCombiner::clusterPulses(const std::vector<PulseType> pulses) const {
0117
0118
0119 std::vector<PulseType> ordered_pulses{pulses};
0120
0121
0122 std::sort(ordered_pulses.begin(), ordered_pulses.end(),
0123 [](PulseType a, PulseType b) { return a.getTime() < b.getTime(); });
0124
0125
0126 std::vector<std::vector<PulseType>> cluster_pulses;
0127 float clusterEndTime = 0;
0128 bool makeNewPulse = true;
0129
0130 for (auto pulse : ordered_pulses) {
0131 float pulseStartTime = pulse.getTime();
0132 float pulseEndTime = pulse.getTime() + pulse.getInterval() * pulse.getAmplitude().size();
0133 if (!makeNewPulse) {
0134 if (pulseStartTime < clusterEndTime + m_cfg.minimum_separation) {
0135 cluster_pulses.back().push_back(pulse);
0136 clusterEndTime = std::max(clusterEndTime, pulseEndTime);
0137 } else {
0138 makeNewPulse = true;
0139 }
0140 }
0141 if (makeNewPulse) {
0142 cluster_pulses.push_back({pulse});
0143 clusterEndTime = pulseEndTime;
0144 makeNewPulse = false;
0145 }
0146 }
0147
0148 return cluster_pulses;
0149
0150 }
0151
0152 std::vector<float> PulseCombiner::sumPulses(const std::vector<PulseType> pulses) const {
0153
0154
0155 float maxTime = 0;
0156 for (auto pulse : pulses) {
0157 maxTime =
0158 std::max(maxTime, pulse.getTime() + pulse.getInterval() * pulse.getAmplitude().size());
0159 }
0160
0161
0162 int maxStep = std::round((maxTime - pulses[0].getTime()) / pulses[0].getInterval());
0163
0164 std::vector<float> newPulse(maxStep, 0.0);
0165
0166 for (auto pulse : pulses) {
0167
0168 int startStep = (pulse.getTime() - pulses[0].getTime()) / pulse.getInterval();
0169 int pulseSize = pulse.getAmplitude().size();
0170 int endStep = startStep + pulseSize;
0171 for (int i = startStep; i < endStep; i++) {
0172
0173 newPulse[i] += pulse.getAmplitude()[i - startStep];
0174 }
0175 }
0176
0177 return newPulse;
0178 }
0179
0180 }