From 151b2c9d4ff89bd9923bbc67477896c1a6a5bc1c Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Alicia=20V=C3=A1zquez-Ramos?= Date: Thu, 9 Oct 2025 04:05:54 -0500 Subject: [PATCH 01/18] Setup to start extended fragments feature --- .../XARAPUCA/SBNDXARAPUCADecoder_module.cc | 21 ++++++++++--------- .../Decoders/XARAPUCA/xarapucadecoder.fcl | 8 +++---- 2 files changed, 15 insertions(+), 14 deletions(-) diff --git a/sbndcode/Decoders/XARAPUCA/SBNDXARAPUCADecoder_module.cc b/sbndcode/Decoders/XARAPUCA/SBNDXARAPUCADecoder_module.cc index ac94c56e1..5be0a9e5d 100644 --- a/sbndcode/Decoders/XARAPUCA/SBNDXARAPUCADecoder_module.cc +++ b/sbndcode/Decoders/XARAPUCA/SBNDXARAPUCADecoder_module.cc @@ -372,15 +372,15 @@ void sbndaq::SBNDXARAPUCADecoder::produce(art::Event& e) } /** -* @brief Searches for the SPEC-TDC ETRIG timestamp closest to the raw timestamp if any SPEC-TDC ETRIG product is found in the event. -* @param[in] e The event to be processed. -* @param[in] corr_raw_timestamp The corrected raw timestamp from the artdaq::RawEventHeader product. -* @param[in,out] timestamp The closest ETRIG timestamp to the raw timestamp (if found). -* @return A boolean indicating if a valid ETRIG timestamp was found close enough to the raw timestamp. -* @details It searches for the SPEC-TDC products in the event and looks for the ETRIG timestamps. If any ETRIG -* timestamp is found, it checks which one is the closest to the raw timestamp and if it is close enough (i.e. -* within fraw_trig_max_diff) it returns it as output. -*/ + * @brief Searches for the SPEC-TDC ETRIG timestamp closest to the raw timestamp if any SPEC-TDC ETRIG product is found in the event. + * @param[in] e The event to be processed. + * @param[in] corr_raw_timestamp The corrected raw timestamp from the artdaq::RawEventHeader product. + * @param[in,out] timestamp The closest ETRIG timestamp to the raw timestamp (if found). + * @return A boolean indicating if a valid ETRIG timestamp was found close enough to the raw timestamp. + * @details It searches for the SPEC-TDC products in the event and looks for the ETRIG timestamps. If any ETRIG + * timestamp is found, it checks which one is the closest to the raw timestamp and if it is close enough (i.e. + * within fraw_trig_max_diff) it returns it as output. + */ bool sbndaq::SBNDXARAPUCADecoder::get_spec_tdc_etrig_timestamp(art::Event& e, uint64_t corr_raw_timestamp, uint64_t& timestamp) { bool ett_found = false; @@ -718,7 +718,7 @@ void sbndaq::SBNDXARAPUCADecoder::decode_fragment(uint64_t timestamp, std::vecto } if (fverbose | fdebug_timing) { - std::cout << std::fixed << std::setprecision(3) << std::endl; + std::cout << std::fixed << std::setprecision(3); if (factive_timing_frame == SPEC_TDC_TIMING) { std::cout << " > SBNDXARAPUCADecoder::decode_fragment: SPEC-TDC time window of " << end_wvfm_timestamp - ini_wvfm_timestamp << " us: [" << ini_wvfm_timestamp << ", " << end_wvfm_timestamp << "] us." << std::endl; } else if (factive_timing_frame == PTB_TIMING) { @@ -726,6 +726,7 @@ void sbndaq::SBNDXARAPUCADecoder::decode_fragment(uint64_t timestamp, std::vecto } else { // CAEN_ONLY_TIMING std::cout << " > SBNDXARAPUCADecoder::decode_fragment: CAEN time window of " << end_wvfm_timestamp - ini_wvfm_timestamp << " us: [" << ini_wvfm_timestamp << ", " << end_wvfm_timestamp << "] us." << std::endl; } + std::cout << " > SBNDXARAPUCADecoder::decode_fragment: TTT_end_ticks = " << TTT_ticks << " ticks. \t TTT_end_ns = " << print_timestamp(TTT_end_ns) << "." << std::endl; } // =============== Start decoding the waveforms =============== // diff --git a/sbndcode/Decoders/XARAPUCA/xarapucadecoder.fcl b/sbndcode/Decoders/XARAPUCA/xarapucadecoder.fcl index 3456450f9..774032157 100644 --- a/sbndcode/Decoders/XARAPUCA/xarapucadecoder.fcl +++ b/sbndcode/Decoders/XARAPUCA/xarapucadecoder.fcl @@ -32,16 +32,16 @@ xarapucadecoder: # - Output data product instance name. waveforms_instance_name: "XARAPUCAChannels" # Name for the instance product containing the raw decoded waveforms. timing_ref_instance_name: "" # Name for the instance product containing the timing reference information. - store_debug_waveforms: 0 # Number of waveforms to store (0: none, -1: all, n: first n waveforms). + store_debug_waveforms: -1 # Number of waveforms to store (0: none, -1: all, n: first n waveforms). # - Debug options. debug_tdc_handle: false # (De)activates SPEC-TDC art::Handle information printing. debug_ptb_handle: false # (De)activates PTB art::Handle information printing. - debug_fragments_handle: false # (De)activates V1740B CAEN fragments art::Handle information printing. - debug_timing: false # (De)activates timing data printing. + debug_fragments_handle: true # (De)activates V1740B CAEN fragments art::Handle information printing. + debug_timing: true # (De)activates timing data printing. debug_buffer: false # (De)activates buffer status printing. debug_waveforms: false # (De)activates waveforms decoding printing. # - Verbose option. - verbose: false # (De)activates verbosity. + verbose: true # (De)activates verbosity. } END_PROLOG \ No newline at end of file From 1e492fdc7c9745bb4264427560fa3a798d2fe9d0 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Alicia=20V=C3=A1zquez-Ramos?= Date: Thu, 9 Oct 2025 05:33:50 -0500 Subject: [PATCH 02/18] Shift timing function --- .../XARAPUCA/SBNDXARAPUCADecoder_module.cc | 214 ++++++++++++------ 1 file changed, 147 insertions(+), 67 deletions(-) diff --git a/sbndcode/Decoders/XARAPUCA/SBNDXARAPUCADecoder_module.cc b/sbndcode/Decoders/XARAPUCA/SBNDXARAPUCADecoder_module.cc index 5be0a9e5d..655c26cfb 100644 --- a/sbndcode/Decoders/XARAPUCA/SBNDXARAPUCADecoder_module.cc +++ b/sbndcode/Decoders/XARAPUCA/SBNDXARAPUCADecoder_module.cc @@ -137,6 +137,7 @@ class sbndaq::SBNDXARAPUCADecoder : public art::EDProducer { bool get_ptb_hlt_timestamp(art::Event& e, uint64_t corr_raw_timestamp, uint64_t & timestamp, uint16_t & hlt_code); bool get_spec_tdc_etrig_timestamp(art::Event& e, uint64_t corr_raw_timestamp, uint64_t & timestamp); + void shift_time(const artdaq::Fragment& fragment, uint64_t TTT_ticks, int64_t TTT_end_ns, uint64_t timestamp, uint32_t num_samples_per_wvfm, double& ini_wvfm_timestamp, double& end_wvfm_timestamp); void save_prod_wvfm(size_t board_idx, size_t ch, double ini_wvfm_timestamp, const std::vector > & wvfms, std::vector & prod_wvfms); void save_debug_wvfm(size_t board_idx, size_t fragment_idx, int ch, double ini_wvfm_timestamp, double end_wvfm_timestamp, const std::vector > & wvfms); @@ -616,6 +617,10 @@ void sbndaq::SBNDXARAPUCADecoder::decode_fragment(uint64_t timestamp, std::vecto if (valid_fragment) { if (fverbose) std::cout << "\n > SBNDXARAPUCADecoder::decode_fragment: decoding V1740 CAEN fragment " << fragment_indices[board_idx] << " from the board " << board_idx << " (slot " << fboard_id_list[board_idx] << "):" << std::endl; + //bool is_nominal_length = false; + //bool is_within_nominal_length = false; + //bool is_first = false; + // =============== Accesses Event metadata and Event header for this fragment =============== // CAENV1740Fragment caen_fragment(fragment); @@ -659,76 +664,81 @@ void sbndaq::SBNDXARAPUCADecoder::decode_fragment(uint64_t timestamp, std::vecto // =============== Extracts timing information for this fragment =============== // // Gets the timing information of the CAEN fragment. - int64_t pulse_duration_ns = num_samples_per_wvfm * fns_per_sample; // ns. - uint64_t frag_timestamp = fragment.timestamp(); // ns. - int64_t frag_timestamp_s = frag_timestamp / NANOSEC_IN_SEC; // s. - int64_t frag_timestamp_ns = frag_timestamp % NANOSEC_IN_SEC; // ns. +// int64_t pulse_duration_ns = num_samples_per_wvfm * fns_per_sample; // ns. +// uint64_t frag_timestamp = fragment.timestamp(); // ns. +// int64_t frag_timestamp_s = frag_timestamp / NANOSEC_IN_SEC; // s. +// int64_t frag_timestamp_ns = frag_timestamp % NANOSEC_IN_SEC; // ns. uint32_t TTT_ticks = header.triggerTime(); int64_t TTT_end_ns = TTT_ticks * NANOSEC_PER_TICK; // ns. - // Gets the full TTT timestamp. - uint64_t full_TTT = 0; - // If the fragment timestamp is greater than the TTT end timestamp, it means that rollover occurred. - if (frag_timestamp_ns > TTT_end_ns) { - if (fverbose | fdebug_timing) std::cout << " > SBNDXARAPUCADecoder::decode_fragment: CAEN TTT rollover occurred w.r.t. the fragment timestamp (FTS)." << std::endl; - full_TTT = (frag_timestamp_s + 1) * NANOSEC_IN_SEC + TTT_end_ns; - } else { - full_TTT = frag_timestamp_s * NANOSEC_IN_SEC + TTT_end_ns; - } - - int64_t ref_timestamp = 0; - - double ini_wvfm_timestamp = 0; - double end_wvfm_timestamp = 0; - - // If an ETRIG or HLT timestamp was found it restarts the time from it. Otherwise the CAEN time frame is assigned. - if (factive_timing_frame != CAEN_ONLY_TIMING) { - ref_timestamp = signed_difference(full_TTT, timestamp); // ns. - - ini_wvfm_timestamp = (ref_timestamp - pulse_duration_ns) * NANOSEC_TO_MICROSEC; // us. - end_wvfm_timestamp = ref_timestamp * NANOSEC_TO_MICROSEC; // us. - } else { - ref_timestamp = full_TTT; // ns. - - ini_wvfm_timestamp = ((ref_timestamp - pulse_duration_ns) % NANOSEC_IN_SEC) * NANOSEC_TO_MICROSEC; // ns. - end_wvfm_timestamp = (ref_timestamp % NANOSEC_IN_SEC) * NANOSEC_TO_MICROSEC; // us. - } - if (fdebug_timing) { - std::cout << std::fixed << std::setprecision(0); - std::cout << "\t\t ns/tick = " << NANOSEC_PER_TICK << ", ns/sample = " << fns_per_sample << std::endl; - std::cout << "\t\t TTT header.TriggerTime() [TTT_ticks] = " << TTT_ticks << " ticks. \t TTT_end_ns = " << print_timestamp(TTT_end_ns) << "." << std::endl; std::cout << "\t\t TTT header.extendedTriggerTime() [TTT_ticks] = " << header.extendedTriggerTime() << " ticks. \t TTT_end_ns = " << print_timestamp(header.extendedTriggerTime() * NANOSEC_PER_TICK) << "." << std::endl; std::cout << "\t\t TTT header.triggerTimeRollOver(): " << header.triggerTimeRollOver() << std::endl; - std::cout << "\t\t Full Fragment timestamp: " << print_timestamp(frag_timestamp) << " = " << frag_timestamp_s << " s " << frag_timestamp_ns << " ns." << std::endl; - std::cout << "\t\t Full TTT - fragment timestamp = "<< abs_difference(full_TTT, frag_timestamp) << " ns." << " Post-percent: " << (double(abs_difference(full_TTT, frag_timestamp)) / double(pulse_duration_ns)) * 100 << "%." << std::endl; - if (factive_timing_frame == SPEC_TDC_TIMING) { - std::cout << "\t ETRIG (SPEC-TDC) timestamp of the fragment: " << std::endl; - std::cout << "\t\t Full UTC ETRIG timestamp: " << print_timestamp(timestamp) << "." << std::endl; - std::cout << "\t\t ETRIG SPEC-TDC difference applied to the CAEN frame (full timestamps): " << print_timestamp(full_TTT) << " - " << print_timestamp(timestamp) << " = " << ref_timestamp << " ns." << std::endl; - } else if (factive_timing_frame == PTB_TIMING) { - std::cout << "\t HLT ETRIG (PTB) timestamp of the fragment: " << std::endl; - std::cout << "\t\t Full UTC HLT ETRIG timestamp: " << print_timestamp(timestamp) << "." << std::endl; - std::cout << "\t\t HLT ETRIG (PTB) difference applied to the CAEN frame (full timestamps): " << print_timestamp(full_TTT) << " - " << print_timestamp(timestamp) << " = " << ref_timestamp << " ns." << std::endl; - } else if (factive_timing_frame == CAEN_ONLY_TIMING) { - std::cout << "\t CAEN trigger timestamp (TTT) of the fragment: " << std::endl; - std::cout << "\t\t Full UTC TTT timestamp: " << print_timestamp(full_TTT) << " = " << full_TTT / NANOSEC_IN_SEC << " s " << TTT_end_ns << " ns." << std::endl; - } - } - - if (fverbose | fdebug_timing) { - std::cout << std::fixed << std::setprecision(3); - if (factive_timing_frame == SPEC_TDC_TIMING) { - std::cout << " > SBNDXARAPUCADecoder::decode_fragment: SPEC-TDC time window of " << end_wvfm_timestamp - ini_wvfm_timestamp << " us: [" << ini_wvfm_timestamp << ", " << end_wvfm_timestamp << "] us." << std::endl; - } else if (factive_timing_frame == PTB_TIMING) { - std::cout << " > SBNDXARAPUCADecoder::decode_fragment: PTB time window of " << end_wvfm_timestamp - ini_wvfm_timestamp << " us: [" << ini_wvfm_timestamp << ", " << end_wvfm_timestamp << "] us." << std::endl; - } else { // CAEN_ONLY_TIMING - std::cout << " > SBNDXARAPUCADecoder::decode_fragment: CAEN time window of " << end_wvfm_timestamp - ini_wvfm_timestamp << " us: [" << ini_wvfm_timestamp << ", " << end_wvfm_timestamp << "] us." << std::endl; - } - std::cout << " > SBNDXARAPUCADecoder::decode_fragment: TTT_end_ticks = " << TTT_ticks << " ticks. \t TTT_end_ns = " << print_timestamp(TTT_end_ns) << "." << std::endl; } - +// +// // Gets the full TTT timestamp. +// uint64_t full_TTT = 0; +// // If the fragment timestamp is greater than the TTT end timestamp, it means that rollover occurred. +// if (frag_timestamp_ns > TTT_end_ns) { +// if (fverbose | fdebug_timing) std::cout << " > SBNDXARAPUCADecoder::decode_fragment: CAEN TTT rollover occurred w.r.t. the fragment timestamp (FTS)." << std::endl; +// full_TTT = (frag_timestamp_s + 1) * NANOSEC_IN_SEC + TTT_end_ns; +// } else { +// full_TTT = frag_timestamp_s * NANOSEC_IN_SEC + TTT_end_ns; +// } +// +// int64_t ref_timestamp = 0; +// +// double ini_wvfm_timestamp = 0; +// double end_wvfm_timestamp = 0; +// +// // If an ETRIG or HLT timestamp was found it restarts the time from it. Otherwise the CAEN time frame is assigned. +// if (factive_timing_frame != CAEN_ONLY_TIMING) { +// ref_timestamp = signed_difference(full_TTT, timestamp); // ns. +// +// ini_wvfm_timestamp = (ref_timestamp - pulse_duration_ns) * NANOSEC_TO_MICROSEC; // us. +// end_wvfm_timestamp = ref_timestamp * NANOSEC_TO_MICROSEC; // us. +// } else { +// ref_timestamp = full_TTT; // ns. +// +// ini_wvfm_timestamp = ((ref_timestamp - pulse_duration_ns) % NANOSEC_IN_SEC) * NANOSEC_TO_MICROSEC; // ns. +// end_wvfm_timestamp = (ref_timestamp % NANOSEC_IN_SEC) * NANOSEC_TO_MICROSEC; // us. +// } +// +// if (fdebug_timing) { +// std::cout << std::fixed << std::setprecision(0); +// std::cout << "\t\t ns/tick = " << NANOSEC_PER_TICK << ", ns/sample = " << fns_per_sample << std::endl; +// std::cout << "\t\t TTT header.TriggerTime() [TTT_ticks] = " << TTT_ticks << " ticks. \t TTT_end_ns = " << print_timestamp(TTT_end_ns) << "." << std::endl; +// std::cout << "\t\t TTT header.extendedTriggerTime() [TTT_ticks] = " << header.extendedTriggerTime() << " ticks. \t TTT_end_ns = " << print_timestamp(header.extendedTriggerTime() * NANOSEC_PER_TICK) << "." << std::endl; +// std::cout << "\t\t TTT header.triggerTimeRollOver(): " << header.triggerTimeRollOver() << std::endl; +// std::cout << "\t\t Full Fragment timestamp: " << print_timestamp(frag_timestamp) << " = " << frag_timestamp_s << " s " << frag_timestamp_ns << " ns." << std::endl; +// std::cout << "\t\t Full TTT - fragment timestamp = "<< abs_difference(full_TTT, frag_timestamp) << " ns." << " Post-percent: " << (double(abs_difference(full_TTT, frag_timestamp)) / double(pulse_duration_ns)) * 100 << "%." << std::endl; +// if (factive_timing_frame == SPEC_TDC_TIMING) { +// std::cout << "\t ETRIG (SPEC-TDC) timestamp of the fragment: " << std::endl; +// std::cout << "\t\t Full UTC ETRIG timestamp: " << print_timestamp(timestamp) << "." << std::endl; +// std::cout << "\t\t ETRIG SPEC-TDC difference applied to the CAEN frame (full timestamps): " << print_timestamp(full_TTT) << " - " << print_timestamp(timestamp) << " = " << ref_timestamp << " ns." << std::endl; +// } else if (factive_timing_frame == PTB_TIMING) { +// std::cout << "\t HLT ETRIG (PTB) timestamp of the fragment: " << std::endl; +// std::cout << "\t\t Full UTC HLT ETRIG timestamp: " << print_timestamp(timestamp) << "." << std::endl; +// std::cout << "\t\t HLT ETRIG (PTB) difference applied to the CAEN frame (full timestamps): " << print_timestamp(full_TTT) << " - " << print_timestamp(timestamp) << " = " << ref_timestamp << " ns." << std::endl; +// } else if (factive_timing_frame == CAEN_ONLY_TIMING) { +// std::cout << "\t CAEN trigger timestamp (TTT) of the fragment: " << std::endl; +// std::cout << "\t\t Full UTC TTT timestamp: " << print_timestamp(full_TTT) << " = " << full_TTT / NANOSEC_IN_SEC << " s " << TTT_end_ns << " ns." << std::endl; +// } +// } +// +// if (fverbose | fdebug_timing) { +// std::cout << std::fixed << std::setprecision(3); +// if (factive_timing_frame == SPEC_TDC_TIMING) { +// std::cout << " > SBNDXARAPUCADecoder::decode_fragment: SPEC-TDC time window of " << end_wvfm_timestamp - ini_wvfm_timestamp << " us: [" << ini_wvfm_timestamp << ", " << end_wvfm_timestamp << "] us." << std::endl; +// } else if (factive_timing_frame == PTB_TIMING) { +// std::cout << " > SBNDXARAPUCADecoder::decode_fragment: PTB time window of " << end_wvfm_timestamp - ini_wvfm_timestamp << " us: [" << ini_wvfm_timestamp << ", " << end_wvfm_timestamp << "] us." << std::endl; +// } else { // CAEN_ONLY_TIMING +// std::cout << " > SBNDXARAPUCADecoder::decode_fragment: CAEN time window of " << end_wvfm_timestamp - ini_wvfm_timestamp << " us: [" << ini_wvfm_timestamp << ", " << end_wvfm_timestamp << "] us." << std::endl; +// } +// std::cout << " > SBNDXARAPUCADecoder::decode_fragment: TTT_end_ticks = " << TTT_ticks << " ticks. \t TTT_end_ns = " << print_timestamp(TTT_end_ns) << "." << std::endl; +// } +// // =============== Start decoding the waveforms =============== // if (fverbose) std::cout << " > SBNDXARAPUCADecoder::decode_fragment: binary decoding of the waveforms starting... " << std::endl; @@ -771,6 +781,11 @@ void sbndaq::SBNDXARAPUCADecoder::decode_fragment(uint64_t timestamp, std::vecto S++; } } + + + double ini_wvfm_timestamp = 0; + double end_wvfm_timestamp = 0; + shift_time(fragment, TTT_ticks, TTT_end_ns, timestamp, num_samples_per_wvfm, ini_wvfm_timestamp, end_wvfm_timestamp); // The decoded waveforms are dumped into two products: // - A xarapucadecoder-art.root file with the OpDetWaveforms as the product of this producer for further analysis. @@ -878,6 +893,71 @@ void sbndaq::SBNDXARAPUCADecoder::save_debug_wvfm(size_t board_idx, size_t fragm } +void sbndaq::SBNDXARAPUCADecoder::shift_time(const artdaq::Fragment& fragment, uint64_t TTT_ticks, int64_t TTT_end_ns, uint64_t timestamp, uint32_t num_samples_per_wvfm, double& ini_wvfm_timestamp, double& end_wvfm_timestamp) { + + int64_t pulse_duration_ns = num_samples_per_wvfm * fns_per_sample; // ns. + uint64_t frag_timestamp = fragment.timestamp(); // ns. + int64_t frag_timestamp_s = frag_timestamp / NANOSEC_IN_SEC; // s. + int64_t frag_timestamp_ns = frag_timestamp % NANOSEC_IN_SEC; // ns. + + // Gets the full TTT timestamp. + uint64_t full_TTT = 0; + // If the fragment timestamp is greater than the TTT end timestamp, it means that rollover occurred. + if (frag_timestamp_ns > TTT_end_ns) { + if (fverbose | fdebug_timing) std::cout << " > SBNDXARAPUCADecoder::decode_fragment: CAEN TTT rollover occurred w.r.t. the fragment timestamp (FTS)." << std::endl; + full_TTT = (frag_timestamp_s + 1) * NANOSEC_IN_SEC + TTT_end_ns; + } else { + full_TTT = frag_timestamp_s * NANOSEC_IN_SEC + TTT_end_ns; + } + + int64_t ref_timestamp = 0; + + // If an ETRIG or HLT timestamp was found it restarts the time from it. Otherwise the CAEN time frame is assigned. + if (factive_timing_frame != CAEN_ONLY_TIMING) { + ref_timestamp = signed_difference(full_TTT, timestamp); // ns. + + ini_wvfm_timestamp = (ref_timestamp - pulse_duration_ns) * NANOSEC_TO_MICROSEC; // us. + end_wvfm_timestamp = ref_timestamp * NANOSEC_TO_MICROSEC; // us. + } else { + ref_timestamp = full_TTT; // ns. + + ini_wvfm_timestamp = ((ref_timestamp - pulse_duration_ns) % NANOSEC_IN_SEC) * NANOSEC_TO_MICROSEC; // ns. + end_wvfm_timestamp = (ref_timestamp % NANOSEC_IN_SEC) * NANOSEC_TO_MICROSEC; // us. + } + + if (fdebug_timing) { + std::cout << std::fixed << std::setprecision(0); + std::cout << "\t\t ns/tick = " << NANOSEC_PER_TICK << ", ns/sample = " << fns_per_sample << std::endl; + std::cout << "\t\t TTT header.TriggerTime() [TTT_ticks] = " << TTT_ticks << " ticks. \t TTT_end_ns = " << print_timestamp(TTT_end_ns) << "." << std::endl; + std::cout << "\t\t Full Fragment timestamp: " << print_timestamp(frag_timestamp) << " = " << frag_timestamp_s << " s " << frag_timestamp_ns << " ns." << std::endl; + std::cout << "\t\t Full TTT - fragment timestamp = "<< abs_difference(full_TTT, frag_timestamp) << " ns." << " Post-percent: " << (double(abs_difference(full_TTT, frag_timestamp)) / double(pulse_duration_ns)) * 100 << "%." << std::endl; + if (factive_timing_frame == SPEC_TDC_TIMING) { + std::cout << "\t ETRIG (SPEC-TDC) timestamp of the fragment: " << std::endl; + std::cout << "\t\t Full UTC ETRIG timestamp: " << print_timestamp(timestamp) << "." << std::endl; + std::cout << "\t\t ETRIG SPEC-TDC difference applied to the CAEN frame (full timestamps): " << print_timestamp(full_TTT) << " - " << print_timestamp(timestamp) << " = " << ref_timestamp << " ns." << std::endl; + } else if (factive_timing_frame == PTB_TIMING) { + std::cout << "\t HLT ETRIG (PTB) timestamp of the fragment: " << std::endl; + std::cout << "\t\t Full UTC HLT ETRIG timestamp: " << print_timestamp(timestamp) << "." << std::endl; + std::cout << "\t\t HLT ETRIG (PTB) difference applied to the CAEN frame (full timestamps): " << print_timestamp(full_TTT) << " - " << print_timestamp(timestamp) << " = " << ref_timestamp << " ns." << std::endl; + } else if (factive_timing_frame == CAEN_ONLY_TIMING) { + std::cout << "\t CAEN trigger timestamp (TTT) of the fragment: " << std::endl; + std::cout << "\t\t Full UTC TTT timestamp: " << print_timestamp(full_TTT) << " = " << full_TTT / NANOSEC_IN_SEC << " s " << TTT_end_ns << " ns." << std::endl; + } + } + + if (fverbose | fdebug_timing) { + std::cout << std::fixed << std::setprecision(3); + if (factive_timing_frame == SPEC_TDC_TIMING) { + std::cout << " > SBNDXARAPUCADecoder::decode_fragment: SPEC-TDC time window of " << end_wvfm_timestamp - ini_wvfm_timestamp << " us: [" << ini_wvfm_timestamp << ", " << end_wvfm_timestamp << "] us." << std::endl; + } else if (factive_timing_frame == PTB_TIMING) { + std::cout << " > SBNDXARAPUCADecoder::decode_fragment: PTB time window of " << end_wvfm_timestamp - ini_wvfm_timestamp << " us: [" << ini_wvfm_timestamp << ", " << end_wvfm_timestamp << "] us." << std::endl; + } else { // CAEN_ONLY_TIMING + std::cout << " > SBNDXARAPUCADecoder::decode_fragment: CAEN time window of " << end_wvfm_timestamp - ini_wvfm_timestamp << " us: [" << ini_wvfm_timestamp << ", " << end_wvfm_timestamp << "] us." << std::endl; + } + std::cout << " > SBNDXARAPUCADecoder::decode_fragment: TTT_end_ticks = " << TTT_ticks << " ticks. \t TTT_end_ns = " << print_timestamp(TTT_end_ns) << "." << std::endl; + } +} + /** * @brief Extract a sample from a 64-bit buffer using the specified bit positions. * @@ -975,11 +1055,11 @@ uint64_t sbndaq::SBNDXARAPUCADecoder::abs_difference(uint64_t t1, uint64_t t2) { } /** -* @brief Formats a timestamp in nanoseconds into a easily readable string format. -* @param[in] timestamp The timestamp in nanoseconds to be formatted. -* @return A string representation of the timestamp in the format "(seconds)nanoseconds ns". -* @details The function divides the input timestamp by 1,000,000,000 to obtain the seconds component and uses the modulus operator to get the remaining nanoseconds. -*/ + * @brief Formats a timestamp in nanoseconds into a easily readable string format. + * @param[in] timestamp The timestamp in nanoseconds to be formatted. + * @return A string representation of the timestamp in the format "(seconds)nanoseconds ns". + * @details The function divides the input timestamp by 1,000,000,000 to obtain the seconds component and uses the modulus operator to get the remaining nanoseconds. + */ std::string sbndaq::SBNDXARAPUCADecoder::print_timestamp(uint64_t timestamp) { return "(" + std::to_string(timestamp / NANOSEC_IN_SEC) + ")" + std::to_string(timestamp % NANOSEC_IN_SEC) + " ns"; } From 3f93cebdce39d9be4f21d180cc9fdcf3d5a576dd Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Alicia=20V=C3=A1zquez-Ramos?= Date: Thu, 9 Oct 2025 06:07:47 -0500 Subject: [PATCH 03/18] Waveforms decoding function --- .../XARAPUCA/SBNDXARAPUCADecoder_module.cc | 195 ++++++++---------- .../Decoders/XARAPUCA/xarapucadecoder.fcl | 2 +- 2 files changed, 89 insertions(+), 108 deletions(-) diff --git a/sbndcode/Decoders/XARAPUCA/SBNDXARAPUCADecoder_module.cc b/sbndcode/Decoders/XARAPUCA/SBNDXARAPUCADecoder_module.cc index 655c26cfb..72020207c 100644 --- a/sbndcode/Decoders/XARAPUCA/SBNDXARAPUCADecoder_module.cc +++ b/sbndcode/Decoders/XARAPUCA/SBNDXARAPUCADecoder_module.cc @@ -138,6 +138,7 @@ class sbndaq::SBNDXARAPUCADecoder : public art::EDProducer { bool get_ptb_hlt_timestamp(art::Event& e, uint64_t corr_raw_timestamp, uint64_t & timestamp, uint16_t & hlt_code); bool get_spec_tdc_etrig_timestamp(art::Event& e, uint64_t corr_raw_timestamp, uint64_t & timestamp); void shift_time(const artdaq::Fragment& fragment, uint64_t TTT_ticks, int64_t TTT_end_ns, uint64_t timestamp, uint32_t num_samples_per_wvfm, double& ini_wvfm_timestamp, double& end_wvfm_timestamp); + void decode_waveforms(const artdaq::Fragment& fragment, std::vector>& wvfms, size_t header_size, uint32_t num_channels, uint32_t num_samples_per_wvfm, uint32_t num_words_per_wvfms, uint32_t num_samples_per_group); void save_prod_wvfm(size_t board_idx, size_t ch, double ini_wvfm_timestamp, const std::vector > & wvfms, std::vector & prod_wvfms); void save_debug_wvfm(size_t board_idx, size_t fragment_idx, int ch, double ini_wvfm_timestamp, double end_wvfm_timestamp, const std::vector > & wvfms); @@ -634,7 +635,8 @@ void sbndaq::SBNDXARAPUCADecoder::decode_fragment(uint64_t timestamp, std::vecto // Gets the number of words of the header and the waveforms. uint32_t num_words_per_event = header.eventSize; - uint32_t num_words_per_header = sizeof(CAENV1740EventHeader) / sizeof(uint32_t); + size_t header_size = sizeof(CAENV1740EventHeader); + uint32_t num_words_per_header = header_size / sizeof(uint32_t); uint32_t num_words_per_wvfms = (num_words_per_event - num_words_per_header); uint32_t num_bits_per_all_wvfms = num_words_per_wvfms * BITS_PER_WORD; @@ -663,12 +665,6 @@ void sbndaq::SBNDXARAPUCADecoder::decode_fragment(uint64_t timestamp, std::vecto // =============== Extracts timing information for this fragment =============== // - // Gets the timing information of the CAEN fragment. -// int64_t pulse_duration_ns = num_samples_per_wvfm * fns_per_sample; // ns. -// uint64_t frag_timestamp = fragment.timestamp(); // ns. -// int64_t frag_timestamp_s = frag_timestamp / NANOSEC_IN_SEC; // s. -// int64_t frag_timestamp_ns = frag_timestamp % NANOSEC_IN_SEC; // ns. - uint32_t TTT_ticks = header.triggerTime(); int64_t TTT_end_ns = TTT_ticks * NANOSEC_PER_TICK; // ns. @@ -676,113 +672,53 @@ void sbndaq::SBNDXARAPUCADecoder::decode_fragment(uint64_t timestamp, std::vecto std::cout << "\t\t TTT header.extendedTriggerTime() [TTT_ticks] = " << header.extendedTriggerTime() << " ticks. \t TTT_end_ns = " << print_timestamp(header.extendedTriggerTime() * NANOSEC_PER_TICK) << "." << std::endl; std::cout << "\t\t TTT header.triggerTimeRollOver(): " << header.triggerTimeRollOver() << std::endl; } + +// // =============== Start decoding the waveforms =============== // + std::vector > wvfms(num_channels, std::vector(num_samples_per_wvfm, 0)); + decode_waveforms(fragment, wvfms, header_size, num_channels, num_samples_per_wvfm, num_words_per_wvfms, num_samples_per_group); +// if (fverbose) std::cout << " > SBNDXARAPUCADecoder::decode_fragment: binary decoding of the waveforms starting... " << std::endl; +// +// std::vector > wvfms(num_channels, std::vector(num_samples_per_wvfm, 0)); // -// // Gets the full TTT timestamp. -// uint64_t full_TTT = 0; -// // If the fragment timestamp is greater than the TTT end timestamp, it means that rollover occurred. -// if (frag_timestamp_ns > TTT_end_ns) { -// if (fverbose | fdebug_timing) std::cout << " > SBNDXARAPUCADecoder::decode_fragment: CAEN TTT rollover occurred w.r.t. the fragment timestamp (FTS)." << std::endl; -// full_TTT = (frag_timestamp_s + 1) * NANOSEC_IN_SEC + TTT_end_ns; -// } else { -// full_TTT = frag_timestamp_s * NANOSEC_IN_SEC + TTT_end_ns; -// } -// -// int64_t ref_timestamp = 0; -// -// double ini_wvfm_timestamp = 0; -// double end_wvfm_timestamp = 0; -// -// // If an ETRIG or HLT timestamp was found it restarts the time from it. Otherwise the CAEN time frame is assigned. -// if (factive_timing_frame != CAEN_ONLY_TIMING) { -// ref_timestamp = signed_difference(full_TTT, timestamp); // ns. -// -// ini_wvfm_timestamp = (ref_timestamp - pulse_duration_ns) * NANOSEC_TO_MICROSEC; // us. -// end_wvfm_timestamp = ref_timestamp * NANOSEC_TO_MICROSEC; // us. -// } else { -// ref_timestamp = full_TTT; // ns. +// // Absolute sample number [0, TOTAL_NUM_SAMPLES] where TOTAL_NUM_SAMPLES is the total number of samples stored for an event. +// uint32_t S = 0; +// // Buffer variables. +// uint64_t buffer = 0; +// uint32_t bits_in_buffer = 0; // -// ini_wvfm_timestamp = ((ref_timestamp - pulse_duration_ns) % NANOSEC_IN_SEC) * NANOSEC_TO_MICROSEC; // ns. -// end_wvfm_timestamp = (ref_timestamp % NANOSEC_IN_SEC) * NANOSEC_TO_MICROSEC; // us. -// } +// // Data pointer to the beggining of the waveforms stores in the event. +// const uint32_t* data_ptr = reinterpret_cast(fragment.dataBeginBytes() + sizeof(CAENV1740EventHeader)); +// // Accesses each word, stores it in the buffer and then the samples are extracted from the buffer. +// for (size_t j = 0; j < num_words_per_wvfms; j++) { +// uint64_t word = read_word(data_ptr); // -// if (fdebug_timing) { -// std::cout << std::fixed << std::setprecision(0); -// std::cout << "\t\t ns/tick = " << NANOSEC_PER_TICK << ", ns/sample = " << fns_per_sample << std::endl; -// std::cout << "\t\t TTT header.TriggerTime() [TTT_ticks] = " << TTT_ticks << " ticks. \t TTT_end_ns = " << print_timestamp(TTT_end_ns) << "." << std::endl; -// std::cout << "\t\t TTT header.extendedTriggerTime() [TTT_ticks] = " << header.extendedTriggerTime() << " ticks. \t TTT_end_ns = " << print_timestamp(header.extendedTriggerTime() * NANOSEC_PER_TICK) << "." << std::endl; -// std::cout << "\t\t TTT header.triggerTimeRollOver(): " << header.triggerTimeRollOver() << std::endl; -// std::cout << "\t\t Full Fragment timestamp: " << print_timestamp(frag_timestamp) << " = " << frag_timestamp_s << " s " << frag_timestamp_ns << " ns." << std::endl; -// std::cout << "\t\t Full TTT - fragment timestamp = "<< abs_difference(full_TTT, frag_timestamp) << " ns." << " Post-percent: " << (double(abs_difference(full_TTT, frag_timestamp)) / double(pulse_duration_ns)) * 100 << "%." << std::endl; -// if (factive_timing_frame == SPEC_TDC_TIMING) { -// std::cout << "\t ETRIG (SPEC-TDC) timestamp of the fragment: " << std::endl; -// std::cout << "\t\t Full UTC ETRIG timestamp: " << print_timestamp(timestamp) << "." << std::endl; -// std::cout << "\t\t ETRIG SPEC-TDC difference applied to the CAEN frame (full timestamps): " << print_timestamp(full_TTT) << " - " << print_timestamp(timestamp) << " = " << ref_timestamp << " ns." << std::endl; -// } else if (factive_timing_frame == PTB_TIMING) { -// std::cout << "\t HLT ETRIG (PTB) timestamp of the fragment: " << std::endl; -// std::cout << "\t\t Full UTC HLT ETRIG timestamp: " << print_timestamp(timestamp) << "." << std::endl; -// std::cout << "\t\t HLT ETRIG (PTB) difference applied to the CAEN frame (full timestamps): " << print_timestamp(full_TTT) << " - " << print_timestamp(timestamp) << " = " << ref_timestamp << " ns." << std::endl; -// } else if (factive_timing_frame == CAEN_ONLY_TIMING) { -// std::cout << "\t CAEN trigger timestamp (TTT) of the fragment: " << std::endl; -// std::cout << "\t\t Full UTC TTT timestamp: " << print_timestamp(full_TTT) << " = " << full_TTT / NANOSEC_IN_SEC << " s " << TTT_end_ns << " ns." << std::endl; -// } -// } +// // Adds the new word to the buffer and increments the number of bits stored in it. +// if (fdebug_buffer) std::cout << buffer << "[word: " << word << "]" << std::endl; +// buffer |= word << bits_in_buffer; +// bits_in_buffer += BITS_PER_WORD; // bytes * 8 bits/byte +// if (fdebug_buffer) std::cout << " +" << buffer << " [bits in buffer: "<< bits_in_buffer << "]" << std::endl; // -// if (fverbose | fdebug_timing) { -// std::cout << std::fixed << std::setprecision(3); -// if (factive_timing_frame == SPEC_TDC_TIMING) { -// std::cout << " > SBNDXARAPUCADecoder::decode_fragment: SPEC-TDC time window of " << end_wvfm_timestamp - ini_wvfm_timestamp << " us: [" << ini_wvfm_timestamp << ", " << end_wvfm_timestamp << "] us." << std::endl; -// } else if (factive_timing_frame == PTB_TIMING) { -// std::cout << " > SBNDXARAPUCADecoder::decode_fragment: PTB time window of " << end_wvfm_timestamp - ini_wvfm_timestamp << " us: [" << ini_wvfm_timestamp << ", " << end_wvfm_timestamp << "] us." << std::endl; -// } else { // CAEN_ONLY_TIMING -// std::cout << " > SBNDXARAPUCADecoder::decode_fragment: CAEN time window of " << end_wvfm_timestamp - ini_wvfm_timestamp << " us: [" << ini_wvfm_timestamp << ", " << end_wvfm_timestamp << "] us." << std::endl; +// // Obtains 12-bit sequences from the buffer and assigns each sample to the channel and channel sample it belongs to. +// while (bits_in_buffer >= BITS_PER_SAMPLE) { +// // Computes board channel, channel sample and group channel and assigns the sample to those indices. +// uint32_t g = (S / num_samples_per_group); // Group index. +// uint32_t c = ((S / NUM_CONSECUTIVE_SAMPLES) % NUM_CHANNELS_PER_GROUP) + g * NUM_GROUPS; // Channel index. +// uint32_t s = (S % NUM_CONSECUTIVE_SAMPLES) + ((S / NUM_SAMPLES_PER_ROUND) * NUM_CONSECUTIVE_SAMPLES) % num_samples_per_wvfm; // Sample/channel index. +// uint16_t sample = get_sample(buffer, BITS_PER_SAMPLE - 1, 0); +// wvfms[c][s] = sample; +// if (fdebug_waveforms) std::cout << "\tSample: " << sample << "\tg: " << g << "\tch: " << c << "\ts:" << s << "\tS: " << S << std::endl; +// +// // Updates the buffer status removing the read bits and decreasing the number of bits stored in it. +// buffer >>= BITS_PER_SAMPLE; +// bits_in_buffer -= BITS_PER_SAMPLE; +// if (fdebug_buffer) std::cout << " -" << buffer << " [bits in buffer: "<< bits_in_buffer << "]" << std::endl; +// +// // Increments the absolute sample step. +// S++; // } -// std::cout << " > SBNDXARAPUCADecoder::decode_fragment: TTT_end_ticks = " << TTT_ticks << " ticks. \t TTT_end_ns = " << print_timestamp(TTT_end_ns) << "." << std::endl; // } -// - // =============== Start decoding the waveforms =============== // - if (fverbose) std::cout << " > SBNDXARAPUCADecoder::decode_fragment: binary decoding of the waveforms starting... " << std::endl; - - std::vector > wvfms(num_channels, std::vector(num_samples_per_wvfm, 0)); - - // Absolute sample number [0, TOTAL_NUM_SAMPLES] where TOTAL_NUM_SAMPLES is the total number of samples stored for an event. - uint32_t S = 0; - // Buffer variables. - uint64_t buffer = 0; - uint32_t bits_in_buffer = 0; - - // Data pointer to the beggining of the waveforms stores in the event. - const uint32_t* data_ptr = reinterpret_cast(fragment.dataBeginBytes() + sizeof(CAENV1740EventHeader)); - // Accesses each word, stores it in the buffer and then the samples are extracted from the buffer. - for (size_t j = 0; j < num_words_per_wvfms; j++) { - uint64_t word = read_word(data_ptr); - - // Adds the new word to the buffer and increments the number of bits stored in it. - if (fdebug_buffer) std::cout << buffer << "[word: " << word << "]" << std::endl; - buffer |= word << bits_in_buffer; - bits_in_buffer += BITS_PER_WORD; // bytes * 8 bits/byte - if (fdebug_buffer) std::cout << " +" << buffer << " [bits in buffer: "<< bits_in_buffer << "]" << std::endl; - - // Obtains 12-bit sequences from the buffer and assigns each sample to the channel and channel sample it belongs to. - while (bits_in_buffer >= BITS_PER_SAMPLE) { - // Computes board channel, channel sample and group channel and assigns the sample to those indices. - uint32_t g = (S / num_samples_per_group); // Group index. - uint32_t c = ((S / NUM_CONSECUTIVE_SAMPLES) % NUM_CHANNELS_PER_GROUP) + g * NUM_GROUPS; // Channel index. - uint32_t s = (S % NUM_CONSECUTIVE_SAMPLES) + ((S / NUM_SAMPLES_PER_ROUND) * NUM_CONSECUTIVE_SAMPLES) % num_samples_per_wvfm; // Sample/channel index. - uint16_t sample = get_sample(buffer, BITS_PER_SAMPLE - 1, 0); - wvfms[c][s] = sample; - if (fdebug_waveforms) std::cout << "\tSample: " << sample << "\tg: " << g << "\tch: " << c << "\ts:" << s << "\tS: " << S << std::endl; - - // Updates the buffer status removing the read bits and decreasing the number of bits stored in it. - buffer >>= BITS_PER_SAMPLE; - bits_in_buffer -= BITS_PER_SAMPLE; - if (fdebug_buffer) std::cout << " -" << buffer << " [bits in buffer: "<< bits_in_buffer << "]" << std::endl; - - // Increments the absolute sample step. - S++; - } - } - + // =============== Shifts timing to the selected timing reference frame =============== // double ini_wvfm_timestamp = 0; double end_wvfm_timestamp = 0; shift_time(fragment, TTT_ticks, TTT_end_ns, timestamp, num_samples_per_wvfm, ini_wvfm_timestamp, end_wvfm_timestamp); @@ -958,6 +894,51 @@ void sbndaq::SBNDXARAPUCADecoder::shift_time(const artdaq::Fragment& fragment, u } } +void sbndaq::SBNDXARAPUCADecoder::decode_waveforms(const artdaq::Fragment& fragment, std::vector>& wvfms, size_t header_size, uint32_t num_channels, uint32_t num_samples_per_wvfm, uint32_t num_words_per_wvfms, uint32_t num_samples_per_group) { + // =============== Start decoding the waveforms =============== // + if (fverbose) std::cout << " > SBNDXARAPUCADecoder::decode_fragment: binary decoding of the waveforms starting... " << std::endl; + + //std::vector > wvfms(num_channels, std::vector(num_samples_per_wvfm, 0)); + + // Absolute sample number [0, TOTAL_NUM_SAMPLES] where TOTAL_NUM_SAMPLES is the total number of samples stored for an event. + uint32_t S = 0; + // Buffer variables. + uint64_t buffer = 0; + uint32_t bits_in_buffer = 0; + + // Data pointer to the beggining of the waveforms stores in the event. + const uint32_t* data_ptr = reinterpret_cast(fragment.dataBeginBytes() + header_size); + // Accesses each word, stores it in the buffer and then the samples are extracted from the buffer. + for (size_t j = 0; j < num_words_per_wvfms; j++) { + uint64_t word = read_word(data_ptr); + + // Adds the new word to the buffer and increments the number of bits stored in it. + if (fdebug_buffer) std::cout << buffer << "[word: " << word << "]" << std::endl; + buffer |= word << bits_in_buffer; + bits_in_buffer += BITS_PER_WORD; // bytes * 8 bits/byte + if (fdebug_buffer) std::cout << " +" << buffer << " [bits in buffer: "<< bits_in_buffer << "]" << std::endl; + + // Obtains 12-bit sequences from the buffer and assigns each sample to the channel and channel sample it belongs to. + while (bits_in_buffer >= BITS_PER_SAMPLE) { + // Computes board channel, channel sample and group channel and assigns the sample to those indices. + uint32_t g = (S / num_samples_per_group); // Group index. + uint32_t c = ((S / NUM_CONSECUTIVE_SAMPLES) % NUM_CHANNELS_PER_GROUP) + g * NUM_GROUPS; // Channel index. + uint32_t s = (S % NUM_CONSECUTIVE_SAMPLES) + ((S / NUM_SAMPLES_PER_ROUND) * NUM_CONSECUTIVE_SAMPLES) % num_samples_per_wvfm; // Sample/channel index. + uint16_t sample = get_sample(buffer, BITS_PER_SAMPLE - 1, 0); + wvfms[c][s] = sample; + if (fdebug_waveforms) std::cout << "\tSample: " << sample << "\tg: " << g << "\tch: " << c << "\ts:" << s << "\tS: " << S << std::endl; + + // Updates the buffer status removing the read bits and decreasing the number of bits stored in it. + buffer >>= BITS_PER_SAMPLE; + bits_in_buffer -= BITS_PER_SAMPLE; + if (fdebug_buffer) std::cout << " -" << buffer << " [bits in buffer: "<< bits_in_buffer << "]" << std::endl; + + // Increments the absolute sample step. + S++; + } + } +} + /** * @brief Extract a sample from a 64-bit buffer using the specified bit positions. * diff --git a/sbndcode/Decoders/XARAPUCA/xarapucadecoder.fcl b/sbndcode/Decoders/XARAPUCA/xarapucadecoder.fcl index 774032157..022a6888c 100644 --- a/sbndcode/Decoders/XARAPUCA/xarapucadecoder.fcl +++ b/sbndcode/Decoders/XARAPUCA/xarapucadecoder.fcl @@ -32,7 +32,7 @@ xarapucadecoder: # - Output data product instance name. waveforms_instance_name: "XARAPUCAChannels" # Name for the instance product containing the raw decoded waveforms. timing_ref_instance_name: "" # Name for the instance product containing the timing reference information. - store_debug_waveforms: -1 # Number of waveforms to store (0: none, -1: all, n: first n waveforms). + store_debug_waveforms: 33 # Number of waveforms to store (0: none, -1: all, n: first n waveforms). # - Debug options. debug_tdc_handle: false # (De)activates SPEC-TDC art::Handle information printing. debug_ptb_handle: false # (De)activates PTB art::Handle information printing. From b416a56d558710b69fd964fa9a1f67a07df790c7 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Alicia=20V=C3=A1zquez-Ramos?= Date: Thu, 9 Oct 2025 07:20:43 -0500 Subject: [PATCH 04/18] Add dump waveforms function --- .../XARAPUCA/SBNDXARAPUCADecoder_module.cc | 135 ++++++++---------- 1 file changed, 63 insertions(+), 72 deletions(-) diff --git a/sbndcode/Decoders/XARAPUCA/SBNDXARAPUCADecoder_module.cc b/sbndcode/Decoders/XARAPUCA/SBNDXARAPUCADecoder_module.cc index 72020207c..0131a5e49 100644 --- a/sbndcode/Decoders/XARAPUCA/SBNDXARAPUCADecoder_module.cc +++ b/sbndcode/Decoders/XARAPUCA/SBNDXARAPUCADecoder_module.cc @@ -74,7 +74,6 @@ class sbndaq::SBNDXARAPUCADecoder : public art::EDProducer { void produce(art::Event& e) override; private: - constexpr static uint64_t NANOSEC_IN_SEC = 1'000'000'000; /**< Number of nanoseconds in one second. */ constexpr static uint64_t MICROSEC_IN_NANOSEC = 1'000; /**< Number of nanoseconds in one microsecond. */ constexpr static double NANOSEC_TO_MICROSEC = 1E-3; /**< Conversion factor from nanoseconds to microseconds. */ @@ -91,6 +90,7 @@ class sbndaq::SBNDXARAPUCADecoder : public art::EDProducer { constexpr static uint16_t PTB_TIMING = 1; /**< Timing reference frame: HLT (High Level Trigger) timestamp from the PTB (Penn Trigger Board). */ constexpr static uint16_t CAEN_ONLY_TIMING = 2; /**< Timing reference frame: CAEN-only. */ + constexpr static uint16_t TTT_DEFAULT = 0; /**< Default integer value for the nominal TTT. */ constexpr static uint16_t HLT_NOT_FOUND = 999; /**< Random value to indicate no HL trigger found. */ constexpr static uint16_t HLT_TOO_FAR = 1000; /**< Random value to indicate HL trigger found but too far from the raw timestamp. */ @@ -140,6 +140,7 @@ class sbndaq::SBNDXARAPUCADecoder : public art::EDProducer { void shift_time(const artdaq::Fragment& fragment, uint64_t TTT_ticks, int64_t TTT_end_ns, uint64_t timestamp, uint32_t num_samples_per_wvfm, double& ini_wvfm_timestamp, double& end_wvfm_timestamp); void decode_waveforms(const artdaq::Fragment& fragment, std::vector>& wvfms, size_t header_size, uint32_t num_channels, uint32_t num_samples_per_wvfm, uint32_t num_words_per_wvfms, uint32_t num_samples_per_group); + void dump_waveforms(std::vector & prod_wvfms, const std::vector>& wvfms, std::vector & fragment_indices, size_t board_index, uint32_t num_channels, double ini_wvfm_timestamp, double end_wvfm_timestamp); void save_prod_wvfm(size_t board_idx, size_t ch, double ini_wvfm_timestamp, const std::vector > & wvfms, std::vector & prod_wvfms); void save_debug_wvfm(size_t board_idx, size_t fragment_idx, int ch, double ini_wvfm_timestamp, double end_wvfm_timestamp, const std::vector > & wvfms); @@ -621,7 +622,8 @@ void sbndaq::SBNDXARAPUCADecoder::decode_fragment(uint64_t timestamp, std::vecto //bool is_nominal_length = false; //bool is_within_nominal_length = false; //bool is_first = false; - + //int32_t nominal_TTT = TTT_DEFAULT; + // =============== Accesses Event metadata and Event header for this fragment =============== // CAENV1740Fragment caen_fragment(fragment); @@ -663,6 +665,8 @@ void sbndaq::SBNDXARAPUCADecoder::decode_fragment(uint64_t timestamp, std::vecto std::cout << "\t Number of samples per group (this fragment): " << num_samples_per_group << std::endl; } + std::vector > wvfms(num_channels, std::vector(num_samples_per_wvfm, 0)); + // =============== Extracts timing information for this fragment =============== // uint32_t TTT_ticks = header.triggerTime(); @@ -673,81 +677,41 @@ void sbndaq::SBNDXARAPUCADecoder::decode_fragment(uint64_t timestamp, std::vecto std::cout << "\t\t TTT header.triggerTimeRollOver(): " << header.triggerTimeRollOver() << std::endl; } -// // =============== Start decoding the waveforms =============== // - std::vector > wvfms(num_channels, std::vector(num_samples_per_wvfm, 0)); + // =============== Start decoding the waveforms =============== // + //std::vector > fragment_wvfms(num_channels, std::vector(num_samples_per_wvfm, 0)); decode_waveforms(fragment, wvfms, header_size, num_channels, num_samples_per_wvfm, num_words_per_wvfms, num_samples_per_group); -// if (fverbose) std::cout << " > SBNDXARAPUCADecoder::decode_fragment: binary decoding of the waveforms starting... " << std::endl; -// -// std::vector > wvfms(num_channels, std::vector(num_samples_per_wvfm, 0)); -// -// // Absolute sample number [0, TOTAL_NUM_SAMPLES] where TOTAL_NUM_SAMPLES is the total number of samples stored for an event. -// uint32_t S = 0; -// // Buffer variables. -// uint64_t buffer = 0; -// uint32_t bits_in_buffer = 0; -// -// // Data pointer to the beggining of the waveforms stores in the event. -// const uint32_t* data_ptr = reinterpret_cast(fragment.dataBeginBytes() + sizeof(CAENV1740EventHeader)); -// // Accesses each word, stores it in the buffer and then the samples are extracted from the buffer. -// for (size_t j = 0; j < num_words_per_wvfms; j++) { -// uint64_t word = read_word(data_ptr); -// -// // Adds the new word to the buffer and increments the number of bits stored in it. -// if (fdebug_buffer) std::cout << buffer << "[word: " << word << "]" << std::endl; -// buffer |= word << bits_in_buffer; -// bits_in_buffer += BITS_PER_WORD; // bytes * 8 bits/byte -// if (fdebug_buffer) std::cout << " +" << buffer << " [bits in buffer: "<< bits_in_buffer << "]" << std::endl; -// -// // Obtains 12-bit sequences from the buffer and assigns each sample to the channel and channel sample it belongs to. -// while (bits_in_buffer >= BITS_PER_SAMPLE) { -// // Computes board channel, channel sample and group channel and assigns the sample to those indices. -// uint32_t g = (S / num_samples_per_group); // Group index. -// uint32_t c = ((S / NUM_CONSECUTIVE_SAMPLES) % NUM_CHANNELS_PER_GROUP) + g * NUM_GROUPS; // Channel index. -// uint32_t s = (S % NUM_CONSECUTIVE_SAMPLES) + ((S / NUM_SAMPLES_PER_ROUND) * NUM_CONSECUTIVE_SAMPLES) % num_samples_per_wvfm; // Sample/channel index. -// uint16_t sample = get_sample(buffer, BITS_PER_SAMPLE - 1, 0); -// wvfms[c][s] = sample; -// if (fdebug_waveforms) std::cout << "\tSample: " << sample << "\tg: " << g << "\tch: " << c << "\ts:" << s << "\tS: " << S << std::endl; -// -// // Updates the buffer status removing the read bits and decreasing the number of bits stored in it. -// buffer >>= BITS_PER_SAMPLE; -// bits_in_buffer -= BITS_PER_SAMPLE; -// if (fdebug_buffer) std::cout << " -" << buffer << " [bits in buffer: "<< bits_in_buffer << "]" << std::endl; -// -// // Increments the absolute sample step. -// S++; -// } -// } // =============== Shifts timing to the selected timing reference frame =============== // double ini_wvfm_timestamp = 0; double end_wvfm_timestamp = 0; shift_time(fragment, TTT_ticks, TTT_end_ns, timestamp, num_samples_per_wvfm, ini_wvfm_timestamp, end_wvfm_timestamp); - // The decoded waveforms are dumped into two products: - // - A xarapucadecoder-art.root file with the OpDetWaveforms as the product of this producer for further analysis. - // - A decoder_hist.root file gathering a waveform histograms. - if (fverbose) std::cout << " > SBNDXARAPUCADecoder::decode_fragment: binary decoding complete, dumping products..." << std::endl; - - uint32_t num_debug_wvfms; - - if (fstore_debug_waveforms == -1) { - num_debug_wvfms = num_channels; - } else { - num_debug_wvfms = std::min(num_channels, fstore_debug_waveforms); - } - - uint32_t ch; - - for (ch = 0; ch < num_debug_wvfms; ch++) { - save_prod_wvfm(board_idx, ch, ini_wvfm_timestamp, wvfms, prod_wvfms); - save_debug_wvfm(board_idx, fragment_indices[board_idx], ch, ini_wvfm_timestamp, end_wvfm_timestamp, wvfms); - } - - for (;ch < num_channels; ch++) { - save_prod_wvfm(board_idx, ch, ini_wvfm_timestamp, wvfms, prod_wvfms); - } - - fragment_indices[board_idx]++; + dump_waveforms(prod_wvfms, wvfms, fragment_indices, board_idx, num_channels, ini_wvfm_timestamp, end_wvfm_timestamp); + // // The decoded waveforms are dumped into two products: + // // - A xarapucadecoder-art.root file with the OpDetWaveforms as the product of this producer for further analysis. + // // - A decoder_hist.root file gathering a waveform histograms. + // if (fverbose) std::cout << " > SBNDXARAPUCADecoder::decode_fragment: binary decoding complete, dumping products..." << std::endl; + // + // uint32_t num_debug_wvfms; +// + // if (fstore_debug_waveforms == -1) { + // num_debug_wvfms = num_channels; + // } else { + // num_debug_wvfms = std::min(num_channels, fstore_debug_waveforms); + // } +// + // uint32_t ch; +// + // for (ch = 0; ch < num_debug_wvfms; ch++) { + // save_prod_wvfm(board_idx, ch, ini_wvfm_timestamp, wvfms, prod_wvfms); + // save_debug_wvfm(board_idx, fragment_indices[board_idx], ch, ini_wvfm_timestamp, end_wvfm_timestamp, wvfms); + // } +// + // for (;ch < num_channels; ch++) { + // save_prod_wvfm(board_idx, ch, ini_wvfm_timestamp, wvfms, prod_wvfms); + // } +// + // fragment_indices[board_idx]++; } } @@ -898,8 +862,6 @@ void sbndaq::SBNDXARAPUCADecoder::decode_waveforms(const artdaq::Fragment& fragm // =============== Start decoding the waveforms =============== // if (fverbose) std::cout << " > SBNDXARAPUCADecoder::decode_fragment: binary decoding of the waveforms starting... " << std::endl; - //std::vector > wvfms(num_channels, std::vector(num_samples_per_wvfm, 0)); - // Absolute sample number [0, TOTAL_NUM_SAMPLES] where TOTAL_NUM_SAMPLES is the total number of samples stored for an event. uint32_t S = 0; // Buffer variables. @@ -939,6 +901,35 @@ void sbndaq::SBNDXARAPUCADecoder::decode_waveforms(const artdaq::Fragment& fragm } } +void sbndaq::SBNDXARAPUCADecoder::dump_waveforms(std::vector & prod_wvfms, const std::vector>& wvfms, std::vector & fragment_indices, size_t board_idx, uint32_t num_channels, double ini_wvfm_timestamp, double end_wvfm_timestamp) { + + // The decoded waveforms are dumped into two products: + // - A xarapucadecoder-art.root file with the OpDetWaveforms as the product of this producer for further analysis. + // - A decoder_hist.root file gathering a waveform histograms. + if (fverbose) std::cout << " > SBNDXARAPUCADecoder::decode_fragment: binary decoding complete, dumping products..." << std::endl; + + uint32_t num_debug_wvfms; + + if (fstore_debug_waveforms == -1) { + num_debug_wvfms = num_channels; + } else { + num_debug_wvfms = std::min(num_channels, fstore_debug_waveforms); + } + + uint32_t ch; + + for (ch = 0; ch < num_debug_wvfms; ch++) { + save_prod_wvfm(board_idx, ch, ini_wvfm_timestamp, wvfms, prod_wvfms); + save_debug_wvfm(board_idx, fragment_indices[board_idx], ch, ini_wvfm_timestamp, end_wvfm_timestamp, wvfms); + } + + for (;ch < num_channels; ch++) { + save_prod_wvfm(board_idx, ch, ini_wvfm_timestamp, wvfms, prod_wvfms); + } + + fragment_indices[board_idx]++; +} + /** * @brief Extract a sample from a 64-bit buffer using the specified bit positions. * From 0d9f64460644030a1db0559000e96aaaabc1fdf6 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Alicia=20V=C3=A1zquez-Ramos?= Date: Fri, 10 Oct 2025 05:44:36 -0500 Subject: [PATCH 05/18] Combine waveforms and correctly differentiates nominal from extended --- .../XARAPUCA/SBNDXARAPUCADecoder_module.cc | 120 +++++++++++------- .../Decoders/XARAPUCA/xarapucadecoder.fcl | 2 +- 2 files changed, 72 insertions(+), 50 deletions(-) diff --git a/sbndcode/Decoders/XARAPUCA/SBNDXARAPUCADecoder_module.cc b/sbndcode/Decoders/XARAPUCA/SBNDXARAPUCADecoder_module.cc index 0131a5e49..ff9b9c99f 100644 --- a/sbndcode/Decoders/XARAPUCA/SBNDXARAPUCADecoder_module.cc +++ b/sbndcode/Decoders/XARAPUCA/SBNDXARAPUCADecoder_module.cc @@ -133,17 +133,19 @@ class sbndaq::SBNDXARAPUCADecoder : public art::EDProducer { bool fverbose; /**< If `true` it increases verbosity of console output for detailed processing steps. */ // Class methods. - void decode_fragment(uint64_t timestamp, std::vector & fragment_indices, const artdaq::Fragment& fragment, std::vector & prod_wvfms); + void decode_fragment(uint64_t timestamp, uint64_t& nominal_frag_timestamp, int32_t& nominal_TTT, std::vector & fragment_indices, const artdaq::Fragment& fragment, std::vector & prod_wvfms, std::vector>& wvfms); bool get_ptb_hlt_timestamp(art::Event& e, uint64_t corr_raw_timestamp, uint64_t & timestamp, uint16_t & hlt_code); bool get_spec_tdc_etrig_timestamp(art::Event& e, uint64_t corr_raw_timestamp, uint64_t & timestamp); - void shift_time(const artdaq::Fragment& fragment, uint64_t TTT_ticks, int64_t TTT_end_ns, uint64_t timestamp, uint32_t num_samples_per_wvfm, double& ini_wvfm_timestamp, double& end_wvfm_timestamp); + void shift_time(uint64_t TTT_ticks, int64_t TTT_end_ns, uint64_t frag_timestamp, uint64_t timestamp, uint32_t num_samples_per_wvfm, double& ini_wvfm_timestamp, double& end_wvfm_timestamp); void decode_waveforms(const artdaq::Fragment& fragment, std::vector>& wvfms, size_t header_size, uint32_t num_channels, uint32_t num_samples_per_wvfm, uint32_t num_words_per_wvfms, uint32_t num_samples_per_group); - void dump_waveforms(std::vector & prod_wvfms, const std::vector>& wvfms, std::vector & fragment_indices, size_t board_index, uint32_t num_channels, double ini_wvfm_timestamp, double end_wvfm_timestamp); + void dump_waveforms(std::vector & prod_wvfms, std::vector>& wvfms, std::vector & fragment_indices, size_t board_index, uint32_t num_channels, double ini_wvfm_timestamp, double end_wvfm_timestamp); void save_prod_wvfm(size_t board_idx, size_t ch, double ini_wvfm_timestamp, const std::vector > & wvfms, std::vector & prod_wvfms); void save_debug_wvfm(size_t board_idx, size_t fragment_idx, int ch, double ini_wvfm_timestamp, double end_wvfm_timestamp, const std::vector > & wvfms); + void combine_waveforms(std::vector>& wvfms, const std::vector>& fragment_wvfms, uint32_t num_channels); + uint16_t get_sample(uint64_t buffer, uint32_t msb, uint32_t lsb); uint32_t read_word(const uint32_t* & data_ptr); unsigned int get_channel_id(unsigned int board, unsigned int board_channel); @@ -304,6 +306,10 @@ void sbndaq::SBNDXARAPUCADecoder::produce(art::Event& e) bool found_caen = false; std::vector fragment_indices(fnum_caen_boards, 0); + std::vector> wvfms; + std::cout << "wvfms_size: " << wvfms.size() << std::endl; + int32_t nominal_TTT = TTT_DEFAULT; + uint64_t nominal_frag_timestamp = TTT_DEFAULT; if (fverbose | fdebug_fragments_handle) std::cout << "\n > SBNDXARAPUCADecoder::produce: searching for V1740 fragments..." << std::endl; @@ -341,7 +347,7 @@ void sbndaq::SBNDXARAPUCADecoder::produce(art::Event& e) for (size_t f = 0; f < num_caen_fragments; f++) { const artdaq::Fragment fragment = *container_fragment[f].get(); - decode_fragment(timestamp, fragment_indices, fragment, *prod_wvfms); + decode_fragment(timestamp, nominal_frag_timestamp, nominal_TTT, fragment_indices, fragment, *prod_wvfms, wvfms); } // End CAEN V1740 fragments loop. } } // End Container fragments loop. @@ -353,7 +359,7 @@ void sbndaq::SBNDXARAPUCADecoder::produce(art::Event& e) // It searches for all CAEN V1740 fragments. for (size_t f = 0; f < frag_handle_size; f++) { const artdaq::Fragment fragment = fragment_handle->at(f); - decode_fragment(timestamp, fragment_indices, fragment, *prod_wvfms); + decode_fragment(timestamp, nominal_frag_timestamp, nominal_TTT, fragment_indices, fragment, *prod_wvfms, wvfms); } // End CAEN V1740 fragments loop. } } // End extracting CAEN V1740 fragments. @@ -599,7 +605,10 @@ bool sbndaq::SBNDXARAPUCADecoder::get_ptb_hlt_timestamp(art::Event& e, uint64_t * - Populates the output vector (`prod_wvfms`) with decoded waveforms and optionally generates debug waveforms output. * */ -void sbndaq::SBNDXARAPUCADecoder::decode_fragment(uint64_t timestamp, std::vector & fragment_indices, const artdaq::Fragment& fragment, std::vector & prod_wvfms) { + +void sbndaq::SBNDXARAPUCADecoder::decode_fragment(uint64_t timestamp, uint64_t& nominal_frag_timestamp, int32_t& nominal_TTT, std::vector & fragment_indices, const artdaq::Fragment& fragment, std::vector & prod_wvfms, std::vector>& wvfms) { + std::cout << "decode_wvfms_size: " << wvfms.size() << std::endl; + auto fragment_id = fragment.fragmentID() - ffragment_id_offset; auto it = std::find(fboard_id_list.begin(), fboard_id_list.end(), fragment_id); size_t board_idx; @@ -619,10 +628,13 @@ void sbndaq::SBNDXARAPUCADecoder::decode_fragment(uint64_t timestamp, std::vecto if (valid_fragment) { if (fverbose) std::cout << "\n > SBNDXARAPUCADecoder::decode_fragment: decoding V1740 CAEN fragment " << fragment_indices[board_idx] << " from the board " << board_idx << " (slot " << fboard_id_list[board_idx] << "):" << std::endl; - //bool is_nominal_length = false; + bool is_nominal_length = false; //bool is_within_nominal_length = false; - //bool is_first = false; - //int32_t nominal_TTT = TTT_DEFAULT; + bool is_first = false; + + + double ini_wvfm_timestamp = 0; + double end_wvfm_timestamp = 0; // =============== Accesses Event metadata and Event header for this fragment =============== // @@ -646,14 +658,15 @@ void sbndaq::SBNDXARAPUCADecoder::decode_fragment(uint64_t timestamp, std::vecto uint32_t num_remaining_bits = num_bits_per_all_wvfms % BITS_PER_SAMPLE; uint32_t num_samples_per_wvfm = num_samples_per_all_wvfms / num_channels; uint32_t num_samples_per_group = num_samples_per_wvfm * NUM_CHANNELS_PER_GROUP; + uint32_t num_nominal_samples_per_wvfm = metadata->nSamples; if (fverbose | fdebug_waveforms) { - if (metadata->nSamples == num_samples_per_wvfm) { + if (num_nominal_samples_per_wvfm == num_samples_per_wvfm) { std::cout << " > SBNDXARAPUCADecoder::decode_fragment: [NOMINAL FRAGMENT] " << num_samples_per_wvfm << " samples/waveform." << " (" << num_samples_per_group << " samples per group - 8 channels per group -)." << std::endl; } else { std::cout << " > SBNDXARAPUCADecoder::decode_fragment: [EXTENDED FRAGMENT] " << num_samples_per_wvfm << " samples/waveform." << " (" << num_samples_per_group << " samples per group - 8 channels per group -)." << std::endl; } - std::cout << " > SBNDXARAPUCADecoder::decode_fragment: nominal number of samples per waveform: " << metadata->nSamples << "." << std::endl; + std::cout << " > SBNDXARAPUCADecoder::decode_fragment: nominal number of samples per waveform: " << num_nominal_samples_per_wvfm << "." << std::endl; std::cout << " > SBNDXARAPUCADecoder::decode_fragment: number of words for this fragment: " << num_words_per_event << " (Header: " << num_words_per_header << ", Waveform: " << num_words_per_wvfms << ") words." << std::endl; } @@ -665,10 +678,11 @@ void sbndaq::SBNDXARAPUCADecoder::decode_fragment(uint64_t timestamp, std::vecto std::cout << "\t Number of samples per group (this fragment): " << num_samples_per_group << std::endl; } - std::vector > wvfms(num_channels, std::vector(num_samples_per_wvfm, 0)); + //std::vector > wvfms(num_channels, std::vector(num_samples_per_wvfm, 0)); // =============== Extracts timing information for this fragment =============== // + uint64_t frag_timestamp = fragment.timestamp(); // ns. uint32_t TTT_ticks = header.triggerTime(); int64_t TTT_end_ns = TTT_ticks * NANOSEC_PER_TICK; // ns. @@ -677,41 +691,38 @@ void sbndaq::SBNDXARAPUCADecoder::decode_fragment(uint64_t timestamp, std::vecto std::cout << "\t\t TTT header.triggerTimeRollOver(): " << header.triggerTimeRollOver() << std::endl; } - // =============== Start decoding the waveforms =============== // - //std::vector > fragment_wvfms(num_channels, std::vector(num_samples_per_wvfm, 0)); - decode_waveforms(fragment, wvfms, header_size, num_channels, num_samples_per_wvfm, num_words_per_wvfms, num_samples_per_group); - - // =============== Shifts timing to the selected timing reference frame =============== // - double ini_wvfm_timestamp = 0; - double end_wvfm_timestamp = 0; - shift_time(fragment, TTT_ticks, TTT_end_ns, timestamp, num_samples_per_wvfm, ini_wvfm_timestamp, end_wvfm_timestamp); - - dump_waveforms(prod_wvfms, wvfms, fragment_indices, board_idx, num_channels, ini_wvfm_timestamp, end_wvfm_timestamp); - // // The decoded waveforms are dumped into two products: - // // - A xarapucadecoder-art.root file with the OpDetWaveforms as the product of this producer for further analysis. - // // - A decoder_hist.root file gathering a waveform histograms. - // if (fverbose) std::cout << " > SBNDXARAPUCADecoder::decode_fragment: binary decoding complete, dumping products..." << std::endl; - // - // uint32_t num_debug_wvfms; -// - // if (fstore_debug_waveforms == -1) { - // num_debug_wvfms = num_channels; - // } else { - // num_debug_wvfms = std::min(num_channels, fstore_debug_waveforms); - // } -// - // uint32_t ch; + //// =============== Start decoding the waveforms =============== // + std::vector > fragment_wvfms(num_channels, std::vector(num_samples_per_wvfm, 0)); + decode_waveforms(fragment, fragment_wvfms, header_size, num_channels, num_samples_per_wvfm, num_words_per_wvfms, num_samples_per_group); // - // for (ch = 0; ch < num_debug_wvfms; ch++) { - // save_prod_wvfm(board_idx, ch, ini_wvfm_timestamp, wvfms, prod_wvfms); - // save_debug_wvfm(board_idx, fragment_indices[board_idx], ch, ini_wvfm_timestamp, end_wvfm_timestamp, wvfms); - // } + //// =============== Shifts timing to the selected timing reference frame =============== // // - // for (;ch < num_channels; ch++) { - // save_prod_wvfm(board_idx, ch, ini_wvfm_timestamp, wvfms, prod_wvfms); - // } -// - // fragment_indices[board_idx]++; + //shift_time(fragment, TTT_ticks, TTT_end_ns, timestamp, num_samples_per_wvfm, ini_wvfm_timestamp, end_wvfm_timestamp); + //dump_waveforms(prod_wvfms, wvfms, fragment_indices, board_idx, num_channels, ini_wvfm_timestamp, end_wvfm_timestamp); + //combine_waveforms(wvfms, fragment_wvfms, num_channels); + + is_nominal_length = (num_nominal_samples_per_wvfm == num_samples_per_wvfm); + is_first = (fragment_indices[board_idx] == 0); + + if (is_nominal_length) { + if (!is_first) { + std::cout << " NOT FIRST NOMINAL fragment " << std::endl; + std::cout << " nominal_TTT: " << nominal_TTT << " TTT_end_ns: " << TTT_end_ns << std::endl; + std::cout << " nominal_frag_timestamp: " << nominal_frag_timestamp << " frag_timestamp : " << frag_timestamp << std::endl; + shift_time(TTT_ticks, nominal_TTT, nominal_frag_timestamp, timestamp, num_nominal_samples_per_wvfm, ini_wvfm_timestamp, end_wvfm_timestamp); + dump_waveforms(prod_wvfms, wvfms, fragment_indices, board_idx, num_channels, ini_wvfm_timestamp, end_wvfm_timestamp); + } else { + std::cout << " FIRST NOMINAL fragment " << std::endl; + } + combine_waveforms(wvfms, fragment_wvfms, num_channels); + nominal_TTT = TTT_end_ns; + nominal_frag_timestamp = frag_timestamp; + } else { + std::cout << " EXTENDED fragment " << std::endl; + combine_waveforms(wvfms, fragment_wvfms, num_channels); + } + + fragment_indices[board_idx]++; } } @@ -793,10 +804,9 @@ void sbndaq::SBNDXARAPUCADecoder::save_debug_wvfm(size_t board_idx, size_t fragm } -void sbndaq::SBNDXARAPUCADecoder::shift_time(const artdaq::Fragment& fragment, uint64_t TTT_ticks, int64_t TTT_end_ns, uint64_t timestamp, uint32_t num_samples_per_wvfm, double& ini_wvfm_timestamp, double& end_wvfm_timestamp) { +void sbndaq::SBNDXARAPUCADecoder::shift_time(uint64_t TTT_ticks, int64_t TTT_end_ns, uint64_t frag_timestamp, uint64_t timestamp, uint32_t num_samples_per_wvfm, double& ini_wvfm_timestamp, double& end_wvfm_timestamp) { int64_t pulse_duration_ns = num_samples_per_wvfm * fns_per_sample; // ns. - uint64_t frag_timestamp = fragment.timestamp(); // ns. int64_t frag_timestamp_s = frag_timestamp / NANOSEC_IN_SEC; // s. int64_t frag_timestamp_ns = frag_timestamp % NANOSEC_IN_SEC; // ns. @@ -901,7 +911,7 @@ void sbndaq::SBNDXARAPUCADecoder::decode_waveforms(const artdaq::Fragment& fragm } } -void sbndaq::SBNDXARAPUCADecoder::dump_waveforms(std::vector & prod_wvfms, const std::vector>& wvfms, std::vector & fragment_indices, size_t board_idx, uint32_t num_channels, double ini_wvfm_timestamp, double end_wvfm_timestamp) { +void sbndaq::SBNDXARAPUCADecoder::dump_waveforms(std::vector & prod_wvfms, std::vector>& wvfms, std::vector & fragment_indices, size_t board_idx, uint32_t num_channels, double ini_wvfm_timestamp, double end_wvfm_timestamp) { // The decoded waveforms are dumped into two products: // - A xarapucadecoder-art.root file with the OpDetWaveforms as the product of this producer for further analysis. @@ -927,7 +937,19 @@ void sbndaq::SBNDXARAPUCADecoder::dump_waveforms(std::vector >& wvfms, const std::vector>& fragment_wvfms, uint32_t num_channels) { + if (wvfms.empty()) { + std::cout << "Empty waveforms, resizing to " << num_channels << " channels." << std::endl; + wvfms.resize(num_channels); + std::cout << "BEF COMB - wvfms_size = " << wvfms.size() << " x " << wvfms[0].size() << std::endl; + } + for (uint32_t ch = 0; ch < num_channels; ch++) { + wvfms[ch].insert(wvfms[ch].end(), fragment_wvfms[ch].begin(), fragment_wvfms[ch].end()); + } + std::cout << "AFT COMB - wvfms_size = " << wvfms.size() << " x " << wvfms[0].size() << std::endl; } /** diff --git a/sbndcode/Decoders/XARAPUCA/xarapucadecoder.fcl b/sbndcode/Decoders/XARAPUCA/xarapucadecoder.fcl index 022a6888c..b9ab4ba0a 100644 --- a/sbndcode/Decoders/XARAPUCA/xarapucadecoder.fcl +++ b/sbndcode/Decoders/XARAPUCA/xarapucadecoder.fcl @@ -32,7 +32,7 @@ xarapucadecoder: # - Output data product instance name. waveforms_instance_name: "XARAPUCAChannels" # Name for the instance product containing the raw decoded waveforms. timing_ref_instance_name: "" # Name for the instance product containing the timing reference information. - store_debug_waveforms: 33 # Number of waveforms to store (0: none, -1: all, n: first n waveforms). + store_debug_waveforms: 2 # Number of waveforms to store (0: none, -1: all, n: first n waveforms). # - Debug options. debug_tdc_handle: false # (De)activates SPEC-TDC art::Handle information printing. debug_ptb_handle: false # (De)activates PTB art::Handle information printing. From c1a42c050f51eba1d4f0103edeeaf89b4f1b5b8f Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Alicia=20V=C3=A1zquez-Ramos?= Date: Tue, 14 Oct 2025 06:59:02 -0500 Subject: [PATCH 06/18] Combine all extended fragments succesfully --- .../XARAPUCA/SBNDXARAPUCADecoder_module.cc | 32 +++++++++---------- .../Decoders/XARAPUCA/xarapucadecoder.fcl | 2 +- 2 files changed, 17 insertions(+), 17 deletions(-) diff --git a/sbndcode/Decoders/XARAPUCA/SBNDXARAPUCADecoder_module.cc b/sbndcode/Decoders/XARAPUCA/SBNDXARAPUCADecoder_module.cc index ff9b9c99f..61231e201 100644 --- a/sbndcode/Decoders/XARAPUCA/SBNDXARAPUCADecoder_module.cc +++ b/sbndcode/Decoders/XARAPUCA/SBNDXARAPUCADecoder_module.cc @@ -133,7 +133,7 @@ class sbndaq::SBNDXARAPUCADecoder : public art::EDProducer { bool fverbose; /**< If `true` it increases verbosity of console output for detailed processing steps. */ // Class methods. - void decode_fragment(uint64_t timestamp, uint64_t& nominal_frag_timestamp, int32_t& nominal_TTT, std::vector & fragment_indices, const artdaq::Fragment& fragment, std::vector & prod_wvfms, std::vector>& wvfms); + void decode_fragment(uint64_t timestamp, uint64_t& nominal_frag_timestamp, int32_t& nominal_TTT, std::vector & fragment_indices, const artdaq::Fragment& fragment, std::vector & prod_wvfms, std::vector>& wvfms, bool last_one); bool get_ptb_hlt_timestamp(art::Event& e, uint64_t corr_raw_timestamp, uint64_t & timestamp, uint16_t & hlt_code); bool get_spec_tdc_etrig_timestamp(art::Event& e, uint64_t corr_raw_timestamp, uint64_t & timestamp); @@ -310,6 +310,7 @@ void sbndaq::SBNDXARAPUCADecoder::produce(art::Event& e) std::cout << "wvfms_size: " << wvfms.size() << std::endl; int32_t nominal_TTT = TTT_DEFAULT; uint64_t nominal_frag_timestamp = TTT_DEFAULT; + bool last_one = false; if (fverbose | fdebug_fragments_handle) std::cout << "\n > SBNDXARAPUCADecoder::produce: searching for V1740 fragments..." << std::endl; @@ -347,7 +348,8 @@ void sbndaq::SBNDXARAPUCADecoder::produce(art::Event& e) for (size_t f = 0; f < num_caen_fragments; f++) { const artdaq::Fragment fragment = *container_fragment[f].get(); - decode_fragment(timestamp, nominal_frag_timestamp, nominal_TTT, fragment_indices, fragment, *prod_wvfms, wvfms); + last_one = f == (num_caen_fragments - 1); + decode_fragment(timestamp, nominal_frag_timestamp, nominal_TTT, fragment_indices, fragment, *prod_wvfms, wvfms, last_one); } // End CAEN V1740 fragments loop. } } // End Container fragments loop. @@ -359,7 +361,8 @@ void sbndaq::SBNDXARAPUCADecoder::produce(art::Event& e) // It searches for all CAEN V1740 fragments. for (size_t f = 0; f < frag_handle_size; f++) { const artdaq::Fragment fragment = fragment_handle->at(f); - decode_fragment(timestamp, nominal_frag_timestamp, nominal_TTT, fragment_indices, fragment, *prod_wvfms, wvfms); + last_one = f == (frag_handle_size - 1); + decode_fragment(timestamp, nominal_frag_timestamp, nominal_TTT, fragment_indices, fragment, *prod_wvfms, wvfms, last_one); } // End CAEN V1740 fragments loop. } } // End extracting CAEN V1740 fragments. @@ -606,9 +609,7 @@ bool sbndaq::SBNDXARAPUCADecoder::get_ptb_hlt_timestamp(art::Event& e, uint64_t * */ -void sbndaq::SBNDXARAPUCADecoder::decode_fragment(uint64_t timestamp, uint64_t& nominal_frag_timestamp, int32_t& nominal_TTT, std::vector & fragment_indices, const artdaq::Fragment& fragment, std::vector & prod_wvfms, std::vector>& wvfms) { - std::cout << "decode_wvfms_size: " << wvfms.size() << std::endl; - +void sbndaq::SBNDXARAPUCADecoder::decode_fragment(uint64_t timestamp, uint64_t& nominal_frag_timestamp, int32_t& nominal_TTT, std::vector & fragment_indices, const artdaq::Fragment& fragment, std::vector & prod_wvfms, std::vector>& wvfms, bool last_one) { auto fragment_id = fragment.fragmentID() - ffragment_id_offset; auto it = std::find(fboard_id_list.begin(), fboard_id_list.end(), fragment_id); size_t board_idx; @@ -678,8 +679,6 @@ void sbndaq::SBNDXARAPUCADecoder::decode_fragment(uint64_t timestamp, uint64_t& std::cout << "\t Number of samples per group (this fragment): " << num_samples_per_group << std::endl; } - //std::vector > wvfms(num_channels, std::vector(num_samples_per_wvfm, 0)); - // =============== Extracts timing information for this fragment =============== // uint64_t frag_timestamp = fragment.timestamp(); // ns. @@ -694,13 +693,7 @@ void sbndaq::SBNDXARAPUCADecoder::decode_fragment(uint64_t timestamp, uint64_t& //// =============== Start decoding the waveforms =============== // std::vector > fragment_wvfms(num_channels, std::vector(num_samples_per_wvfm, 0)); decode_waveforms(fragment, fragment_wvfms, header_size, num_channels, num_samples_per_wvfm, num_words_per_wvfms, num_samples_per_group); -// - //// =============== Shifts timing to the selected timing reference frame =============== // -// - //shift_time(fragment, TTT_ticks, TTT_end_ns, timestamp, num_samples_per_wvfm, ini_wvfm_timestamp, end_wvfm_timestamp); - //dump_waveforms(prod_wvfms, wvfms, fragment_indices, board_idx, num_channels, ini_wvfm_timestamp, end_wvfm_timestamp); - //combine_waveforms(wvfms, fragment_wvfms, num_channels); - + is_nominal_length = (num_nominal_samples_per_wvfm == num_samples_per_wvfm); is_first = (fragment_indices[board_idx] == 0); @@ -721,8 +714,15 @@ void sbndaq::SBNDXARAPUCADecoder::decode_fragment(uint64_t timestamp, uint64_t& std::cout << " EXTENDED fragment " << std::endl; combine_waveforms(wvfms, fragment_wvfms, num_channels); } - + fragment_indices[board_idx]++; + + if (last_one) { + std::cout << " LAST fragment " << std::endl; + shift_time(TTT_ticks, nominal_TTT, nominal_frag_timestamp, timestamp, num_nominal_samples_per_wvfm, ini_wvfm_timestamp, end_wvfm_timestamp); + dump_waveforms(prod_wvfms, wvfms, fragment_indices, board_idx, num_channels, ini_wvfm_timestamp, end_wvfm_timestamp); + } + } } diff --git a/sbndcode/Decoders/XARAPUCA/xarapucadecoder.fcl b/sbndcode/Decoders/XARAPUCA/xarapucadecoder.fcl index b9ab4ba0a..774032157 100644 --- a/sbndcode/Decoders/XARAPUCA/xarapucadecoder.fcl +++ b/sbndcode/Decoders/XARAPUCA/xarapucadecoder.fcl @@ -32,7 +32,7 @@ xarapucadecoder: # - Output data product instance name. waveforms_instance_name: "XARAPUCAChannels" # Name for the instance product containing the raw decoded waveforms. timing_ref_instance_name: "" # Name for the instance product containing the timing reference information. - store_debug_waveforms: 2 # Number of waveforms to store (0: none, -1: all, n: first n waveforms). + store_debug_waveforms: -1 # Number of waveforms to store (0: none, -1: all, n: first n waveforms). # - Debug options. debug_tdc_handle: false # (De)activates SPEC-TDC art::Handle information printing. debug_ptb_handle: false # (De)activates PTB art::Handle information printing. From e1656068b0c2a39177683a04ae40e82dec54869e Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Alicia=20V=C3=A1zquez-Ramos?= Date: Wed, 15 Oct 2025 06:06:52 -0500 Subject: [PATCH 07/18] Add new comments for code documenting. New variable for debugging the extended fragments combination --- .../XARAPUCA/SBNDXARAPUCADecoder_module.cc | 806 ++++++++++-------- .../Decoders/XARAPUCA/xarapucadecoder.fcl | 7 +- 2 files changed, 464 insertions(+), 349 deletions(-) diff --git a/sbndcode/Decoders/XARAPUCA/SBNDXARAPUCADecoder_module.cc b/sbndcode/Decoders/XARAPUCA/SBNDXARAPUCADecoder_module.cc index 61231e201..7c46afb10 100644 --- a/sbndcode/Decoders/XARAPUCA/SBNDXARAPUCADecoder_module.cc +++ b/sbndcode/Decoders/XARAPUCA/SBNDXARAPUCADecoder_module.cc @@ -130,29 +130,36 @@ class sbndaq::SBNDXARAPUCADecoder : public art::EDProducer { bool fdebug_timing; /**< If `true` timing data is printed. */ bool fdebug_buffer; /**< If `true` the buffer status is printed. */ bool fdebug_waveforms; /**< If `true` waveforms decoding data is printed. */ + bool fdebug_extended_fragments; /**< If `true` extended fragments information is printed. */ bool fverbose; /**< If `true` it increases verbosity of console output for detailed processing steps. */ - // Class methods. + // Main processing method. void decode_fragment(uint64_t timestamp, uint64_t& nominal_frag_timestamp, int32_t& nominal_TTT, std::vector & fragment_indices, const artdaq::Fragment& fragment, std::vector & prod_wvfms, std::vector>& wvfms, bool last_one); - bool get_ptb_hlt_timestamp(art::Event& e, uint64_t corr_raw_timestamp, uint64_t & timestamp, uint16_t & hlt_code); - bool get_spec_tdc_etrig_timestamp(art::Event& e, uint64_t corr_raw_timestamp, uint64_t & timestamp); + // Timing. void shift_time(uint64_t TTT_ticks, int64_t TTT_end_ns, uint64_t frag_timestamp, uint64_t timestamp, uint32_t num_samples_per_wvfm, double& ini_wvfm_timestamp, double& end_wvfm_timestamp); - void decode_waveforms(const artdaq::Fragment& fragment, std::vector>& wvfms, size_t header_size, uint32_t num_channels, uint32_t num_samples_per_wvfm, uint32_t num_words_per_wvfms, uint32_t num_samples_per_group); - - void dump_waveforms(std::vector & prod_wvfms, std::vector>& wvfms, std::vector & fragment_indices, size_t board_index, uint32_t num_channels, double ini_wvfm_timestamp, double end_wvfm_timestamp); - void save_prod_wvfm(size_t board_idx, size_t ch, double ini_wvfm_timestamp, const std::vector > & wvfms, std::vector & prod_wvfms); - void save_debug_wvfm(size_t board_idx, size_t fragment_idx, int ch, double ini_wvfm_timestamp, double end_wvfm_timestamp, const std::vector > & wvfms); + bool get_spec_tdc_etrig_timestamp(art::Event& e, uint64_t corr_raw_timestamp, uint64_t & timestamp); + bool get_ptb_hlt_timestamp(art::Event& e, uint64_t corr_raw_timestamp, uint64_t & timestamp, uint16_t & hlt_code); - void combine_waveforms(std::vector>& wvfms, const std::vector>& fragment_wvfms, uint32_t num_channels); - + // Waveforms decoding. + void decode_waveforms(const artdaq::Fragment& fragment, std::vector>& wvfms, size_t header_size, uint32_t num_channels, uint32_t num_samples_per_wvfm, uint32_t num_words_per_wvfms, uint32_t num_samples_per_group); uint16_t get_sample(uint64_t buffer, uint32_t msb, uint32_t lsb); uint32_t read_word(const uint32_t* & data_ptr); unsigned int get_channel_id(unsigned int board, unsigned int board_channel); - std::string print_timestamp(uint64_t timestamp); + // Combines decoded waveforms. + void combine_waveforms(std::vector>& wvfms, const std::vector>& fragment_wvfms, uint32_t num_channels); + + // Dumps and saves waveforms. + void dump_waveforms(std::vector & prod_wvfms, std::vector>& wvfms, std::vector & fragment_indices, size_t board_index, uint32_t num_channels, double ini_wvfm_timestamp, double end_wvfm_timestamp); + void save_prod_wvfm(size_t board_idx, size_t ch, double ini_wvfm_timestamp, const std::vector > & wvfms, std::vector & prod_wvfms); + void save_debug_wvfm(size_t board_idx, size_t fragment_idx, int ch, double ini_wvfm_timestamp, double end_wvfm_timestamp, const std::vector > & wvfms); + + // Auxiliary methods. int64_t signed_difference(uint64_t t1, uint64_t t2); uint64_t abs_difference(uint64_t t1, uint64_t t2); + std::string print_timestamp(uint64_t timestamp); + }; /** @@ -210,6 +217,7 @@ sbndaq::SBNDXARAPUCADecoder::SBNDXARAPUCADecoder(fhicl::ParameterSet const& p) fdebug_fragments_handle = p.get ("debug_fragments_handle", false); fdebug_timing = p.get ("debug_timing", false); fdebug_waveforms = p.get ("debug_waveforms", false); + fdebug_extended_fragments = p.get ("debug_extended_fragments", false); fdebug_buffer = p.get ("debug_buffer", false); fverbose = p.get ("verbose", false); @@ -229,8 +237,7 @@ sbndaq::SBNDXARAPUCADecoder::SBNDXARAPUCADecoder(fhicl::ParameterSet const& p) * 3. It searches for CAEN V1740 fragments in the event, decodes them and creates the output products: a vector of raw::OpDetWaveform. * 4. It dumps the products in the event. */ -void sbndaq::SBNDXARAPUCADecoder::produce(art::Event& e) -{ +void sbndaq::SBNDXARAPUCADecoder::produce(art::Event& e) { if (fverbose) std::cout << "\n > SBNDXARAPUCADecoder::produce: entering the produce function." << std::endl; // Advances the event counter. @@ -307,7 +314,10 @@ void sbndaq::SBNDXARAPUCADecoder::produce(art::Event& e) std::vector fragment_indices(fnum_caen_boards, 0); std::vector> wvfms; - std::cout << "wvfms_size: " << wvfms.size() << std::endl; + if (fdebug_extended_fragments) { + std::cout << " Waveforms size: " << wvfms.size() << std::endl; + } + int32_t nominal_TTT = TTT_DEFAULT; uint64_t nominal_frag_timestamp = TTT_DEFAULT; bool last_one = false; @@ -383,6 +393,241 @@ void sbndaq::SBNDXARAPUCADecoder::produce(art::Event& e) } } +// =============== Main fragment processing method =============== // + +/** + * @brief Decodes a CAEN V1740 fragment, extracts the waveforms and combines them into the output product. + * @param[in] timestamp The valid timestamp used as reference for the event. + * @param[in,out] nominal_frag_timestamp The nominal timestamp calculated for the fragment being processed. + * @param[in,out] nominal_TTT The nominal Trigger Time Tag (TTT) calculated for the fragment being processed. + * @param[in,out] fragment_indices A vector containing the indices of the fragments already processed for each board. + * @param[in] fragment The artdaq::Fragment object to be processed. + * @param[in,out] prod_wvfms The vector of raw::OpDetWaveform objects to be filled with the decoded waveforms. + * @param[in,out] wvfms A 2D vector containing the waveforms for all channels and boards decoded so far. + * @param[in] last_one A boolean flag indicating if the fragment being processed is the last one in the event. + + * @details This method decodes a CAEN V1740 fragment, extracts the waveforms for each channel, shifts them in time according to the + * timing reference and combines them into the output product. + * 1. It checks if the fragment ID corresponds to a valid board. + * 2. It accesses the metadata and header of the fragment to get information about the number of channels, samples, words, etc. + * 3. It calculates the number of samples per waveform and checks if it is a nominal or extended fragment. + * 4. It decodes the waveforms for each channel in the fragment. + * 5. It shifts the waveforms in time according to the timing reference. + * 6. It combines the decoded waveforms into the output product. + * 7. It dumps the waveforms if required. + * + * @pre The art::Event object containing the fragment has been processed to get a valid timing reference. + * @post The vector of raw::OpDetWaveform objects is filled with the decoded waveforms from the fragment. + * @see shift_time + * @see decode_waveforms + * @see combine_waveforms + * @see dump_waveforms + */ + +void sbndaq::SBNDXARAPUCADecoder::decode_fragment(uint64_t timestamp, uint64_t& nominal_frag_timestamp, int32_t& nominal_TTT, std::vector & fragment_indices, const artdaq::Fragment& fragment, std::vector & prod_wvfms, std::vector>& wvfms, bool last_one) { + auto fragment_id = fragment.fragmentID() - ffragment_id_offset; + auto it = std::find(fboard_id_list.begin(), fboard_id_list.end(), fragment_id); + size_t board_idx; + bool valid_fragment = false; + + if (it != fboard_id_list.end()) { + board_idx = it - fboard_id_list.begin(); + if (board_idx >= fnum_caen_boards) { + if (fverbose) std::cout << " > SBNDXARAPUCADecoder::decode_fragment: fragment ID " << fragment_id << " (" << board_idx << ") is out of range. Skipping this fragment..." << std::endl; + } else { + valid_fragment = true; + } + } else { + if (fverbose) std::cout << " > SBNDXARAPUCADecoder::decode_fragment: fragment ID " << fragment_id << " is not valid. Skipping this fragment..." << std::endl; + } + + if (valid_fragment) { + if (fverbose) std::cout << "\n > SBNDXARAPUCADecoder::decode_fragment: decoding V1740 CAEN fragment " << fragment_indices[board_idx] << " from the board " << board_idx << " (slot " << fboard_id_list[board_idx] << "):" << std::endl; + + bool is_nominal_length = false; + bool is_first = false; + + double ini_wvfm_timestamp = 0; + double end_wvfm_timestamp = 0; + + // =============== Accesses Event metadata and Event header for this fragment =============== // + + CAENV1740Fragment caen_fragment(fragment); + CAENV1740FragmentMetadata const* metadata = caen_fragment.Metadata(); + uint32_t num_channels = metadata->nChannels; + if (fverbose) std::cout << " > SBNDXARAPUCADecoder::decode_fragment: number of channels: " << num_channels << std::endl; + + // Accesses the event and header data of the CAEN fragment. + CAENV1740Event const* event = caen_fragment.Event(); + CAENV1740EventHeader header = event->Header; + + // Gets the number of words of the header and the waveforms. + uint32_t num_words_per_event = header.eventSize; + size_t header_size = sizeof(CAENV1740EventHeader); + uint32_t num_words_per_header = header_size / sizeof(uint32_t); + uint32_t num_words_per_wvfms = (num_words_per_event - num_words_per_header); + + uint32_t num_bits_per_all_wvfms = num_words_per_wvfms * BITS_PER_WORD; + uint32_t num_samples_per_all_wvfms = num_bits_per_all_wvfms / BITS_PER_SAMPLE; + uint32_t num_remaining_bits = num_bits_per_all_wvfms % BITS_PER_SAMPLE; + uint32_t num_samples_per_wvfm = num_samples_per_all_wvfms / num_channels; + uint32_t num_samples_per_group = num_samples_per_wvfm * NUM_CHANNELS_PER_GROUP; + uint32_t num_nominal_samples_per_wvfm = metadata->nSamples; + + if (fverbose | fdebug_waveforms) { + if (num_nominal_samples_per_wvfm == num_samples_per_wvfm) { + std::cout << " > SBNDXARAPUCADecoder::decode_fragment: [NOMINAL FRAGMENT] " << num_samples_per_wvfm << " samples/waveform." << " (" << num_samples_per_group << " samples per group - 8 channels per group -)." << std::endl; + } else { + std::cout << " > SBNDXARAPUCADecoder::decode_fragment: [EXTENDED FRAGMENT] " << num_samples_per_wvfm << " samples/waveform." << " (" << num_samples_per_group << " samples per group - 8 channels per group -)." << std::endl; + } + std::cout << " > SBNDXARAPUCADecoder::decode_fragment: nominal number of samples per waveform: " << num_nominal_samples_per_wvfm << "." << std::endl; + std::cout << " > SBNDXARAPUCADecoder::decode_fragment: number of words for this fragment: " << num_words_per_event << " (Header: " << num_words_per_header << ", Waveform: " << num_words_per_wvfms << ") words." << std::endl; + } + + if (fdebug_waveforms) { + std::cout << "\t Number of bits for all the waveforms of this fragment: " << BITS_PER_WORD << "\t" << num_bits_per_all_wvfms << std::endl; + std::cout << "\t Number of samples for all the waveforms of this fragment: " << num_samples_per_all_wvfms << std::endl; + std::cout << "\t Number of remaining bits for this fragment: " << num_remaining_bits << std::endl; + std::cout << "\t Number of samples per wvfm (this fragment): " << num_samples_per_wvfm << std::endl; + std::cout << "\t Number of samples per group (this fragment): " << num_samples_per_group << std::endl; + } + + // =============== Extracts timing information for this fragment =============== // + + uint64_t frag_timestamp = fragment.timestamp(); // ns. + uint32_t TTT_ticks = header.triggerTime(); + int64_t TTT_end_ns = TTT_ticks * NANOSEC_PER_TICK; // ns. + + if (fdebug_timing) { + std::cout << "\t\t TTT header.extendedTriggerTime() [TTT_ticks] = " << header.extendedTriggerTime() << " ticks. \t TTT_end_ns = " << print_timestamp(header.extendedTriggerTime() * NANOSEC_PER_TICK) << "." << std::endl; + std::cout << "\t\t TTT header.triggerTimeRollOver(): " << header.triggerTimeRollOver() << std::endl; + } + + //// =============== Start decoding the waveforms =============== // + std::vector > fragment_wvfms(num_channels, std::vector(num_samples_per_wvfm, 0)); + decode_waveforms(fragment, fragment_wvfms, header_size, num_channels, num_samples_per_wvfm, num_words_per_wvfms, num_samples_per_group); + + is_nominal_length = (num_nominal_samples_per_wvfm == num_samples_per_wvfm); + is_first = (fragment_indices[board_idx] == 0); + + if (fverbose) { + std::cout << " > SBNDXARAPUCADecoder::decode_fragment: processing the decoded fragment and combines the extended ones to their nominal ones if needed." << std::endl; + } + if (is_nominal_length) { + if (!is_first) { + if (fdebug_extended_fragments) { + std::cout << "\t\t NOT FIRST NOMINAL fragment " << std::endl; + std::cout << "\t\t nominal_TTT: " << nominal_TTT << " TTT_end_ns: " << TTT_end_ns << std::endl; + std::cout << "\t\t nominal_frag_timestamp: " << nominal_frag_timestamp << " frag_timestamp : " << frag_timestamp << std::endl; + } + shift_time(TTT_ticks, nominal_TTT, nominal_frag_timestamp, timestamp, num_nominal_samples_per_wvfm, ini_wvfm_timestamp, end_wvfm_timestamp); + dump_waveforms(prod_wvfms, wvfms, fragment_indices, board_idx, num_channels, ini_wvfm_timestamp, end_wvfm_timestamp); + } else { + if (fdebug_extended_fragments) std::cout << "\t\t FIRST NOMINAL fragment " << std::endl; + } + combine_waveforms(wvfms, fragment_wvfms, num_channels); + nominal_TTT = TTT_end_ns; + nominal_frag_timestamp = frag_timestamp; + } else { + if (fdebug_extended_fragments) std::cout << "\t\t EXTENDED fragment " << std::endl; + combine_waveforms(wvfms, fragment_wvfms, num_channels); + } + + fragment_indices[board_idx]++; + + if (last_one) { + if (fdebug_extended_fragments) std::cout << "\t\t LAST fragment " << std::endl; + shift_time(TTT_ticks, nominal_TTT, nominal_frag_timestamp, timestamp, num_nominal_samples_per_wvfm, ini_wvfm_timestamp, end_wvfm_timestamp); + dump_waveforms(prod_wvfms, wvfms, fragment_indices, board_idx, num_channels, ini_wvfm_timestamp, end_wvfm_timestamp); + } + } +} + +// =============== Timing functions =============== // + +/** + * @brief This function shifts the initial and end timestamps of a waveform based on the provided timing information. + * + * @param[in] TTT_ticks The trigger time tag in ticks from the CAEN V1740 header. + * @param[in] TTT_end_ns The end time of the Trigger Time Tag (TTT) in nanoseconds. + * @param[in] frag_timestamp The timestamp of the fragment in nanoseconds. + * @param[in] timestamp The reference timestamp (ETRIG from the SPEC-TDC or HLT from the PTB) in nanoseconds. + * @param[in] num_samples_per_wvfm The number of samples per waveform. + * @param[out] ini_wvfm_timestamp The initial timestamp of the waveform in microseconds (output). + * @param[out] end_wvfm_timestamp The end timestamp of the waveform in microseconds (output). + * + * @details + * This function calculates the initial and end timestamps for a waveform based on the provided timing information. It takes into account + * potential rollovers in the trigger time tag and adjusts the timestamps accordingly. The function supports different timing frames, including + * SPEC-TDC, PTB, and CAEN-only timing. The calculated timestamps are returned in microseconds. + * + * @see get_spec_tdc_etrig_timestamp + * @see get_ptb_hlt_timestamp + */ +void sbndaq::SBNDXARAPUCADecoder::shift_time(uint64_t TTT_ticks, int64_t TTT_end_ns, uint64_t frag_timestamp, uint64_t timestamp, uint32_t num_samples_per_wvfm, double& ini_wvfm_timestamp, double& end_wvfm_timestamp) { + + int64_t pulse_duration_ns = num_samples_per_wvfm * fns_per_sample; // ns. + int64_t frag_timestamp_s = frag_timestamp / NANOSEC_IN_SEC; // s. + int64_t frag_timestamp_ns = frag_timestamp % NANOSEC_IN_SEC; // ns. + + // Gets the full TTT timestamp. + uint64_t full_TTT = 0; + // If the fragment timestamp is greater than the TTT end timestamp, it means that rollover occurred. + if (frag_timestamp_ns > TTT_end_ns) { + if (fverbose | fdebug_timing) std::cout << " > SBNDXARAPUCADecoder::decode_fragment: CAEN TTT rollover occurred w.r.t. the fragment timestamp (FTS)." << std::endl; + full_TTT = (frag_timestamp_s + 1) * NANOSEC_IN_SEC + TTT_end_ns; + } else { + full_TTT = frag_timestamp_s * NANOSEC_IN_SEC + TTT_end_ns; + } + + int64_t ref_timestamp = 0; + + // If an ETRIG or HLT timestamp was found it restarts the time from it. Otherwise the CAEN time frame is assigned. + if (factive_timing_frame != CAEN_ONLY_TIMING) { + ref_timestamp = signed_difference(full_TTT, timestamp); // ns. + + ini_wvfm_timestamp = (ref_timestamp - pulse_duration_ns) * NANOSEC_TO_MICROSEC; // us. + end_wvfm_timestamp = ref_timestamp * NANOSEC_TO_MICROSEC; // us. + } else { + ref_timestamp = full_TTT; // ns. + + ini_wvfm_timestamp = ((ref_timestamp - pulse_duration_ns) % NANOSEC_IN_SEC) * NANOSEC_TO_MICROSEC; // ns. + end_wvfm_timestamp = (ref_timestamp % NANOSEC_IN_SEC) * NANOSEC_TO_MICROSEC; // us. + } + + if (fdebug_timing) { + std::cout << std::fixed << std::setprecision(0); + std::cout << "\t\t ns/tick = " << NANOSEC_PER_TICK << ", ns/sample = " << fns_per_sample << std::endl; + std::cout << "\t\t TTT header.TriggerTime() [TTT_ticks] = " << TTT_ticks << " ticks. \t TTT_end_ns = " << print_timestamp(TTT_end_ns) << "." << std::endl; + std::cout << "\t\t Full Fragment timestamp: " << print_timestamp(frag_timestamp) << " = " << frag_timestamp_s << " s " << frag_timestamp_ns << " ns." << std::endl; + std::cout << "\t\t Full TTT - fragment timestamp = "<< abs_difference(full_TTT, frag_timestamp) << " ns." << " Post-percent: " << (double(abs_difference(full_TTT, frag_timestamp)) / double(pulse_duration_ns)) * 100 << "%." << std::endl; + if (factive_timing_frame == SPEC_TDC_TIMING) { + std::cout << "\t ETRIG (SPEC-TDC) timestamp of the fragment: " << std::endl; + std::cout << "\t\t Full UTC ETRIG timestamp: " << print_timestamp(timestamp) << "." << std::endl; + std::cout << "\t\t ETRIG SPEC-TDC difference applied to the CAEN frame (full timestamps): " << print_timestamp(full_TTT) << " - " << print_timestamp(timestamp) << " = " << ref_timestamp << " ns." << std::endl; + } else if (factive_timing_frame == PTB_TIMING) { + std::cout << "\t HLT ETRIG (PTB) timestamp of the fragment: " << std::endl; + std::cout << "\t\t Full UTC HLT ETRIG timestamp: " << print_timestamp(timestamp) << "." << std::endl; + std::cout << "\t\t HLT ETRIG (PTB) difference applied to the CAEN frame (full timestamps): " << print_timestamp(full_TTT) << " - " << print_timestamp(timestamp) << " = " << ref_timestamp << " ns." << std::endl; + } else if (factive_timing_frame == CAEN_ONLY_TIMING) { + std::cout << "\t CAEN trigger timestamp (TTT) of the fragment: " << std::endl; + std::cout << "\t\t Full UTC TTT timestamp: " << print_timestamp(full_TTT) << " = " << full_TTT / NANOSEC_IN_SEC << " s " << TTT_end_ns << " ns." << std::endl; + } + } + + if (fverbose | fdebug_timing) { + std::cout << std::fixed << std::setprecision(3); + if (factive_timing_frame == SPEC_TDC_TIMING) { + std::cout << " > SBNDXARAPUCADecoder::decode_fragment: SPEC-TDC time window of " << end_wvfm_timestamp - ini_wvfm_timestamp << " us: [" << ini_wvfm_timestamp << ", " << end_wvfm_timestamp << "] us." << std::endl; + } else if (factive_timing_frame == PTB_TIMING) { + std::cout << " > SBNDXARAPUCADecoder::decode_fragment: PTB time window of " << end_wvfm_timestamp - ini_wvfm_timestamp << " us: [" << ini_wvfm_timestamp << ", " << end_wvfm_timestamp << "] us." << std::endl; + } else { // CAEN_ONLY_TIMING + std::cout << " > SBNDXARAPUCADecoder::decode_fragment: CAEN time window of " << end_wvfm_timestamp - ini_wvfm_timestamp << " us: [" << ini_wvfm_timestamp << ", " << end_wvfm_timestamp << "] us." << std::endl; + } + std::cout << " > SBNDXARAPUCADecoder::decode_fragment: TTT_end_ticks = " << TTT_ticks << " ticks. \t TTT_end_ns = " << print_timestamp(TTT_end_ns) << "." << std::endl; + } +} + /** * @brief Searches for the SPEC-TDC ETRIG timestamp closest to the raw timestamp if any SPEC-TDC ETRIG product is found in the event. * @param[in] e The event to be processed. @@ -577,153 +822,226 @@ bool sbndaq::SBNDXARAPUCADecoder::get_ptb_hlt_timestamp(art::Event& e, uint64_t return hlt_found; } +// =============== Decodes the waveforms =============== // + /** - * @brief This function processes a single fragment from a CAEN V1740 and stores the decoded waveforms in the provided product - * container. + * @brief Decodes the waveforms from a CAEN V1740 fragment (binary decoding stage). * - * @param[in,out] fragment_indices A 1D vector tracking the number of fragments processed for each board. * @param[in] fragment The input CAEN V1740 fragment containing raw data to be decoded. - * @param[out] prod_wvfms Vector where the decoded waveforms will be stored as raw::OpDetWaveform objects. - * - * @details - * - Identifies the board index corresponding to the fragment ID. - * - Verifies the fragment ID against known boards and ensures it is within a valid range. - * - - * - Decodes the fragment reading raw 32-bit words from the fragment, storing them in a buffer, - * and extracting 12-bit samples. The decoding includes: - * - Accessing metadata for the number of channels and samples. - * - Getting the initial timestamp with respect to the selected timing frame. - * - Binary decoding of the raw waveform. To assign efficiently each sequential sample extracted. These indices formulas are - * applied: - * - The board channel index: - * \f[ - * c = \left( \frac{S}{3} \mod 8 \right) + g \times 8 - * \f] - * - The channel sample index: - * \f[ - * s = (S \mod 3) + \left( \frac{S}{24} \times 3 \right) \mod s_{w}} - * \f] - * Where the group index is computed as \f$ \frac{S}{s_{g}} \f$. - * - Mapping samples to corresponding channels. - * - Populates the output vector (`prod_wvfms`) with decoded waveforms and optionally generates debug waveforms output. + * @param[out] wvfms A 2D vector where the decoded waveforms will be stored. Each inner vector corresponds to a channel's waveform. + * @param[in] header_size The size of the event header in bytes. + * @param[in] num_channels The number of channels in the fragment. + * @param[in] num_samples_per_wvfm The number of samples per waveform for each channel. + * @param[in] num_words_per_wvfms The total number of 32-bit words containing waveform data in the fragment. + * @param[in] num_samples_per_group The number of samples per group of channels (8 channels per group). * + * @details This function reads raw 32-bit words from the fragment, storing them in a buffer, and extracts 12-bit samples. + * It assigns each sample to the appropriate channel and sample index based on its position in the sequence. The decoding process includes: + * - Initializing a buffer to hold incoming data and tracking the number of bits currently stored. + * - Iterating over each 32-bit word in the waveform data section of the fragment, adding it to the buffer. + * - Extracting 12-bit samples from the buffer as long as there are enough bits available, and assigning them to their respective channels and sample indices using calculated formulas. + * The function ensures that all samples are correctly mapped to their channels, taking into account the grouping of channels and the interleaving of samples. + * @note The function assumes that the input fragment is valid and contains the expected structure for a CAEN V1740 device. + * @see SBN Document 38475-v1 for more details on the binary decoding. */ +void sbndaq::SBNDXARAPUCADecoder::decode_waveforms(const artdaq::Fragment& fragment, std::vector>& wvfms, size_t header_size, uint32_t num_channels, uint32_t num_samples_per_wvfm, uint32_t num_words_per_wvfms, uint32_t num_samples_per_group) { + // =============== Start decoding the waveforms =============== // + if (fverbose) std::cout << " > SBNDXARAPUCADecoder::decode_fragment: binary decoding of the waveforms starting... " << std::endl; + + // Absolute sample number [0, TOTAL_NUM_SAMPLES] where TOTAL_NUM_SAMPLES is the total number of samples stored for an event. + uint32_t S = 0; + // Buffer variables. + uint64_t buffer = 0; + uint32_t bits_in_buffer = 0; -void sbndaq::SBNDXARAPUCADecoder::decode_fragment(uint64_t timestamp, uint64_t& nominal_frag_timestamp, int32_t& nominal_TTT, std::vector & fragment_indices, const artdaq::Fragment& fragment, std::vector & prod_wvfms, std::vector>& wvfms, bool last_one) { - auto fragment_id = fragment.fragmentID() - ffragment_id_offset; - auto it = std::find(fboard_id_list.begin(), fboard_id_list.end(), fragment_id); - size_t board_idx; - bool valid_fragment = false; - - if (it != fboard_id_list.end()) { - board_idx = it - fboard_id_list.begin(); - if (board_idx >= fnum_caen_boards) { - if (fverbose) std::cout << " > SBNDXARAPUCADecoder::decode_fragment: fragment ID " << fragment_id << " (" << board_idx << ") is out of range. Skipping this fragment..." << std::endl; - } else { - valid_fragment = true; - } - } else { - if (fverbose) std::cout << " > SBNDXARAPUCADecoder::decode_fragment: fragment ID " << fragment_id << " is not valid. Skipping this fragment..." << std::endl; - } - - if (valid_fragment) { - if (fverbose) std::cout << "\n > SBNDXARAPUCADecoder::decode_fragment: decoding V1740 CAEN fragment " << fragment_indices[board_idx] << " from the board " << board_idx << " (slot " << fboard_id_list[board_idx] << "):" << std::endl; - - bool is_nominal_length = false; - //bool is_within_nominal_length = false; - bool is_first = false; - + // Data pointer to the beggining of the waveforms stores in the event. + const uint32_t* data_ptr = reinterpret_cast(fragment.dataBeginBytes() + header_size); + // Accesses each word, stores it in the buffer and then the samples are extracted from the buffer. + for (size_t j = 0; j < num_words_per_wvfms; j++) { + uint64_t word = read_word(data_ptr); - double ini_wvfm_timestamp = 0; - double end_wvfm_timestamp = 0; - - // =============== Accesses Event metadata and Event header for this fragment =============== // + // Adds the new word to the buffer and increments the number of bits stored in it. + if (fdebug_buffer) std::cout << buffer << "[word: " << word << "]" << std::endl; + buffer |= word << bits_in_buffer; + bits_in_buffer += BITS_PER_WORD; // bytes * 8 bits/byte + if (fdebug_buffer) std::cout << " +" << buffer << " [bits in buffer: "<< bits_in_buffer << "]" << std::endl; - CAENV1740Fragment caen_fragment(fragment); - CAENV1740FragmentMetadata const* metadata = caen_fragment.Metadata(); - uint32_t num_channels = metadata->nChannels; - if (fverbose) std::cout << " > SBNDXARAPUCADecoder::decode_fragment: number of channels: " << num_channels << std::endl; - - // Accesses the event and header data of the CAEN fragment. - CAENV1740Event const* event = caen_fragment.Event(); - CAENV1740EventHeader header = event->Header; - - // Gets the number of words of the header and the waveforms. - uint32_t num_words_per_event = header.eventSize; - size_t header_size = sizeof(CAENV1740EventHeader); - uint32_t num_words_per_header = header_size / sizeof(uint32_t); - uint32_t num_words_per_wvfms = (num_words_per_event - num_words_per_header); - - uint32_t num_bits_per_all_wvfms = num_words_per_wvfms * BITS_PER_WORD; - uint32_t num_samples_per_all_wvfms = num_bits_per_all_wvfms / BITS_PER_SAMPLE; - uint32_t num_remaining_bits = num_bits_per_all_wvfms % BITS_PER_SAMPLE; - uint32_t num_samples_per_wvfm = num_samples_per_all_wvfms / num_channels; - uint32_t num_samples_per_group = num_samples_per_wvfm * NUM_CHANNELS_PER_GROUP; - uint32_t num_nominal_samples_per_wvfm = metadata->nSamples; - - if (fverbose | fdebug_waveforms) { - if (num_nominal_samples_per_wvfm == num_samples_per_wvfm) { - std::cout << " > SBNDXARAPUCADecoder::decode_fragment: [NOMINAL FRAGMENT] " << num_samples_per_wvfm << " samples/waveform." << " (" << num_samples_per_group << " samples per group - 8 channels per group -)." << std::endl; - } else { - std::cout << " > SBNDXARAPUCADecoder::decode_fragment: [EXTENDED FRAGMENT] " << num_samples_per_wvfm << " samples/waveform." << " (" << num_samples_per_group << " samples per group - 8 channels per group -)." << std::endl; - } - std::cout << " > SBNDXARAPUCADecoder::decode_fragment: nominal number of samples per waveform: " << num_nominal_samples_per_wvfm << "." << std::endl; - std::cout << " > SBNDXARAPUCADecoder::decode_fragment: number of words for this fragment: " << num_words_per_event << " (Header: " << num_words_per_header << ", Waveform: " << num_words_per_wvfms << ") words." << std::endl; + // Obtains 12-bit sequences from the buffer and assigns each sample to the channel and channel sample it belongs to. + while (bits_in_buffer >= BITS_PER_SAMPLE) { + // Computes board channel, channel sample and group channel and assigns the sample to those indices. + uint32_t g = (S / num_samples_per_group); // Group index. + uint32_t c = ((S / NUM_CONSECUTIVE_SAMPLES) % NUM_CHANNELS_PER_GROUP) + g * NUM_GROUPS; // Channel index. + uint32_t s = (S % NUM_CONSECUTIVE_SAMPLES) + ((S / NUM_SAMPLES_PER_ROUND) * NUM_CONSECUTIVE_SAMPLES) % num_samples_per_wvfm; // Sample/channel index. + uint16_t sample = get_sample(buffer, BITS_PER_SAMPLE - 1, 0); + wvfms[c][s] = sample; + if (fdebug_waveforms) std::cout << "\tSample: " << sample << "\tg: " << g << "\tch: " << c << "\ts:" << s << "\tS: " << S << std::endl; + + // Updates the buffer status removing the read bits and decreasing the number of bits stored in it. + buffer >>= BITS_PER_SAMPLE; + bits_in_buffer -= BITS_PER_SAMPLE; + if (fdebug_buffer) std::cout << " -" << buffer << " [bits in buffer: "<< bits_in_buffer << "]" << std::endl; + + // Increments the absolute sample step. + S++; } + } +} - if (fdebug_waveforms) { - std::cout << "\t Number of bits for all the waveforms of this fragment: " << BITS_PER_WORD << "\t" << num_bits_per_all_wvfms << std::endl; - std::cout << "\t Number of samples for all the waveforms of this fragment: " << num_samples_per_all_wvfms << std::endl; - std::cout << "\t Number of remaining bits for this fragment: " << num_remaining_bits << std::endl; - std::cout << "\t Number of samples per wvfm (this fragment): " << num_samples_per_wvfm << std::endl; - std::cout << "\t Number of samples per group (this fragment): " << num_samples_per_group << std::endl; - } +/** + * @brief Extract a sample from a 64-bit buffer using the specified bit positions. + * + * @param[in] buffer An unsigned 64-bit integer which represents a temporal buffer for the read words and where the samples are extracted from. + * @param[in] msb An unsigned 32-bit integer representing the most significative bit (MSB) where the readout from the buffer paramter. + * @param[in] lsb An unsigned 32-bit integer representing the less significative bit (LSB) from we end read + * + * @details The function shifts the buffer to the right by the number of positions specified by `lsb` so that the least significant bit of the + * sample aligns with bit 0. It then applies a mask to isolate the bits between `lsb` and `msb`, inclusive. + * + * @return The extracted sample as a 16-bit unsigned integer. + */ +uint16_t sbndaq::SBNDXARAPUCADecoder::get_sample(uint64_t buffer, uint32_t msb, uint32_t lsb) { + uint64_t mask = (1U << (msb - lsb + 1)) - 1; + uint64_t sample = buffer >> lsb; + return sample & mask; +} - // =============== Extracts timing information for this fragment =============== // +/** + * @brief Read a 32-bit word from the data pointer and advances the pointer. + * + * @param[in, out] data_ptr A reference to a pointer pointing to the current position in the data. + * + * @details This function retrieves a 32-bit word from the memory location pointed to by `data_ptr`. After reading, it advances `data_ptr` to + * the next 32-bit word location. + * + * @return The 32-bit word read from the location pointed to by `data_ptr`. + */ +uint32_t sbndaq::SBNDXARAPUCADecoder::read_word(const uint32_t* & data_ptr) { + uint32_t word = *data_ptr; + data_ptr += 1; + return word; +} - uint64_t frag_timestamp = fragment.timestamp(); // ns. - uint32_t TTT_ticks = header.triggerTime(); - int64_t TTT_end_ns = TTT_ticks * NANOSEC_PER_TICK; // ns. +/** + * @brief Generates a unique global channel identifier using the board slot and the channel number of that board. + * + * @param[in] board Index of the board in `fboard_id_list` from which to derive the board slot. + * @param[in] board_channel The specific channel number on the given board. + * + * @details This function computes a `channel_id` by combining the board slot and the specific + * channel number on that board. + * The unique identifier `channel_id` (\f$ CH_{ID} $\f) is computed as follows: + * \f[ + * CH\_{ID} = B\_{ID} \times 100 + CH\_{B} + * \f] + * + * Where: + * - \f$ B\_{ID} \f$ is the fragment ID retrieved from `fboard_id_list` based on the slot. + * - \f$ CH\_B \f$ is the channel number on that board. + * + * @return A unique identifier for the specified channel as an unsigned integer. + */ +unsigned int sbndaq::SBNDXARAPUCADecoder::get_channel_id(unsigned int board, unsigned int board_channel) { + unsigned int channel_id = fboard_id_list[board] * 100 + board_channel; + return channel_id; +} - if (fdebug_timing) { - std::cout << "\t\t TTT header.extendedTriggerTime() [TTT_ticks] = " << header.extendedTriggerTime() << " ticks. \t TTT_end_ns = " << print_timestamp(header.extendedTriggerTime() * NANOSEC_PER_TICK) << "." << std::endl; - std::cout << "\t\t TTT header.triggerTimeRollOver(): " << header.triggerTimeRollOver() << std::endl; +// =============== Combines the waveforms from extended fragments =============== // + +/** + * @brief Combines the waveforms from the current fragment with the previously stored waveforms. + * @param[in,out] wvfms A 2D vector containing the (combined if it was needed before) waveforms. + * @param[in] fragment_wvfms A 2D vector containing the waveforms from the current fragment to be combined. + * @param[in] num_channels The number of channels per board. + * + * @details + * The function performs the following steps: + * 1. Checks if the `wvfms` vector is empty. If it is, it resizes it to accommodate `num_channels` channels. + * 2. Iterates over each channel from 0 to `num_channels - 1`. + * 3. For each channel, it appends the samples from `fragment_wvfms` to the corresponding channel in `wvfms`. + * + * This approach ensures that waveforms from multiple fragments are concatenated correctly, maintaining the order of samples for each channel. + * + * @pre The `fragment_wvfms` vector should contain waveforms for all channels of the board being processed. + * @pre The `wvfms` vector should be either empty or already contain waveforms for all channels of the board being processed. + */ +void sbndaq::SBNDXARAPUCADecoder::combine_waveforms(std::vector>& wvfms, const std::vector>& fragment_wvfms, uint32_t num_channels) { + if (fdebug_extended_fragments) std::cout << " > SBNDXARAPUCADecoder::combine_waveforms: combining waveforms from extended fragments..." << std::endl; + if (wvfms.empty()) { + if (fdebug_extended_fragments) { + std::cout << "\t\t Empty waveforms, resizing to " << num_channels << " channels." << std::endl; + } + wvfms.resize(num_channels); + if (fverbose | fdebug_extended_fragments) { + std::cout << "\t\t Waveforms size BEFORE combining = " << wvfms.size() << " x " << wvfms[0].size() << std::endl; + } + } + for (uint32_t ch = 0; ch < num_channels; ch++) { + wvfms[ch].insert(wvfms[ch].end(), fragment_wvfms[ch].begin(), fragment_wvfms[ch].end()); + } + if (fverbose | fdebug_extended_fragments) { + std::cout << "\t\t Waveforms size AFTER combining = " << wvfms.size() << " x " << wvfms[0].size() << std::endl; } +} - //// =============== Start decoding the waveforms =============== // - std::vector > fragment_wvfms(num_channels, std::vector(num_samples_per_wvfm, 0)); - decode_waveforms(fragment, fragment_wvfms, header_size, num_channels, num_samples_per_wvfm, num_words_per_wvfms, num_samples_per_group); - - is_nominal_length = (num_nominal_samples_per_wvfm == num_samples_per_wvfm); - is_first = (fragment_indices[board_idx] == 0); +// =============== Dumps the decoded waveforms =============== // + +/** + * @brief Dump products into a `raw::OpDetWaveform` object and into a debug histogram file. + * @param[in,out] prod_wvfms A reference to the vector where the produced `raw::OpDetWaveform` objects are dumped into products. + * @param[in,out] wvfms A 2D vector containing the (combined if needed) waveforms. + * @param[in,out] fragment_indices A reference to a vector keeping track of the number of fragments decoded per board. + * @param[in] board_idx The board index (position in the list of boards). + * @param[in] num_channels The number of channels per board. + * @param[in] ini_wvfm_timestamp The initial timestamp of the waveform in microseconds. + * @param[in] end_wvfm_timestamp The final timestamp of the waveform in microseconds. + * + * @details + * The function performs the following steps: + * 1. Determines the number of debug waveforms to be stored based on the configuration parameter `fstore_debug_waveforms`. + * - If `fstore_debug_waveforms` is set to -1, all channels are considered for debug storage. + * - Otherwise, it takes the minimum between `num_channels` and `fstore_debug_waveforms`. + * 2. Iterates over each channel up to the determined number of debug waveforms: + * - Calls `save_prod_wvfm` to convert and store the waveform in the products. + * - Calls `save_debug_wvfm` to save the waveform as a histogram for debugging purposes. + * 3. For any remaining channels beyond the debug limit, it only calls `save_prod_wvfm` to store the waveform in the products. + * 4. Clears the `wvfms` vector to free up memory after processing. + * + * @pre ini_wvfm_timestamp and end_wvfm_timestamp is assumed to be given in microseconds when the timing frame is not CAEN_ONLY_TIMING. + * @pre The `wvfms` vector should contain waveforms for all channels of the board specified by `board_idx`. + * @pre The `fragment_indices` vector should have been initialized with a size equal to the number of boards being processed. + * @pre The `prod_wvfms` vector should be ready to accept new `raw::OpDetWaveform` objects. + * + * @see raw::OpDetWaveform + * @see save_prod_wvfm + * @see save_debug_wvfm + */ +void sbndaq::SBNDXARAPUCADecoder::dump_waveforms(std::vector & prod_wvfms, std::vector>& wvfms, std::vector & fragment_indices, size_t board_idx, uint32_t num_channels, double ini_wvfm_timestamp, double end_wvfm_timestamp) { - if (is_nominal_length) { - if (!is_first) { - std::cout << " NOT FIRST NOMINAL fragment " << std::endl; - std::cout << " nominal_TTT: " << nominal_TTT << " TTT_end_ns: " << TTT_end_ns << std::endl; - std::cout << " nominal_frag_timestamp: " << nominal_frag_timestamp << " frag_timestamp : " << frag_timestamp << std::endl; - shift_time(TTT_ticks, nominal_TTT, nominal_frag_timestamp, timestamp, num_nominal_samples_per_wvfm, ini_wvfm_timestamp, end_wvfm_timestamp); - dump_waveforms(prod_wvfms, wvfms, fragment_indices, board_idx, num_channels, ini_wvfm_timestamp, end_wvfm_timestamp); - } else { - std::cout << " FIRST NOMINAL fragment " << std::endl; - } - combine_waveforms(wvfms, fragment_wvfms, num_channels); - nominal_TTT = TTT_end_ns; - nominal_frag_timestamp = frag_timestamp; - } else { - std::cout << " EXTENDED fragment " << std::endl; - combine_waveforms(wvfms, fragment_wvfms, num_channels); - } + // The decoded waveforms are dumped into two products: + // - A xarapucadecoder-art.root file with the OpDetWaveforms as the product of this producer for further analysis. + // - A decoder_hist.root file gathering a waveform histograms. + if (fverbose) std::cout << " > SBNDXARAPUCADecoder::decode_fragment: binary decoding complete, dumping products..." << std::endl; - fragment_indices[board_idx]++; + uint32_t num_debug_wvfms; - if (last_one) { - std::cout << " LAST fragment " << std::endl; - shift_time(TTT_ticks, nominal_TTT, nominal_frag_timestamp, timestamp, num_nominal_samples_per_wvfm, ini_wvfm_timestamp, end_wvfm_timestamp); - dump_waveforms(prod_wvfms, wvfms, fragment_indices, board_idx, num_channels, ini_wvfm_timestamp, end_wvfm_timestamp); - } + if (fstore_debug_waveforms == -1) { + num_debug_wvfms = num_channels; + } else { + num_debug_wvfms = std::min(num_channels, fstore_debug_waveforms); + } + + uint32_t ch; + + for (ch = 0; ch < num_debug_wvfms; ch++) { + save_prod_wvfm(board_idx, ch, ini_wvfm_timestamp, wvfms, prod_wvfms); + save_debug_wvfm(board_idx, fragment_indices[board_idx], ch, ini_wvfm_timestamp, end_wvfm_timestamp, wvfms); + } + for (;ch < num_channels; ch++) { + save_prod_wvfm(board_idx, ch, ini_wvfm_timestamp, wvfms, prod_wvfms); } + + wvfms.clear(); } /** @@ -804,211 +1122,7 @@ void sbndaq::SBNDXARAPUCADecoder::save_debug_wvfm(size_t board_idx, size_t fragm } -void sbndaq::SBNDXARAPUCADecoder::shift_time(uint64_t TTT_ticks, int64_t TTT_end_ns, uint64_t frag_timestamp, uint64_t timestamp, uint32_t num_samples_per_wvfm, double& ini_wvfm_timestamp, double& end_wvfm_timestamp) { - - int64_t pulse_duration_ns = num_samples_per_wvfm * fns_per_sample; // ns. - int64_t frag_timestamp_s = frag_timestamp / NANOSEC_IN_SEC; // s. - int64_t frag_timestamp_ns = frag_timestamp % NANOSEC_IN_SEC; // ns. - - // Gets the full TTT timestamp. - uint64_t full_TTT = 0; - // If the fragment timestamp is greater than the TTT end timestamp, it means that rollover occurred. - if (frag_timestamp_ns > TTT_end_ns) { - if (fverbose | fdebug_timing) std::cout << " > SBNDXARAPUCADecoder::decode_fragment: CAEN TTT rollover occurred w.r.t. the fragment timestamp (FTS)." << std::endl; - full_TTT = (frag_timestamp_s + 1) * NANOSEC_IN_SEC + TTT_end_ns; - } else { - full_TTT = frag_timestamp_s * NANOSEC_IN_SEC + TTT_end_ns; - } - - int64_t ref_timestamp = 0; - - // If an ETRIG or HLT timestamp was found it restarts the time from it. Otherwise the CAEN time frame is assigned. - if (factive_timing_frame != CAEN_ONLY_TIMING) { - ref_timestamp = signed_difference(full_TTT, timestamp); // ns. - - ini_wvfm_timestamp = (ref_timestamp - pulse_duration_ns) * NANOSEC_TO_MICROSEC; // us. - end_wvfm_timestamp = ref_timestamp * NANOSEC_TO_MICROSEC; // us. - } else { - ref_timestamp = full_TTT; // ns. - - ini_wvfm_timestamp = ((ref_timestamp - pulse_duration_ns) % NANOSEC_IN_SEC) * NANOSEC_TO_MICROSEC; // ns. - end_wvfm_timestamp = (ref_timestamp % NANOSEC_IN_SEC) * NANOSEC_TO_MICROSEC; // us. - } - - if (fdebug_timing) { - std::cout << std::fixed << std::setprecision(0); - std::cout << "\t\t ns/tick = " << NANOSEC_PER_TICK << ", ns/sample = " << fns_per_sample << std::endl; - std::cout << "\t\t TTT header.TriggerTime() [TTT_ticks] = " << TTT_ticks << " ticks. \t TTT_end_ns = " << print_timestamp(TTT_end_ns) << "." << std::endl; - std::cout << "\t\t Full Fragment timestamp: " << print_timestamp(frag_timestamp) << " = " << frag_timestamp_s << " s " << frag_timestamp_ns << " ns." << std::endl; - std::cout << "\t\t Full TTT - fragment timestamp = "<< abs_difference(full_TTT, frag_timestamp) << " ns." << " Post-percent: " << (double(abs_difference(full_TTT, frag_timestamp)) / double(pulse_duration_ns)) * 100 << "%." << std::endl; - if (factive_timing_frame == SPEC_TDC_TIMING) { - std::cout << "\t ETRIG (SPEC-TDC) timestamp of the fragment: " << std::endl; - std::cout << "\t\t Full UTC ETRIG timestamp: " << print_timestamp(timestamp) << "." << std::endl; - std::cout << "\t\t ETRIG SPEC-TDC difference applied to the CAEN frame (full timestamps): " << print_timestamp(full_TTT) << " - " << print_timestamp(timestamp) << " = " << ref_timestamp << " ns." << std::endl; - } else if (factive_timing_frame == PTB_TIMING) { - std::cout << "\t HLT ETRIG (PTB) timestamp of the fragment: " << std::endl; - std::cout << "\t\t Full UTC HLT ETRIG timestamp: " << print_timestamp(timestamp) << "." << std::endl; - std::cout << "\t\t HLT ETRIG (PTB) difference applied to the CAEN frame (full timestamps): " << print_timestamp(full_TTT) << " - " << print_timestamp(timestamp) << " = " << ref_timestamp << " ns." << std::endl; - } else if (factive_timing_frame == CAEN_ONLY_TIMING) { - std::cout << "\t CAEN trigger timestamp (TTT) of the fragment: " << std::endl; - std::cout << "\t\t Full UTC TTT timestamp: " << print_timestamp(full_TTT) << " = " << full_TTT / NANOSEC_IN_SEC << " s " << TTT_end_ns << " ns." << std::endl; - } - } - - if (fverbose | fdebug_timing) { - std::cout << std::fixed << std::setprecision(3); - if (factive_timing_frame == SPEC_TDC_TIMING) { - std::cout << " > SBNDXARAPUCADecoder::decode_fragment: SPEC-TDC time window of " << end_wvfm_timestamp - ini_wvfm_timestamp << " us: [" << ini_wvfm_timestamp << ", " << end_wvfm_timestamp << "] us." << std::endl; - } else if (factive_timing_frame == PTB_TIMING) { - std::cout << " > SBNDXARAPUCADecoder::decode_fragment: PTB time window of " << end_wvfm_timestamp - ini_wvfm_timestamp << " us: [" << ini_wvfm_timestamp << ", " << end_wvfm_timestamp << "] us." << std::endl; - } else { // CAEN_ONLY_TIMING - std::cout << " > SBNDXARAPUCADecoder::decode_fragment: CAEN time window of " << end_wvfm_timestamp - ini_wvfm_timestamp << " us: [" << ini_wvfm_timestamp << ", " << end_wvfm_timestamp << "] us." << std::endl; - } - std::cout << " > SBNDXARAPUCADecoder::decode_fragment: TTT_end_ticks = " << TTT_ticks << " ticks. \t TTT_end_ns = " << print_timestamp(TTT_end_ns) << "." << std::endl; - } -} - -void sbndaq::SBNDXARAPUCADecoder::decode_waveforms(const artdaq::Fragment& fragment, std::vector>& wvfms, size_t header_size, uint32_t num_channels, uint32_t num_samples_per_wvfm, uint32_t num_words_per_wvfms, uint32_t num_samples_per_group) { - // =============== Start decoding the waveforms =============== // - if (fverbose) std::cout << " > SBNDXARAPUCADecoder::decode_fragment: binary decoding of the waveforms starting... " << std::endl; - - // Absolute sample number [0, TOTAL_NUM_SAMPLES] where TOTAL_NUM_SAMPLES is the total number of samples stored for an event. - uint32_t S = 0; - // Buffer variables. - uint64_t buffer = 0; - uint32_t bits_in_buffer = 0; - - // Data pointer to the beggining of the waveforms stores in the event. - const uint32_t* data_ptr = reinterpret_cast(fragment.dataBeginBytes() + header_size); - // Accesses each word, stores it in the buffer and then the samples are extracted from the buffer. - for (size_t j = 0; j < num_words_per_wvfms; j++) { - uint64_t word = read_word(data_ptr); - - // Adds the new word to the buffer and increments the number of bits stored in it. - if (fdebug_buffer) std::cout << buffer << "[word: " << word << "]" << std::endl; - buffer |= word << bits_in_buffer; - bits_in_buffer += BITS_PER_WORD; // bytes * 8 bits/byte - if (fdebug_buffer) std::cout << " +" << buffer << " [bits in buffer: "<< bits_in_buffer << "]" << std::endl; - - // Obtains 12-bit sequences from the buffer and assigns each sample to the channel and channel sample it belongs to. - while (bits_in_buffer >= BITS_PER_SAMPLE) { - // Computes board channel, channel sample and group channel and assigns the sample to those indices. - uint32_t g = (S / num_samples_per_group); // Group index. - uint32_t c = ((S / NUM_CONSECUTIVE_SAMPLES) % NUM_CHANNELS_PER_GROUP) + g * NUM_GROUPS; // Channel index. - uint32_t s = (S % NUM_CONSECUTIVE_SAMPLES) + ((S / NUM_SAMPLES_PER_ROUND) * NUM_CONSECUTIVE_SAMPLES) % num_samples_per_wvfm; // Sample/channel index. - uint16_t sample = get_sample(buffer, BITS_PER_SAMPLE - 1, 0); - wvfms[c][s] = sample; - if (fdebug_waveforms) std::cout << "\tSample: " << sample << "\tg: " << g << "\tch: " << c << "\ts:" << s << "\tS: " << S << std::endl; - - // Updates the buffer status removing the read bits and decreasing the number of bits stored in it. - buffer >>= BITS_PER_SAMPLE; - bits_in_buffer -= BITS_PER_SAMPLE; - if (fdebug_buffer) std::cout << " -" << buffer << " [bits in buffer: "<< bits_in_buffer << "]" << std::endl; - - // Increments the absolute sample step. - S++; - } - } -} - -void sbndaq::SBNDXARAPUCADecoder::dump_waveforms(std::vector & prod_wvfms, std::vector>& wvfms, std::vector & fragment_indices, size_t board_idx, uint32_t num_channels, double ini_wvfm_timestamp, double end_wvfm_timestamp) { - - // The decoded waveforms are dumped into two products: - // - A xarapucadecoder-art.root file with the OpDetWaveforms as the product of this producer for further analysis. - // - A decoder_hist.root file gathering a waveform histograms. - if (fverbose) std::cout << " > SBNDXARAPUCADecoder::decode_fragment: binary decoding complete, dumping products..." << std::endl; - - uint32_t num_debug_wvfms; - - if (fstore_debug_waveforms == -1) { - num_debug_wvfms = num_channels; - } else { - num_debug_wvfms = std::min(num_channels, fstore_debug_waveforms); - } - - uint32_t ch; - - for (ch = 0; ch < num_debug_wvfms; ch++) { - save_prod_wvfm(board_idx, ch, ini_wvfm_timestamp, wvfms, prod_wvfms); - save_debug_wvfm(board_idx, fragment_indices[board_idx], ch, ini_wvfm_timestamp, end_wvfm_timestamp, wvfms); - } - - for (;ch < num_channels; ch++) { - save_prod_wvfm(board_idx, ch, ini_wvfm_timestamp, wvfms, prod_wvfms); - } - - wvfms.clear(); -} - -void sbndaq::SBNDXARAPUCADecoder::combine_waveforms(std::vector>& wvfms, const std::vector>& fragment_wvfms, uint32_t num_channels) { - if (wvfms.empty()) { - std::cout << "Empty waveforms, resizing to " << num_channels << " channels." << std::endl; - wvfms.resize(num_channels); - std::cout << "BEF COMB - wvfms_size = " << wvfms.size() << " x " << wvfms[0].size() << std::endl; - } - for (uint32_t ch = 0; ch < num_channels; ch++) { - wvfms[ch].insert(wvfms[ch].end(), fragment_wvfms[ch].begin(), fragment_wvfms[ch].end()); - } - std::cout << "AFT COMB - wvfms_size = " << wvfms.size() << " x " << wvfms[0].size() << std::endl; -} - -/** - * @brief Extract a sample from a 64-bit buffer using the specified bit positions. - * - * @param[in] buffer An unsigned 64-bit integer which represents a temporal buffer for the read words and where the samples are extracted from. - * @param[in] msb An unsigned 32-bit integer representing the most significative bit (MSB) where the readout from the buffer paramter. - * @param[in] lsb An unsigned 32-bit integer representing the less significative bit (LSB) from we end read - * - * @details The function shifts the buffer to the right by the number of positions specified by `lsb` so that the least significant bit of the - * sample aligns with bit 0. It then applies a mask to isolate the bits between `lsb` and `msb`, inclusive. - * - * @return The extracted sample as a 16-bit unsigned integer. - */ -uint16_t sbndaq::SBNDXARAPUCADecoder::get_sample(uint64_t buffer, uint32_t msb, uint32_t lsb) { - uint64_t mask = (1U << (msb - lsb + 1)) - 1; - uint64_t sample = buffer >> lsb; - return sample & mask; -} - -/** - * @brief Read a 32-bit word from the data pointer and advances the pointer. - * - * @param[in, out] data_ptr A reference to a pointer pointing to the current position in the data. - * - * @details This function retrieves a 32-bit word from the memory location pointed to by `data_ptr`. After reading, it advances `data_ptr` to - * the next 32-bit word location. - * - * @return The 32-bit word read from the location pointed to by `data_ptr`. - */ -uint32_t sbndaq::SBNDXARAPUCADecoder::read_word(const uint32_t* & data_ptr) { - uint32_t word = *data_ptr; - data_ptr += 1; - return word; -} - -/** - * @brief Generates a unique global channel identifier using the board slot and the channel number of that board. - * - * @param[in] board Index of the board in `fboard_id_list` from which to derive the board slot. - * @param[in] board_channel The specific channel number on the given board. - * - * @details This function computes a `channel_id` by combining the board slot and the specific - * channel number on that board. - * The unique identifier `channel_id` (\f$ CH_{ID} $\f) is computed as follows: - * \f[ - * CH\_{ID} = B\_{ID} \times 100 + CH\_{B} - * \f] - * - * Where: - * - \f$ B\_{ID} \f$ is the fragment ID retrieved from `fboard_id_list` based on the slot. - * - \f$ CH\_B \f$ is the channel number on that board. - * - * @return A unique identifier for the specified channel as an unsigned integer. - */ -unsigned int sbndaq::SBNDXARAPUCADecoder::get_channel_id(unsigned int board, unsigned int board_channel) { - unsigned int channel_id = fboard_id_list[board] * 100 + board_channel; - return channel_id; -} +// ==================== Auxiliary functions ==================== // /** * @brief Returns the signed difference between two timestamps (t1 - t2). diff --git a/sbndcode/Decoders/XARAPUCA/xarapucadecoder.fcl b/sbndcode/Decoders/XARAPUCA/xarapucadecoder.fcl index 774032157..d1ac9b9d1 100644 --- a/sbndcode/Decoders/XARAPUCA/xarapucadecoder.fcl +++ b/sbndcode/Decoders/XARAPUCA/xarapucadecoder.fcl @@ -36,12 +36,13 @@ xarapucadecoder: # - Debug options. debug_tdc_handle: false # (De)activates SPEC-TDC art::Handle information printing. debug_ptb_handle: false # (De)activates PTB art::Handle information printing. - debug_fragments_handle: true # (De)activates V1740B CAEN fragments art::Handle information printing. - debug_timing: true # (De)activates timing data printing. + debug_fragments_handle: false # (De)activates V1740B CAEN fragments art::Handle information printing. + debug_timing: false # (De)activates timing data printing. debug_buffer: false # (De)activates buffer status printing. debug_waveforms: false # (De)activates waveforms decoding printing. + debug_extended_fragments: false # (De)activates extended fragments information printing. # - Verbose option. - verbose: true # (De)activates verbosity. + verbose: false # (De)activates verbosity. } END_PROLOG \ No newline at end of file From 60036c5b1117102af1cbc02941a7acd790ae6484 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Alicia=20V=C3=A1zquez-Ramos?= Date: Wed, 15 Oct 2025 06:19:56 -0500 Subject: [PATCH 08/18] Update SBN Document for reference --- sbndcode/Decoders/XARAPUCA/SBNDXARAPUCADecoder_module.cc | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/sbndcode/Decoders/XARAPUCA/SBNDXARAPUCADecoder_module.cc b/sbndcode/Decoders/XARAPUCA/SBNDXARAPUCADecoder_module.cc index 7c46afb10..687818fae 100644 --- a/sbndcode/Decoders/XARAPUCA/SBNDXARAPUCADecoder_module.cc +++ b/sbndcode/Decoders/XARAPUCA/SBNDXARAPUCADecoder_module.cc @@ -10,7 +10,7 @@ * @brief Defines and implements the SBNDXARAPUCADecoder class which inherits from an art::EDProducer * as the decoder for V1740B digitizers, intended for the X-ARAPUCAs. * @details The current version of the SBND X-ARAPUCAs decoder implements the updates shown in - * the SBN Document 38475-v1 in the SBN Document Database. + * the SBN Document 43891-v1 in the SBN Document Database. * @note A Python version of the binary decoding is available for testing purposes. You can find * it [here: V1740 binary decoder](https://github.com/aliciavr/V1740_binary_decoder). */ From 2f7ff4598d720d713fc8c6c662407576efb2117a Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Alicia=20V=C3=A1zquez-Ramos?= Date: Wed, 5 Nov 2025 04:13:09 -0600 Subject: [PATCH 09/18] Add version number and update number of debug waveforms to 0 --- sbndcode/Decoders/XARAPUCA/SBNDXARAPUCADecoder_module.cc | 1 + sbndcode/Decoders/XARAPUCA/xarapucadecoder.fcl | 2 +- 2 files changed, 2 insertions(+), 1 deletion(-) diff --git a/sbndcode/Decoders/XARAPUCA/SBNDXARAPUCADecoder_module.cc b/sbndcode/Decoders/XARAPUCA/SBNDXARAPUCADecoder_module.cc index 687818fae..321f8db04 100644 --- a/sbndcode/Decoders/XARAPUCA/SBNDXARAPUCADecoder_module.cc +++ b/sbndcode/Decoders/XARAPUCA/SBNDXARAPUCADecoder_module.cc @@ -13,6 +13,7 @@ * the SBN Document 43891-v1 in the SBN Document Database. * @note A Python version of the binary decoding is available for testing purposes. You can find * it [here: V1740 binary decoder](https://github.com/aliciavr/V1740_binary_decoder). + * @version 4.0 */ #include "art/Framework/Core/EDProducer.h" diff --git a/sbndcode/Decoders/XARAPUCA/xarapucadecoder.fcl b/sbndcode/Decoders/XARAPUCA/xarapucadecoder.fcl index d1ac9b9d1..eed2269a9 100644 --- a/sbndcode/Decoders/XARAPUCA/xarapucadecoder.fcl +++ b/sbndcode/Decoders/XARAPUCA/xarapucadecoder.fcl @@ -32,7 +32,7 @@ xarapucadecoder: # - Output data product instance name. waveforms_instance_name: "XARAPUCAChannels" # Name for the instance product containing the raw decoded waveforms. timing_ref_instance_name: "" # Name for the instance product containing the timing reference information. - store_debug_waveforms: -1 # Number of waveforms to store (0: none, -1: all, n: first n waveforms). + store_debug_waveforms: 0 # Number of waveforms to store (0: none, -1: all, n: first n waveforms). # - Debug options. debug_tdc_handle: false # (De)activates SPEC-TDC art::Handle information printing. debug_ptb_handle: false # (De)activates PTB art::Handle information printing. From 15f34cdb45ef5ffb6065bd4973962d9fc3811166 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Alicia=20V=C3=A1zquez-Ramos?= Date: Thu, 6 Nov 2025 03:46:39 -0600 Subject: [PATCH 10/18] First version of timing check implemented (some extended fragments do not fulfill the requirements --- .../XARAPUCA/SBNDXARAPUCADecoder_module.cc | 56 ++++++++++++++----- .../Decoders/XARAPUCA/xarapucadecoder.fcl | 2 +- 2 files changed, 43 insertions(+), 15 deletions(-) diff --git a/sbndcode/Decoders/XARAPUCA/SBNDXARAPUCADecoder_module.cc b/sbndcode/Decoders/XARAPUCA/SBNDXARAPUCADecoder_module.cc index 321f8db04..7115b0473 100644 --- a/sbndcode/Decoders/XARAPUCA/SBNDXARAPUCADecoder_module.cc +++ b/sbndcode/Decoders/XARAPUCA/SBNDXARAPUCADecoder_module.cc @@ -135,7 +135,7 @@ class sbndaq::SBNDXARAPUCADecoder : public art::EDProducer { bool fverbose; /**< If `true` it increases verbosity of console output for detailed processing steps. */ // Main processing method. - void decode_fragment(uint64_t timestamp, uint64_t& nominal_frag_timestamp, int32_t& nominal_TTT, std::vector & fragment_indices, const artdaq::Fragment& fragment, std::vector & prod_wvfms, std::vector>& wvfms, bool last_one); + void decode_fragment(int32_t& prev_TTT, uint64_t timestamp, uint64_t& nominal_frag_timestamp, int32_t& nominal_TTT, std::vector & fragment_indices, const artdaq::Fragment& fragment, std::vector & prod_wvfms, std::vector>& wvfms, bool last_one); // Timing. void shift_time(uint64_t TTT_ticks, int64_t TTT_end_ns, uint64_t frag_timestamp, uint64_t timestamp, uint32_t num_samples_per_wvfm, double& ini_wvfm_timestamp, double& end_wvfm_timestamp); @@ -320,6 +320,7 @@ void sbndaq::SBNDXARAPUCADecoder::produce(art::Event& e) { } int32_t nominal_TTT = TTT_DEFAULT; + int32_t prev_TTT = TTT_DEFAULT; uint64_t nominal_frag_timestamp = TTT_DEFAULT; bool last_one = false; @@ -360,7 +361,7 @@ void sbndaq::SBNDXARAPUCADecoder::produce(art::Event& e) { for (size_t f = 0; f < num_caen_fragments; f++) { const artdaq::Fragment fragment = *container_fragment[f].get(); last_one = f == (num_caen_fragments - 1); - decode_fragment(timestamp, nominal_frag_timestamp, nominal_TTT, fragment_indices, fragment, *prod_wvfms, wvfms, last_one); + decode_fragment(prev_TTT, timestamp, nominal_frag_timestamp, nominal_TTT, fragment_indices, fragment, *prod_wvfms, wvfms, last_one); } // End CAEN V1740 fragments loop. } } // End Container fragments loop. @@ -373,7 +374,7 @@ void sbndaq::SBNDXARAPUCADecoder::produce(art::Event& e) { for (size_t f = 0; f < frag_handle_size; f++) { const artdaq::Fragment fragment = fragment_handle->at(f); last_one = f == (frag_handle_size - 1); - decode_fragment(timestamp, nominal_frag_timestamp, nominal_TTT, fragment_indices, fragment, *prod_wvfms, wvfms, last_one); + decode_fragment(prev_TTT, timestamp, nominal_frag_timestamp, nominal_TTT, fragment_indices, fragment, *prod_wvfms, wvfms, last_one); } // End CAEN V1740 fragments loop. } } // End extracting CAEN V1740 fragments. @@ -425,7 +426,7 @@ void sbndaq::SBNDXARAPUCADecoder::produce(art::Event& e) { * @see dump_waveforms */ -void sbndaq::SBNDXARAPUCADecoder::decode_fragment(uint64_t timestamp, uint64_t& nominal_frag_timestamp, int32_t& nominal_TTT, std::vector & fragment_indices, const artdaq::Fragment& fragment, std::vector & prod_wvfms, std::vector>& wvfms, bool last_one) { +void sbndaq::SBNDXARAPUCADecoder::decode_fragment(int32_t& prev_TTT, uint64_t timestamp, uint64_t& nominal_frag_timestamp, int32_t& nominal_TTT, std::vector & fragment_indices, const artdaq::Fragment& fragment, std::vector & prod_wvfms, std::vector>& wvfms, bool last_one) { auto fragment_id = fragment.fragmentID() - ffragment_id_offset; auto it = std::find(fboard_id_list.begin(), fboard_id_list.end(), fragment_id); size_t board_idx; @@ -445,12 +446,6 @@ void sbndaq::SBNDXARAPUCADecoder::decode_fragment(uint64_t timestamp, uint64_t& if (valid_fragment) { if (fverbose) std::cout << "\n > SBNDXARAPUCADecoder::decode_fragment: decoding V1740 CAEN fragment " << fragment_indices[board_idx] << " from the board " << board_idx << " (slot " << fboard_id_list[board_idx] << "):" << std::endl; - bool is_nominal_length = false; - bool is_first = false; - - double ini_wvfm_timestamp = 0; - double end_wvfm_timestamp = 0; - // =============== Accesses Event metadata and Event header for this fragment =============== // CAENV1740Fragment caen_fragment(fragment); @@ -508,13 +503,30 @@ void sbndaq::SBNDXARAPUCADecoder::decode_fragment(uint64_t timestamp, uint64_t& std::vector > fragment_wvfms(num_channels, std::vector(num_samples_per_wvfm, 0)); decode_waveforms(fragment, fragment_wvfms, header_size, num_channels, num_samples_per_wvfm, num_words_per_wvfms, num_samples_per_group); - is_nominal_length = (num_nominal_samples_per_wvfm == num_samples_per_wvfm); - is_first = (fragment_indices[board_idx] == 0); + double ini_wvfm_timestamp = 0; + double end_wvfm_timestamp = 0; + + bool is_nominal_length = (num_nominal_samples_per_wvfm == num_samples_per_wvfm); + bool is_first = (fragment_indices[board_idx] == 0); + + int32_t TTT_dif = 0; + // If the fragment timestamp is greater than the TTT end timestamp, it means that rollover occurred. + if (nominal_TTT > TTT_end_ns) { + if (fverbose | fdebug_timing) std::cout << " > SBNDXARAPUCADecoder::decode_fragment: CAEN TTT rollover occurred." << std::endl; + TTT_dif = nominal_TTT - (NANOSEC_IN_SEC - TTT_end_ns); + } else { + TTT_dif = TTT_end_ns - nominal_TTT; + } + bool is_in_time = TTT_dif <= static_cast(num_nominal_samples_per_wvfm * fns_per_sample); if (fverbose) { std::cout << " > SBNDXARAPUCADecoder::decode_fragment: processing the decoded fragment and combines the extended ones to their nominal ones if needed." << std::endl; } if (is_nominal_length) { + ///// + int32_t TTT_ini_ns = TTT_end_ns - static_cast(num_nominal_samples_per_wvfm * fns_per_sample); + std::cout << "\t\t NOMINAL fragment (" << num_samples_per_wvfm << "), [" << TTT_ini_ns << ", " << TTT_end_ns << "] diff with prev: " << TTT_end_ns - prev_TTT << " ns, length: " << num_samples_per_wvfm * fns_per_sample << " ns, diff_with_length: " << (TTT_end_ns - prev_TTT) - (num_samples_per_wvfm * fns_per_sample) << std::endl; + ////// if (!is_first) { if (fdebug_extended_fragments) { std::cout << "\t\t NOT FIRST NOMINAL fragment " << std::endl; @@ -529,9 +541,23 @@ void sbndaq::SBNDXARAPUCADecoder::decode_fragment(uint64_t timestamp, uint64_t& combine_waveforms(wvfms, fragment_wvfms, num_channels); nominal_TTT = TTT_end_ns; nominal_frag_timestamp = frag_timestamp; - } else { - if (fdebug_extended_fragments) std::cout << "\t\t EXTENDED fragment " << std::endl; + } else if (is_in_time) { + if (fdebug_extended_fragments) { + std::cout << "\t\t EXTENDED fragment " << std::endl; + std::cout << "\t\t TTT_dif w.r.t. nominal TTT: " << TTT_dif << " ns, is_in_time: " << is_in_time << std::endl; + } + ///// + int32_t TTT_ini_ns = TTT_end_ns - static_cast(num_nominal_samples_per_wvfm * fns_per_sample); + std::cout << "\t\t EXTENDED fragment (" << num_samples_per_wvfm << "), [" << TTT_ini_ns << ", " << TTT_end_ns << "] diff with prev: " << TTT_end_ns - prev_TTT << " ns, length: " << num_samples_per_wvfm * fns_per_sample << " ns, diff_with_length: " << (TTT_end_ns - prev_TTT) - (num_samples_per_wvfm * fns_per_sample) << std::endl; + ////// combine_waveforms(wvfms, fragment_wvfms, num_channels); + } else if (!is_in_time) { + //combine_waveforms(wvfms, fragment_wvfms, num_channels); //TEMP!!!!! + ///// + int32_t TTT_ini_ns = TTT_end_ns - static_cast(num_nominal_samples_per_wvfm * fns_per_sample); + std::cout << "\t\t EXTENDED? fragment (" << num_samples_per_wvfm << "), [" << TTT_ini_ns << ", " << TTT_end_ns << "] diff with prev: " << TTT_end_ns - prev_TTT << " ns, length: " << num_samples_per_wvfm * fns_per_sample << " ns, diff_with_length: " << (TTT_end_ns - prev_TTT) - (num_samples_per_wvfm * fns_per_sample) << std::endl; + ////// + std::cout << "\t\t WARNING: EXTENDED fragment out of time window! TTT_dif: " << TTT_dif << " ns, fragment idx: " << fragment_indices[board_idx] << ", board idx: " << board_idx << " (slot " << fboard_id_list[board_idx] << "), " << num_samples_per_wvfm << " samples. Skipping this fragment..." << std::endl; } fragment_indices[board_idx]++; @@ -541,7 +567,9 @@ void sbndaq::SBNDXARAPUCADecoder::decode_fragment(uint64_t timestamp, uint64_t& shift_time(TTT_ticks, nominal_TTT, nominal_frag_timestamp, timestamp, num_nominal_samples_per_wvfm, ini_wvfm_timestamp, end_wvfm_timestamp); dump_waveforms(prod_wvfms, wvfms, fragment_indices, board_idx, num_channels, ini_wvfm_timestamp, end_wvfm_timestamp); } + prev_TTT = TTT_end_ns; } + } // =============== Timing functions =============== // diff --git a/sbndcode/Decoders/XARAPUCA/xarapucadecoder.fcl b/sbndcode/Decoders/XARAPUCA/xarapucadecoder.fcl index eed2269a9..d1ac9b9d1 100644 --- a/sbndcode/Decoders/XARAPUCA/xarapucadecoder.fcl +++ b/sbndcode/Decoders/XARAPUCA/xarapucadecoder.fcl @@ -32,7 +32,7 @@ xarapucadecoder: # - Output data product instance name. waveforms_instance_name: "XARAPUCAChannels" # Name for the instance product containing the raw decoded waveforms. timing_ref_instance_name: "" # Name for the instance product containing the timing reference information. - store_debug_waveforms: 0 # Number of waveforms to store (0: none, -1: all, n: first n waveforms). + store_debug_waveforms: -1 # Number of waveforms to store (0: none, -1: all, n: first n waveforms). # - Debug options. debug_tdc_handle: false # (De)activates SPEC-TDC art::Handle information printing. debug_ptb_handle: false # (De)activates PTB art::Handle information printing. From 3f44697e583b0dda842ab72e767045551dbac086 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Alicia=20V=C3=A1zquez-Ramos?= Date: Fri, 7 Nov 2025 09:43:44 -0600 Subject: [PATCH 11/18] Add jittering debug option and combine fragments option --- .../XARAPUCA/SBNDXARAPUCADecoder_module.cc | 127 ++++++++++-------- .../Decoders/XARAPUCA/xarapucadecoder.fcl | 7 +- 2 files changed, 76 insertions(+), 58 deletions(-) diff --git a/sbndcode/Decoders/XARAPUCA/SBNDXARAPUCADecoder_module.cc b/sbndcode/Decoders/XARAPUCA/SBNDXARAPUCADecoder_module.cc index 7115b0473..fce201a35 100644 --- a/sbndcode/Decoders/XARAPUCA/SBNDXARAPUCADecoder_module.cc +++ b/sbndcode/Decoders/XARAPUCA/SBNDXARAPUCADecoder_module.cc @@ -125,6 +125,8 @@ class sbndaq::SBNDXARAPUCADecoder : public art::EDProducer { art::ServiceHandle tfs; /**< ServiceHandle object to store the histograms in the decoder_hist.root output file. */ int fstore_debug_waveforms; /**< Number of waveforms to store in the ServiceHandle object for debugging purposes (0: none, -1: all, n: first n waveforms each event). */ + bool fcombine_ext_frag; /**< If `true` combines extended fragments into a single raw::OpDetWaveform object. */ + bool fdebug_tdc_handle; /**< If `true` SPEC-TDC information is printed. */ bool fdebug_ptb_handle; /**< If `true` PTB information is printed. */ bool fdebug_fragments_handle; /**< If `true` V1740B CAEN fragments art::Handle information is printed. */ @@ -132,10 +134,11 @@ class sbndaq::SBNDXARAPUCADecoder : public art::EDProducer { bool fdebug_buffer; /**< If `true` the buffer status is printed. */ bool fdebug_waveforms; /**< If `true` waveforms decoding data is printed. */ bool fdebug_extended_fragments; /**< If `true` extended fragments information is printed. */ + bool fdebug_jittering; /**< If `true` trigger jittering information is printed. */ bool fverbose; /**< If `true` it increases verbosity of console output for detailed processing steps. */ // Main processing method. - void decode_fragment(int32_t& prev_TTT, uint64_t timestamp, uint64_t& nominal_frag_timestamp, int32_t& nominal_TTT, std::vector & fragment_indices, const artdaq::Fragment& fragment, std::vector & prod_wvfms, std::vector>& wvfms, bool last_one); + void decode_fragment(uint64_t timestamp, uint64_t& nominal_frag_timestamp, int32_t& nominal_TTT, int32_t& prev_TTT, std::vector & fragment_indices, const artdaq::Fragment& fragment, std::vector & prod_wvfms, std::vector>& wvfms, bool last_one); // Timing. void shift_time(uint64_t TTT_ticks, int64_t TTT_end_ns, uint64_t frag_timestamp, uint64_t timestamp, uint32_t num_samples_per_wvfm, double& ini_wvfm_timestamp, double& end_wvfm_timestamp); @@ -212,6 +215,9 @@ sbndaq::SBNDXARAPUCADecoder::SBNDXARAPUCADecoder(fhicl::ParameterSet const& p) // Gets the number of waveforms to store in the debug output file. fstore_debug_waveforms = p.get ("store_debug_waveforms", 0); + // Gets the combination of extended fragments option. + fcombine_ext_frag = p.get ("combine_ext_frag", true); + // Gets the debug and verbose options. fdebug_ptb_handle = p.get ("debug_ptb_handle", false); fdebug_tdc_handle = p.get ("debug_tdc_handle", false); @@ -219,6 +225,7 @@ sbndaq::SBNDXARAPUCADecoder::SBNDXARAPUCADecoder(fhicl::ParameterSet const& p) fdebug_timing = p.get ("debug_timing", false); fdebug_waveforms = p.get ("debug_waveforms", false); fdebug_extended_fragments = p.get ("debug_extended_fragments", false); + fdebug_jittering = p.get ("debug_jittering", false); fdebug_buffer = p.get ("debug_buffer", false); fverbose = p.get ("verbose", false); @@ -320,7 +327,7 @@ void sbndaq::SBNDXARAPUCADecoder::produce(art::Event& e) { } int32_t nominal_TTT = TTT_DEFAULT; - int32_t prev_TTT = TTT_DEFAULT; + int32_t prev_TTT = 0; uint64_t nominal_frag_timestamp = TTT_DEFAULT; bool last_one = false; @@ -361,7 +368,7 @@ void sbndaq::SBNDXARAPUCADecoder::produce(art::Event& e) { for (size_t f = 0; f < num_caen_fragments; f++) { const artdaq::Fragment fragment = *container_fragment[f].get(); last_one = f == (num_caen_fragments - 1); - decode_fragment(prev_TTT, timestamp, nominal_frag_timestamp, nominal_TTT, fragment_indices, fragment, *prod_wvfms, wvfms, last_one); + decode_fragment(timestamp, nominal_frag_timestamp, nominal_TTT, prev_TTT, fragment_indices, fragment, *prod_wvfms, wvfms, last_one); } // End CAEN V1740 fragments loop. } } // End Container fragments loop. @@ -374,7 +381,7 @@ void sbndaq::SBNDXARAPUCADecoder::produce(art::Event& e) { for (size_t f = 0; f < frag_handle_size; f++) { const artdaq::Fragment fragment = fragment_handle->at(f); last_one = f == (frag_handle_size - 1); - decode_fragment(prev_TTT, timestamp, nominal_frag_timestamp, nominal_TTT, fragment_indices, fragment, *prod_wvfms, wvfms, last_one); + decode_fragment(timestamp, nominal_frag_timestamp, nominal_TTT, prev_TTT, fragment_indices, fragment, *prod_wvfms, wvfms, last_one); } // End CAEN V1740 fragments loop. } } // End extracting CAEN V1740 fragments. @@ -426,7 +433,7 @@ void sbndaq::SBNDXARAPUCADecoder::produce(art::Event& e) { * @see dump_waveforms */ -void sbndaq::SBNDXARAPUCADecoder::decode_fragment(int32_t& prev_TTT, uint64_t timestamp, uint64_t& nominal_frag_timestamp, int32_t& nominal_TTT, std::vector & fragment_indices, const artdaq::Fragment& fragment, std::vector & prod_wvfms, std::vector>& wvfms, bool last_one) { +void sbndaq::SBNDXARAPUCADecoder::decode_fragment(uint64_t timestamp, uint64_t& nominal_frag_timestamp, int32_t& nominal_TTT, int32_t& prev_TTT, std::vector & fragment_indices, const artdaq::Fragment& fragment, std::vector & prod_wvfms, std::vector>& wvfms, bool last_one) { auto fragment_id = fragment.fragmentID() - ffragment_id_offset; auto it = std::find(fboard_id_list.begin(), fboard_id_list.end(), fragment_id); size_t board_idx; @@ -506,68 +513,76 @@ void sbndaq::SBNDXARAPUCADecoder::decode_fragment(int32_t& prev_TTT, uint64_t ti double ini_wvfm_timestamp = 0; double end_wvfm_timestamp = 0; - bool is_nominal_length = (num_nominal_samples_per_wvfm == num_samples_per_wvfm); - bool is_first = (fragment_indices[board_idx] == 0); - - int32_t TTT_dif = 0; - // If the fragment timestamp is greater than the TTT end timestamp, it means that rollover occurred. - if (nominal_TTT > TTT_end_ns) { - if (fverbose | fdebug_timing) std::cout << " > SBNDXARAPUCADecoder::decode_fragment: CAEN TTT rollover occurred." << std::endl; - TTT_dif = nominal_TTT - (NANOSEC_IN_SEC - TTT_end_ns); - } else { - TTT_dif = TTT_end_ns - nominal_TTT; - } - bool is_in_time = TTT_dif <= static_cast(num_nominal_samples_per_wvfm * fns_per_sample); - if (fverbose) { std::cout << " > SBNDXARAPUCADecoder::decode_fragment: processing the decoded fragment and combines the extended ones to their nominal ones if needed." << std::endl; } - if (is_nominal_length) { - ///// + + if (fcombine_ext_frag) { + bool is_nominal_length = (num_nominal_samples_per_wvfm == num_samples_per_wvfm); + bool is_first = (fragment_indices[board_idx] == 0); + + int32_t TTT_dif = 0; + // If the fragment timestamp is greater than the TTT end timestamp, it means that rollover occurred. + if (nominal_TTT > TTT_end_ns) { + if (fverbose | fdebug_timing) std::cout << " > SBNDXARAPUCADecoder::decode_fragment: CAEN TTT rollover occurred." << std::endl; + TTT_dif = nominal_TTT - (NANOSEC_IN_SEC - TTT_end_ns); + } else { + TTT_dif = TTT_end_ns - nominal_TTT; + } + bool is_in_time = TTT_dif <= static_cast(num_nominal_samples_per_wvfm * fns_per_sample); + int32_t TTT_ini_ns = TTT_end_ns - static_cast(num_nominal_samples_per_wvfm * fns_per_sample); - std::cout << "\t\t NOMINAL fragment (" << num_samples_per_wvfm << "), [" << TTT_ini_ns << ", " << TTT_end_ns << "] diff with prev: " << TTT_end_ns - prev_TTT << " ns, length: " << num_samples_per_wvfm * fns_per_sample << " ns, diff_with_length: " << (TTT_end_ns - prev_TTT) - (num_samples_per_wvfm * fns_per_sample) << std::endl; - ////// - if (!is_first) { + + if (is_nominal_length) { + if (fdebug_jittering) { + std::cout << "\t\t NOMINAL fragment (" << num_samples_per_wvfm << "), [" << TTT_ini_ns << ", " << TTT_end_ns << "] diff with prev: " << TTT_end_ns - prev_TTT << " ns, length: " << num_samples_per_wvfm * fns_per_sample << " ns, diff_with_length: " << (TTT_end_ns - prev_TTT) - (num_samples_per_wvfm * fns_per_sample) << std::endl; + } + if (!is_first) { + if (fdebug_extended_fragments) { + std::cout << "\t\t NOT FIRST NOMINAL fragment " << std::endl; + std::cout << "\t\t nominal_TTT: " << nominal_TTT << " TTT_end_ns: " << TTT_end_ns << std::endl; + std::cout << "\t\t nominal_frag_timestamp: " << nominal_frag_timestamp << " frag_timestamp : " << frag_timestamp << std::endl; + } + shift_time(TTT_ticks, nominal_TTT, nominal_frag_timestamp, timestamp, num_nominal_samples_per_wvfm, ini_wvfm_timestamp, end_wvfm_timestamp); + dump_waveforms(prod_wvfms, wvfms, fragment_indices, board_idx, num_channels, ini_wvfm_timestamp, end_wvfm_timestamp); + } else { + if (fdebug_extended_fragments) std::cout << "\t\t FIRST NOMINAL fragment " << std::endl; + } + combine_waveforms(wvfms, fragment_wvfms, num_channels); + nominal_TTT = TTT_end_ns; + nominal_frag_timestamp = frag_timestamp; + } else if (is_in_time) { if (fdebug_extended_fragments) { - std::cout << "\t\t NOT FIRST NOMINAL fragment " << std::endl; - std::cout << "\t\t nominal_TTT: " << nominal_TTT << " TTT_end_ns: " << TTT_end_ns << std::endl; - std::cout << "\t\t nominal_frag_timestamp: " << nominal_frag_timestamp << " frag_timestamp : " << frag_timestamp << std::endl; + std::cout << "\t\t EXTENDED fragment " << std::endl; + std::cout << "\t\t TTT_dif w.r.t. nominal TTT: " << TTT_dif << " ns, is_in_time: " << is_in_time << std::endl; } + if (fdebug_jittering) { + std::cout << "\t\t EXTENDED fragment (" << num_samples_per_wvfm << "), [" << TTT_ini_ns << ", " << TTT_end_ns << "] diff with prev: " << TTT_end_ns - prev_TTT << " ns, length: " << num_samples_per_wvfm * fns_per_sample << " ns, diff_with_length: " << (TTT_end_ns - prev_TTT) - (num_samples_per_wvfm * fns_per_sample) << std::endl; + } + + combine_waveforms(wvfms, fragment_wvfms, num_channels); + } else if (!is_in_time) { + //combine_waveforms(wvfms, fragment_wvfms, num_channels); //TEMP!!!!! + if (fdebug_jittering) { + std::cout << "\t\t EXTENDED? fragment (" << num_samples_per_wvfm << "), [" << TTT_ini_ns << ", " << TTT_end_ns << "] diff with prev: " << TTT_end_ns - prev_TTT << " ns, length: " << num_samples_per_wvfm * fns_per_sample << " ns, diff_with_length: " << (TTT_end_ns - prev_TTT) - (num_samples_per_wvfm * fns_per_sample) << std::endl; + } + std::cout << "\t\t WARNING: EXTENDED fragment out of time window! TTT_dif: " << TTT_dif << " ns, fragment idx: " << fragment_indices[board_idx] << ", board idx: " << board_idx << " (slot " << fboard_id_list[board_idx] << "), " << num_samples_per_wvfm << " samples. Skipping this fragment..." << std::endl; + } + + fragment_indices[board_idx]++; + + if (last_one) { + if (fdebug_extended_fragments) std::cout << "\t\t LAST fragment " << std::endl; shift_time(TTT_ticks, nominal_TTT, nominal_frag_timestamp, timestamp, num_nominal_samples_per_wvfm, ini_wvfm_timestamp, end_wvfm_timestamp); dump_waveforms(prod_wvfms, wvfms, fragment_indices, board_idx, num_channels, ini_wvfm_timestamp, end_wvfm_timestamp); - } else { - if (fdebug_extended_fragments) std::cout << "\t\t FIRST NOMINAL fragment " << std::endl; } - combine_waveforms(wvfms, fragment_wvfms, num_channels); - nominal_TTT = TTT_end_ns; - nominal_frag_timestamp = frag_timestamp; - } else if (is_in_time) { - if (fdebug_extended_fragments) { - std::cout << "\t\t EXTENDED fragment " << std::endl; - std::cout << "\t\t TTT_dif w.r.t. nominal TTT: " << TTT_dif << " ns, is_in_time: " << is_in_time << std::endl; - } - ///// - int32_t TTT_ini_ns = TTT_end_ns - static_cast(num_nominal_samples_per_wvfm * fns_per_sample); - std::cout << "\t\t EXTENDED fragment (" << num_samples_per_wvfm << "), [" << TTT_ini_ns << ", " << TTT_end_ns << "] diff with prev: " << TTT_end_ns - prev_TTT << " ns, length: " << num_samples_per_wvfm * fns_per_sample << " ns, diff_with_length: " << (TTT_end_ns - prev_TTT) - (num_samples_per_wvfm * fns_per_sample) << std::endl; - ////// - combine_waveforms(wvfms, fragment_wvfms, num_channels); - } else if (!is_in_time) { - //combine_waveforms(wvfms, fragment_wvfms, num_channels); //TEMP!!!!! - ///// - int32_t TTT_ini_ns = TTT_end_ns - static_cast(num_nominal_samples_per_wvfm * fns_per_sample); - std::cout << "\t\t EXTENDED? fragment (" << num_samples_per_wvfm << "), [" << TTT_ini_ns << ", " << TTT_end_ns << "] diff with prev: " << TTT_end_ns - prev_TTT << " ns, length: " << num_samples_per_wvfm * fns_per_sample << " ns, diff_with_length: " << (TTT_end_ns - prev_TTT) - (num_samples_per_wvfm * fns_per_sample) << std::endl; - ////// - std::cout << "\t\t WARNING: EXTENDED fragment out of time window! TTT_dif: " << TTT_dif << " ns, fragment idx: " << fragment_indices[board_idx] << ", board idx: " << board_idx << " (slot " << fboard_id_list[board_idx] << "), " << num_samples_per_wvfm << " samples. Skipping this fragment..." << std::endl; + prev_TTT = TTT_end_ns; + } else { + shift_time(TTT_ticks, TTT_end_ns, frag_timestamp, timestamp, num_samples_per_wvfm, ini_wvfm_timestamp, end_wvfm_timestamp); + dump_waveforms(prod_wvfms, fragment_wvfms, fragment_indices, board_idx, num_channels, ini_wvfm_timestamp, end_wvfm_timestamp); + fragment_indices[board_idx]++; } - - fragment_indices[board_idx]++; - if (last_one) { - if (fdebug_extended_fragments) std::cout << "\t\t LAST fragment " << std::endl; - shift_time(TTT_ticks, nominal_TTT, nominal_frag_timestamp, timestamp, num_nominal_samples_per_wvfm, ini_wvfm_timestamp, end_wvfm_timestamp); - dump_waveforms(prod_wvfms, wvfms, fragment_indices, board_idx, num_channels, ini_wvfm_timestamp, end_wvfm_timestamp); - } - prev_TTT = TTT_end_ns; } } diff --git a/sbndcode/Decoders/XARAPUCA/xarapucadecoder.fcl b/sbndcode/Decoders/XARAPUCA/xarapucadecoder.fcl index d1ac9b9d1..578dba4c8 100644 --- a/sbndcode/Decoders/XARAPUCA/xarapucadecoder.fcl +++ b/sbndcode/Decoders/XARAPUCA/xarapucadecoder.fcl @@ -23,7 +23,7 @@ xarapucadecoder: # - SPEC-TDC access configuration spectdc_product_name: "tdcdecoder" # Name for getting SPEC-TDC Decoder products (if any). spectdc_ftrig_ch: 3 # Channel assigned to flash triggers. - spectdc_etrig_ch: 4 # Channel assigned to ETT (Event Trigger Timestamp) triggers. + spectdc_etrig_ch: 2 # Channel assigned to ETT (Event Trigger Timestamp) triggers. # - PTB access configuration ptb_product_name: "ptbdecoder" # Name for getting PTB Decoder products (if any). allowed_hl_triggers: [1, 2, 3, 4, 5, 14, 15] # List of allowed HLT trigger types (1-5, 14, 15). @@ -32,7 +32,9 @@ xarapucadecoder: # - Output data product instance name. waveforms_instance_name: "XARAPUCAChannels" # Name for the instance product containing the raw decoded waveforms. timing_ref_instance_name: "" # Name for the instance product containing the timing reference information. - store_debug_waveforms: -1 # Number of waveforms to store (0: none, -1: all, n: first n waveforms). + store_debug_waveforms: 0 # Number of waveforms to store (0: none, -1: all, n: first n waveforms). + # Combination of extended fragments. + combine_ext_frag: false # (De)activates the combination of extended fragments into a single raw::OpDetWaveform object. # - Debug options. debug_tdc_handle: false # (De)activates SPEC-TDC art::Handle information printing. debug_ptb_handle: false # (De)activates PTB art::Handle information printing. @@ -41,6 +43,7 @@ xarapucadecoder: debug_buffer: false # (De)activates buffer status printing. debug_waveforms: false # (De)activates waveforms decoding printing. debug_extended_fragments: false # (De)activates extended fragments information printing. + debug_jittering: false # (De)activates trigger jittering information printing. # - Verbose option. verbose: false # (De)activates verbosity. } From 43f761406b187f860d3943471de18d5caaf3ab56 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Alicia=20V=C3=A1zquez-Ramos?= Date: Mon, 24 Nov 2025 11:42:56 -0600 Subject: [PATCH 12/18] Update combination condition with timing features integrating the expected jittering of the extended fragments. --- .../XARAPUCA/SBNDXARAPUCADecoder_module.cc | 137 +++++++++--------- .../Decoders/XARAPUCA/xarapucadecoder.fcl | 11 +- 2 files changed, 78 insertions(+), 70 deletions(-) diff --git a/sbndcode/Decoders/XARAPUCA/SBNDXARAPUCADecoder_module.cc b/sbndcode/Decoders/XARAPUCA/SBNDXARAPUCADecoder_module.cc index fce201a35..4922c7da7 100644 --- a/sbndcode/Decoders/XARAPUCA/SBNDXARAPUCADecoder_module.cc +++ b/sbndcode/Decoders/XARAPUCA/SBNDXARAPUCADecoder_module.cc @@ -126,6 +126,7 @@ class sbndaq::SBNDXARAPUCADecoder : public art::EDProducer { int fstore_debug_waveforms; /**< Number of waveforms to store in the ServiceHandle object for debugging purposes (0: none, -1: all, n: first n waveforms each event). */ bool fcombine_ext_frag; /**< If `true` combines extended fragments into a single raw::OpDetWaveform object. */ + int32_t fallowed_jittering; /**< Allowed jittering (in ns) between fragments to be combined. */ bool fdebug_tdc_handle; /**< If `true` SPEC-TDC information is printed. */ bool fdebug_ptb_handle; /**< If `true` PTB information is printed. */ @@ -138,7 +139,7 @@ class sbndaq::SBNDXARAPUCADecoder : public art::EDProducer { bool fverbose; /**< If `true` it increases verbosity of console output for detailed processing steps. */ // Main processing method. - void decode_fragment(uint64_t timestamp, uint64_t& nominal_frag_timestamp, int32_t& nominal_TTT, int32_t& prev_TTT, std::vector & fragment_indices, const artdaq::Fragment& fragment, std::vector & prod_wvfms, std::vector>& wvfms, bool last_one); + void decode_fragment(uint64_t timestamp, uint64_t& first_frag_timestamp, size_t& first_frag_idx, int32_t& first_TTT, int32_t& prev_TTT, std::vector & fragment_indices, const artdaq::Fragment& fragment, std::vector & prod_wvfms, std::vector>& wvfms, bool last_one); // Timing. void shift_time(uint64_t TTT_ticks, int64_t TTT_end_ns, uint64_t frag_timestamp, uint64_t timestamp, uint32_t num_samples_per_wvfm, double& ini_wvfm_timestamp, double& end_wvfm_timestamp); @@ -152,10 +153,10 @@ class sbndaq::SBNDXARAPUCADecoder : public art::EDProducer { unsigned int get_channel_id(unsigned int board, unsigned int board_channel); // Combines decoded waveforms. - void combine_waveforms(std::vector>& wvfms, const std::vector>& fragment_wvfms, uint32_t num_channels); + void append_waveforms(std::vector>& wvfms, const std::vector>& fragment_wvfms, uint32_t num_channels); // Dumps and saves waveforms. - void dump_waveforms(std::vector & prod_wvfms, std::vector>& wvfms, std::vector & fragment_indices, size_t board_index, uint32_t num_channels, double ini_wvfm_timestamp, double end_wvfm_timestamp); + void dump_waveforms(std::vector & prod_wvfms, std::vector>& wvfms, size_t first_frag_idx, size_t board_index, uint32_t num_channels, double ini_wvfm_timestamp, double end_wvfm_timestamp); void save_prod_wvfm(size_t board_idx, size_t ch, double ini_wvfm_timestamp, const std::vector > & wvfms, std::vector & prod_wvfms); void save_debug_wvfm(size_t board_idx, size_t fragment_idx, int ch, double ini_wvfm_timestamp, double end_wvfm_timestamp, const std::vector > & wvfms); @@ -217,6 +218,7 @@ sbndaq::SBNDXARAPUCADecoder::SBNDXARAPUCADecoder(fhicl::ParameterSet const& p) // Gets the combination of extended fragments option. fcombine_ext_frag = p.get ("combine_ext_frag", true); + fallowed_jittering = p.get ("allowed_jittering", 64); // Gets the debug and verbose options. fdebug_ptb_handle = p.get ("debug_ptb_handle", false); @@ -320,15 +322,16 @@ void sbndaq::SBNDXARAPUCADecoder::produce(art::Event& e) { // Flag to track if valid CAEN fragments are found. bool found_caen = false; - std::vector fragment_indices(fnum_caen_boards, 0); + std::vector fragment_indices(fnum_caen_boards, -1); std::vector> wvfms; if (fdebug_extended_fragments) { std::cout << " Waveforms size: " << wvfms.size() << std::endl; } - int32_t nominal_TTT = TTT_DEFAULT; + size_t first_frag_idx = 0; + int32_t first_TTT = TTT_DEFAULT; int32_t prev_TTT = 0; - uint64_t nominal_frag_timestamp = TTT_DEFAULT; + uint64_t first_frag_timestamp = TTT_DEFAULT; bool last_one = false; if (fverbose | fdebug_fragments_handle) std::cout << "\n > SBNDXARAPUCADecoder::produce: searching for V1740 fragments..." << std::endl; @@ -368,7 +371,7 @@ void sbndaq::SBNDXARAPUCADecoder::produce(art::Event& e) { for (size_t f = 0; f < num_caen_fragments; f++) { const artdaq::Fragment fragment = *container_fragment[f].get(); last_one = f == (num_caen_fragments - 1); - decode_fragment(timestamp, nominal_frag_timestamp, nominal_TTT, prev_TTT, fragment_indices, fragment, *prod_wvfms, wvfms, last_one); + decode_fragment(timestamp, first_frag_timestamp, first_frag_idx, first_TTT, prev_TTT, fragment_indices, fragment, *prod_wvfms, wvfms, last_one); } // End CAEN V1740 fragments loop. } } // End Container fragments loop. @@ -381,7 +384,7 @@ void sbndaq::SBNDXARAPUCADecoder::produce(art::Event& e) { for (size_t f = 0; f < frag_handle_size; f++) { const artdaq::Fragment fragment = fragment_handle->at(f); last_one = f == (frag_handle_size - 1); - decode_fragment(timestamp, nominal_frag_timestamp, nominal_TTT, prev_TTT, fragment_indices, fragment, *prod_wvfms, wvfms, last_one); + decode_fragment(timestamp, first_frag_timestamp, first_frag_idx, first_TTT, prev_TTT, fragment_indices, fragment, *prod_wvfms, wvfms, last_one); } // End CAEN V1740 fragments loop. } } // End extracting CAEN V1740 fragments. @@ -407,8 +410,9 @@ void sbndaq::SBNDXARAPUCADecoder::produce(art::Event& e) { /** * @brief Decodes a CAEN V1740 fragment, extracts the waveforms and combines them into the output product. * @param[in] timestamp The valid timestamp used as reference for the event. - * @param[in,out] nominal_frag_timestamp The nominal timestamp calculated for the fragment being processed. - * @param[in,out] nominal_TTT The nominal Trigger Time Tag (TTT) calculated for the fragment being processed. + * @param[in,out] first_frag_timestamp The nominal timestamp calculated for the fragment being processed. + * @param[in, out] first_frag_idx The first index of the fragments being combined. + * @param[in,out] first_TTT The nominal Trigger Time Tag (TTT) calculated for the fragment being processed. * @param[in,out] fragment_indices A vector containing the indices of the fragments already processed for each board. * @param[in] fragment The artdaq::Fragment object to be processed. * @param[in,out] prod_wvfms The vector of raw::OpDetWaveform objects to be filled with the decoded waveforms. @@ -429,11 +433,11 @@ void sbndaq::SBNDXARAPUCADecoder::produce(art::Event& e) { * @post The vector of raw::OpDetWaveform objects is filled with the decoded waveforms from the fragment. * @see shift_time * @see decode_waveforms - * @see combine_waveforms + * @see append_waveforms * @see dump_waveforms */ -void sbndaq::SBNDXARAPUCADecoder::decode_fragment(uint64_t timestamp, uint64_t& nominal_frag_timestamp, int32_t& nominal_TTT, int32_t& prev_TTT, std::vector & fragment_indices, const artdaq::Fragment& fragment, std::vector & prod_wvfms, std::vector>& wvfms, bool last_one) { +void sbndaq::SBNDXARAPUCADecoder::decode_fragment(uint64_t timestamp, uint64_t& first_frag_timestamp, size_t& first_frag_idx, int32_t& first_TTT, int32_t& prev_TTT, std::vector & fragment_indices, const artdaq::Fragment& fragment, std::vector & prod_wvfms, std::vector>& wvfms, bool last_one) { auto fragment_id = fragment.fragmentID() - ffragment_id_offset; auto it = std::find(fboard_id_list.begin(), fboard_id_list.end(), fragment_id); size_t board_idx; @@ -451,6 +455,7 @@ void sbndaq::SBNDXARAPUCADecoder::decode_fragment(uint64_t timestamp, uint64_t& } if (valid_fragment) { + fragment_indices[board_idx]++; if (fverbose) std::cout << "\n > SBNDXARAPUCADecoder::decode_fragment: decoding V1740 CAEN fragment " << fragment_indices[board_idx] << " from the board " << board_idx << " (slot " << fboard_id_list[board_idx] << "):" << std::endl; // =============== Accesses Event metadata and Event header for this fragment =============== // @@ -518,71 +523,72 @@ void sbndaq::SBNDXARAPUCADecoder::decode_fragment(uint64_t timestamp, uint64_t& } if (fcombine_ext_frag) { - bool is_nominal_length = (num_nominal_samples_per_wvfm == num_samples_per_wvfm); + + // Combination variables and checks. + + bool is_nominal = (num_nominal_samples_per_wvfm == num_samples_per_wvfm); bool is_first = (fragment_indices[board_idx] == 0); + int32_t frag_length = num_samples_per_wvfm * fns_per_sample; // ns. + + // - Computation of the difference w.r.t. previous TTT difference. int32_t TTT_dif = 0; - // If the fragment timestamp is greater than the TTT end timestamp, it means that rollover occurred. - if (nominal_TTT > TTT_end_ns) { + if (prev_TTT > TTT_end_ns) { if (fverbose | fdebug_timing) std::cout << " > SBNDXARAPUCADecoder::decode_fragment: CAEN TTT rollover occurred." << std::endl; - TTT_dif = nominal_TTT - (NANOSEC_IN_SEC - TTT_end_ns); + TTT_dif = prev_TTT - (NANOSEC_IN_SEC - TTT_end_ns); } else { - TTT_dif = TTT_end_ns - nominal_TTT; + TTT_dif = TTT_end_ns - prev_TTT; } - bool is_in_time = TTT_dif <= static_cast(num_nominal_samples_per_wvfm * fns_per_sample); - - int32_t TTT_ini_ns = TTT_end_ns - static_cast(num_nominal_samples_per_wvfm * fns_per_sample); - - if (is_nominal_length) { - if (fdebug_jittering) { - std::cout << "\t\t NOMINAL fragment (" << num_samples_per_wvfm << "), [" << TTT_ini_ns << ", " << TTT_end_ns << "] diff with prev: " << TTT_end_ns - prev_TTT << " ns, length: " << num_samples_per_wvfm * fns_per_sample << " ns, diff_with_length: " << (TTT_end_ns - prev_TTT) - (num_samples_per_wvfm * fns_per_sample) << std::endl; - } - if (!is_first) { - if (fdebug_extended_fragments) { - std::cout << "\t\t NOT FIRST NOMINAL fragment " << std::endl; - std::cout << "\t\t nominal_TTT: " << nominal_TTT << " TTT_end_ns: " << TTT_end_ns << std::endl; - std::cout << "\t\t nominal_frag_timestamp: " << nominal_frag_timestamp << " frag_timestamp : " << frag_timestamp << std::endl; + + // - Computation of the difference between TTTs difference and the length of the fragment in ns (to detect jittering between fragments). + //int32_t J = TTT_dif - frag_length; + + // - Combination boolean variable. + //bool dump_comb_wvfms = true; + /* if (is_nominal) { // Nominal fragment + if (!is_first && (TTT_dif <= (frag_length - fallowed_jittering))) { + std::cout << "\t\t WARNING: NOMINAL fragment too close to previous one! TTT_dif: " << TTT_dif << " ns, fragment idx: " << fragment_indices[board_idx] << ", board idx: " << board_idx << " (slot " << fboard_id_list[board_idx] << "), " << num_samples_per_wvfm << " samples. Skipping this fragment..." << std::endl; } - shift_time(TTT_ticks, nominal_TTT, nominal_frag_timestamp, timestamp, num_nominal_samples_per_wvfm, ini_wvfm_timestamp, end_wvfm_timestamp); - dump_waveforms(prod_wvfms, wvfms, fragment_indices, board_idx, num_channels, ini_wvfm_timestamp, end_wvfm_timestamp); - } else { - if (fdebug_extended_fragments) std::cout << "\t\t FIRST NOMINAL fragment " << std::endl; - } - combine_waveforms(wvfms, fragment_wvfms, num_channels); - nominal_TTT = TTT_end_ns; - nominal_frag_timestamp = frag_timestamp; - } else if (is_in_time) { - if (fdebug_extended_fragments) { - std::cout << "\t\t EXTENDED fragment " << std::endl; - std::cout << "\t\t TTT_dif w.r.t. nominal TTT: " << TTT_dif << " ns, is_in_time: " << is_in_time << std::endl; - } - if (fdebug_jittering) { - std::cout << "\t\t EXTENDED fragment (" << num_samples_per_wvfm << "), [" << TTT_ini_ns << ", " << TTT_end_ns << "] diff with prev: " << TTT_end_ns - prev_TTT << " ns, length: " << num_samples_per_wvfm * fns_per_sample << " ns, diff_with_length: " << (TTT_end_ns - prev_TTT) - (num_samples_per_wvfm * fns_per_sample) << std::endl; - } + } else { // Extended fragment + if (std::abs(J) <= fallowed_jittering) { + dump_comb_wvfms = false; + } else if (TTT_dif <= (frag_length - fallowed_jittering)) { + dump_comb_wvfms = false; + std::cout << "\t\t WARNING: EXTENDED fragment too close to previous one! TTT_dif: " << TTT_dif << " ns, fragment idx: " << fragment_indices[board_idx] << ", board idx: " << board_idx << " (slot " << fboard_id_list[board_idx] << "), " << num_samples_per_wvfm << " samples. Skipping this fragment..." << std::endl; + } + }*/ - combine_waveforms(wvfms, fragment_wvfms, num_channels); - } else if (!is_in_time) { - //combine_waveforms(wvfms, fragment_wvfms, num_channels); //TEMP!!!!! - if (fdebug_jittering) { - std::cout << "\t\t EXTENDED? fragment (" << num_samples_per_wvfm << "), [" << TTT_ini_ns << ", " << TTT_end_ns << "] diff with prev: " << TTT_end_ns - prev_TTT << " ns, length: " << num_samples_per_wvfm * fns_per_sample << " ns, diff_with_length: " << (TTT_end_ns - prev_TTT) - (num_samples_per_wvfm * fns_per_sample) << std::endl; - } - std::cout << "\t\t WARNING: EXTENDED fragment out of time window! TTT_dif: " << TTT_dif << " ns, fragment idx: " << fragment_indices[board_idx] << ", board idx: " << board_idx << " (slot " << fboard_id_list[board_idx] << "), " << num_samples_per_wvfm << " samples. Skipping this fragment..." << std::endl; + + bool dump_comb_wvfms = !is_first && (is_nominal || (!is_nominal && (TTT_dif > (frag_length + fallowed_jittering)))); + + if (is_first) { + first_frag_idx = fragment_indices[board_idx]; + first_TTT = TTT_end_ns; + first_frag_timestamp = frag_timestamp; } - - fragment_indices[board_idx]++; + if (dump_comb_wvfms) { + shift_time(TTT_ticks, first_TTT, first_frag_timestamp, timestamp, num_nominal_samples_per_wvfm, ini_wvfm_timestamp, end_wvfm_timestamp); + dump_waveforms(prod_wvfms, wvfms, first_frag_idx, board_idx, num_channels, ini_wvfm_timestamp, end_wvfm_timestamp); + first_frag_idx = fragment_indices[board_idx]; + first_TTT = TTT_end_ns; + first_frag_timestamp = frag_timestamp; + } + append_waveforms(wvfms, fragment_wvfms, num_channels); + if (last_one) { if (fdebug_extended_fragments) std::cout << "\t\t LAST fragment " << std::endl; - shift_time(TTT_ticks, nominal_TTT, nominal_frag_timestamp, timestamp, num_nominal_samples_per_wvfm, ini_wvfm_timestamp, end_wvfm_timestamp); - dump_waveforms(prod_wvfms, wvfms, fragment_indices, board_idx, num_channels, ini_wvfm_timestamp, end_wvfm_timestamp); + fragment_indices[board_idx]++; + shift_time(TTT_ticks, first_TTT, first_frag_timestamp, timestamp, num_nominal_samples_per_wvfm, ini_wvfm_timestamp, end_wvfm_timestamp); + dump_waveforms(prod_wvfms, wvfms, first_frag_idx, board_idx, num_channels, ini_wvfm_timestamp, end_wvfm_timestamp); } + prev_TTT = TTT_end_ns; - } else { + + } else { // Combination of extended fragments disabled. shift_time(TTT_ticks, TTT_end_ns, frag_timestamp, timestamp, num_samples_per_wvfm, ini_wvfm_timestamp, end_wvfm_timestamp); - dump_waveforms(prod_wvfms, fragment_wvfms, fragment_indices, board_idx, num_channels, ini_wvfm_timestamp, end_wvfm_timestamp); - fragment_indices[board_idx]++; + dump_waveforms(prod_wvfms, fragment_wvfms, first_frag_idx, board_idx, num_channels, ini_wvfm_timestamp, end_wvfm_timestamp); } - } } @@ -1008,8 +1014,8 @@ unsigned int sbndaq::SBNDXARAPUCADecoder::get_channel_id(unsigned int board, uns * @pre The `fragment_wvfms` vector should contain waveforms for all channels of the board being processed. * @pre The `wvfms` vector should be either empty or already contain waveforms for all channels of the board being processed. */ -void sbndaq::SBNDXARAPUCADecoder::combine_waveforms(std::vector>& wvfms, const std::vector>& fragment_wvfms, uint32_t num_channels) { - if (fdebug_extended_fragments) std::cout << " > SBNDXARAPUCADecoder::combine_waveforms: combining waveforms from extended fragments..." << std::endl; +void sbndaq::SBNDXARAPUCADecoder::append_waveforms(std::vector>& wvfms, const std::vector>& fragment_wvfms, uint32_t num_channels) { + if (fdebug_extended_fragments) std::cout << " > SBNDXARAPUCADecoder::append_waveforms: combining waveforms from extended fragments..." << std::endl; if (wvfms.empty()) { if (fdebug_extended_fragments) { std::cout << "\t\t Empty waveforms, resizing to " << num_channels << " channels." << std::endl; @@ -1059,7 +1065,7 @@ void sbndaq::SBNDXARAPUCADecoder::combine_waveforms(std::vector & prod_wvfms, std::vector>& wvfms, std::vector & fragment_indices, size_t board_idx, uint32_t num_channels, double ini_wvfm_timestamp, double end_wvfm_timestamp) { +void sbndaq::SBNDXARAPUCADecoder::dump_waveforms(std::vector & prod_wvfms, std::vector>& wvfms, size_t first_frag_idx, size_t board_idx, uint32_t num_channels, double ini_wvfm_timestamp, double end_wvfm_timestamp) { // The decoded waveforms are dumped into two products: // - A xarapucadecoder-art.root file with the OpDetWaveforms as the product of this producer for further analysis. @@ -1078,7 +1084,7 @@ void sbndaq::SBNDXARAPUCADecoder::dump_waveforms(std::vector Date: Tue, 25 Nov 2025 05:02:28 -0600 Subject: [PATCH 13/18] Add warning for some unexpected types of fragments and fix fragments indexing. Improve jittering application. --- .../XARAPUCA/SBNDXARAPUCADecoder_module.cc | 44 +++++++++++-------- .../Decoders/XARAPUCA/xarapucadecoder.fcl | 6 +-- 2 files changed, 29 insertions(+), 21 deletions(-) diff --git a/sbndcode/Decoders/XARAPUCA/SBNDXARAPUCADecoder_module.cc b/sbndcode/Decoders/XARAPUCA/SBNDXARAPUCADecoder_module.cc index 4922c7da7..76d26660a 100644 --- a/sbndcode/Decoders/XARAPUCA/SBNDXARAPUCADecoder_module.cc +++ b/sbndcode/Decoders/XARAPUCA/SBNDXARAPUCADecoder_module.cc @@ -541,23 +541,7 @@ void sbndaq::SBNDXARAPUCADecoder::decode_fragment(uint64_t timestamp, uint64_t& } // - Computation of the difference between TTTs difference and the length of the fragment in ns (to detect jittering between fragments). - //int32_t J = TTT_dif - frag_length; - - // - Combination boolean variable. - //bool dump_comb_wvfms = true; - /* if (is_nominal) { // Nominal fragment - if (!is_first && (TTT_dif <= (frag_length - fallowed_jittering))) { - std::cout << "\t\t WARNING: NOMINAL fragment too close to previous one! TTT_dif: " << TTT_dif << " ns, fragment idx: " << fragment_indices[board_idx] << ", board idx: " << board_idx << " (slot " << fboard_id_list[board_idx] << "), " << num_samples_per_wvfm << " samples. Skipping this fragment..." << std::endl; - } - } else { // Extended fragment - if (std::abs(J) <= fallowed_jittering) { - dump_comb_wvfms = false; - } else if (TTT_dif <= (frag_length - fallowed_jittering)) { - dump_comb_wvfms = false; - std::cout << "\t\t WARNING: EXTENDED fragment too close to previous one! TTT_dif: " << TTT_dif << " ns, fragment idx: " << fragment_indices[board_idx] << ", board idx: " << board_idx << " (slot " << fboard_id_list[board_idx] << "), " << num_samples_per_wvfm << " samples. Skipping this fragment..." << std::endl; - } - }*/ - + int32_t J = TTT_dif - frag_length; bool dump_comb_wvfms = !is_first && (is_nominal || (!is_nominal && (TTT_dif > (frag_length + fallowed_jittering)))); @@ -573,19 +557,43 @@ void sbndaq::SBNDXARAPUCADecoder::decode_fragment(uint64_t timestamp, uint64_t& first_frag_idx = fragment_indices[board_idx]; first_TTT = TTT_end_ns; first_frag_timestamp = frag_timestamp; + if (fdebug_jittering) std::cout << "NC - "; + } else { + if (fdebug_jittering) std::cout << "C - "; } append_waveforms(wvfms, fragment_wvfms, num_channels); if (last_one) { if (fdebug_extended_fragments) std::cout << "\t\t LAST fragment " << std::endl; - fragment_indices[board_idx]++; shift_time(TTT_ticks, first_TTT, first_frag_timestamp, timestamp, num_nominal_samples_per_wvfm, ini_wvfm_timestamp, end_wvfm_timestamp); dump_waveforms(prod_wvfms, wvfms, first_frag_idx, board_idx, num_channels, ini_wvfm_timestamp, end_wvfm_timestamp); } + if (fdebug_jittering) { + if (is_first) { + std::cout << "\t\t FIRST "; + } + if (is_nominal) { + int32_t TTT_ini_ns = TTT_end_ns - static_cast(num_nominal_samples_per_wvfm * fns_per_sample); + std::cout << "NOMINAL fragment " << fboard_id_list[board_idx] << " - " << fragment_indices[board_idx] << " (" << num_samples_per_wvfm << "): [" << TTT_ini_ns << ", " << TTT_end_ns << "] diff with prev: " << TTT_dif << " ns, length: " << frag_length << " ns, diff_with_length (jitt): " << J << std::endl; + } else { + int32_t TTT_ini_ns = TTT_end_ns - static_cast(num_nominal_samples_per_wvfm * fns_per_sample); + std::cout << "EXTENDED fragment " << fboard_id_list[board_idx] << " - " << fragment_indices[board_idx] << " (" << num_samples_per_wvfm << "): [" << TTT_ini_ns << ", " << TTT_end_ns << "] diff with prev: " << TTT_dif << " ns, length: " << frag_length << " ns, diff_with_length (jitt): " << J << std::endl; + } + } + + // WARNINGS + if (TTT_dif < frag_length - fallowed_jittering) { + if (!is_first) { + if (!is_nominal) std::cout << "\t\t WARNING: EXTENDED fragment too close! This fragment is being combined." << std::endl; + if (is_nominal) std::cout << "\t\t WARNING: NOMINAL fragment too close! This fragment is not being combined." << std::endl; + } + } + prev_TTT = TTT_end_ns; } else { // Combination of extended fragments disabled. + first_frag_idx = fragment_indices[board_idx]; shift_time(TTT_ticks, TTT_end_ns, frag_timestamp, timestamp, num_samples_per_wvfm, ini_wvfm_timestamp, end_wvfm_timestamp); dump_waveforms(prod_wvfms, fragment_wvfms, first_frag_idx, board_idx, num_channels, ini_wvfm_timestamp, end_wvfm_timestamp); } diff --git a/sbndcode/Decoders/XARAPUCA/xarapucadecoder.fcl b/sbndcode/Decoders/XARAPUCA/xarapucadecoder.fcl index d880a853e..adeb66bd8 100644 --- a/sbndcode/Decoders/XARAPUCA/xarapucadecoder.fcl +++ b/sbndcode/Decoders/XARAPUCA/xarapucadecoder.fcl @@ -32,7 +32,7 @@ xarapucadecoder: # - Output data product instance name. waveforms_instance_name: "XARAPUCAChannels" # Name for the instance product containing the raw decoded waveforms. timing_ref_instance_name: "" # Name for the instance product containing the timing reference information. - store_debug_waveforms: -1 # Number of waveforms to store (0: none, -1: all, n: first n waveforms). + store_debug_waveforms: 0 # Number of waveforms to store (0: none, -1: all, n: first n waveforms). # Combination of extended fragments. combine_ext_frag: true # (De)activates the combination of extended fragments into a single raw::OpDetWaveform object. allowed_jittering: 64 # Allowed jittering (in ns) between fragments to be combined. @@ -44,9 +44,9 @@ xarapucadecoder: debug_buffer: false # (De)activates buffer status printing. debug_waveforms: false # (De)activates waveforms decoding printing. debug_extended_fragments: false # (De)activates extended fragments information printing. - debug_jittering: true # (De)activates trigger jittering information printing. + debug_jittering: false # (De)activates trigger jittering information printing. # - Verbose option. - verbose: true # (De)activates verbosity. + verbose: false # (De)activates verbosity. } END_PROLOG \ No newline at end of file From bb1ac486547cf1bb578734ce76ed8402d23e366d Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Alicia=20V=C3=A1zquez-Ramos?= Date: Thu, 12 Feb 2026 16:42:45 -0600 Subject: [PATCH 14/18] feat (frameshift): Add frameshift module to the configuration and access its products. Additionally, set a frameshift mode boolean t be activated when selecting the frameshift timestamp (this one to be integrated in the workflow) --- .../XARAPUCA/SBNDXARAPUCADecoder_module.cc | 64 +++++++++++++++++-- .../Decoders/XARAPUCA/run_xarapucadecoder.fcl | 4 +- .../Decoders/XARAPUCA/xarapucadecoder.fcl | 12 ++-- 3 files changed, 70 insertions(+), 10 deletions(-) diff --git a/sbndcode/Decoders/XARAPUCA/SBNDXARAPUCADecoder_module.cc b/sbndcode/Decoders/XARAPUCA/SBNDXARAPUCADecoder_module.cc index 76d26660a..69806c5a1 100644 --- a/sbndcode/Decoders/XARAPUCA/SBNDXARAPUCADecoder_module.cc +++ b/sbndcode/Decoders/XARAPUCA/SBNDXARAPUCADecoder_module.cc @@ -39,6 +39,8 @@ #include "sbndcode/Timing/SBNDRawTimingObj.h" #include "sbnobj/SBND/Timing/DAQTimestamp.hh" +#include "sbnobj/SBND/Timing/FrameShiftInfo.hh" + #include "lardataobj/RawData/OpDetWaveform.h" #include "art_root_io/TFileService.h" @@ -107,6 +109,7 @@ class sbndaq::SBNDXARAPUCADecoder : public art::EDProducer { std::string fwaveforms_instance_name; /**< Name assigned to the product instance containing the waveforms for each channel and board generated by this art::EDProducer. */ std::string ftiming_ref_instance_name; /**< Name assigned to the product instance containing the timing reference information for each event generated by this art::EDProducer. */ + bool fframeshift_mode; /**< FrameShift mode: 0 use timing priority, 1 use FrameShift timestamp as reference. */ uint16_t ftiming_priority; /**< Timing priority configured: 0 SPEC-TDC RWM, 1 SPEC-TDC ETT, 2 CAEN-only. */ uint16_t factive_timing_frame; /**< Active timing frame while processing each event. */ unsigned int fns_per_sample; /**< Number of nanoseconds per sample. */ @@ -122,6 +125,8 @@ class sbndaq::SBNDXARAPUCADecoder : public art::EDProducer { std::string fptb_product_name; /**< Label identifying the module containing the PTB decoder products. */ std::vector fallowed_hl_triggers; /**< List of allowed high-level triggers from the PTB. */ + std::string fframeshift_product_name; /**< Label identifying the module containing the FrameShift module products. */ + art::ServiceHandle tfs; /**< ServiceHandle object to store the histograms in the decoder_hist.root output file. */ int fstore_debug_waveforms; /**< Number of waveforms to store in the ServiceHandle object for debugging purposes (0: none, -1: all, n: first n waveforms each event). */ @@ -130,6 +135,7 @@ class sbndaq::SBNDXARAPUCADecoder : public art::EDProducer { bool fdebug_tdc_handle; /**< If `true` SPEC-TDC information is printed. */ bool fdebug_ptb_handle; /**< If `true` PTB information is printed. */ + bool fdebug_frameshift_handle; /**< If `true` FrameShift information is printed. */ bool fdebug_fragments_handle; /**< If `true` V1740B CAEN fragments art::Handle information is printed. */ bool fdebug_timing; /**< If `true` timing data is printed. */ bool fdebug_buffer; /**< If `true` the buffer status is printed. */ @@ -145,7 +151,8 @@ class sbndaq::SBNDXARAPUCADecoder : public art::EDProducer { void shift_time(uint64_t TTT_ticks, int64_t TTT_end_ns, uint64_t frag_timestamp, uint64_t timestamp, uint32_t num_samples_per_wvfm, double& ini_wvfm_timestamp, double& end_wvfm_timestamp); bool get_spec_tdc_etrig_timestamp(art::Event& e, uint64_t corr_raw_timestamp, uint64_t & timestamp); bool get_ptb_hlt_timestamp(art::Event& e, uint64_t corr_raw_timestamp, uint64_t & timestamp, uint16_t & hlt_code); - + bool get_frameshift_timestamp(art::Event& e, uint64_t& timestamp, uint16_t& timing_type, uint16_t& timing_channel); + // Waveforms decoding. void decode_waveforms(const artdaq::Fragment& fragment, std::vector>& wvfms, size_t header_size, uint32_t num_channels, uint32_t num_samples_per_wvfm, uint32_t num_words_per_wvfms, uint32_t num_samples_per_group); uint16_t get_sample(uint64_t buffer, uint32_t msb, uint32_t lsb); @@ -195,6 +202,7 @@ sbndaq::SBNDXARAPUCADecoder::SBNDXARAPUCADecoder(fhicl::ParameterSet const& p) ftiming_ref_instance_name = p.get ("timing_ref_instance_name", ""); // Gets timing configuration. + fframeshift_mode = p.get ("frameshift_mode", true); ftiming_priority = p.get ("timing_priority", SPEC_TDC_TIMING); factive_timing_frame = CAEN_ONLY_TIMING; fns_per_sample = p.get ("ns_per_sample", 16); @@ -212,6 +220,9 @@ sbndaq::SBNDXARAPUCADecoder::SBNDXARAPUCADecoder(fhicl::ParameterSet const& p) // PTB access configuration. fptb_product_name = p.get("ptb_product_name", "ptbdecoder"); fallowed_hl_triggers = p.get>("allowed_hl_triggers", {1, 2, 3, 4, 5, 14, 15}); + + // FrameShift access configuration. + fframeshift_product_name = p.get("frameshift_product_name", "frameshift"); // Gets the number of waveforms to store in the debug output file. fstore_debug_waveforms = p.get ("store_debug_waveforms", 0); @@ -223,6 +234,7 @@ sbndaq::SBNDXARAPUCADecoder::SBNDXARAPUCADecoder(fhicl::ParameterSet const& p) // Gets the debug and verbose options. fdebug_ptb_handle = p.get ("debug_ptb_handle", false); fdebug_tdc_handle = p.get ("debug_tdc_handle", false); + fdebug_frameshift_handle = p.get ("debug_frameshift_handle", false); fdebug_fragments_handle = p.get ("debug_fragments_handle", false); fdebug_timing = p.get ("debug_timing", false); fdebug_waveforms = p.get ("debug_waveforms", false); @@ -255,9 +267,8 @@ void sbndaq::SBNDXARAPUCADecoder::produce(art::Event& e) { // Initializes the output instance products. auto prod_wvfms = std::make_unique > (); - auto prod_event_timing_ref_info = std::make_unique (); - prod_event_timing_ref_info->timingType = CAEN_ONLY_TIMING; // CAEN-only timing frame as default. - prod_event_timing_ref_info->timingChannel = 0; + // CAEN-only timing frame as default. + auto prod_event_timing_ref_info = std::make_unique(CAEN_ONLY_TIMING, 0); // CAEN-only timing frame as default. if (fverbose) std::cout << "\n > SBNDXARAPUCADecoder::produce: products initialized." << std::endl; @@ -276,7 +287,17 @@ void sbndaq::SBNDXARAPUCADecoder::produce(art::Event& e) { } // [0] ETRIG timestamp, [1] HLT timestamp, [2] CAEN-only timestamp. - uint64_t timestamp = 0; + uint64_t timestamp = 0; + + //// ============= TESTING ========== ==== //// + if (get_frameshift_timestamp(e, timestamp, prod_event_timing_ref_info->timingType, prod_event_timing_ref_info->timingChannel)) { + if (fverbose | fdebug_frameshift_handle) { + std::cout << "\n > SBNDXARAPUCADecoder::produce: FrameShift reference, " << print_timestamp(timestamp) << ", found. Using FrameShift timing frame as reference." << std::endl; + std::cout << "\t FrameShift reference details: timing type: " << prod_event_timing_ref_info->timingType << ", timing channel: " << prod_event_timing_ref_info->timingChannel << "." << std::endl; + } + } else { + if (fverbose | fdebug_frameshift_handle) std::cout << "\n > SBNDXARAPUCADecoder::produce: FrameShift reference not found. Using CAEN-only timing frame as reference." << std::endl; + } // Gets the SPEC-TDC product (if any). if (ftiming_priority == SPEC_TDC_TIMING) { @@ -880,6 +901,39 @@ bool sbndaq::SBNDXARAPUCADecoder::get_ptb_hlt_timestamp(art::Event& e, uint64_t return hlt_found; } +/** + * @brief Searches for the Frame Shift Info product in the event and checks if it is valid. + * @param[in] e The event to be processed. + * @param[in,out] timestamp The timestamp of the frame shift info product (if found). + * @return A boolean indicating if a valid frame shift info product was found in the event. + * @details It searches for the Frame Shift Info product in the event. If it is found, it checks if the art::Handle is valid and if it contains a valid frame shift info object. If all checks are passed, it returns true, otherwise it throws an error. + */ +bool sbndaq::SBNDXARAPUCADecoder::get_frameshift_timestamp(art::Event& e, uint64_t& timestamp, uint16_t& timing_type, uint16_t& timing_channel) { + bool frameshift_found = false; + + art::Handle frameshiftHandle; + e.getByLabel(fframeshift_product_name, frameshiftHandle); + + + if (fverbose | fdebug_frameshift_handle) std::cout << "\n > SBNDXARAPUCADecoder::get_frameshift_timestamp: Frameshift timing frame selected. Searching for Frameshift products..." << std::endl; + + // The art::Handle object is not valid. + if (!frameshiftHandle.isValid()) { + if (fdebug_frameshift_handle) std::cout << "\n\tFrameshift handle not valid for " << fframeshift_product_name << "." << std::endl; + throw std::runtime_error("XA Decoder: Frame Shift Info object is invalid, check data quality"); + + } else { + + timestamp = frameshiftHandle->FrameDefault(); + timing_type = frameshiftHandle->TimingTypeDefault(); + timing_channel = frameshiftHandle->TimingChannelDefault(); + + frameshift_found = true; + } + + return frameshift_found; +} + // =============== Decodes the waveforms =============== // /** diff --git a/sbndcode/Decoders/XARAPUCA/run_xarapucadecoder.fcl b/sbndcode/Decoders/XARAPUCA/run_xarapucadecoder.fcl index 710a35c71..13d9a860a 100644 --- a/sbndcode/Decoders/XARAPUCA/run_xarapucadecoder.fcl +++ b/sbndcode/Decoders/XARAPUCA/run_xarapucadecoder.fcl @@ -1,6 +1,7 @@ #include "xarapucadecoder.fcl" #include "spectdc_decoder_sbnd.fcl" #include "SBNDPTBDecoderDefaults.fcl" +#include "frameshift_sbnd_data.fcl" process_name: XARAPUCADecoder @@ -26,6 +27,7 @@ physics: { producers: { tdcdecoder: @local::spec_tdc_decoder_sbnd ptbdecoder: @local::SBNDPTBDecoderDefaults + frameshift: @local::frameshift_data xarapucadecoder: @local::xarapucadecoder } @@ -34,7 +36,7 @@ physics: { analyzers:{} - reco: [tdcdecoder, ptbdecoder, xarapucadecoder] + reco: [tdcdecoder, ptbdecoder, frameshift, xarapucadecoder] # Defines the output stream, there could be more than one if using filters. diff --git a/sbndcode/Decoders/XARAPUCA/xarapucadecoder.fcl b/sbndcode/Decoders/XARAPUCA/xarapucadecoder.fcl index adeb66bd8..208e5ed9f 100644 --- a/sbndcode/Decoders/XARAPUCA/xarapucadecoder.fcl +++ b/sbndcode/Decoders/XARAPUCA/xarapucadecoder.fcl @@ -14,6 +14,7 @@ xarapucadecoder: fragment_id_offset: 41216 # Offset to be applied to the fragment IDs (0xA100). board_id_list: [7, 13, 16, 19] # Slots where the boards are installed. # - Timing configuration. + frameshift_mode: false # FrameShift mode (false: use timing priority, true: use FrameShift timestamp as reference). timing_priority: 0 # 0 SPEC-TDC ETRIG, 1 PTB HLT (1-5, 14,15), 2 CAEN-only. ns_per_sample: 16 # Nanoseconds per sample. # - RAW timestamp configuration: @@ -23,10 +24,12 @@ xarapucadecoder: # - SPEC-TDC access configuration spectdc_product_name: "tdcdecoder" # Name for getting SPEC-TDC Decoder products (if any). spectdc_ftrig_ch: 3 # Channel assigned to flash triggers. - spectdc_etrig_ch: 4 # Channel assigned to ETT (Event Trigger Timestamp) triggers. + spectdc_etrig_ch: 2#4 # Channel assigned to ETT (Event Trigger Timestamp) triggers. # - PTB access configuration ptb_product_name: "ptbdecoder" # Name for getting PTB Decoder products (if any). allowed_hl_triggers: [1, 2, 3, 4, 5, 14, 15] # List of allowed HLT trigger types (1-5, 14, 15). + # - FrameShift access configuration + frameshift_product_name: "frameshift" # Name for getting FrameShift module products (if any). # OUTPUT configuration: # - Output data product instance name. @@ -34,19 +37,20 @@ xarapucadecoder: timing_ref_instance_name: "" # Name for the instance product containing the timing reference information. store_debug_waveforms: 0 # Number of waveforms to store (0: none, -1: all, n: first n waveforms). # Combination of extended fragments. - combine_ext_frag: true # (De)activates the combination of extended fragments into a single raw::OpDetWaveform object. + combine_ext_frag: false # (De)activates the combination of extended fragments into a single raw::OpDetWaveform object. allowed_jittering: 64 # Allowed jittering (in ns) between fragments to be combined. # - Debug options. debug_tdc_handle: false # (De)activates SPEC-TDC art::Handle information printing. + debug_frameshift_handle: true # (De)activates FrameShift art::Handle information printing. debug_ptb_handle: false # (De)activates PTB art::Handle information printing. debug_fragments_handle: false # (De)activates V1740B CAEN fragments art::Handle information printing. - debug_timing: false # (De)activates timing data printing. + debug_timing: true # (De)activates timing data printing. debug_buffer: false # (De)activates buffer status printing. debug_waveforms: false # (De)activates waveforms decoding printing. debug_extended_fragments: false # (De)activates extended fragments information printing. debug_jittering: false # (De)activates trigger jittering information printing. # - Verbose option. - verbose: false # (De)activates verbosity. + verbose: true # (De)activates verbosity. } END_PROLOG \ No newline at end of file From 7951a669b8f4dcb0bb7c786947688c8d50d9e1ec Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Alicia=20V=C3=A1zquez-Ramos?= Date: Thu, 12 Feb 2026 18:02:37 -0600 Subject: [PATCH 15/18] chore(frameshift): refactor get_frameshift_timestamp to improve functionality and modularity --- .../XARAPUCA/SBNDXARAPUCADecoder_module.cc | 70 +++++++++++-------- 1 file changed, 39 insertions(+), 31 deletions(-) diff --git a/sbndcode/Decoders/XARAPUCA/SBNDXARAPUCADecoder_module.cc b/sbndcode/Decoders/XARAPUCA/SBNDXARAPUCADecoder_module.cc index 69806c5a1..c950b18d0 100644 --- a/sbndcode/Decoders/XARAPUCA/SBNDXARAPUCADecoder_module.cc +++ b/sbndcode/Decoders/XARAPUCA/SBNDXARAPUCADecoder_module.cc @@ -151,7 +151,7 @@ class sbndaq::SBNDXARAPUCADecoder : public art::EDProducer { void shift_time(uint64_t TTT_ticks, int64_t TTT_end_ns, uint64_t frag_timestamp, uint64_t timestamp, uint32_t num_samples_per_wvfm, double& ini_wvfm_timestamp, double& end_wvfm_timestamp); bool get_spec_tdc_etrig_timestamp(art::Event& e, uint64_t corr_raw_timestamp, uint64_t & timestamp); bool get_ptb_hlt_timestamp(art::Event& e, uint64_t corr_raw_timestamp, uint64_t & timestamp, uint16_t & hlt_code); - bool get_frameshift_timestamp(art::Event& e, uint64_t& timestamp, uint16_t& timing_type, uint16_t& timing_channel); + std::unique_ptr get_frameshift_timestamp(art::Event& e, uint64_t& timestamp); // Waveforms decoding. void decode_waveforms(const artdaq::Fragment& fragment, std::vector>& wvfms, size_t header_size, uint32_t num_channels, uint32_t num_samples_per_wvfm, uint32_t num_words_per_wvfms, uint32_t num_samples_per_group); @@ -272,6 +272,21 @@ void sbndaq::SBNDXARAPUCADecoder::produce(art::Event& e) { if (fverbose) std::cout << "\n > SBNDXARAPUCADecoder::produce: products initialized." << std::endl; + uint64_t timestamp = 0; + + // ============= FRAMESHIFT MODE ============ // + if (auto fs_timing_ref_info = get_frameshift_timestamp(e, timestamp)) { + *prod_event_timing_ref_info = *fs_timing_ref_info; + if (fverbose | fdebug_frameshift_handle) { + std::cout << "\n > SBNDXARAPUCADecoder::produce: FrameShift reference, " << print_timestamp(timestamp) << ", found. Using FrameShift timing frame as reference." << std::endl; + std::cout << "\t FrameShift reference details: timing type: " << prod_event_timing_ref_info->timingType << ", timing channel: " << prod_event_timing_ref_info->timingChannel << "." << std::endl; + } + } else { + if (fverbose | fdebug_frameshift_handle) std::cout << "\n > SBNDXARAPUCADecoder::produce: FrameShift reference not found. Using CAEN-only timing frame as reference." << std::endl; + } + + + // ============= TIMING PRIORITY MODE ============ // // Gets the raw timestamp from the artdaq::RawEventHeader product. uint64_t corr_raw_timestamp = 0; art::Handle header_handle; @@ -287,17 +302,6 @@ void sbndaq::SBNDXARAPUCADecoder::produce(art::Event& e) { } // [0] ETRIG timestamp, [1] HLT timestamp, [2] CAEN-only timestamp. - uint64_t timestamp = 0; - - //// ============= TESTING ========== ==== //// - if (get_frameshift_timestamp(e, timestamp, prod_event_timing_ref_info->timingType, prod_event_timing_ref_info->timingChannel)) { - if (fverbose | fdebug_frameshift_handle) { - std::cout << "\n > SBNDXARAPUCADecoder::produce: FrameShift reference, " << print_timestamp(timestamp) << ", found. Using FrameShift timing frame as reference." << std::endl; - std::cout << "\t FrameShift reference details: timing type: " << prod_event_timing_ref_info->timingType << ", timing channel: " << prod_event_timing_ref_info->timingChannel << "." << std::endl; - } - } else { - if (fverbose | fdebug_frameshift_handle) std::cout << "\n > SBNDXARAPUCADecoder::produce: FrameShift reference not found. Using CAEN-only timing frame as reference." << std::endl; - } // Gets the SPEC-TDC product (if any). if (ftiming_priority == SPEC_TDC_TIMING) { @@ -902,36 +906,40 @@ bool sbndaq::SBNDXARAPUCADecoder::get_ptb_hlt_timestamp(art::Event& e, uint64_t } /** - * @brief Searches for the Frame Shift Info product in the event and checks if it is valid. + * @brief Searches for the frameshift timestamp in the event if any frameshift product is found and returns it as a TimingReferenceInfo object. * @param[in] e The event to be processed. - * @param[in,out] timestamp The timestamp of the frame shift info product (if found). - * @return A boolean indicating if a valid frame shift info product was found in the event. - * @details It searches for the Frame Shift Info product in the event. If it is found, it checks if the art::Handle is valid and if it contains a valid frame shift info object. If all checks are passed, it returns true, otherwise it throws an error. + * @param[in,out] timestamp The frameshift timestamp (if found). + * @param[in,out] timing_type The type of the frameshift timestamp (if found). + * @param[in,out] timing_channel The channel of the frameshift timestamp (if found). + * @return A unique pointer to a TimingReferenceInfo object containing the frameshift timestamp information (if found), or nullptr if no valid frameshift product is found. + * @details It searches for the frameshift products in the event and looks for the default frameshift timestamp, type and channel. If any valid frameshift product is found, it returns its information as a TimingReferenceInfo object. */ -bool sbndaq::SBNDXARAPUCADecoder::get_frameshift_timestamp(art::Event& e, uint64_t& timestamp, uint16_t& timing_type, uint16_t& timing_channel) { - bool frameshift_found = false; +std::unique_ptr sbndaq::SBNDXARAPUCADecoder::get_frameshift_timestamp(art::Event& e, uint64_t& timestamp) { + std::unique_ptr fs_timing_ref_info = nullptr; art::Handle frameshiftHandle; e.getByLabel(fframeshift_product_name, frameshiftHandle); - - if (fverbose | fdebug_frameshift_handle) std::cout << "\n > SBNDXARAPUCADecoder::get_frameshift_timestamp: Frameshift timing frame selected. Searching for Frameshift products..." << std::endl; + if (fverbose || fdebug_frameshift_handle) std::cout << "\n > SBNDXARAPUCADecoder::get_frameshift_timestamp: Frameshift timing frame selected. Searching for Frameshift products..." << std::endl; - // The art::Handle object is not valid. - if (!frameshiftHandle.isValid()) { - if (fdebug_frameshift_handle) std::cout << "\n\tFrameshift handle not valid for " << fframeshift_product_name << "." << std::endl; - throw std::runtime_error("XA Decoder: Frame Shift Info object is invalid, check data quality"); + if (frameshiftHandle.isValid()) { + + uint16_t timing_type = frameshiftHandle->TimingTypeDefault(); + uint16_t timing_channel = frameshiftHandle->TimingChannelDefault(); + if (timing_type != sbnd::timing::kNoShiftType) { // Only if timing type is valid, the timestamp is considered valid. + timestamp = frameshiftHandle->FrameDefault(); + fs_timing_ref_info = std::make_unique(timing_type, timing_channel); + } else { + timestamp = 0; + } + } else { - - timestamp = frameshiftHandle->FrameDefault(); - timing_type = frameshiftHandle->TimingTypeDefault(); - timing_channel = frameshiftHandle->TimingChannelDefault(); - - frameshift_found = true; + if (fdebug_frameshift_handle) std::cout << "\n\tFrameshift handle not valid for " << fframeshift_product_name << "." << std::endl; + throw std::runtime_error("XA Decoder: Frame Shift Info object is invalid, check data quality"); } - return frameshift_found; + return fs_timing_ref_info; } // =============== Decodes the waveforms =============== // From 435675614b30bf4ee57b0180dc8b29a20735d306 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Alicia=20V=C3=A1zquez-Ramos?= Date: Fri, 13 Feb 2026 09:08:31 -0600 Subject: [PATCH 16/18] refactor(timing)\!: Remove access to SPEC-TDC and PTB. Change timing frame to FRAMESHIFT or CAEN-only. Integrate FRAMESHIFT timing frame into the workflow and output products --- .../XARAPUCA/SBNDXARAPUCADecoder_module.cc | 364 ++---------------- .../Decoders/XARAPUCA/run_xarapucadecoder.fcl | 6 +- .../Decoders/XARAPUCA/xarapucadecoder.fcl | 23 +- 3 files changed, 37 insertions(+), 356 deletions(-) diff --git a/sbndcode/Decoders/XARAPUCA/SBNDXARAPUCADecoder_module.cc b/sbndcode/Decoders/XARAPUCA/SBNDXARAPUCADecoder_module.cc index c950b18d0..cdac59958 100644 --- a/sbndcode/Decoders/XARAPUCA/SBNDXARAPUCADecoder_module.cc +++ b/sbndcode/Decoders/XARAPUCA/SBNDXARAPUCADecoder_module.cc @@ -33,9 +33,6 @@ #include "sbndaq-artdaq-core/Overlays/FragmentType.hh" #include "sbndaq-artdaq-core/Overlays/SBND/CAENV1740Fragment.hh" -#include "sbndcode/Decoders/PTB/sbndptb.h" -#include "sbndaq-artdaq-core/Overlays/SBND/PTBFragment.hh" - #include "sbndcode/Timing/SBNDRawTimingObj.h" #include "sbnobj/SBND/Timing/DAQTimestamp.hh" @@ -89,13 +86,10 @@ class sbndaq::SBNDXARAPUCADecoder : public art::EDProducer { constexpr static uint32_t NUM_CONSECUTIVE_SAMPLES = 3; /**< Number of consecutive samples for the same channel when decoding waveforms. */ constexpr static uint16_t NANOSEC_PER_TICK = 8; /**< Number of nanoseconds per Trigger Time Tag (TTT) tick. */ - constexpr static uint16_t SPEC_TDC_TIMING = 0; /**< Timing reference frame: ETRIG (Event Trigger) timestamp from the SPEC-TDC. */ - constexpr static uint16_t PTB_TIMING = 1; /**< Timing reference frame: HLT (High Level Trigger) timestamp from the PTB (Penn Trigger Board). */ - constexpr static uint16_t CAEN_ONLY_TIMING = 2; /**< Timing reference frame: CAEN-only. */ + constexpr static uint16_t FRAMESHIFT_TIMING = 0; /**< Timing reference frame: FrameShift timestamp. */ + constexpr static uint16_t CAEN_ONLY_TIMING = 1; /**< Timing reference frame: CAEN-only. */ constexpr static uint16_t TTT_DEFAULT = 0; /**< Default integer value for the nominal TTT. */ - constexpr static uint16_t HLT_NOT_FOUND = 999; /**< Random value to indicate no HL trigger found. */ - constexpr static uint16_t HLT_TOO_FAR = 1000; /**< Random value to indicate HL trigger found but too far from the raw timestamp. */ unsigned int fevent_counter; /**< Event counter. */ @@ -110,21 +104,9 @@ class sbndaq::SBNDXARAPUCADecoder : public art::EDProducer { std::string ftiming_ref_instance_name; /**< Name assigned to the product instance containing the timing reference information for each event generated by this art::EDProducer. */ bool fframeshift_mode; /**< FrameShift mode: 0 use timing priority, 1 use FrameShift timestamp as reference. */ - uint16_t ftiming_priority; /**< Timing priority configured: 0 SPEC-TDC RWM, 1 SPEC-TDC ETT, 2 CAEN-only. */ uint16_t factive_timing_frame; /**< Active timing frame while processing each event. */ unsigned int fns_per_sample; /**< Number of nanoseconds per sample. */ - std::string fraw_event_header_product_name; /**< Label identifying the module that created the artdaq::detail::RawEventHeader data product. */ - uint16_t fraw_trig_max_diff; /**< Maximum difference (in ns) allowed between trigger timestamps and raw timestamp. */ - uint32_t fraw_timestamp_correction; /**< Correction (in ns) to be applied to the raw timestamp. */ - - std::string fspectdc_product_name; /**< Label identifying the module containing the SPEC-TDC decoder products. */ - uint32_t fspectdc_ftrig_ch; /**< Channel assigned by the SPEC-TDC to the flash triggers. */ - uint32_t fspectdc_etrig_ch; /**< Channel assigned by the SPEC-TDC to the event triggers. */ - - std::string fptb_product_name; /**< Label identifying the module containing the PTB decoder products. */ - std::vector fallowed_hl_triggers; /**< List of allowed high-level triggers from the PTB. */ - std::string fframeshift_product_name; /**< Label identifying the module containing the FrameShift module products. */ art::ServiceHandle tfs; /**< ServiceHandle object to store the histograms in the decoder_hist.root output file. */ @@ -133,8 +115,6 @@ class sbndaq::SBNDXARAPUCADecoder : public art::EDProducer { bool fcombine_ext_frag; /**< If `true` combines extended fragments into a single raw::OpDetWaveform object. */ int32_t fallowed_jittering; /**< Allowed jittering (in ns) between fragments to be combined. */ - bool fdebug_tdc_handle; /**< If `true` SPEC-TDC information is printed. */ - bool fdebug_ptb_handle; /**< If `true` PTB information is printed. */ bool fdebug_frameshift_handle; /**< If `true` FrameShift information is printed. */ bool fdebug_fragments_handle; /**< If `true` V1740B CAEN fragments art::Handle information is printed. */ bool fdebug_timing; /**< If `true` timing data is printed. */ @@ -149,8 +129,6 @@ class sbndaq::SBNDXARAPUCADecoder : public art::EDProducer { // Timing. void shift_time(uint64_t TTT_ticks, int64_t TTT_end_ns, uint64_t frag_timestamp, uint64_t timestamp, uint32_t num_samples_per_wvfm, double& ini_wvfm_timestamp, double& end_wvfm_timestamp); - bool get_spec_tdc_etrig_timestamp(art::Event& e, uint64_t corr_raw_timestamp, uint64_t & timestamp); - bool get_ptb_hlt_timestamp(art::Event& e, uint64_t corr_raw_timestamp, uint64_t & timestamp, uint16_t & hlt_code); std::unique_ptr get_frameshift_timestamp(art::Event& e, uint64_t& timestamp); // Waveforms decoding. @@ -168,7 +146,7 @@ class sbndaq::SBNDXARAPUCADecoder : public art::EDProducer { void save_debug_wvfm(size_t board_idx, size_t fragment_idx, int ch, double ini_wvfm_timestamp, double end_wvfm_timestamp, const std::vector > & wvfms); // Auxiliary methods. - int64_t signed_difference(uint64_t t1, uint64_t t2); + int64_t signed_difference_UTC_timestamp(uint64_t t1, uint64_t t2); uint64_t abs_difference(uint64_t t1, uint64_t t2); std::string print_timestamp(uint64_t timestamp); @@ -202,25 +180,9 @@ sbndaq::SBNDXARAPUCADecoder::SBNDXARAPUCADecoder(fhicl::ParameterSet const& p) ftiming_ref_instance_name = p.get ("timing_ref_instance_name", ""); // Gets timing configuration. - fframeshift_mode = p.get ("frameshift_mode", true); - ftiming_priority = p.get ("timing_priority", SPEC_TDC_TIMING); factive_timing_frame = CAEN_ONLY_TIMING; fns_per_sample = p.get ("ns_per_sample", 16); - // Gets the raw timestamp configuration. - fraw_event_header_product_name = p.get ("raw_timestamp_product_name", "daq"); - fraw_trig_max_diff = p.get ("raw_trig_max_diff", 3000000); - fraw_timestamp_correction = p.get ("raw_timestamp_correction", 367000); - - // SPEC-TDC access configuration. - fspectdc_product_name = p.get("spectdc_product_name", "tdcdecoder"); - fspectdc_ftrig_ch = p.get("spectdc_ftrig_ch", 3); - fspectdc_etrig_ch = p.get("spectdc_etrig_ch", 4); - - // PTB access configuration. - fptb_product_name = p.get("ptb_product_name", "ptbdecoder"); - fallowed_hl_triggers = p.get>("allowed_hl_triggers", {1, 2, 3, 4, 5, 14, 15}); - // FrameShift access configuration. fframeshift_product_name = p.get("frameshift_product_name", "frameshift"); @@ -232,8 +194,6 @@ sbndaq::SBNDXARAPUCADecoder::SBNDXARAPUCADecoder(fhicl::ParameterSet const& p) fallowed_jittering = p.get ("allowed_jittering", 64); // Gets the debug and verbose options. - fdebug_ptb_handle = p.get ("debug_ptb_handle", false); - fdebug_tdc_handle = p.get ("debug_tdc_handle", false); fdebug_frameshift_handle = p.get ("debug_frameshift_handle", false); fdebug_fragments_handle = p.get ("debug_fragments_handle", false); fdebug_timing = p.get ("debug_timing", false); @@ -254,7 +214,7 @@ sbndaq::SBNDXARAPUCADecoder::SBNDXARAPUCADecoder(fhicl::ParameterSet const& p) * @details It is the main function of the art::EDProducer module: it processes each event, searches for CAEN V1740 fragments, decodes * them and creates the output products. * 1. It gets the raw timestamp from the artdaq::RawEventHeader product. - * 2. It tries to get a valid timing reference from the selected time frame (SPEC-TDC ETRIG, PTB HLT or CAEN-only). If the selected + * 2. It tries to get a valid timing reference from the selected time frame (FRAMESHIFT or CAEN-only). If the selected * timing frame is not found, it tries to get the next one in the priority list. * 3. It searches for CAEN V1740 fragments in the event, decodes them and creates the output products: a vector of raw::OpDetWaveform. * 4. It dumps the products in the event. @@ -274,76 +234,20 @@ void sbndaq::SBNDXARAPUCADecoder::produce(art::Event& e) { uint64_t timestamp = 0; - // ============= FRAMESHIFT MODE ============ // + // ============= FRAMESHIFT TIMING ============ // if (auto fs_timing_ref_info = get_frameshift_timestamp(e, timestamp)) { *prod_event_timing_ref_info = *fs_timing_ref_info; + factive_timing_frame = FRAMESHIFT_TIMING; if (fverbose | fdebug_frameshift_handle) { - std::cout << "\n > SBNDXARAPUCADecoder::produce: FrameShift reference, " << print_timestamp(timestamp) << ", found. Using FrameShift timing frame as reference." << std::endl; - std::cout << "\t FrameShift reference details: timing type: " << prod_event_timing_ref_info->timingType << ", timing channel: " << prod_event_timing_ref_info->timingChannel << "." << std::endl; + std::cout << "\n > SBNDXARAPUCADecoder::produce: FRAMESHIFT reference, " << print_timestamp(timestamp) << ", found. Using FRAMESHIFT timing frame as reference." << std::endl; + std::cout << "\t FRAMESHIFT reference details: timing type: " << prod_event_timing_ref_info->timingType << ", timing channel: " << prod_event_timing_ref_info->timingChannel << "." << std::endl; } } else { if (fverbose | fdebug_frameshift_handle) std::cout << "\n > SBNDXARAPUCADecoder::produce: FrameShift reference not found. Using CAEN-only timing frame as reference." << std::endl; } + // ============================================== // - // ============= TIMING PRIORITY MODE ============ // - // Gets the raw timestamp from the artdaq::RawEventHeader product. - uint64_t corr_raw_timestamp = 0; - art::Handle header_handle; - e.getByLabel(fraw_event_header_product_name, "RawEventHeader", header_handle); - if (header_handle.isValid()) { - auto raw_header = artdaq::RawEvent(*header_handle); - corr_raw_timestamp = raw_header.timestamp() - fraw_timestamp_correction; - - if (fverbose | fdebug_tdc_handle | fdebug_ptb_handle | fdebug_timing) std::cout << "\n > SBNDXARAPUCADecoder::produce: RAW timestamp from the event header: " << print_timestamp(corr_raw_timestamp) << "." << std::endl; - if (fdebug_tdc_handle | fdebug_ptb_handle | fdebug_timing) { - std::cout << "\t RAW timestamp: BEFORE correction: " << print_timestamp(raw_header.timestamp()) << " - AFTER correction: " << print_timestamp(corr_raw_timestamp) << "." << std::endl; - } - } - - // [0] ETRIG timestamp, [1] HLT timestamp, [2] CAEN-only timestamp. - - // Gets the SPEC-TDC product (if any). - if (ftiming_priority == SPEC_TDC_TIMING) { - if (get_spec_tdc_etrig_timestamp(e, corr_raw_timestamp, timestamp)) { - prod_event_timing_ref_info->timingType = SPEC_TDC_TIMING; - prod_event_timing_ref_info->timingChannel = fspectdc_etrig_ch; - factive_timing_frame = SPEC_TDC_TIMING; - if (fverbose | fdebug_tdc_handle) std::cout << "\n > SBNDXARAPUCADecoder::produce: SPEC-TDC ETRIG reference, " << print_timestamp(timestamp) << ", found close enough to the raw timestamp. Using SPEC-TDC timing frame as reference." << std::endl; - } else { - ftiming_priority = PTB_TIMING; - if (fverbose | fdebug_tdc_handle) std::cout << "\n > SBNDXARAPUCADecoder::produce: SPEC-TDC ETRIG reference not found. Trying to find PTB reference..." << std::endl; - } - } - - // Gets the PTB product (if any). - if (ftiming_priority == PTB_TIMING) { - uint16_t hlt_code = HLT_NOT_FOUND; - if (get_ptb_hlt_timestamp(e, corr_raw_timestamp, timestamp, hlt_code)) { - prod_event_timing_ref_info->timingType = PTB_TIMING; - prod_event_timing_ref_info->timingChannel = hlt_code; - factive_timing_frame = PTB_TIMING; - if (fverbose | fdebug_ptb_handle) std::cout << "\n > SBNDXARAPUCADecoder::produce: PTB HLT reference, " << print_timestamp(timestamp) << ", found close enough to the raw timestamp. Using PTB timing frame as reference." << std::endl; - } else { - ftiming_priority = CAEN_ONLY_TIMING; - if (fverbose | fdebug_ptb_handle) std::cout << "\n > SBNDXARAPUCADecoder::produce: PTB reference not found. Searching for CAEN-only reference..." << std::endl; - } - } - - if (fverbose | fdebug_tdc_handle | fdebug_ptb_handle | fdebug_timing) { - std::cout << "\n > SBNDXARAPUCADecoder::produce: selected timing frame: "; - - if (factive_timing_frame == SPEC_TDC_TIMING) { - std::cout << "SPEC-TDC."; - } else if (factive_timing_frame == PTB_TIMING) { - std::cout << "PTB."; - } else if (ftiming_priority == CAEN_ONLY_TIMING) { - std::cout << "CAEN-only."; - } - - std::cout << " Timestamp: " << print_timestamp(timestamp) <<", timing type: " << prod_event_timing_ref_info->timingType << ", channel: " << prod_event_timing_ref_info->timingChannel << "." << std::endl; - } - // Flag to track if valid CAEN fragments are found. bool found_caen = false; @@ -634,7 +538,7 @@ void sbndaq::SBNDXARAPUCADecoder::decode_fragment(uint64_t timestamp, uint64_t& * @param[in] TTT_ticks The trigger time tag in ticks from the CAEN V1740 header. * @param[in] TTT_end_ns The end time of the Trigger Time Tag (TTT) in nanoseconds. * @param[in] frag_timestamp The timestamp of the fragment in nanoseconds. - * @param[in] timestamp The reference timestamp (ETRIG from the SPEC-TDC or HLT from the PTB) in nanoseconds. + * @param[in] timestamp The reference timestamp (from FRAMESHIFT or CAEN-only) in nanoseconds. * @param[in] num_samples_per_wvfm The number of samples per waveform. * @param[out] ini_wvfm_timestamp The initial timestamp of the waveform in microseconds (output). * @param[out] end_wvfm_timestamp The end timestamp of the waveform in microseconds (output). @@ -642,10 +546,8 @@ void sbndaq::SBNDXARAPUCADecoder::decode_fragment(uint64_t timestamp, uint64_t& * @details * This function calculates the initial and end timestamps for a waveform based on the provided timing information. It takes into account * potential rollovers in the trigger time tag and adjusts the timestamps accordingly. The function supports different timing frames, including - * SPEC-TDC, PTB, and CAEN-only timing. The calculated timestamps are returned in microseconds. + * FRAMESHIFT and CAEN-only timing. The calculated timestamps are returned in microseconds. * - * @see get_spec_tdc_etrig_timestamp - * @see get_ptb_hlt_timestamp */ void sbndaq::SBNDXARAPUCADecoder::shift_time(uint64_t TTT_ticks, int64_t TTT_end_ns, uint64_t frag_timestamp, uint64_t timestamp, uint32_t num_samples_per_wvfm, double& ini_wvfm_timestamp, double& end_wvfm_timestamp) { @@ -653,26 +555,26 @@ void sbndaq::SBNDXARAPUCADecoder::shift_time(uint64_t TTT_ticks, int64_t TTT_end int64_t frag_timestamp_s = frag_timestamp / NANOSEC_IN_SEC; // s. int64_t frag_timestamp_ns = frag_timestamp % NANOSEC_IN_SEC; // ns. - // Gets the full TTT timestamp. - uint64_t full_TTT = 0; + // Gets the UNIX TTT timestamp. + uint64_t TTT_UNIX_timestamp = 0; // If the fragment timestamp is greater than the TTT end timestamp, it means that rollover occurred. if (frag_timestamp_ns > TTT_end_ns) { if (fverbose | fdebug_timing) std::cout << " > SBNDXARAPUCADecoder::decode_fragment: CAEN TTT rollover occurred w.r.t. the fragment timestamp (FTS)." << std::endl; - full_TTT = (frag_timestamp_s + 1) * NANOSEC_IN_SEC + TTT_end_ns; + TTT_UNIX_timestamp = (frag_timestamp_s + 1) * NANOSEC_IN_SEC + TTT_end_ns; } else { - full_TTT = frag_timestamp_s * NANOSEC_IN_SEC + TTT_end_ns; + TTT_UNIX_timestamp = frag_timestamp_s * NANOSEC_IN_SEC + TTT_end_ns; } int64_t ref_timestamp = 0; - // If an ETRIG or HLT timestamp was found it restarts the time from it. Otherwise the CAEN time frame is assigned. + // If an frameshift timestamp was found it restarts the time from it. Otherwise the CAEN time frame is assigned. if (factive_timing_frame != CAEN_ONLY_TIMING) { - ref_timestamp = signed_difference(full_TTT, timestamp); // ns. + ref_timestamp = signed_difference_UTC_timestamp(TTT_UNIX_timestamp, timestamp); // ns. ini_wvfm_timestamp = (ref_timestamp - pulse_duration_ns) * NANOSEC_TO_MICROSEC; // us. end_wvfm_timestamp = ref_timestamp * NANOSEC_TO_MICROSEC; // us. } else { - ref_timestamp = full_TTT; // ns. + ref_timestamp = TTT_UNIX_timestamp; // ns. ini_wvfm_timestamp = ((ref_timestamp - pulse_duration_ns) % NANOSEC_IN_SEC) * NANOSEC_TO_MICROSEC; // ns. end_wvfm_timestamp = (ref_timestamp % NANOSEC_IN_SEC) * NANOSEC_TO_MICROSEC; // us. @@ -683,27 +585,21 @@ void sbndaq::SBNDXARAPUCADecoder::shift_time(uint64_t TTT_ticks, int64_t TTT_end std::cout << "\t\t ns/tick = " << NANOSEC_PER_TICK << ", ns/sample = " << fns_per_sample << std::endl; std::cout << "\t\t TTT header.TriggerTime() [TTT_ticks] = " << TTT_ticks << " ticks. \t TTT_end_ns = " << print_timestamp(TTT_end_ns) << "." << std::endl; std::cout << "\t\t Full Fragment timestamp: " << print_timestamp(frag_timestamp) << " = " << frag_timestamp_s << " s " << frag_timestamp_ns << " ns." << std::endl; - std::cout << "\t\t Full TTT - fragment timestamp = "<< abs_difference(full_TTT, frag_timestamp) << " ns." << " Post-percent: " << (double(abs_difference(full_TTT, frag_timestamp)) / double(pulse_duration_ns)) * 100 << "%." << std::endl; - if (factive_timing_frame == SPEC_TDC_TIMING) { - std::cout << "\t ETRIG (SPEC-TDC) timestamp of the fragment: " << std::endl; - std::cout << "\t\t Full UTC ETRIG timestamp: " << print_timestamp(timestamp) << "." << std::endl; - std::cout << "\t\t ETRIG SPEC-TDC difference applied to the CAEN frame (full timestamps): " << print_timestamp(full_TTT) << " - " << print_timestamp(timestamp) << " = " << ref_timestamp << " ns." << std::endl; - } else if (factive_timing_frame == PTB_TIMING) { - std::cout << "\t HLT ETRIG (PTB) timestamp of the fragment: " << std::endl; - std::cout << "\t\t Full UTC HLT ETRIG timestamp: " << print_timestamp(timestamp) << "." << std::endl; - std::cout << "\t\t HLT ETRIG (PTB) difference applied to the CAEN frame (full timestamps): " << print_timestamp(full_TTT) << " - " << print_timestamp(timestamp) << " = " << ref_timestamp << " ns." << std::endl; - } else if (factive_timing_frame == CAEN_ONLY_TIMING) { + std::cout << "\t\t Full TTT - fragment timestamp = "<< abs_difference(TTT_UNIX_timestamp, frag_timestamp) << " ns." << " Post-percent: " << (double(abs_difference(TTT_UNIX_timestamp, frag_timestamp)) / double(pulse_duration_ns)) * 100 << "%." << std::endl; + if (factive_timing_frame == FRAMESHIFT_TIMING) { + std::cout << "\t FRAMESHIFT timestamp of the fragment: " << std::endl; + std::cout << "\t\t Full UTC FRAMESHIFT timestamp: " << print_timestamp(timestamp) << "." << std::endl; + std::cout << "\t\t FRAMESHIFT difference applied to the CAEN frame (UNIX timestamps): " << print_timestamp(TTT_UNIX_timestamp) << " - " << print_timestamp(timestamp) << " = " << ref_timestamp << " ns." << std::endl; + } else { std::cout << "\t CAEN trigger timestamp (TTT) of the fragment: " << std::endl; - std::cout << "\t\t Full UTC TTT timestamp: " << print_timestamp(full_TTT) << " = " << full_TTT / NANOSEC_IN_SEC << " s " << TTT_end_ns << " ns." << std::endl; + std::cout << "\t\t Full UTC TTT timestamp: " << print_timestamp(TTT_UNIX_timestamp) << " = " << TTT_UNIX_timestamp / NANOSEC_IN_SEC << " s " << TTT_end_ns << " ns." << std::endl; } } if (fverbose | fdebug_timing) { std::cout << std::fixed << std::setprecision(3); - if (factive_timing_frame == SPEC_TDC_TIMING) { - std::cout << " > SBNDXARAPUCADecoder::decode_fragment: SPEC-TDC time window of " << end_wvfm_timestamp - ini_wvfm_timestamp << " us: [" << ini_wvfm_timestamp << ", " << end_wvfm_timestamp << "] us." << std::endl; - } else if (factive_timing_frame == PTB_TIMING) { - std::cout << " > SBNDXARAPUCADecoder::decode_fragment: PTB time window of " << end_wvfm_timestamp - ini_wvfm_timestamp << " us: [" << ini_wvfm_timestamp << ", " << end_wvfm_timestamp << "] us." << std::endl; + if (factive_timing_frame == FRAMESHIFT_TIMING) { + std::cout << " > SBNDXARAPUCADecoder::decode_fragment: FRAMESHIFT time window of " << end_wvfm_timestamp - ini_wvfm_timestamp << " us: [" << ini_wvfm_timestamp << ", " << end_wvfm_timestamp << "] us." << std::endl; } else { // CAEN_ONLY_TIMING std::cout << " > SBNDXARAPUCADecoder::decode_fragment: CAEN time window of " << end_wvfm_timestamp - ini_wvfm_timestamp << " us: [" << ini_wvfm_timestamp << ", " << end_wvfm_timestamp << "] us." << std::endl; } @@ -711,200 +607,6 @@ void sbndaq::SBNDXARAPUCADecoder::shift_time(uint64_t TTT_ticks, int64_t TTT_end } } -/** - * @brief Searches for the SPEC-TDC ETRIG timestamp closest to the raw timestamp if any SPEC-TDC ETRIG product is found in the event. - * @param[in] e The event to be processed. - * @param[in] corr_raw_timestamp The corrected raw timestamp from the artdaq::RawEventHeader product. - * @param[in,out] timestamp The closest ETRIG timestamp to the raw timestamp (if found). - * @return A boolean indicating if a valid ETRIG timestamp was found close enough to the raw timestamp. - * @details It searches for the SPEC-TDC products in the event and looks for the ETRIG timestamps. If any ETRIG - * timestamp is found, it checks which one is the closest to the raw timestamp and if it is close enough (i.e. - * within fraw_trig_max_diff) it returns it as output. - */ -bool sbndaq::SBNDXARAPUCADecoder::get_spec_tdc_etrig_timestamp(art::Event& e, uint64_t corr_raw_timestamp, uint64_t& timestamp) { - bool ett_found = false; - - art::Handle > tdc_handle; - e.getByLabel(fspectdc_product_name, tdc_handle); - - if (fverbose | fdebug_tdc_handle) std::cout << "\n > SBNDXARAPUCADecoder::get_spec_tdc_etrig_timestamp: searching for SPEC-TDC products..." << std::endl; - - // The art::Handle object is not valid. - if (!tdc_handle.isValid()) { - if (fdebug_tdc_handle) std::cout << "\n\tTDC-SPEC handle not valid for " << fspectdc_product_name << "." << std::endl; - - // The art::Handle object is empty. - } else if (tdc_handle->empty()) { - if (fdebug_tdc_handle) std::cout << "\n\tTDC-SPEC handle is empty." << std::endl; - - // The art::Handle object is valid and not empty. - } else { - if (fdebug_tdc_handle) std::cout << " \n\tDecoded TDC-SPEC products found: " << tdc_handle->size() << " products." << std::endl; - - unsigned int num_event_triggers = 0; - unsigned int num_flash_triggers = 0; - - uint64_t min_diff = std::numeric_limits::max(); - uint64_t closest_tdc_timestamp = 0; - - if (fdebug_tdc_handle) std::cout << "\t\tTDC Channel \t TDC Name \t\t TDC Timestamp [ns] \t\t TDC Offset [ns]"; - - // Loops over the SPEC-TDC products in the event. - for (size_t t = 0; t < tdc_handle->size(); t++) { - const uint64_t tdc_timestamp = tdc_handle->at(t).Timestamp(); // Timestamp of the signal [ns]. - const uint32_t tdc_channel = tdc_handle->at(t).Channel(); // Hardware channel. - - if (fdebug_tdc_handle) { - const std::string tdc_name = tdc_handle->at(t).Name(); // Name of channel input. - const uint64_t tdc_offset = tdc_handle->at(t).Offset(); // Channel specific offset [ns]. - std::cout << "\n\t\t\t " << tdc_channel << " \t\t\t" << tdc_name.c_str() - << "\t\t" << print_timestamp(tdc_timestamp) - << "\t\t " << tdc_offset; - } - - // Gets the closest ETRIG timestamp to the raw timestamp and counts the number of ETRIG and FTRIG. - if (tdc_channel == fspectdc_etrig_ch) { - num_event_triggers++; - - //uint64_t diff = (tdc_timestamp < corr_raw_timestamp) ? (corr_raw_timestamp - tdc_timestamp) : (tdc_timestamp - corr_raw_timestamp); - uint64_t diff = abs_difference(tdc_timestamp, corr_raw_timestamp); - if (diff < min_diff) { - min_diff = diff; - closest_tdc_timestamp = tdc_timestamp; - } - - if (fdebug_tdc_handle) std::cout << "\t\t" << diff << " ns away from the raw timestamp."; - - } else if (tdc_channel == fspectdc_ftrig_ch) { - num_flash_triggers++; - } - - } // End SPEC-TDC products extraction loop. - - if (fdebug_tdc_handle) { - std::cout << "\n\tNumber of event triggers (ETRIG): " << num_event_triggers << "." << std::endl; - std::cout << "\tNumber of flash triggers (FTRIG): " << num_flash_triggers << "." << std::endl; - if (closest_tdc_timestamp) { - std::cout << "\n\tClosest ETRIG timestamp to the raw timestamp: " << print_timestamp(closest_tdc_timestamp) << " with a difference of " << min_diff << " ns." << std::endl; - } else { - std::cout << "\n\tNo ETRIG timestamps found." << std::endl; - } - } - - // Checks if the closest ETRIG timestamp is close enough to the raw timestamp. - if (min_diff > fraw_trig_max_diff) { - closest_tdc_timestamp = 0; - } else { - ett_found = true; - timestamp = closest_tdc_timestamp; - } - } - - tdc_handle.removeProduct(); - return ett_found; -} - -/** - * @brief Searches for the PTB HLT timestamp closest to the raw timestamp if any PTB HLT product is found in the event. - * @param[in] e The event to be processed. - * @param[in] corr_raw_timestamp The corrected raw timestamp from the artdaq::RawEventHeader product. - * @param[in,out] timestamp The closest HLT timestamp to the raw timestamp (if found). - * @param[in,out] hlt_code The code of the closest HL trigger to the raw timestamp (if found). - * @return A boolean indicating if a valid HLT timestamp was found close enough to the raw timestamp. - * @details It searches for the PTB products in the event and looks for the HLT timestamps allowed in the fallowed_hl_triggers - * list. If any HLT timestamp is found, it checks which one is the closest to the raw timestamp and if it is close enough - * (i.e. within fraw_trig_max_diff) it returns it as output along with its trigger code. - */ -bool sbndaq::SBNDXARAPUCADecoder::get_ptb_hlt_timestamp(art::Event& e, uint64_t corr_raw_timestamp, uint64_t& timestamp, uint16_t& hlt_code) { - bool hlt_found = false; - - art::Handle > ptb_handle; - e.getByLabel(fptb_product_name, ptb_handle); - - if (fverbose | fdebug_ptb_handle) std::cout << "\n > SBNDXARAPUCADecoder::get_ptb_hlt_timestamp: PTB timing frame selected. Searching for PTB products..." << std::endl; - - // The art::Handle object is not valid. - if (!ptb_handle.isValid()) { - if (fdebug_ptb_handle) std::cout << "\n\tPTB handle not valid for " << fptb_product_name << "." << std::endl; - - // The art::Handle object is empty. - } else if (ptb_handle->empty()) { - if (fdebug_ptb_handle) std::cout << "\n\tPTB handle is empty." << std::endl; - - // The art::Handle object is valid and not empty. - } else { - if (fdebug_ptb_handle) std::cout << " \n\tDecoded PTB products found: " << ptb_handle->size() << " products."; - - uint64_t min_diff = std::numeric_limits::max(); - uint64_t closest_ptb_timestamp = 0; - uint16_t hlt_type = HLT_NOT_FOUND; - - // Loops over the PTB products in the event. - for (size_t i = 0; i < ptb_handle->size(); i++) { - std::vector hlt_triggers = ptb_handle->at(i).GetHLTriggers(); - - if (!hlt_triggers.empty()) { - if (fdebug_ptb_handle) std::cout << "\n\t\t Number of HL triggers: " << hlt_triggers.size() << "." << std::endl; - - // Loops over the HL triggers in the PTB product. - for (size_t j = 0; j < hlt_triggers.size(); j++) { - raw::ptb::Trigger hlt_trig = hlt_triggers.at(j); - uint64_t raw_ptb_timestamp = hlt_trig.timestamp; - uint64_t ptb_timestamp = raw_ptb_timestamp * 20; - std::bitset<32> hlt_word_bitset = std::bitset<32>(hlt_trig.trigger_word); - - if (fdebug_ptb_handle) { - std::cout << "\t\t\t HLT " << j << ": "; - std::cout << "Timestamp: " << print_timestamp(ptb_timestamp); - std::cout << "\t\tTrigger word: [" << hlt_word_bitset << "]"; - } - - uint32_t allowed_hlt = 0; // Random trigger code. In this case it is used as flag to check if an allowed HLT trigger is found. - // Loops over the allowed HL triggers. - for (size_t k = 0; k < fallowed_hl_triggers.size(); k++) { - if (hlt_word_bitset[fallowed_hl_triggers[k]]) { - allowed_hlt = fallowed_hl_triggers[k]; - uint64_t diff = abs_difference(ptb_timestamp, corr_raw_timestamp); - if (diff < min_diff) { - min_diff = diff; - closest_ptb_timestamp = ptb_timestamp; - hlt_type = allowed_hlt; - } - if (fdebug_ptb_handle) std::cout << " - Allowed HLT: " << allowed_hlt << " - " << diff << " ns away from the raw timestamp." << std::endl; - } - } - if ((fdebug_ptb_handle) && !allowed_hlt) std::cout << std::endl; - } - - } else { - if (fdebug_ptb_handle) std::cout << "\n\t\t No allowed HL triggers found." << std::endl; - } - } // End PTB products extraction loop. - - if (fdebug_ptb_handle) { - if (closest_ptb_timestamp) { - std::cout << "\n\t Closest HLT trigger to the raw timestamp: " << print_timestamp(closest_ptb_timestamp) << " - HLT type: " << hlt_type << ". With a difference of " << min_diff << " ns." << std::endl; - } else { - std::cout << "\n\t No allowed HL triggers found." << std::endl; - } - } - - // Checks if the closest HLT timestamp is close enough to the raw timestamp. - if (min_diff > fraw_trig_max_diff) { - closest_ptb_timestamp = 0; - hlt_code = HLT_TOO_FAR; - } else { - hlt_found = true; - timestamp = closest_ptb_timestamp; - hlt_code = hlt_type; - } - - } - - ptb_handle.removeProduct(); - return hlt_found; -} - /** * @brief Searches for the frameshift timestamp in the event if any frameshift product is found and returns it as a TimingReferenceInfo object. * @param[in] e The event to be processed. @@ -1208,7 +910,7 @@ void sbndaq::SBNDXARAPUCADecoder::save_prod_wvfm(size_t board_idx, size_t ch, do * * @details * The function generates a histogram with: - * - X-axis representing time in microseconds if the timing frame is SPEC_TDC_TIMING or PTB_TIMING, otherwise in samples. + * - X-axis representing time in microseconds if the timing frame is from the FRAMESHIFT reference, otherwise in samples. * - Y-axis representing ADC counts. * The histogram is stored using ROOT's `TFileService`. * @@ -1224,11 +926,9 @@ void sbndaq::SBNDXARAPUCADecoder::save_debug_wvfm(size_t board_idx, size_t fragm if (factive_timing_frame != CAEN_ONLY_TIMING) { TH1I* hist = tfs->make(hist_name.str().c_str(), hist_name.str().c_str(), wvfms[ch].size(), ini_wvfm_timestamp, end_wvfm_timestamp); hist->GetYaxis()->SetTitle("ADCs"); - if (factive_timing_frame == SPEC_TDC_TIMING) { - hist->GetXaxis()->SetTitle("Time w.r.t. ETRIG (SPEC-TDC) [us]"); - } else if (factive_timing_frame == PTB_TIMING) { - hist->GetXaxis()->SetTitle("Time w.r.t. HLT ETRIG (PTB) [us]"); - } + if (factive_timing_frame == FRAMESHIFT_TIMING) { + hist->GetXaxis()->SetTitle("Time w.r.t. Frameshift reference [us]"); + } for (size_t i = 0; i < wvfms[ch].size(); i++) { hist->SetBinContent(i+1, wvfms[ch][i]); } @@ -1252,7 +952,7 @@ void sbndaq::SBNDXARAPUCADecoder::save_debug_wvfm(size_t board_idx, size_t fragm * @return The signed difference between the two timestamps (t1 - t2) in nanoseconds. * @pre The timestamp is given in nanoseconds and the maximum value is less than 2^63 ns. */ -int64_t sbndaq::SBNDXARAPUCADecoder::signed_difference(uint64_t t1, uint64_t t2) { +int64_t sbndaq::SBNDXARAPUCADecoder::signed_difference_UTC_timestamp(uint64_t t1, uint64_t t2) { int64_t signed_diff = 0; if (t2 < t1) { diff --git a/sbndcode/Decoders/XARAPUCA/run_xarapucadecoder.fcl b/sbndcode/Decoders/XARAPUCA/run_xarapucadecoder.fcl index 13d9a860a..8f89b66d6 100644 --- a/sbndcode/Decoders/XARAPUCA/run_xarapucadecoder.fcl +++ b/sbndcode/Decoders/XARAPUCA/run_xarapucadecoder.fcl @@ -1,6 +1,4 @@ #include "xarapucadecoder.fcl" -#include "spectdc_decoder_sbnd.fcl" -#include "SBNDPTBDecoderDefaults.fcl" #include "frameshift_sbnd_data.fcl" process_name: XARAPUCADecoder @@ -25,8 +23,6 @@ outputs: { physics: { producers: { - tdcdecoder: @local::spec_tdc_decoder_sbnd - ptbdecoder: @local::SBNDPTBDecoderDefaults frameshift: @local::frameshift_data xarapucadecoder: @local::xarapucadecoder } @@ -36,7 +32,7 @@ physics: { analyzers:{} - reco: [tdcdecoder, ptbdecoder, frameshift, xarapucadecoder] + reco: [frameshift, xarapucadecoder] # Defines the output stream, there could be more than one if using filters. diff --git a/sbndcode/Decoders/XARAPUCA/xarapucadecoder.fcl b/sbndcode/Decoders/XARAPUCA/xarapucadecoder.fcl index 208e5ed9f..508cd9ee7 100644 --- a/sbndcode/Decoders/XARAPUCA/xarapucadecoder.fcl +++ b/sbndcode/Decoders/XARAPUCA/xarapucadecoder.fcl @@ -14,20 +14,7 @@ xarapucadecoder: fragment_id_offset: 41216 # Offset to be applied to the fragment IDs (0xA100). board_id_list: [7, 13, 16, 19] # Slots where the boards are installed. # - Timing configuration. - frameshift_mode: false # FrameShift mode (false: use timing priority, true: use FrameShift timestamp as reference). - timing_priority: 0 # 0 SPEC-TDC ETRIG, 1 PTB HLT (1-5, 14,15), 2 CAEN-only. ns_per_sample: 16 # Nanoseconds per sample. - # - RAW timestamp configuration: - raw_event_header_product_name: "daq" # Label identifying the module that created the artdaq::detail::RawEventHeader data product. - raw_trig_max_diff: 3000000 # Maximum difference (in ns) allowed between trigger timestamps and raw timestamp. - raw_timestamp_correction: 367000 # Correction (in ns) to be applied to the raw timestamp. - # - SPEC-TDC access configuration - spectdc_product_name: "tdcdecoder" # Name for getting SPEC-TDC Decoder products (if any). - spectdc_ftrig_ch: 3 # Channel assigned to flash triggers. - spectdc_etrig_ch: 2#4 # Channel assigned to ETT (Event Trigger Timestamp) triggers. - # - PTB access configuration - ptb_product_name: "ptbdecoder" # Name for getting PTB Decoder products (if any). - allowed_hl_triggers: [1, 2, 3, 4, 5, 14, 15] # List of allowed HLT trigger types (1-5, 14, 15). # - FrameShift access configuration frameshift_product_name: "frameshift" # Name for getting FrameShift module products (if any). @@ -35,16 +22,14 @@ xarapucadecoder: # - Output data product instance name. waveforms_instance_name: "XARAPUCAChannels" # Name for the instance product containing the raw decoded waveforms. timing_ref_instance_name: "" # Name for the instance product containing the timing reference information. - store_debug_waveforms: 0 # Number of waveforms to store (0: none, -1: all, n: first n waveforms). + store_debug_waveforms: 2 # Number of waveforms to store (0: none, -1: all, n: first n waveforms). # Combination of extended fragments. - combine_ext_frag: false # (De)activates the combination of extended fragments into a single raw::OpDetWaveform object. + combine_ext_frag: true # (De)activates the combination of extended fragments into a single raw::OpDetWaveform object. allowed_jittering: 64 # Allowed jittering (in ns) between fragments to be combined. # - Debug options. - debug_tdc_handle: false # (De)activates SPEC-TDC art::Handle information printing. - debug_frameshift_handle: true # (De)activates FrameShift art::Handle information printing. - debug_ptb_handle: false # (De)activates PTB art::Handle information printing. + debug_frameshift_handle: true # (De)activates FrameShift art::Handle information printing. debug_fragments_handle: false # (De)activates V1740B CAEN fragments art::Handle information printing. - debug_timing: true # (De)activates timing data printing. + debug_timing: true # (De)activates timing data printing. debug_buffer: false # (De)activates buffer status printing. debug_waveforms: false # (De)activates waveforms decoding printing. debug_extended_fragments: false # (De)activates extended fragments information printing. From d0c37f836eb99b8684957bbcaa18a1a0a947450f Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Alicia=20V=C3=A1zquez-Ramos?= Date: Fri, 13 Feb 2026 11:07:32 -0600 Subject: [PATCH 17/18] fix(debug): fix last sample time of the waveforms shown in the decoder_hist output --- .../XARAPUCA/SBNDXARAPUCADecoder_module.cc | 45 ++++++++++++------- .../Decoders/XARAPUCA/xarapucadecoder.fcl | 2 +- 2 files changed, 29 insertions(+), 18 deletions(-) diff --git a/sbndcode/Decoders/XARAPUCA/SBNDXARAPUCADecoder_module.cc b/sbndcode/Decoders/XARAPUCA/SBNDXARAPUCADecoder_module.cc index cdac59958..ce1066dda 100644 --- a/sbndcode/Decoders/XARAPUCA/SBNDXARAPUCADecoder_module.cc +++ b/sbndcode/Decoders/XARAPUCA/SBNDXARAPUCADecoder_module.cc @@ -125,10 +125,10 @@ class sbndaq::SBNDXARAPUCADecoder : public art::EDProducer { bool fverbose; /**< If `true` it increases verbosity of console output for detailed processing steps. */ // Main processing method. - void decode_fragment(uint64_t timestamp, uint64_t& first_frag_timestamp, size_t& first_frag_idx, int32_t& first_TTT, int32_t& prev_TTT, std::vector & fragment_indices, const artdaq::Fragment& fragment, std::vector & prod_wvfms, std::vector>& wvfms, bool last_one); + void decode_fragment(uint64_t timestamp, uint64_t& first_frag_timestamp, size_t& first_frag_idx, int32_t& first_TTT, int32_t& prev_TTT, std::vector & fragment_indices, const artdaq::Fragment& fragment, std::vector & prod_wvfms, std::vector>& wvfms, bool last_one, size_t& appended_samples); // Timing. - void shift_time(uint64_t TTT_ticks, int64_t TTT_end_ns, uint64_t frag_timestamp, uint64_t timestamp, uint32_t num_samples_per_wvfm, double& ini_wvfm_timestamp, double& end_wvfm_timestamp); + void shift_time(uint64_t TTT_ticks, int64_t TTT_end_ns, uint64_t frag_timestamp, uint64_t timestamp, uint32_t num_samples_per_wvfm, double& ini_wvfm_timestamp, double& end_wvfm_timestamp, size_t& appended_samples); std::unique_ptr get_frameshift_timestamp(art::Event& e, uint64_t& timestamp); // Waveforms decoding. @@ -257,6 +257,7 @@ void sbndaq::SBNDXARAPUCADecoder::produce(art::Event& e) { std::cout << " Waveforms size: " << wvfms.size() << std::endl; } + size_t appended_samples = 0; size_t first_frag_idx = 0; int32_t first_TTT = TTT_DEFAULT; int32_t prev_TTT = 0; @@ -300,7 +301,7 @@ void sbndaq::SBNDXARAPUCADecoder::produce(art::Event& e) { for (size_t f = 0; f < num_caen_fragments; f++) { const artdaq::Fragment fragment = *container_fragment[f].get(); last_one = f == (num_caen_fragments - 1); - decode_fragment(timestamp, first_frag_timestamp, first_frag_idx, first_TTT, prev_TTT, fragment_indices, fragment, *prod_wvfms, wvfms, last_one); + decode_fragment(timestamp, first_frag_timestamp, first_frag_idx, first_TTT, prev_TTT, fragment_indices, fragment, *prod_wvfms, wvfms, last_one, appended_samples); } // End CAEN V1740 fragments loop. } } // End Container fragments loop. @@ -313,7 +314,7 @@ void sbndaq::SBNDXARAPUCADecoder::produce(art::Event& e) { for (size_t f = 0; f < frag_handle_size; f++) { const artdaq::Fragment fragment = fragment_handle->at(f); last_one = f == (frag_handle_size - 1); - decode_fragment(timestamp, first_frag_timestamp, first_frag_idx, first_TTT, prev_TTT, fragment_indices, fragment, *prod_wvfms, wvfms, last_one); + decode_fragment(timestamp, first_frag_timestamp, first_frag_idx, first_TTT, prev_TTT, fragment_indices, fragment, *prod_wvfms, wvfms, last_one, appended_samples); } // End CAEN V1740 fragments loop. } } // End extracting CAEN V1740 fragments. @@ -366,7 +367,7 @@ void sbndaq::SBNDXARAPUCADecoder::produce(art::Event& e) { * @see dump_waveforms */ -void sbndaq::SBNDXARAPUCADecoder::decode_fragment(uint64_t timestamp, uint64_t& first_frag_timestamp, size_t& first_frag_idx, int32_t& first_TTT, int32_t& prev_TTT, std::vector & fragment_indices, const artdaq::Fragment& fragment, std::vector & prod_wvfms, std::vector>& wvfms, bool last_one) { +void sbndaq::SBNDXARAPUCADecoder::decode_fragment(uint64_t timestamp, uint64_t& first_frag_timestamp, size_t& first_frag_idx, int32_t& first_TTT, int32_t& prev_TTT, std::vector & fragment_indices, const artdaq::Fragment& fragment, std::vector & prod_wvfms, std::vector>& wvfms, bool last_one, size_t& appended_samples) { auto fragment_id = fragment.fragmentID() - ffragment_id_offset; auto it = std::find(fboard_id_list.begin(), fboard_id_list.end(), fragment_id); size_t board_idx; @@ -481,7 +482,7 @@ void sbndaq::SBNDXARAPUCADecoder::decode_fragment(uint64_t timestamp, uint64_t& } if (dump_comb_wvfms) { - shift_time(TTT_ticks, first_TTT, first_frag_timestamp, timestamp, num_nominal_samples_per_wvfm, ini_wvfm_timestamp, end_wvfm_timestamp); + shift_time(TTT_ticks, first_TTT, first_frag_timestamp, timestamp, num_nominal_samples_per_wvfm, ini_wvfm_timestamp, end_wvfm_timestamp, appended_samples); dump_waveforms(prod_wvfms, wvfms, first_frag_idx, board_idx, num_channels, ini_wvfm_timestamp, end_wvfm_timestamp); first_frag_idx = fragment_indices[board_idx]; first_TTT = TTT_end_ns; @@ -491,10 +492,12 @@ void sbndaq::SBNDXARAPUCADecoder::decode_fragment(uint64_t timestamp, uint64_t& if (fdebug_jittering) std::cout << "C - "; } append_waveforms(wvfms, fragment_wvfms, num_channels); - + appended_samples = wvfms[0].size() - num_nominal_samples_per_wvfm; + std::cout << "APPENDED_SAMPLES = " << appended_samples << std::endl; + if (last_one) { if (fdebug_extended_fragments) std::cout << "\t\t LAST fragment " << std::endl; - shift_time(TTT_ticks, first_TTT, first_frag_timestamp, timestamp, num_nominal_samples_per_wvfm, ini_wvfm_timestamp, end_wvfm_timestamp); + shift_time(TTT_ticks, first_TTT, first_frag_timestamp, timestamp, num_nominal_samples_per_wvfm, ini_wvfm_timestamp, end_wvfm_timestamp, appended_samples); dump_waveforms(prod_wvfms, wvfms, first_frag_idx, board_idx, num_channels, ini_wvfm_timestamp, end_wvfm_timestamp); } @@ -523,7 +526,7 @@ void sbndaq::SBNDXARAPUCADecoder::decode_fragment(uint64_t timestamp, uint64_t& } else { // Combination of extended fragments disabled. first_frag_idx = fragment_indices[board_idx]; - shift_time(TTT_ticks, TTT_end_ns, frag_timestamp, timestamp, num_samples_per_wvfm, ini_wvfm_timestamp, end_wvfm_timestamp); + shift_time(TTT_ticks, TTT_end_ns, frag_timestamp, timestamp, num_samples_per_wvfm, ini_wvfm_timestamp, end_wvfm_timestamp, appended_samples); dump_waveforms(prod_wvfms, fragment_wvfms, first_frag_idx, board_idx, num_channels, ini_wvfm_timestamp, end_wvfm_timestamp); } } @@ -549,7 +552,7 @@ void sbndaq::SBNDXARAPUCADecoder::decode_fragment(uint64_t timestamp, uint64_t& * FRAMESHIFT and CAEN-only timing. The calculated timestamps are returned in microseconds. * */ -void sbndaq::SBNDXARAPUCADecoder::shift_time(uint64_t TTT_ticks, int64_t TTT_end_ns, uint64_t frag_timestamp, uint64_t timestamp, uint32_t num_samples_per_wvfm, double& ini_wvfm_timestamp, double& end_wvfm_timestamp) { +void sbndaq::SBNDXARAPUCADecoder::shift_time(uint64_t TTT_ticks, int64_t TTT_end_ns, uint64_t frag_timestamp, uint64_t timestamp, uint32_t num_samples_per_wvfm, double& ini_wvfm_timestamp, double& end_wvfm_timestamp, size_t& appended_samples) { int64_t pulse_duration_ns = num_samples_per_wvfm * fns_per_sample; // ns. int64_t frag_timestamp_s = frag_timestamp / NANOSEC_IN_SEC; // s. @@ -566,20 +569,28 @@ void sbndaq::SBNDXARAPUCADecoder::shift_time(uint64_t TTT_ticks, int64_t TTT_end } int64_t ref_timestamp = 0; + int64_t appended_ns = static_cast(appended_samples) * static_cast(fns_per_sample); // this is just for the debug output. // If an frameshift timestamp was found it restarts the time from it. Otherwise the CAEN time frame is assigned. + std::cout << " NUM SAMPLES PER WVFM = " << num_samples_per_wvfm << std::endl; + std::cout << " APPENDED WAVEFORM SAMPLES = " << appended_samples << std::endl; if (factive_timing_frame != CAEN_ONLY_TIMING) { ref_timestamp = signed_difference_UTC_timestamp(TTT_UNIX_timestamp, timestamp); // ns. - + std::cout << " REF TIMESTAMP: " << ref_timestamp << std::endl; ini_wvfm_timestamp = (ref_timestamp - pulse_duration_ns) * NANOSEC_TO_MICROSEC; // us. - end_wvfm_timestamp = ref_timestamp * NANOSEC_TO_MICROSEC; // us. + std::cout << " END TIMESTAMP: " << end_wvfm_timestamp << std::endl; + std::cout << "appended_samples * fns_per_sample = " << appended_samples * fns_per_sample << std::endl; + end_wvfm_timestamp = (ref_timestamp + appended_ns) * NANOSEC_TO_MICROSEC; // us. + std::cout << " END TIMESTAMP: " << end_wvfm_timestamp << std::endl; } else { ref_timestamp = TTT_UNIX_timestamp; // ns. ini_wvfm_timestamp = ((ref_timestamp - pulse_duration_ns) % NANOSEC_IN_SEC) * NANOSEC_TO_MICROSEC; // ns. - end_wvfm_timestamp = (ref_timestamp % NANOSEC_IN_SEC) * NANOSEC_TO_MICROSEC; // us. + end_wvfm_timestamp = ((ref_timestamp + appended_ns)% NANOSEC_IN_SEC) * NANOSEC_TO_MICROSEC; // us. } - + appended_samples = 0; + std::cout << " NUM SAMPLES PER WVFM = " << num_samples_per_wvfm << std::endl; + std::cout << " APPENDED WAVEFORM SAMPLES = " << appended_samples << std::endl; if (fdebug_timing) { std::cout << std::fixed << std::setprecision(0); std::cout << "\t\t ns/tick = " << NANOSEC_PER_TICK << ", ns/sample = " << fns_per_sample << std::endl; @@ -800,9 +811,9 @@ void sbndaq::SBNDXARAPUCADecoder::append_waveforms(std::vector Date: Fri, 13 Feb 2026 11:29:01 -0600 Subject: [PATCH 18/18] chore(cleaning): Clean output and restore to default configuration (combine fragments and no debug outpout) --- .../Decoders/XARAPUCA/SBNDXARAPUCADecoder_module.cc | 11 +---------- sbndcode/Decoders/XARAPUCA/xarapucadecoder.fcl | 10 +++++----- 2 files changed, 6 insertions(+), 15 deletions(-) diff --git a/sbndcode/Decoders/XARAPUCA/SBNDXARAPUCADecoder_module.cc b/sbndcode/Decoders/XARAPUCA/SBNDXARAPUCADecoder_module.cc index ce1066dda..844b5f6de 100644 --- a/sbndcode/Decoders/XARAPUCA/SBNDXARAPUCADecoder_module.cc +++ b/sbndcode/Decoders/XARAPUCA/SBNDXARAPUCADecoder_module.cc @@ -13,7 +13,7 @@ * the SBN Document 43891-v1 in the SBN Document Database. * @note A Python version of the binary decoding is available for testing purposes. You can find * it [here: V1740 binary decoder](https://github.com/aliciavr/V1740_binary_decoder). - * @version 4.0 + * @version 5.0 */ #include "art/Framework/Core/EDProducer.h" @@ -493,7 +493,6 @@ void sbndaq::SBNDXARAPUCADecoder::decode_fragment(uint64_t timestamp, uint64_t& } append_waveforms(wvfms, fragment_wvfms, num_channels); appended_samples = wvfms[0].size() - num_nominal_samples_per_wvfm; - std::cout << "APPENDED_SAMPLES = " << appended_samples << std::endl; if (last_one) { if (fdebug_extended_fragments) std::cout << "\t\t LAST fragment " << std::endl; @@ -572,16 +571,10 @@ void sbndaq::SBNDXARAPUCADecoder::shift_time(uint64_t TTT_ticks, int64_t TTT_end int64_t appended_ns = static_cast(appended_samples) * static_cast(fns_per_sample); // this is just for the debug output. // If an frameshift timestamp was found it restarts the time from it. Otherwise the CAEN time frame is assigned. - std::cout << " NUM SAMPLES PER WVFM = " << num_samples_per_wvfm << std::endl; - std::cout << " APPENDED WAVEFORM SAMPLES = " << appended_samples << std::endl; if (factive_timing_frame != CAEN_ONLY_TIMING) { ref_timestamp = signed_difference_UTC_timestamp(TTT_UNIX_timestamp, timestamp); // ns. - std::cout << " REF TIMESTAMP: " << ref_timestamp << std::endl; ini_wvfm_timestamp = (ref_timestamp - pulse_duration_ns) * NANOSEC_TO_MICROSEC; // us. - std::cout << " END TIMESTAMP: " << end_wvfm_timestamp << std::endl; - std::cout << "appended_samples * fns_per_sample = " << appended_samples * fns_per_sample << std::endl; end_wvfm_timestamp = (ref_timestamp + appended_ns) * NANOSEC_TO_MICROSEC; // us. - std::cout << " END TIMESTAMP: " << end_wvfm_timestamp << std::endl; } else { ref_timestamp = TTT_UNIX_timestamp; // ns. @@ -589,8 +582,6 @@ void sbndaq::SBNDXARAPUCADecoder::shift_time(uint64_t TTT_ticks, int64_t TTT_end end_wvfm_timestamp = ((ref_timestamp + appended_ns)% NANOSEC_IN_SEC) * NANOSEC_TO_MICROSEC; // us. } appended_samples = 0; - std::cout << " NUM SAMPLES PER WVFM = " << num_samples_per_wvfm << std::endl; - std::cout << " APPENDED WAVEFORM SAMPLES = " << appended_samples << std::endl; if (fdebug_timing) { std::cout << std::fixed << std::setprecision(0); std::cout << "\t\t ns/tick = " << NANOSEC_PER_TICK << ", ns/sample = " << fns_per_sample << std::endl; diff --git a/sbndcode/Decoders/XARAPUCA/xarapucadecoder.fcl b/sbndcode/Decoders/XARAPUCA/xarapucadecoder.fcl index 376e292f9..0351ba27f 100644 --- a/sbndcode/Decoders/XARAPUCA/xarapucadecoder.fcl +++ b/sbndcode/Decoders/XARAPUCA/xarapucadecoder.fcl @@ -22,20 +22,20 @@ xarapucadecoder: # - Output data product instance name. waveforms_instance_name: "XARAPUCAChannels" # Name for the instance product containing the raw decoded waveforms. timing_ref_instance_name: "" # Name for the instance product containing the timing reference information. - store_debug_waveforms: 1 # Number of waveforms to store (0: none, -1: all, n: first n waveforms). + store_debug_waveforms: 0 # Number of waveforms to store (0: none, -1: all, n: first n waveforms). # Combination of extended fragments. - combine_ext_frag: true # (De)activates the combination of extended fragments into a single raw::OpDetWaveform object. + combine_ext_frag: true # (De)activates the combination of extended fragments into a single raw::OpDetWaveform object. allowed_jittering: 64 # Allowed jittering (in ns) between fragments to be combined. # - Debug options. - debug_frameshift_handle: true # (De)activates FrameShift art::Handle information printing. + debug_frameshift_handle: false # (De)activates FrameShift art::Handle information printing. debug_fragments_handle: false # (De)activates V1740B CAEN fragments art::Handle information printing. - debug_timing: true # (De)activates timing data printing. + debug_timing: false # (De)activates timing data printing. debug_buffer: false # (De)activates buffer status printing. debug_waveforms: false # (De)activates waveforms decoding printing. debug_extended_fragments: false # (De)activates extended fragments information printing. debug_jittering: false # (De)activates trigger jittering information printing. # - Verbose option. - verbose: true # (De)activates verbosity. + verbose: false # (De)activates verbosity. } END_PROLOG \ No newline at end of file