File indexing completed on 2026-04-17 07:50:33
0001
0002
0003
0004
0005 #include <edm4eic/EDM4eicVersion.h>
0006 #include <tuple>
0007
0008 #if EDM4EIC_VERSION_MAJOR > 8 || (EDM4EIC_VERSION_MAJOR == 8 && EDM4EIC_VERSION_MINOR >= 7)
0009 #include <edm4eic/CALOROC1ASample.h>
0010 #include <edm4eic/CALOROC1BSample.h>
0011 #include <podio/RelationRange.h>
0012 #include <algorithm>
0013 #include <cmath>
0014 #include <cstddef>
0015 #include <vector>
0016
0017 #include "CALOROCDigitization.h"
0018
0019 namespace {
0020
0021 struct RawEntry {
0022 double adc{0};
0023 double toa{0};
0024 double tot{0};
0025 };
0026 }
0027
0028 namespace eicrecon {
0029
0030 void CALOROCDigitization::init() {}
0031
0032 void CALOROCDigitization::process(const CALOROCDigitization::Input& input,
0033 const CALOROCDigitization::Output& output) const {
0034 const auto [in_pulses] = input;
0035 auto [out_digi_hits] = output;
0036
0037 for (const auto& pulse : *in_pulses) {
0038 double pulse_t = pulse.getTime();
0039 double pulse_dt = pulse.getInterval();
0040 std::size_t n_amps = pulse.getAmplitude().size();
0041 std::size_t time_stamp =
0042 static_cast<std::size_t>(std::ceil((pulse_t - m_cfg.adc_phase) / m_cfg.time_window));
0043 std::size_t idx_amp_first = static_cast<std::size_t>(
0044 (m_cfg.adc_phase + time_stamp * m_cfg.time_window - pulse_t) / pulse_dt);
0045 std::size_t sample_tick = static_cast<std::size_t>(m_cfg.time_window / pulse_dt);
0046
0047 std::vector<RawEntry> raw_samples(m_cfg.n_samples);
0048
0049
0050
0051
0052 for (std::size_t i = 0; i < m_cfg.n_samples; i++) {
0053 std::size_t idx_amp = idx_amp_first + i * sample_tick;
0054 if (idx_amp < n_amps)
0055 raw_samples[i].adc = pulse.getAmplitude()[idx_amp];
0056 else
0057 break;
0058 }
0059
0060 std::size_t idx_sample = 0;
0061 std::size_t idx_toa = 0;
0062 double t_upcross = 0;
0063 bool is_above_threshold = false;
0064
0065
0066
0067 for (std::size_t i = 1; i < n_amps; i++) {
0068 double t = pulse_t + i * pulse_dt;
0069 if (i > idx_amp_first)
0070 idx_sample = (i + sample_tick - idx_amp_first - 1) / sample_tick;
0071 if (idx_sample == m_cfg.n_samples)
0072 break;
0073
0074
0075 if (!is_above_threshold && pulse.getAmplitude()[i] > m_cfg.toa_thres) {
0076 idx_toa = idx_sample;
0077 t_upcross = get_crossing_time(m_cfg.toa_thres, pulse_dt, t, pulse.getAmplitude()[i],
0078 pulse.getAmplitude()[i - 1]);
0079 raw_samples[idx_toa].toa =
0080 m_cfg.adc_phase + (time_stamp + idx_toa) * m_cfg.time_window - t_upcross;
0081 is_above_threshold = true;
0082 }
0083
0084
0085 if (is_above_threshold && pulse.getAmplitude()[i] < m_cfg.tot_thres) {
0086 raw_samples[idx_toa].tot =
0087 get_crossing_time(m_cfg.tot_thres, pulse_dt, t, pulse.getAmplitude()[i],
0088 pulse.getAmplitude()[i - 1]) -
0089 t_upcross;
0090 is_above_threshold = false;
0091 }
0092 }
0093
0094
0095 auto out_digi_hit = out_digi_hits->create();
0096 out_digi_hit.setCellID(pulse.getCellID());
0097 out_digi_hit.setSamplePhase(std::llround(m_cfg.adc_phase / m_cfg.dyRangeTOA * m_cfg.capTOA));
0098 out_digi_hit.setTimeStamp(time_stamp);
0099
0100 for (const auto& raw_sample : raw_samples) {
0101 auto adc =
0102 std::clamp(std::llround(raw_sample.adc / m_cfg.dyRangeSingleGainADC * m_cfg.capADC), 0LL,
0103 static_cast<long long>(m_cfg.capADC) - 1);
0104 auto toa = std::clamp(std::llround(raw_sample.toa / m_cfg.dyRangeTOA * m_cfg.capTOA), 0LL,
0105 static_cast<long long>(m_cfg.capTOA) - 1);
0106 auto tot = std::clamp(std::llround(raw_sample.tot / m_cfg.dyRangeTOT * m_cfg.capTOT), 0LL,
0107 static_cast<long long>(m_cfg.capTOT) - 1);
0108
0109 out_digi_hit.addToASamples([&]() {
0110 edm4eic::CALOROC1ASample aSample;
0111 aSample.ADC = adc;
0112 aSample.timeOfArrival = toa;
0113 aSample.timeOverThreshold = tot;
0114 return aSample;
0115 }());
0116
0117 auto high_adc =
0118 std::clamp(std::llround(raw_sample.adc / m_cfg.dyRangeHighGainADC * m_cfg.capADC), 0LL,
0119 static_cast<long long>(m_cfg.capADC) - 1);
0120 auto low_adc =
0121 std::clamp(std::llround(raw_sample.adc / m_cfg.dyRangeLowGainADC * m_cfg.capADC), 0LL,
0122 static_cast<long long>(m_cfg.capADC) - 1);
0123
0124 out_digi_hit.addToBSamples([&]() {
0125 edm4eic::CALOROC1BSample bSample;
0126 bSample.highGainADC = high_adc;
0127 bSample.lowGainADC = low_adc;
0128 bSample.timeOfArrival = toa;
0129 return bSample;
0130 }());
0131 }
0132 }
0133 }
0134
0135 double CALOROCDigitization::get_crossing_time(double thres, double dt, double t, double amp1,
0136 double amp2) const {
0137 double numerator = (amp1 - thres) * dt;
0138 double denominator = amp2 - amp1;
0139 double added = t;
0140 return (numerator / denominator) + added;
0141 }
0142 }
0143 #endif