File indexing completed on 2024-06-29 07:05:54
0001
0002
0003
0004
0005
0006
0007
0008
0009
0010
0011
0012
0013
0014 #include "CalorimeterHitDigi.h"
0015
0016 #include <DD4hep/Detector.h>
0017 #include <DD4hep/IDDescriptor.h>
0018 #include <DD4hep/Readout.h>
0019 #include <DD4hep/config.h>
0020 #include <DDSegmentation/BitFieldCoder.h>
0021 #include <Evaluator/DD4hepUnits.h>
0022 #include <algorithms/service.h>
0023 #include <edm4hep/CaloHitContributionCollection.h>
0024 #include <fmt/core.h>
0025 #include <podio/RelationRange.h>
0026 #include <cmath>
0027 #include <cstddef>
0028 #include <gsl/pointers>
0029 #include <limits>
0030 #include <stdexcept>
0031 #include <string>
0032 #include <unordered_map>
0033 #include <utility>
0034 #include <vector>
0035
0036 #include "algorithms/calorimetry/CalorimeterHitDigiConfig.h"
0037 #include "services/evaluator/EvaluatorSvc.h"
0038
0039 using namespace dd4hep;
0040
0041 namespace eicrecon {
0042
0043
0044
0045
0046
0047
0048
0049
0050
0051
0052 void CalorimeterHitDigi::init() {
0053
0054
0055
0056
0057
0058
0059
0060
0061
0062
0063
0064
0065
0066
0067
0068
0069 if (m_cfg.eRes.empty()) {
0070 m_cfg.eRes.resize(3);
0071 } else if (m_cfg.eRes.size() != 3) {
0072 error("Invalid m_cfg.eRes.size()");
0073 throw std::runtime_error("Invalid m_cfg.eRes.size()");
0074 }
0075
0076
0077 tRes = m_cfg.tRes / dd4hep::ns;
0078 stepTDC = dd4hep::ns / m_cfg.resolutionTDC;
0079
0080
0081 if (m_cfg.readout.empty()) {
0082 error("readoutClass is not provided, it is needed to know the fields in readout ids");
0083 throw std::runtime_error("readoutClass is not provided");
0084 }
0085
0086
0087 try {
0088 id_spec = m_geo.detector()->readout(m_cfg.readout).idSpec();
0089 } catch (...) {
0090
0091
0092
0093 debug("Failed to load ID decoder for {}", m_cfg.readout);
0094 throw std::runtime_error(fmt::format("Failed to load ID decoder for {}", m_cfg.readout));
0095 }
0096
0097 decltype(id_mask) id_inverse_mask = 0;
0098
0099 if (!m_cfg.fields.empty()) {
0100 for (auto & field : m_cfg.fields) {
0101 id_inverse_mask |= id_spec.field(field)->mask();
0102 }
0103 debug("ID mask in {:s}: {:#064b}", m_cfg.readout, id_mask);
0104 }
0105 id_mask = ~id_inverse_mask;
0106
0107 std::function hit_to_map = [this](const edm4hep::SimCalorimeterHit &h) {
0108 std::unordered_map<std::string, double> params;
0109 for(const auto &p : id_spec.fields()) {
0110 const std::string &name = p.first;
0111 const dd4hep::IDDescriptor::Field* field = p.second;
0112 params.emplace(name, field->value(h.getCellID()));
0113 trace("{} = {}", name, field->value(h.getCellID()));
0114 }
0115 return params;
0116 };
0117
0118 auto& serviceSvc = algorithms::ServiceSvc::instance();
0119 corrMeanScale = serviceSvc.service<EvaluatorSvc>("EvaluatorSvc")->compile(m_cfg.corrMeanScale, hit_to_map);
0120 }
0121
0122
0123 void CalorimeterHitDigi::process(
0124 const CalorimeterHitDigi::Input& input,
0125 const CalorimeterHitDigi::Output& output) const {
0126
0127 const auto [simhits] = input;
0128 auto [rawhits] = output;
0129
0130
0131 std::unordered_map<uint64_t, std::vector<std::size_t>> merge_map;
0132 std::size_t ix = 0;
0133 for (const auto &ahit : *simhits) {
0134 uint64_t hid = ahit.getCellID() & id_mask;
0135
0136 trace("org cell ID in {:s}: {:#064b}", m_cfg.readout, ahit.getCellID());
0137 trace("new cell ID in {:s}: {:#064b}", m_cfg.readout, hid);
0138
0139 merge_map[hid].push_back(ix);
0140
0141 ix++;
0142 }
0143
0144
0145
0146 for (const auto &[id, ixs] : merge_map) {
0147 double edep = 0;
0148 double time = std::numeric_limits<double>::max();
0149 double max_edep = 0;
0150 auto leading_hit = (*simhits)[ixs[0]];
0151
0152 for (size_t i = 0; i < ixs.size(); ++i) {
0153 auto hit = (*simhits)[ixs[i]];
0154
0155 double timeC = std::numeric_limits<double>::max();
0156 for (const auto& c : hit.getContributions()) {
0157 if (c.getTime() <= timeC) {
0158 timeC = c.getTime();
0159 }
0160 }
0161 if (timeC > m_cfg.capTime) continue;
0162 edep += hit.getEnergy();
0163 trace("adding {} \t total: {}", hit.getEnergy(), edep);
0164
0165
0166 if (hit.getEnergy() > max_edep) {
0167 max_edep = hit.getEnergy();
0168 leading_hit = hit;
0169 if (timeC <= time) {
0170 time = timeC;
0171 }
0172 }
0173 }
0174 if (time > m_cfg.capTime) continue;
0175
0176
0177 const double eResRel = (edep > m_cfg.threshold)
0178 ? m_gaussian(m_generator) * std::sqrt(
0179 std::pow(m_cfg.eRes[0] / std::sqrt(edep), 2) +
0180 std::pow(m_cfg.eRes[1], 2) +
0181 std::pow(m_cfg.eRes[2] / (edep), 2)
0182 )
0183 : 0;
0184 double corrMeanScale_value = corrMeanScale(leading_hit);
0185 double ped = m_cfg.pedMeanADC + m_gaussian(m_generator) * m_cfg.pedSigmaADC;
0186 unsigned long long adc = std::llround(ped + edep * corrMeanScale_value * ( 1.0 + eResRel) / m_cfg.dyRangeADC * m_cfg.capADC);
0187 unsigned long long tdc = std::llround((time + m_gaussian(m_generator) * tRes) * stepTDC);
0188
0189 if (edep> 1.e-3) trace("E sim {} \t adc: {} \t time: {}\t maxtime: {} \t tdc: {} \t corrMeanScale: {}", edep, adc, time, m_cfg.capTime, tdc, corrMeanScale_value);
0190 rawhits->create(
0191 leading_hit.getCellID(),
0192 (adc > m_cfg.capADC ? m_cfg.capADC : adc),
0193 tdc
0194 );
0195 }
0196 }
0197
0198 }