From 3df4f3ebfa3255535eeda4efae9e61e7d3ceef61 Mon Sep 17 00:00:00 2001 From: manuel Date: Fri, 17 Apr 2026 16:36:11 +0200 Subject: [PATCH] Expose DAPHNE ETH peak descriptor arrays --- pybindsrc/DAPHNEEthUnpacker.cpp | 294 +++++++++++++++++++------------- pybindsrc/unpack.cpp | 53 ++++-- 2 files changed, 215 insertions(+), 132 deletions(-) diff --git a/pybindsrc/DAPHNEEthUnpacker.cpp b/pybindsrc/DAPHNEEthUnpacker.cpp index 4b4a51a..65f9f66 100644 --- a/pybindsrc/DAPHNEEthUnpacker.cpp +++ b/pybindsrc/DAPHNEEthUnpacker.cpp @@ -1,5 +1,5 @@ /** - * @file DAPHNEEthUnpacker.cc Fast C++ -> numpy DAPHNE format unpacker + * @file DAPHNEEthUnpacker.cc Fast C++ -> numpy DAPHNE Ethernet unpacker * * This is part of the DUNE DAQ , copyright 2020. * Licensing/copyright details are in the COPYING file that you should have @@ -16,56 +16,40 @@ namespace py = pybind11; namespace dunedaq::rawdatautils::daphneeth { -/** - * @brief Gets number of DAPHNEFrames in a fragment - */ -uint32_t get_n_frames(daqdataformats::Fragment const& frag){ +uint32_t get_n_frames(daqdataformats::Fragment const& frag) +{ return (frag.get_size() - sizeof(daqdataformats::FragmentHeader)) / sizeof(fddetdataformats::DAPHNEEthFrame); } -/** - * @brief Gets number of DAPHNEStreamFrames in a fragment - */ -uint32_t get_n_frames_stream(daqdataformats::Fragment const& frag){ +uint32_t get_n_frames_stream(daqdataformats::Fragment const& frag) +{ return (frag.get_size() - sizeof(daqdataformats::FragmentHeader)) / sizeof(fddetdataformats::DAPHNEEthStreamFrame); } - -/** - * @brief Unpacks channel numbers for DAPHNEEthStreamFrames into a numpy array with dimensions - * (nframes, s_channels_per_frame) - */ - -py::array_t np_array_channels_stream_data(void* data, int nframes){ - - const auto channels_per_daphne = fddetdataformats::DAPHNEEthStreamFrame::s_num_channels; +py::array_t np_array_channels_stream_data(void* data, int nframes) +{ + const auto channels_per_daphne = fddetdataformats::DAPHNEEthStreamFrame::s_num_channels; py::array_t channels(channels_per_daphne * nframes); auto ptr = static_cast(channels.request().ptr); - for (size_t i=0; i<(size_t)nframes; ++i) { + for (size_t i = 0; i < static_cast(nframes); ++i) { auto fr = reinterpret_cast(static_cast(data) + i * sizeof(fddetdataformats::DAPHNEEthStreamFrame)); + ptr[i * channels_per_daphne + 0] = fr->get_channel0(); + ptr[i * channels_per_daphne + 1] = fr->get_channel1(); + ptr[i * channels_per_daphne + 2] = fr->get_channel2(); + ptr[i * channels_per_daphne + 3] = fr->get_channel3(); + } - ptr[i*channels_per_daphne + 0] = fr->get_channel0(); - ptr[i*channels_per_daphne + 1] = fr->get_channel1(); - ptr[i*channels_per_daphne + 2] = fr->get_channel2(); - ptr[i*channels_per_daphne + 3] = fr->get_channel3(); - - } channels.resize({nframes, channels_per_daphne}); - - return channels; + return channels; } -/** - * @brief Unpacks channel numbers for DAPHNEFrames into a numpy array with dimensions - * (nframes) - */ -py::array_t np_array_channels_data(void* data, int nframes){ - +py::array_t np_array_channels_data(void* data, int nframes) +{ py::array_t channels(nframes); auto ptr = static_cast(channels.request().ptr); - for (size_t i=0; i<(size_t)nframes; ++i) { + for (size_t i = 0; i < static_cast(nframes); ++i) { auto fr = reinterpret_cast(static_cast(data) + i * sizeof(fddetdataformats::DAPHNEEthFrame)); ptr[i] = fr->get_channel(); } @@ -73,79 +57,56 @@ py::array_t np_array_channels_data(void* data, int nframes){ return channels; } -/** - * @brief Unpacks channel numbers for Fragment that contains DAPHNEFrames into a numpy array with dimensions */ -py::array_t np_array_channels(daqdataformats::Fragment& frag){ +py::array_t np_array_channels(daqdataformats::Fragment& frag) +{ return np_array_channels_data(frag.get_data(), (frag.get_size() - sizeof(daqdataformats::FragmentHeader)) / sizeof(fddetdataformats::DAPHNEEthFrame)); } -/** - * @brief Unpacks channel numbers for Fragment that contains DAPHNEStreamFrames into a numpy array with dimensions - */ -py::array_t np_array_channels_stream(daqdataformats::Fragment& frag){ +py::array_t np_array_channels_stream(daqdataformats::Fragment& frag) +{ return np_array_channels_stream_data(frag.get_data(), (frag.get_size() - sizeof(daqdataformats::FragmentHeader)) / sizeof(fddetdataformats::DAPHNEEthStreamFrame)); } - -/** - * @brief Unpacks data containing DAPHNEFrames into a numpy array with the ADC - * values and dimension (number of DAPHNEFrames, channels_per_daphne) - * Warning: It doesn't check that nframes is a sensible value (can read out of bounds) - */ -py::array_t np_array_adc_data(void* data, int nframes){ - - const auto adcs_per_channel = fddetdataformats::DAPHNEEthFrame::s_num_adcs; +py::array_t np_array_adc_data(void* data, int nframes) +{ + const auto adcs_per_channel = fddetdataformats::DAPHNEEthFrame::s_num_adcs; py::array_t ret(nframes * adcs_per_channel); auto ptr = static_cast(ret.request().ptr); - for (size_t i=0; i<(size_t)nframes; ++i) { + for (size_t i = 0; i < static_cast(nframes); ++i) { auto fr = reinterpret_cast(static_cast(data) + i * sizeof(fddetdataformats::DAPHNEEthFrame)); - for (size_t j=0; jget_adc(j); + for (size_t j = 0; j < adcs_per_channel; ++j) { + ptr[i * adcs_per_channel + j] = fr->get_adc(j); } - //for (size_t j=0; j np_array_adc_stream_data(void* data, int nframes){ - - const auto channels_per_daphne = fddetdataformats::DAPHNEEthStreamFrame::s_num_channels; - const auto adcs_per_channel = fddetdataformats::DAPHNEEthStreamFrame::s_adcs_per_channel; +py::array_t np_array_adc_stream_data(void* data, int nframes) +{ + const auto channels_per_daphne = fddetdataformats::DAPHNEEthStreamFrame::s_num_channels; + const auto adcs_per_channel = fddetdataformats::DAPHNEEthStreamFrame::s_adcs_per_channel; - py::array_t ret(channels_per_daphne * nframes * adcs_per_channel); auto ptr = static_cast(ret.request().ptr); - for (size_t i=0; i<(size_t)nframes; ++i) { + for (size_t i = 0; i < static_cast(nframes); ++i) { auto fr = reinterpret_cast(static_cast(data) + i * sizeof(fddetdataformats::DAPHNEEthStreamFrame)); - for (size_t j=0; jget_adc(j,k); + for (size_t j = 0; j < adcs_per_channel; ++j) { + for (size_t k = 0; k < channels_per_daphne; ++k) { + ptr[channels_per_daphne * (adcs_per_channel * i + j) + k] = fr->get_adc(j, k); + } + } } - ret.resize({nframes*adcs_per_channel, channels_per_daphne}); - + ret.resize({nframes * adcs_per_channel, channels_per_daphne}); return ret; } -/** - * @brief Unpacks data containing DAPHNEFrames into a numpy array with the - * timestamps with dimension (number of DAPHNEFrames) - * Warning: It doesn't check that nframes is a sensible value (can read out of bounds) - */ - -py::array_t np_array_timestamp_data(void* data, int nframes){ - +py::array_t np_array_timestamp_data(void* data, int nframes) +{ py::array_t ret(nframes); auto ptr = static_cast(ret.request().ptr); - for (size_t i=0; i<(size_t)nframes; ++i) { + for (size_t i = 0; i < static_cast(nframes); ++i) { auto fr = reinterpret_cast(static_cast(data) + i * sizeof(fddetdataformats::DAPHNEEthFrame)); ptr[i] = fr->get_timestamp(); } @@ -153,61 +114,164 @@ py::array_t np_array_timestamp_data(void* data, int nframes){ return ret; } -/** - * @brief Unpacks data containing DAPHNEStreamFrames into a numpy array with the - * timestamps with dimension (number of DAPHNEStreamFrames) - * Warning: It doesn't check that nframes is a sensible value (can read out of bounds) - */ -py::array_t np_array_timestamp_stream_data(void* data, int nframes) { - +py::array_t np_array_timestamp_stream_data(void* data, int nframes) +{ const auto adcs_per_channel = fddetdataformats::DAPHNEEthStreamFrame::s_adcs_per_channel; const size_t ticks_per_adc = 1; - py::array_t ret(nframes*adcs_per_channel); - + py::array_t ret(nframes * adcs_per_channel); auto ptr = static_cast(ret.request().ptr); - for (size_t i=0; i<(size_t)nframes; ++i) { + for (size_t i = 0; i < static_cast(nframes); ++i) { auto fr = reinterpret_cast(static_cast(data) + i * sizeof(fddetdataformats::DAPHNEEthStreamFrame)); - for (size_t j=0; jget_timestamp()+j*ticks_per_adc; + for (size_t j = 0; j < adcs_per_channel; ++j) { + ptr[i * adcs_per_channel + j] = fr->get_timestamp() + j * ticks_per_adc; + } } return ret; } +template +py::array_t np_array_peak_field_data(void* data, int nframes, Getter getter) +{ + constexpr int peaks_per_frame = fddetdataformats::DAPHNEEthFrame::PeakDescriptorData::max_peaks; -/** - * @brief Unpacks a Fragment containing DAPHNEFrames into a numpy array with the - * ADC values and dimension (number of DAPHNEFrames in the Fragment, 320) - */ -py::array_t np_array_adc(daqdataformats::Fragment& frag){ + py::array_t ret(nframes * peaks_per_frame); + auto ptr = static_cast(ret.request().ptr); + for (size_t i = 0; i < static_cast(nframes); ++i) { + auto fr = reinterpret_cast(static_cast(data) + i * sizeof(fddetdataformats::DAPHNEEthFrame)); + const auto& peaks = fr->get_peaks_data(); + for (int peak = 0; peak < peaks_per_frame; ++peak) { + ptr[i * peaks_per_frame + peak] = static_cast(getter(peaks, peak)); + } + } + ret.resize({nframes, peaks_per_frame}); + return ret; +} + +py::array_t np_array_peak_found_data(void* data, int nframes) +{ + return np_array_peak_field_data( + data, + nframes, + [](const fddetdataformats::DAPHNEEthFrame::PeakDescriptorData& peaks, int peak) -> uint8_t { + return static_cast(peaks.is_found(peak)); + }); +} + +py::array_t np_array_peak_num_subpeaks_data(void* data, int nframes) +{ + return np_array_peak_field_data( + data, + nframes, + [](const fddetdataformats::DAPHNEEthFrame::PeakDescriptorData& peaks, int peak) -> uint8_t { + return peaks.get_num_subpeaks(peak); + }); +} + +py::array_t np_array_peak_adc_integral_data(void* data, int nframes) +{ + return np_array_peak_field_data( + data, + nframes, + [](const fddetdataformats::DAPHNEEthFrame::PeakDescriptorData& peaks, int peak) -> uint32_t { + return peaks.get_adc_integral(peak); + }); +} + +py::array_t np_array_peak_adc_max_data(void* data, int nframes) +{ + return np_array_peak_field_data( + data, + nframes, + [](const fddetdataformats::DAPHNEEthFrame::PeakDescriptorData& peaks, int peak) -> uint16_t { + return peaks.get_adc_max(peak); + }); +} + +py::array_t np_array_peak_sample_max_data(void* data, int nframes) +{ + return np_array_peak_field_data( + data, + nframes, + [](const fddetdataformats::DAPHNEEthFrame::PeakDescriptorData& peaks, int peak) -> uint16_t { + return peaks.get_sample_max(peak); + }); +} + +py::array_t np_array_peak_samples_over_baseline_data(void* data, int nframes) +{ + return np_array_peak_field_data( + data, + nframes, + [](const fddetdataformats::DAPHNEEthFrame::PeakDescriptorData& peaks, int peak) -> uint16_t { + return peaks.get_samples_over_baseline(peak); + }); +} + +py::array_t np_array_peak_sample_start_data(void* data, int nframes) +{ + return np_array_peak_field_data( + data, + nframes, + [](const fddetdataformats::DAPHNEEthFrame::PeakDescriptorData& peaks, int peak) -> uint16_t { + return peaks.get_sample_start(peak); + }); +} + +py::array_t np_array_adc(daqdataformats::Fragment& frag) +{ return np_array_adc_data(frag.get_data(), (frag.get_size() - sizeof(daqdataformats::FragmentHeader)) / sizeof(fddetdataformats::DAPHNEEthFrame)); } -/** - * @brief Unpacks a Fragment containing DAPHNEStreamFrames into a numpy array with the - * ADC values and dimension (number of DAPHNEStreamFrames in the Fragment, 4) - */ -py::array_t np_array_adc_stream(daqdataformats::Fragment& frag){ +py::array_t np_array_adc_stream(daqdataformats::Fragment& frag) +{ return np_array_adc_stream_data(frag.get_data(), (frag.get_size() - sizeof(daqdataformats::FragmentHeader)) / sizeof(fddetdataformats::DAPHNEEthStreamFrame)); } - -/** - * @brief Unpacks the timestamps in a Fragment containing WIBFrames into a numpy - * array with dimension (number of DAPHNEFrames in the Fragment) - */ -py::array_t np_array_timestamp(daqdataformats::Fragment& frag){ +py::array_t np_array_timestamp(daqdataformats::Fragment& frag) +{ return np_array_timestamp_data(frag.get_data(), (frag.get_size() - sizeof(daqdataformats::FragmentHeader)) / sizeof(fddetdataformats::DAPHNEEthFrame)); } -/** - * @brief Unpacks the timestamps in a Fragment containing DAPHNEStreamFrames into a numpy - * array with dimension (number of DAPHNEStreamFrames in the Fragment) - */ -py::array_t np_array_timestamp_stream(daqdataformats::Fragment& frag){ +py::array_t np_array_timestamp_stream(daqdataformats::Fragment& frag) +{ return np_array_timestamp_stream_data(frag.get_data(), (frag.get_size() - sizeof(daqdataformats::FragmentHeader)) / sizeof(fddetdataformats::DAPHNEEthStreamFrame)); } +py::array_t np_array_peak_found(daqdataformats::Fragment& frag) +{ + return np_array_peak_found_data(frag.get_data(), (frag.get_size() - sizeof(daqdataformats::FragmentHeader)) / sizeof(fddetdataformats::DAPHNEEthFrame)); +} + +py::array_t np_array_peak_num_subpeaks(daqdataformats::Fragment& frag) +{ + return np_array_peak_num_subpeaks_data(frag.get_data(), (frag.get_size() - sizeof(daqdataformats::FragmentHeader)) / sizeof(fddetdataformats::DAPHNEEthFrame)); +} + +py::array_t np_array_peak_adc_integral(daqdataformats::Fragment& frag) +{ + return np_array_peak_adc_integral_data(frag.get_data(), (frag.get_size() - sizeof(daqdataformats::FragmentHeader)) / sizeof(fddetdataformats::DAPHNEEthFrame)); +} + +py::array_t np_array_peak_adc_max(daqdataformats::Fragment& frag) +{ + return np_array_peak_adc_max_data(frag.get_data(), (frag.get_size() - sizeof(daqdataformats::FragmentHeader)) / sizeof(fddetdataformats::DAPHNEEthFrame)); +} + +py::array_t np_array_peak_sample_max(daqdataformats::Fragment& frag) +{ + return np_array_peak_sample_max_data(frag.get_data(), (frag.get_size() - sizeof(daqdataformats::FragmentHeader)) / sizeof(fddetdataformats::DAPHNEEthFrame)); +} + +py::array_t np_array_peak_samples_over_baseline(daqdataformats::Fragment& frag) +{ + return np_array_peak_samples_over_baseline_data(frag.get_data(), (frag.get_size() - sizeof(daqdataformats::FragmentHeader)) / sizeof(fddetdataformats::DAPHNEEthFrame)); +} + +py::array_t np_array_peak_sample_start(daqdataformats::Fragment& frag) +{ + return np_array_peak_sample_start_data(frag.get_data(), (frag.get_size() - sizeof(daqdataformats::FragmentHeader)) / sizeof(fddetdataformats::DAPHNEEthFrame)); +} -} // namespace dunedaq::rawdatautils::daphne // NOLINT +} // namespace dunedaq::rawdatautils::daphneeth diff --git a/pybindsrc/unpack.cpp b/pybindsrc/unpack.cpp index dde4786..ac64260 100644 --- a/pybindsrc/unpack.cpp +++ b/pybindsrc/unpack.cpp @@ -26,17 +26,16 @@ namespace py = pybind11; namespace dunedaq { namespace rawdatautils { -void print_hex_fragment(daqdataformats::Fragment const& frag) { +void print_hex_fragment(daqdataformats::Fragment const& frag) +{ uint64_t* data = static_cast(frag.get_data()); - size_t data_size = (frag.get_size() - sizeof(daqdataformats::FragmentHeader))/8; + size_t data_size = (frag.get_size() - sizeof(daqdataformats::FragmentHeader)) / 8; - for ( size_t i(0); i np_array_adc(daqdataformats::Fragment& frag); extern py::array_t np_array_adc_data(void* data, int nframes); @@ -60,7 +59,6 @@ namespace wibeth { extern py::array_t np_array_timestamp_data(void* data, uint32_t n_frames); } - namespace daphne { extern uint32_t get_n_frames(daqdataformats::Fragment const& frag); extern py::array_t np_array_adc(daqdataformats::Fragment& frag); @@ -77,7 +75,6 @@ namespace daphne { extern py::array_t np_array_timestamp_stream(daqdataformats::Fragment& frag); extern py::array_t np_array_timestamp_stream_data(void* data, int nframes); extern py::array_t np_array_channels_stream_data(void* data, int nframes); - } namespace daphneeth { @@ -88,6 +85,20 @@ namespace daphneeth { extern py::array_t np_array_timestamp(daqdataformats::Fragment& frag); extern py::array_t np_array_timestamp_data(void* data, int nframes); extern py::array_t np_array_channels_data(void* data, int nframes); + extern py::array_t np_array_peak_found(daqdataformats::Fragment& frag); + extern py::array_t np_array_peak_found_data(void* data, int nframes); + extern py::array_t np_array_peak_num_subpeaks(daqdataformats::Fragment& frag); + extern py::array_t np_array_peak_num_subpeaks_data(void* data, int nframes); + extern py::array_t np_array_peak_adc_integral(daqdataformats::Fragment& frag); + extern py::array_t np_array_peak_adc_integral_data(void* data, int nframes); + extern py::array_t np_array_peak_adc_max(daqdataformats::Fragment& frag); + extern py::array_t np_array_peak_adc_max_data(void* data, int nframes); + extern py::array_t np_array_peak_sample_max(daqdataformats::Fragment& frag); + extern py::array_t np_array_peak_sample_max_data(void* data, int nframes); + extern py::array_t np_array_peak_samples_over_baseline(daqdataformats::Fragment& frag); + extern py::array_t np_array_peak_samples_over_baseline_data(void* data, int nframes); + extern py::array_t np_array_peak_sample_start(daqdataformats::Fragment& frag); + extern py::array_t np_array_peak_sample_start_data(void* data, int nframes); extern uint32_t get_n_frames_stream(daqdataformats::Fragment const& frag); extern py::array_t np_array_adc_stream(daqdataformats::Fragment& frag); @@ -96,7 +107,6 @@ namespace daphneeth { extern py::array_t np_array_timestamp_stream(daqdataformats::Fragment& frag); extern py::array_t np_array_timestamp_stream_data(void* data, int nframes); extern py::array_t np_array_channels_stream_data(void* data, int nframes); - } namespace tde { @@ -105,15 +115,13 @@ namespace tde { extern py::array_t np_array_adc_data(void* data, uint32_t n_frames); extern py::array_t np_array_timestamp(daqdataformats::Fragment const& frag); extern py::array_t np_array_timestamp_data(void* data, uint32_t n_frames); - } namespace unpack { namespace python { -void -register_unpack(py::module& m) { - +void register_unpack(py::module& m) +{ m.def("print_hex_fragment", &print_hex_fragment); py::module_ wib_module = m.def_submodule("wib"); @@ -144,7 +152,6 @@ register_unpack(py::module& m) { daphne_module.def("np_array_timestamp_data", &daphne::np_array_timestamp_data); daphne_module.def("np_array_channels_data", &daphne::np_array_channels_data); daphne_module.def("np_array_channels", &daphne::np_array_channels); - daphne_module.def("get_n_frames_stream", &daphne::get_n_frames_stream); daphne_module.def("np_array_adc_stream", &daphne::np_array_adc_stream); daphne_module.def("np_array_timestamp_stream", &daphne::np_array_timestamp_stream); @@ -161,7 +168,20 @@ register_unpack(py::module& m) { daphneeth_module.def("np_array_timestamp_data", &daphneeth::np_array_timestamp_data); daphneeth_module.def("np_array_channels_data", &daphneeth::np_array_channels_data); daphneeth_module.def("np_array_channels", &daphneeth::np_array_channels); - + daphneeth_module.def("np_array_peak_found", &daphneeth::np_array_peak_found); + daphneeth_module.def("np_array_peak_found_data", &daphneeth::np_array_peak_found_data); + daphneeth_module.def("np_array_peak_num_subpeaks", &daphneeth::np_array_peak_num_subpeaks); + daphneeth_module.def("np_array_peak_num_subpeaks_data", &daphneeth::np_array_peak_num_subpeaks_data); + daphneeth_module.def("np_array_peak_adc_integral", &daphneeth::np_array_peak_adc_integral); + daphneeth_module.def("np_array_peak_adc_integral_data", &daphneeth::np_array_peak_adc_integral_data); + daphneeth_module.def("np_array_peak_adc_max", &daphneeth::np_array_peak_adc_max); + daphneeth_module.def("np_array_peak_adc_max_data", &daphneeth::np_array_peak_adc_max_data); + daphneeth_module.def("np_array_peak_sample_max", &daphneeth::np_array_peak_sample_max); + daphneeth_module.def("np_array_peak_sample_max_data", &daphneeth::np_array_peak_sample_max_data); + daphneeth_module.def("np_array_peak_samples_over_baseline", &daphneeth::np_array_peak_samples_over_baseline); + daphneeth_module.def("np_array_peak_samples_over_baseline_data", &daphneeth::np_array_peak_samples_over_baseline_data); + daphneeth_module.def("np_array_peak_sample_start", &daphneeth::np_array_peak_sample_start); + daphneeth_module.def("np_array_peak_sample_start_data", &daphneeth::np_array_peak_sample_start_data); daphneeth_module.def("get_n_frames_stream", &daphneeth::get_n_frames_stream); daphneeth_module.def("np_array_adc_stream", &daphneeth::np_array_adc_stream); daphneeth_module.def("np_array_timestamp_stream", &daphneeth::np_array_timestamp_stream); @@ -169,17 +189,16 @@ register_unpack(py::module& m) { daphneeth_module.def("np_array_timestamp_stream_data", &daphneeth::np_array_timestamp_stream_data); daphneeth_module.def("np_array_channels_stream_data", &daphneeth::np_array_channels_stream_data); daphneeth_module.def("np_array_channels_stream", &daphneeth::np_array_channels_stream); - + py::module_ tde_module = m.def_submodule("tde"); tde_module.def("get_n_frames", &tde::get_n_frames); tde_module.def("np_array_adc", &tde::np_array_adc); tde_module.def("np_array_timestamp", &tde::np_array_timestamp); tde_module.def("np_array_adc_data", &tde::np_array_adc_data); tde_module.def("np_array_timestamp_data", &tde::np_array_timestamp_data); - } } // namespace python +} // namespace unpack } // namespace rawdatautils } // namespace dunedaq -}