From e6ffd2d9b19b30773f5c31ac9d43cbccb347f4c1 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Alicia=20V=C3=A1zquez-Ramos?= Date: Fri, 11 Oct 2024 05:32:10 -0500 Subject: [PATCH 01/19] Starting point for XARAPUCA decoder --- sbndcode/Decoders/CMakeLists.txt | 1 + sbndcode/Decoders/XARAPUCA/CMakeLists.txt | 17 +++++ .../XARAPUCA/SBNDXARAPUCADecoder_module.cc | 62 +++++++++++++++++++ .../Decoders/XARAPUCA/run_xarapucadecoder.fcl | 45 ++++++++++++++ .../Decoders/XARAPUCA/xarapucadecoder.fcl | 8 +++ 5 files changed, 133 insertions(+) create mode 100644 sbndcode/Decoders/XARAPUCA/CMakeLists.txt create mode 100644 sbndcode/Decoders/XARAPUCA/SBNDXARAPUCADecoder_module.cc create mode 100644 sbndcode/Decoders/XARAPUCA/run_xarapucadecoder.fcl create mode 100644 sbndcode/Decoders/XARAPUCA/xarapucadecoder.fcl diff --git a/sbndcode/Decoders/CMakeLists.txt b/sbndcode/Decoders/CMakeLists.txt index 88856ea08..9b68bd0ca 100644 --- a/sbndcode/Decoders/CMakeLists.txt +++ b/sbndcode/Decoders/CMakeLists.txt @@ -3,3 +3,4 @@ add_subdirectory(PTB) add_subdirectory(SPECTDC) add_subdirectory(PMT) add_subdirectory(CRT) +add_subdirectory(XARAPUCA) \ No newline at end of file diff --git a/sbndcode/Decoders/XARAPUCA/CMakeLists.txt b/sbndcode/Decoders/XARAPUCA/CMakeLists.txt new file mode 100644 index 000000000..85458703c --- /dev/null +++ b/sbndcode/Decoders/XARAPUCA/CMakeLists.txt @@ -0,0 +1,17 @@ +art_make( + MODULE_LIBRARIES + sbndaq_artdaq_core::sbndaq-artdaq-core_Overlays_SBND + sbnobj::SBND_Timing + + lardataobj::RecoBase + + art_root_io::TFileService_service + art_root_io::tfile_support + artdaq_core::artdaq-core_Data + + ROOT::Core + ROOT::Tree + +) + +install_fhicl() \ No newline at end of file diff --git a/sbndcode/Decoders/XARAPUCA/SBNDXARAPUCADecoder_module.cc b/sbndcode/Decoders/XARAPUCA/SBNDXARAPUCADecoder_module.cc new file mode 100644 index 000000000..6a3c12337 --- /dev/null +++ b/sbndcode/Decoders/XARAPUCA/SBNDXARAPUCADecoder_module.cc @@ -0,0 +1,62 @@ +//////////////////////////////////////////////////////////////////////// +// Class: SBNDXARAPUCADecoder +// Plugin Type: producer +// File: SBNDXARAPUCADecoder_module.cc +// Author Alicia Vázquez-Ramos (aliciavr@ugr.es) +//////////////////////////////////////////////////////////////////////// + +#include "art/Framework/Core/EDProducer.h" +#include "art/Framework/Core/ModuleMacros.h" +#include "art/Framework/Principal/Event.h" +#include "art/Framework/Principal/Handle.h" +#include "art/Framework/Principal/Run.h" +#include "art/Framework/Principal/SubRun.h" +#include "canvas/Utilities/InputTag.h" +#include "fhiclcpp/ParameterSet.h" +#include "messagefacility/MessageLogger/MessageLogger.h" + +#include + +namespace sbndaq { + class SBNDXARAPUCADecoder; +} + + +class sbndaq::SBNDXARAPUCADecoder : public art::EDProducer { +public: + explicit SBNDXARAPUCADecoder(fhicl::ParameterSet const& p); + // The compiler-generated destructor is fine for non-base + // classes without bare pointers or other resource use. + + // Plugins should not be copied or assigned. + SBNDXARAPUCADecoder(SBNDXARAPUCADecoder const&) = delete; + SBNDXARAPUCADecoder(SBNDXARAPUCADecoder&&) = delete; + SBNDXARAPUCADecoder& operator=(SBNDXARAPUCADecoder const&) = delete; + SBNDXARAPUCADecoder& operator=(SBNDXARAPUCADecoder&&) = delete; + + // Required functions. + void produce(art::Event& e) override; + +private: + + // Declare member data here. + +}; + + +sbndaq::SBNDXARAPUCADecoder::SBNDXARAPUCADecoder(fhicl::ParameterSet const& p) + : EDProducer{p} // , + // More initializers here. +{ + std::cout << "Entering the constructor" << std::endl; + // Call appropriate produces<>() functions here. + // Call appropriate consumes<>() for any products to be retrieved by this module. +} + +void sbndaq::SBNDXARAPUCADecoder::produce(art::Event& e) +{ + std::cout << "Entering the produce function" << std::endl; + // Implementation of required member function here. +} + +DEFINE_ART_MODULE(sbndaq::SBNDXARAPUCADecoder) diff --git a/sbndcode/Decoders/XARAPUCA/run_xarapucadecoder.fcl b/sbndcode/Decoders/XARAPUCA/run_xarapucadecoder.fcl new file mode 100644 index 000000000..ccc3cd07c --- /dev/null +++ b/sbndcode/Decoders/XARAPUCA/run_xarapucadecoder.fcl @@ -0,0 +1,45 @@ +#include "xarapucadecoder.fcl" + +process_name: XARAPUCADecoder + +services: { + TFileService : {fileName: "decoder_hist.root"} +} + +source: { + module_type: RootInput + maxEvents: -1 # Number of events to create +} + +outputs: { + out1: { + module_type: RootOutput + fileName: "xarapucadecoder-art.root" + } +} + +physics: { + + producers: { + xarapucadecoder: @local::xarapucadecoder + } + + filters:{} + + analyzers:{} + + + reco: [xarapucadecoder] + + + # define the output stream, there could be more than one if using filters + stream1: [out1] + + # trigger_paths is a keyword and contains the paths that modify the art::event, + # ie filters and producers + trigger_paths: [reco] + + # end_paths is a keyword and contains the paths that do not modify the art::Event, + # ie analyzers and output streams. these all run simultaneously + end_paths: [stream1] +} \ No newline at end of file diff --git a/sbndcode/Decoders/XARAPUCA/xarapucadecoder.fcl b/sbndcode/Decoders/XARAPUCA/xarapucadecoder.fcl new file mode 100644 index 000000000..4bd47e973 --- /dev/null +++ b/sbndcode/Decoders/XARAPUCA/xarapucadecoder.fcl @@ -0,0 +1,8 @@ +BEGIN_PROLOG + +xarapucadecoder: +{ + module_type: "SBNDXARAPUCADecoder" +} + +END_PROLOG \ No newline at end of file From d652dc0b4f733e9de5939b87f099549a4e8c9cd5 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Alicia=20V=C3=A1zquez-Ramos?= Date: Fri, 11 Oct 2024 11:34:43 -0500 Subject: [PATCH 02/19] Add product (OpDetWaveform) initialization and instance name to the fcl configuration --- .../Decoders/XARAPUCA/SBNDXARAPUCADecoder_module.cc | 12 +++++++++++- sbndcode/Decoders/XARAPUCA/xarapucadecoder.fcl | 4 ++++ 2 files changed, 15 insertions(+), 1 deletion(-) diff --git a/sbndcode/Decoders/XARAPUCA/SBNDXARAPUCADecoder_module.cc b/sbndcode/Decoders/XARAPUCA/SBNDXARAPUCADecoder_module.cc index 6a3c12337..97135040a 100644 --- a/sbndcode/Decoders/XARAPUCA/SBNDXARAPUCADecoder_module.cc +++ b/sbndcode/Decoders/XARAPUCA/SBNDXARAPUCADecoder_module.cc @@ -17,6 +17,8 @@ #include +#include "lardataobj/RawData/OpDetWaveform.h" + namespace sbndaq { class SBNDXARAPUCADecoder; } @@ -40,7 +42,7 @@ class sbndaq::SBNDXARAPUCADecoder : public art::EDProducer { private: // Declare member data here. - + std::string fch_instance_name; }; @@ -48,8 +50,13 @@ sbndaq::SBNDXARAPUCADecoder::SBNDXARAPUCADecoder(fhicl::ParameterSet const& p) : EDProducer{p} // , // More initializers here. { + std::cout << "Entering the constructor" << std::endl; + + fch_instance_name = p.get("xarapucaInstanceName"); + std::cout << "xarapucaInstanceName: " << fch_instance_name << std::endl; // Call appropriate produces<>() functions here. + produces< std::vector > (fch_instance_name); // Call appropriate consumes<>() for any products to be retrieved by this module. } @@ -57,6 +64,9 @@ void sbndaq::SBNDXARAPUCADecoder::produce(art::Event& e) { std::cout << "Entering the produce function" << std::endl; // Implementation of required member function here. + auto wvfms = std::make_unique >(); + + e.put(std::move(wvfms), fch_instance_name); } DEFINE_ART_MODULE(sbndaq::SBNDXARAPUCADecoder) diff --git a/sbndcode/Decoders/XARAPUCA/xarapucadecoder.fcl b/sbndcode/Decoders/XARAPUCA/xarapucadecoder.fcl index 4bd47e973..b267259f9 100644 --- a/sbndcode/Decoders/XARAPUCA/xarapucadecoder.fcl +++ b/sbndcode/Decoders/XARAPUCA/xarapucadecoder.fcl @@ -3,6 +3,10 @@ BEGIN_PROLOG xarapucadecoder: { module_type: "SBNDXARAPUCADecoder" + + # OUTPUT configuration + # Output data product instance name + xarapucaInstanceName: "XARAPUCAChannels" } END_PROLOG \ No newline at end of file From 94cc62e2d3f23597704d14175b1f8be3a439b9be Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Alicia=20V=C3=A1zquez-Ramos?= Date: Mon, 14 Oct 2024 06:08:07 -0500 Subject: [PATCH 03/19] Add art::Handle for artdaq::Fragment checking if there are valid CAEN Fragments and add the needed parameters to the xarapucadecoder.fcl file. --- .../XARAPUCA/SBNDXARAPUCADecoder_module.cc | 62 +++++++++++++++++-- .../Decoders/XARAPUCA/xarapucadecoder.fcl | 7 +++ 2 files changed, 63 insertions(+), 6 deletions(-) diff --git a/sbndcode/Decoders/XARAPUCA/SBNDXARAPUCADecoder_module.cc b/sbndcode/Decoders/XARAPUCA/SBNDXARAPUCADecoder_module.cc index 97135040a..923a2ff9f 100644 --- a/sbndcode/Decoders/XARAPUCA/SBNDXARAPUCADecoder_module.cc +++ b/sbndcode/Decoders/XARAPUCA/SBNDXARAPUCADecoder_module.cc @@ -17,6 +17,9 @@ #include +#include "artdaq-core/Data/Fragment.hh" +#include "sbndaq-artdaq-core/Overlays/Common/CAENV1740Fragment.hh" + #include "lardataobj/RawData/OpDetWaveform.h" namespace sbndaq { @@ -42,7 +45,15 @@ class sbndaq::SBNDXARAPUCADecoder : public art::EDProducer { private: // Declare member data here. + uint event_counter; + + uint fnum_caen_boards; + + std::string fcaen_module_label; + std::vector fcaen_fragment_name; + std::string fch_instance_name; + }; @@ -50,13 +61,23 @@ sbndaq::SBNDXARAPUCADecoder::SBNDXARAPUCADecoder(fhicl::ParameterSet const& p) : EDProducer{p} // , // More initializers here. { - std::cout << "Entering the constructor" << std::endl; + + event_counter = 0; + + fnum_caen_boards = p.get ("num_caen_boards"); + + fcaen_module_label = p.get ("caen_module_label"); + fcaen_fragment_name = p.get > ("caen_fragment_name"); + + fch_instance_name = p.get ("xarapucaInstanceName"); + + std::cout << event_counter << "\t - xarapucaInstanceName: " << fch_instance_name << "\t - caen module label: " << fcaen_module_label << std::endl; + std::cout << "Num CAEN boards: " << fnum_caen_boards << std::endl; - fch_instance_name = p.get("xarapucaInstanceName"); - std::cout << "xarapucaInstanceName: " << fch_instance_name << std::endl; // Call appropriate produces<>() functions here. produces< std::vector > (fch_instance_name); + // Call appropriate consumes<>() for any products to be retrieved by this module. } @@ -64,9 +85,38 @@ void sbndaq::SBNDXARAPUCADecoder::produce(art::Event& e) { std::cout << "Entering the produce function" << std::endl; // Implementation of required member function here. - auto wvfms = std::make_unique >(); - - e.put(std::move(wvfms), fch_instance_name); + event_counter++; + + // Initialize output product + auto wvfms = std::make_unique > (); + + // Create a vector for all fragments for boards + std::vector< std::vector < artdaq::Fragment> > fragments (fnum_caen_boards); + + bool found_caen = false; + + for (const std::string &caen_name: fcaen_fragment_name) { + art::Handle > fragment_handle; + e.getByLabel(fcaen_module_label, caen_name, fragment_handle); + + if (!fragment_handle.isValid()) { + std::cout << "\tHandle not valid for " << caen_name << std::endl; + } else if (fragment_handle->size() == 0) { + std::cout << "\tHandle with size " << fragment_handle->size() << " for " << caen_name << std::endl; + } else { + found_caen |= true; + std::cout << "\tHandle valid for " << caen_name << " with size " << fragment_handle->size() << std::endl; + } + } + + if (!found_caen) { + std::cout << "\tNo CAEN V1740 fragments of any type found, pushing empty waveforms." << std::endl; + e.put(std::move(wvfms), fch_instance_name); + } else { + e.put(std::move(wvfms), fch_instance_name); + } + + std::cout << std::endl; } DEFINE_ART_MODULE(sbndaq::SBNDXARAPUCADecoder) diff --git a/sbndcode/Decoders/XARAPUCA/xarapucadecoder.fcl b/sbndcode/Decoders/XARAPUCA/xarapucadecoder.fcl index b267259f9..ddd6a14d3 100644 --- a/sbndcode/Decoders/XARAPUCA/xarapucadecoder.fcl +++ b/sbndcode/Decoders/XARAPUCA/xarapucadecoder.fcl @@ -4,6 +4,13 @@ xarapucadecoder: { module_type: "SBNDXARAPUCADecoder" + # INPUT configuration + # CAEN Fragments + caen_module_label: "daq" + caen_fragment_name: [ "CAENV1740", "ContainerCAENV1740" ] + # Boards + num_caen_boards: 1 + # OUTPUT configuration # Output data product instance name xarapucaInstanceName: "XARAPUCAChannels" From 35eceec0d7d5eac09f38da9ece64527e54879624 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Alicia=20V=C3=A1zquez-Ramos?= Date: Tue, 15 Oct 2024 03:49:08 -0500 Subject: [PATCH 04/19] Access to CAEN V1740 fragments from the handler checking the type of fragment --- .../XARAPUCA/SBNDXARAPUCADecoder_module.cc | 35 ++++++++++++++++++- 1 file changed, 34 insertions(+), 1 deletion(-) diff --git a/sbndcode/Decoders/XARAPUCA/SBNDXARAPUCADecoder_module.cc b/sbndcode/Decoders/XARAPUCA/SBNDXARAPUCADecoder_module.cc index 923a2ff9f..009a074e1 100644 --- a/sbndcode/Decoders/XARAPUCA/SBNDXARAPUCADecoder_module.cc +++ b/sbndcode/Decoders/XARAPUCA/SBNDXARAPUCADecoder_module.cc @@ -18,6 +18,8 @@ #include #include "artdaq-core/Data/Fragment.hh" +#include "artdaq-core/Data/ContainerFragment.hh" +#include "sbndaq-artdaq-core/Overlays/FragmentType.hh" #include "sbndaq-artdaq-core/Overlays/Common/CAENV1740Fragment.hh" #include "lardataobj/RawData/OpDetWaveform.h" @@ -98,15 +100,46 @@ void sbndaq::SBNDXARAPUCADecoder::produce(art::Event& e) for (const std::string &caen_name: fcaen_fragment_name) { art::Handle > fragment_handle; e.getByLabel(fcaen_module_label, caen_name, fragment_handle); - + if (!fragment_handle.isValid()) { std::cout << "\tHandle not valid for " << caen_name << std::endl; + } else if (fragment_handle->size() == 0) { std::cout << "\tHandle with size " << fragment_handle->size() << " for " << caen_name << std::endl; + } else { found_caen |= true; std::cout << "\tHandle valid for " << caen_name << " with size " << fragment_handle->size() << std::endl; + + // It is a group of containers containing a group of CAEN V1740 fragments + if (fragment_handle->front().type() == artdaq::Fragment::ContainerFragmentType){ + std::cout << "\t\tCONTAINER" << std::endl; + + // For every container + for (auto container: *fragment_handle) { + artdaq::ContainerFragment container_fragment(container); + + // Search for all CAEN V1740 fragments inside the container + if (container_fragment.fragment_type() == sbndaq::detail::FragmentType::CAENV1740) { + for (size_t i = 0; i < container_fragment.block_count(); i++) { + artdaq::Fragment fragment = *container_fragment[i].get(); + std::cout << "\t\t\t Accessing fragment " << i << " CAENV1740: " << fragment; + } + } + } + + // It is a group of CAEN V1740 fragments + } else if (fragment_handle->front().type() == sbndaq::detail::FragmentType::CAENV1740) { + std::cout << "\t\tCAENV1740" << std::endl; + + // Search for all CAEN V1740 fragments + for (size_t i = 0; i < fragment_handle->size(); i++) { + artdaq::Fragment fragment = fragment_handle->at(i); + std::cout << "\t\t\t Accessing fragment " << i << " CAENVV1740: " << fragment; + } + } } + fragment_handle.removeProduct(); } if (!found_caen) { From 9eeaeddf12350dcc2cc6516abcd95858275d33d5 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Alicia=20V=C3=A1zquez-Ramos?= Date: Tue, 15 Oct 2024 09:06:17 -0500 Subject: [PATCH 05/19] Add the add_fragment functionto allow checking the validity of the ID fragment before the fragment is being added to the fragments vector to be processed --- .../XARAPUCA/SBNDXARAPUCADecoder_module.cc | 23 +++++++++++++++---- 1 file changed, 18 insertions(+), 5 deletions(-) diff --git a/sbndcode/Decoders/XARAPUCA/SBNDXARAPUCADecoder_module.cc b/sbndcode/Decoders/XARAPUCA/SBNDXARAPUCADecoder_module.cc index 009a074e1..e24ee1f74 100644 --- a/sbndcode/Decoders/XARAPUCA/SBNDXARAPUCADecoder_module.cc +++ b/sbndcode/Decoders/XARAPUCA/SBNDXARAPUCADecoder_module.cc @@ -56,6 +56,9 @@ class sbndaq::SBNDXARAPUCADecoder : public art::EDProducer { std::string fch_instance_name; + // Private functions. + void add_fragment(artdaq::Fragment& fragment, std::vector >& fragments); + }; @@ -78,7 +81,7 @@ sbndaq::SBNDXARAPUCADecoder::SBNDXARAPUCADecoder(fhicl::ParameterSet const& p) std::cout << "Num CAEN boards: " << fnum_caen_boards << std::endl; // Call appropriate produces<>() functions here. - produces< std::vector > (fch_instance_name); + produces > (fch_instance_name); // Call appropriate consumes<>() for any products to be retrieved by this module. } @@ -93,12 +96,12 @@ void sbndaq::SBNDXARAPUCADecoder::produce(art::Event& e) auto wvfms = std::make_unique > (); // Create a vector for all fragments for boards - std::vector< std::vector < artdaq::Fragment> > fragments (fnum_caen_boards); + std::vector > fragments (fnum_caen_boards); bool found_caen = false; for (const std::string &caen_name: fcaen_fragment_name) { - art::Handle > fragment_handle; + art::Handle > fragment_handle; e.getByLabel(fcaen_module_label, caen_name, fragment_handle); if (!fragment_handle.isValid()) { @@ -123,7 +126,7 @@ void sbndaq::SBNDXARAPUCADecoder::produce(art::Event& e) if (container_fragment.fragment_type() == sbndaq::detail::FragmentType::CAENV1740) { for (size_t i = 0; i < container_fragment.block_count(); i++) { artdaq::Fragment fragment = *container_fragment[i].get(); - std::cout << "\t\t\t Accessing fragment " << i << " CAENV1740: " << fragment; + add_fragment(fragment, fragments); } } } @@ -135,7 +138,7 @@ void sbndaq::SBNDXARAPUCADecoder::produce(art::Event& e) // Search for all CAEN V1740 fragments for (size_t i = 0; i < fragment_handle->size(); i++) { artdaq::Fragment fragment = fragment_handle->at(i); - std::cout << "\t\t\t Accessing fragment " << i << " CAENVV1740: " << fragment; + add_fragment(fragment, fragments); } } } @@ -152,4 +155,14 @@ void sbndaq::SBNDXARAPUCADecoder::produce(art::Event& e) std::cout << std::endl; } +void sbndaq::SBNDXARAPUCADecoder::add_fragment(artdaq::Fragment& fragment, std::vector >& fragments) { + auto fragment_ID = fragment.fragmentID(); + if (fragment_ID < 0 || fragment_ID >= fnum_caen_boards) { + std::cout << "\t\t\tFragment ID " << fragment_ID << " is out of range. Skipping this fragment..." << std::endl; + } else { + std::cout << "\t\t\tGetting a CAENV1740 fragment: [" << fragment_ID << "]" << fragment; + fragments.at(fragment_ID).push_back(fragment); + } +} + DEFINE_ART_MODULE(sbndaq::SBNDXARAPUCADecoder) From 35223d0972ac86b7e9ec86fd73905a9bb164a77c Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Alicia=20V=C3=A1zquez-Ramos?= Date: Wed, 16 Oct 2024 07:07:05 -0500 Subject: [PATCH 06/19] Add access to artdaq headers and decode the waveforms from the binary --- .../XARAPUCA/SBNDXARAPUCADecoder_module.cc | 82 ++++++++++++++++++- .../Decoders/XARAPUCA/xarapucadecoder.fcl | 2 +- 2 files changed, 80 insertions(+), 4 deletions(-) diff --git a/sbndcode/Decoders/XARAPUCA/SBNDXARAPUCADecoder_module.cc b/sbndcode/Decoders/XARAPUCA/SBNDXARAPUCADecoder_module.cc index e24ee1f74..892ee4512 100644 --- a/sbndcode/Decoders/XARAPUCA/SBNDXARAPUCADecoder_module.cc +++ b/sbndcode/Decoders/XARAPUCA/SBNDXARAPUCADecoder_module.cc @@ -58,6 +58,8 @@ class sbndaq::SBNDXARAPUCADecoder : public art::EDProducer { // Private functions. void add_fragment(artdaq::Fragment& fragment, std::vector >& fragments); + uint16_t get_range(uint64_t buffer, uint32_t msb, uint32_t lsb); + uint32_t read_word(const uint32_t* & data_ptr); }; @@ -93,7 +95,7 @@ void sbndaq::SBNDXARAPUCADecoder::produce(art::Event& e) event_counter++; // Initialize output product - auto wvfms = std::make_unique > (); + auto prod_wvfms = std::make_unique > (); // Create a vector for all fragments for boards std::vector > fragments (fnum_caen_boards); @@ -147,9 +149,71 @@ void sbndaq::SBNDXARAPUCADecoder::produce(art::Event& e) if (!found_caen) { std::cout << "\tNo CAEN V1740 fragments of any type found, pushing empty waveforms." << std::endl; - e.put(std::move(wvfms), fch_instance_name); + e.put(std::move(prod_wvfms), fch_instance_name); + } else { - e.put(std::move(wvfms), fch_instance_name); + std::cout << "\tDecoding fragments... " << std::endl; + + for (size_t b = 0; b < fragments.size(); b++) { + for (size_t f = 0; f < fragments[b].size(); f++) { + std::cout << "\t\tCAEN fragment " << f << " from board " << b << std::endl; + + CAENV1740Fragment caen_fragment(fragments[b][f]); + CAENV1740FragmentMetadata const* metadata = caen_fragment.Metadata(); + uint32_t num_channels = metadata->nChannels; + uint32_t num_samples_per_wvfm = metadata->nSamples; + uint32_t num_samples_per_group = num_samples_per_wvfm * 8; + uint32_t TTT_ns = metadata->timeStampNSec; + uint32_t TTT_s = metadata->timeStampSec; + std::cout << "\t\t\tNumber of channels: " << num_channels << std::endl; + std::cout << "\t\t\tNumber of samples: " << num_samples_per_wvfm << "(" << num_samples_per_group << " samples per group - 8 channels -)"<< std::endl; + std::cout << "\t\t\tTTT_ns: " << TTT_ns << " ns. \t" << "TTT_s: " << TTT_s << " s." << std::endl; + + CAENV1740Event const* event = caen_fragment.Event(); + CAENV1740EventHeader header = event->Header; + uint32_t num_words_per_event = header.eventSize; + uint32_t num_words_per_header = sizeof(CAENV1740EventHeader)/sizeof(uint32_t); + uint32_t num_words_per_wvfm = (num_words_per_event - num_words_per_header); + + std::cout << "\t\t\tNumber of words per event: " << num_words_per_event << " [Header: " << num_words_per_header << ", Waveform: " << num_words_per_wvfm << "] words" << std::endl; + + // =============== Start decoding the waveforms =============== // + std::vector > wvfms(num_channels, std::vector(num_samples_per_wvfm, 0)); + + // Absolute sample number + uint32_t S = 0; + // Buffer variables + uint64_t buffer = 0; + uint32_t bits_in_buffer = 0; + + uint32_t sample_bits = 12; + + // Data pointer to the beggining of the waveforms stores in the event. + const uint32_t* data_ptr = reinterpret_cast(fragments[b][f].dataBeginBytes() + sizeof(CAENV1740EventHeader)); + for (size_t j = 0; j < num_words_per_wvfm; j++) { + uint64_t word = read_word(data_ptr); + //std::cout << buffer << "[word: " << word << "]" << std::endl; + buffer |= word << bits_in_buffer; + bits_in_buffer += sizeof(uint32_t) * 8; + //std::cout << " +" << buffer << " [bits in buffer: "<< bits_in_buffer << "]" << std::endl; + + // Get sequences of 12 bits + while (bits_in_buffer >= sample_bits) { + uint32_t g = (S / num_samples_per_group); // Group index. + uint32_t c = ((S / 3) % 8) + g * 8; // Channel index. + uint32_t s = (S % 3) + ((S / 24) * 3) % num_samples_per_wvfm; // Sample/channel index. + uint16_t sample = get_range(buffer, sample_bits - 1, 0); + //std::cout << "\tSample: " << sample << "\tg: " << g << "\tch: " << c << "\ts:" << s << "\tS: " << S << std::endl; + wvfms[c][s] = sample; + buffer >>= sample_bits; + bits_in_buffer -= sample_bits; + //std::cout << " -" << buffer << " [bits in buffer: "<< bits_in_buffer << "]" << std::endl; + S++; + } + } + } + } + e.put(std::move(prod_wvfms), fch_instance_name); } std::cout << std::endl; @@ -165,4 +229,16 @@ void sbndaq::SBNDXARAPUCADecoder::add_fragment(artdaq::Fragment& fragment, std:: } } +uint16_t sbndaq::SBNDXARAPUCADecoder::get_range(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; +} + +uint32_t sbndaq::SBNDXARAPUCADecoder::read_word(const uint32_t* & data_ptr) { + uint32_t word = *data_ptr; + data_ptr += 1; + return word; +} + DEFINE_ART_MODULE(sbndaq::SBNDXARAPUCADecoder) diff --git a/sbndcode/Decoders/XARAPUCA/xarapucadecoder.fcl b/sbndcode/Decoders/XARAPUCA/xarapucadecoder.fcl index ddd6a14d3..9c0d8a04b 100644 --- a/sbndcode/Decoders/XARAPUCA/xarapucadecoder.fcl +++ b/sbndcode/Decoders/XARAPUCA/xarapucadecoder.fcl @@ -9,7 +9,7 @@ xarapucadecoder: caen_module_label: "daq" caen_fragment_name: [ "CAENV1740", "ContainerCAENV1740" ] # Boards - num_caen_boards: 1 + num_caen_boards: 4 # OUTPUT configuration # Output data product instance name From 2c669b31816d7aa914b8db71ff5e3840297b7fde Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Alicia=20V=C3=A1zquez-Ramos?= Date: Wed, 16 Oct 2024 09:58:19 -0500 Subject: [PATCH 07/19] Push waveform products after finish decoding --- sbndcode/Decoders/XARAPUCA/SBNDXARAPUCADecoder_module.cc | 9 +++++++-- 1 file changed, 7 insertions(+), 2 deletions(-) diff --git a/sbndcode/Decoders/XARAPUCA/SBNDXARAPUCADecoder_module.cc b/sbndcode/Decoders/XARAPUCA/SBNDXARAPUCADecoder_module.cc index 892ee4512..3962dcb08 100644 --- a/sbndcode/Decoders/XARAPUCA/SBNDXARAPUCADecoder_module.cc +++ b/sbndcode/Decoders/XARAPUCA/SBNDXARAPUCADecoder_module.cc @@ -153,7 +153,6 @@ void sbndaq::SBNDXARAPUCADecoder::produce(art::Event& e) } else { std::cout << "\tDecoding fragments... " << std::endl; - for (size_t b = 0; b < fragments.size(); b++) { for (size_t f = 0; f < fragments[b].size(); f++) { std::cout << "\t\tCAEN fragment " << f << " from board " << b << std::endl; @@ -211,12 +210,18 @@ void sbndaq::SBNDXARAPUCADecoder::produce(art::Event& e) S++; } } + + for (size_t ch = 0; ch < wvfms.size(); ch++) { + raw::OpDetWaveform waveform(0, ch, wvfms[ch]); + prod_wvfms->push_back(waveform); + } } } + e.put(std::move(prod_wvfms), fch_instance_name); } - std::cout << std::endl; + std::cout << "End of producer function." << std::endl; } void sbndaq::SBNDXARAPUCADecoder::add_fragment(artdaq::Fragment& fragment, std::vector >& fragments) { From 3f2d5d0d8481fb173b7a62fc165c2bbe5c044f98 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Alicia=20V=C3=A1zquez-Ramos?= Date: Thu, 17 Oct 2024 04:48:06 -0500 Subject: [PATCH 08/19] Add TTT to the waveforms in us --- .../XARAPUCA/SBNDXARAPUCADecoder_module.cc | 20 ++++++++++++++----- .../Decoders/XARAPUCA/xarapucadecoder.fcl | 2 ++ 2 files changed, 17 insertions(+), 5 deletions(-) diff --git a/sbndcode/Decoders/XARAPUCA/SBNDXARAPUCADecoder_module.cc b/sbndcode/Decoders/XARAPUCA/SBNDXARAPUCADecoder_module.cc index 3962dcb08..7ced81258 100644 --- a/sbndcode/Decoders/XARAPUCA/SBNDXARAPUCADecoder_module.cc +++ b/sbndcode/Decoders/XARAPUCA/SBNDXARAPUCADecoder_module.cc @@ -56,7 +56,10 @@ class sbndaq::SBNDXARAPUCADecoder : public art::EDProducer { std::string fch_instance_name; - // Private functions. + float fns_per_sample; + uint16_t fns_per_tick; + + // Functions. void add_fragment(artdaq::Fragment& fragment, std::vector >& fragments); uint16_t get_range(uint64_t buffer, uint32_t msb, uint32_t lsb); uint32_t read_word(const uint32_t* & data_ptr); @@ -78,6 +81,9 @@ sbndaq::SBNDXARAPUCADecoder::SBNDXARAPUCADecoder(fhicl::ParameterSet const& p) fcaen_fragment_name = p.get > ("caen_fragment_name"); fch_instance_name = p.get ("xarapucaInstanceName"); + + fns_per_sample = p.get("ns_per_sample"); + fns_per_tick = 8; std::cout << event_counter << "\t - xarapucaInstanceName: " << fch_instance_name << "\t - caen module label: " << fcaen_module_label << std::endl; std::cout << "Num CAEN boards: " << fnum_caen_boards << std::endl; @@ -162,14 +168,18 @@ void sbndaq::SBNDXARAPUCADecoder::produce(art::Event& e) uint32_t num_channels = metadata->nChannels; uint32_t num_samples_per_wvfm = metadata->nSamples; uint32_t num_samples_per_group = num_samples_per_wvfm * 8; - uint32_t TTT_ns = metadata->timeStampNSec; - uint32_t TTT_s = metadata->timeStampSec; std::cout << "\t\t\tNumber of channels: " << num_channels << std::endl; std::cout << "\t\t\tNumber of samples: " << num_samples_per_wvfm << "(" << num_samples_per_group << " samples per group - 8 channels -)"<< std::endl; - std::cout << "\t\t\tTTT_ns: " << TTT_ns << " ns. \t" << "TTT_s: " << TTT_s << " s." << std::endl; CAENV1740Event const* event = caen_fragment.Event(); CAENV1740EventHeader header = event->Header; + float TTT_end_ns = header.triggerTime() * fns_per_tick; + float TTT_ini_ns = TTT_end_ns - num_samples_per_wvfm * fns_per_sample; + float TTT_end_us = TTT_end_ns * 1E-3f; + float TTT_ini_us = TTT_ini_ns * 1E-3f; + std::cout << std::fixed << std::setprecision(3); + std::cout << "TTT_ini [us]: " << TTT_ini_us << "\tTTT_end [us]: " << TTT_end_us << std::endl; + uint32_t num_words_per_event = header.eventSize; uint32_t num_words_per_header = sizeof(CAENV1740EventHeader)/sizeof(uint32_t); uint32_t num_words_per_wvfm = (num_words_per_event - num_words_per_header); @@ -212,7 +222,7 @@ void sbndaq::SBNDXARAPUCADecoder::produce(art::Event& e) } for (size_t ch = 0; ch < wvfms.size(); ch++) { - raw::OpDetWaveform waveform(0, ch, wvfms[ch]); + raw::OpDetWaveform waveform(TTT_ini_us, ch, wvfms[ch]); prod_wvfms->push_back(waveform); } } diff --git a/sbndcode/Decoders/XARAPUCA/xarapucadecoder.fcl b/sbndcode/Decoders/XARAPUCA/xarapucadecoder.fcl index 9c0d8a04b..fadc40b86 100644 --- a/sbndcode/Decoders/XARAPUCA/xarapucadecoder.fcl +++ b/sbndcode/Decoders/XARAPUCA/xarapucadecoder.fcl @@ -10,6 +10,8 @@ xarapucadecoder: caen_fragment_name: [ "CAENV1740", "ContainerCAENV1740" ] # Boards num_caen_boards: 4 + # Time + ns_per_sample: 16 # OUTPUT configuration # Output data product instance name From 9c8d59c6afaa2c4dc5ae247f5c78ece8fbdbcd5e Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Alicia=20V=C3=A1zquez-Ramos?= Date: Thu, 17 Oct 2024 08:57:48 -0500 Subject: [PATCH 09/19] Add histogram output for the waveforms --- .../XARAPUCA/SBNDXARAPUCADecoder_module.cc | 14 ++++++++++++++ 1 file changed, 14 insertions(+) diff --git a/sbndcode/Decoders/XARAPUCA/SBNDXARAPUCADecoder_module.cc b/sbndcode/Decoders/XARAPUCA/SBNDXARAPUCADecoder_module.cc index 7ced81258..5f229a4bd 100644 --- a/sbndcode/Decoders/XARAPUCA/SBNDXARAPUCADecoder_module.cc +++ b/sbndcode/Decoders/XARAPUCA/SBNDXARAPUCADecoder_module.cc @@ -24,6 +24,9 @@ #include "lardataobj/RawData/OpDetWaveform.h" +#include "art_root_io/TFileService.h" +#include "TH1D.h" + namespace sbndaq { class SBNDXARAPUCADecoder; } @@ -59,6 +62,9 @@ class sbndaq::SBNDXARAPUCADecoder : public art::EDProducer { float fns_per_sample; uint16_t fns_per_tick; + std::stringstream hist_name; + art::ServiceHandle tfs; + // Functions. void add_fragment(artdaq::Fragment& fragment, std::vector >& fragments); uint16_t get_range(uint64_t buffer, uint32_t msb, uint32_t lsb); @@ -224,6 +230,14 @@ void sbndaq::SBNDXARAPUCADecoder::produce(art::Event& e) for (size_t ch = 0; ch < wvfms.size(); ch++) { raw::OpDetWaveform waveform(TTT_ini_us, ch, wvfms[ch]); prod_wvfms->push_back(waveform); + hist_name.str(""); + hist_name << "Event " << event_counter << " CH " << ch << " [frag: " << f << ", board: " << b << "] waveform"; + TH1D* hist = tfs->make(hist_name.str().c_str(), hist_name.str().c_str(), wvfms[ch].size(), TTT_ini_us, TTT_end_us); + hist->GetYaxis()->SetTitle("ADCs"); + hist->GetXaxis()->SetTitle("Time [us]"); + for (size_t i = 0; i < wvfms[ch].size(); i++) { + hist->SetBinContent(i+1, wvfms[ch][i]); + } } } } From 05417a445845b9180102333f2d3d4004f0815e51 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Alicia=20V=C3=A1zquez-Ramos?= Date: Thu, 31 Oct 2024 05:38:30 -0500 Subject: [PATCH 10/19] Add expected fragment IDs and check their validity. Enable reading data from multiple boards --- .../XARAPUCA/SBNDXARAPUCADecoder_module.cc | 29 +++++++++++++++---- .../Decoders/XARAPUCA/xarapucadecoder.fcl | 2 ++ 2 files changed, 25 insertions(+), 6 deletions(-) diff --git a/sbndcode/Decoders/XARAPUCA/SBNDXARAPUCADecoder_module.cc b/sbndcode/Decoders/XARAPUCA/SBNDXARAPUCADecoder_module.cc index 5f229a4bd..04b3e1951 100644 --- a/sbndcode/Decoders/XARAPUCA/SBNDXARAPUCADecoder_module.cc +++ b/sbndcode/Decoders/XARAPUCA/SBNDXARAPUCADecoder_module.cc @@ -16,6 +16,7 @@ #include "messagefacility/MessageLogger/MessageLogger.h" #include +#include #include "artdaq-core/Data/Fragment.hh" #include "artdaq-core/Data/ContainerFragment.hh" @@ -53,6 +54,8 @@ class sbndaq::SBNDXARAPUCADecoder : public art::EDProducer { uint event_counter; uint fnum_caen_boards; + uint ffragment_id_offset; + std::vector fboard_id_list; std::string fcaen_module_label; std::vector fcaen_fragment_name; @@ -82,6 +85,9 @@ sbndaq::SBNDXARAPUCADecoder::SBNDXARAPUCADecoder(fhicl::ParameterSet const& p) event_counter = 0; fnum_caen_boards = p.get ("num_caen_boards"); + ffragment_id_offset = p.get ("fragment_id_offset"); + + fboard_id_list = p.get > ("board_id_list"); fcaen_module_label = p.get ("caen_module_label"); fcaen_fragment_name = p.get > ("caen_fragment_name"); @@ -130,7 +136,7 @@ void sbndaq::SBNDXARAPUCADecoder::produce(art::Event& e) // It is a group of containers containing a group of CAEN V1740 fragments if (fragment_handle->front().type() == artdaq::Fragment::ContainerFragmentType){ - std::cout << "\t\tCONTAINER" << std::endl; + std::cout << "\t\tCONTAINER"; // For every container for (auto container: *fragment_handle) { @@ -139,6 +145,7 @@ void sbndaq::SBNDXARAPUCADecoder::produce(art::Event& e) // Search for all CAEN V1740 fragments inside the container if (container_fragment.fragment_type() == sbndaq::detail::FragmentType::CAENV1740) { for (size_t i = 0; i < container_fragment.block_count(); i++) { + std::cout << "\t\t[container_size: " << container_fragment.block_count() << "]" << std::endl; artdaq::Fragment fragment = *container_fragment[i].get(); add_fragment(fragment, fragments); } @@ -186,6 +193,8 @@ void sbndaq::SBNDXARAPUCADecoder::produce(art::Event& e) std::cout << std::fixed << std::setprecision(3); std::cout << "TTT_ini [us]: " << TTT_ini_us << "\tTTT_end [us]: " << TTT_end_us << std::endl; + //std::cout << "\t\t\tBoard ID (from header): " << header.boardID << std::endl; + uint32_t num_words_per_event = header.eventSize; uint32_t num_words_per_header = sizeof(CAENV1740EventHeader)/sizeof(uint32_t); uint32_t num_words_per_wvfm = (num_words_per_event - num_words_per_header); @@ -249,13 +258,21 @@ void sbndaq::SBNDXARAPUCADecoder::produce(art::Event& e) } void sbndaq::SBNDXARAPUCADecoder::add_fragment(artdaq::Fragment& fragment, std::vector >& fragments) { - auto fragment_ID = fragment.fragmentID(); - if (fragment_ID < 0 || fragment_ID >= fnum_caen_boards) { - std::cout << "\t\t\tFragment ID " << fragment_ID << " is out of range. Skipping this fragment..." << std::endl; + auto fragment_id = fragment.fragmentID() - ffragment_id_offset; + auto it = std::find(fboard_id_list.begin(), fboard_id_list.end(), fragment_id); + + if (it != fboard_id_list.end()) { + uint index = it - fboard_id_list.begin(); + if (index < 0 || index >= fnum_caen_boards) { + std::cout << "\t\t\tFragment ID " << fragment_id << " (" << index << ") is out of range. Skipping this fragment..." << std::endl; + } else { + std::cout << "\t\t\tGetting a CAENV1740 fragment: [" << fragment_id << " (" << index << ") " << "]" << fragment; + fragments.at(index).push_back(fragment); + } } else { - std::cout << "\t\t\tGetting a CAENV1740 fragment: [" << fragment_ID << "]" << fragment; - fragments.at(fragment_ID).push_back(fragment); + std::cout << "\t\t\tFragment ID " << fragment_id << " is not valid. Skipping this fragment..." << std::endl; } + } uint16_t sbndaq::SBNDXARAPUCADecoder::get_range(uint64_t buffer, uint32_t msb, uint32_t lsb) { diff --git a/sbndcode/Decoders/XARAPUCA/xarapucadecoder.fcl b/sbndcode/Decoders/XARAPUCA/xarapucadecoder.fcl index fadc40b86..fa2453423 100644 --- a/sbndcode/Decoders/XARAPUCA/xarapucadecoder.fcl +++ b/sbndcode/Decoders/XARAPUCA/xarapucadecoder.fcl @@ -10,6 +10,8 @@ xarapucadecoder: caen_fragment_name: [ "CAENV1740", "ContainerCAENV1740" ] # Boards num_caen_boards: 4 + fragment_id_offset: 40960 + board_id_list: [7, 13, 16, 19] # Time ns_per_sample: 16 From 27225d2fb1436c929e3adb56fddaf4c5c32a83fd Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Alicia=20V=C3=A1zquez-Ramos?= Date: Thu, 31 Oct 2024 06:08:37 -0500 Subject: [PATCH 11/19] Get a unique ID for every waveform stored related to the board slot and the board channel --- .../Decoders/XARAPUCA/SBNDXARAPUCADecoder_module.cc | 12 ++++++++++-- 1 file changed, 10 insertions(+), 2 deletions(-) diff --git a/sbndcode/Decoders/XARAPUCA/SBNDXARAPUCADecoder_module.cc b/sbndcode/Decoders/XARAPUCA/SBNDXARAPUCADecoder_module.cc index 04b3e1951..7698f8217 100644 --- a/sbndcode/Decoders/XARAPUCA/SBNDXARAPUCADecoder_module.cc +++ b/sbndcode/Decoders/XARAPUCA/SBNDXARAPUCADecoder_module.cc @@ -72,6 +72,7 @@ class sbndaq::SBNDXARAPUCADecoder : public art::EDProducer { void add_fragment(artdaq::Fragment& fragment, std::vector >& fragments); uint16_t get_range(uint64_t buffer, uint32_t msb, uint32_t lsb); uint32_t read_word(const uint32_t* & data_ptr); + uint get_channel_id(uint board, uint board_channel); }; @@ -237,10 +238,12 @@ void sbndaq::SBNDXARAPUCADecoder::produce(art::Event& e) } for (size_t ch = 0; ch < wvfms.size(); ch++) { - raw::OpDetWaveform waveform(TTT_ini_us, ch, wvfms[ch]); + uint channel_id = get_channel_id(b, ch); + raw::OpDetWaveform waveform(TTT_ini_us, channel_id, wvfms[ch]); + //std::cout << "Pushing waveform from board " << b << "(slot " << fboard_id_list[b] << ") channel " << ch << "(ch_id " << channel_id << ")" << std::endl; prod_wvfms->push_back(waveform); hist_name.str(""); - hist_name << "Event " << event_counter << " CH " << ch << " [frag: " << f << ", board: " << b << "] waveform"; + hist_name << "Event " << event_counter << " CH " << ch << " [frag " << f << ", board " << b << " (slot " << fboard_id_list[b] << ") ] waveform"; TH1D* hist = tfs->make(hist_name.str().c_str(), hist_name.str().c_str(), wvfms[ch].size(), TTT_ini_us, TTT_end_us); hist->GetYaxis()->SetTitle("ADCs"); hist->GetXaxis()->SetTitle("Time [us]"); @@ -287,4 +290,9 @@ uint32_t sbndaq::SBNDXARAPUCADecoder::read_word(const uint32_t* & data_ptr) { return word; } +uint sbndaq::SBNDXARAPUCADecoder::get_channel_id(uint board, uint board_channel) { + uint channel_id = fboard_id_list[board] * 1000 + board_channel; + return channel_id; +} + DEFINE_ART_MODULE(sbndaq::SBNDXARAPUCADecoder) From bf0c4b77458c150399f1ececee45ec5d7b60c9bc Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Alicia=20V=C3=A1zquez-Ramos?= Date: Mon, 4 Nov 2024 10:03:54 -0600 Subject: [PATCH 12/19] Add comments and documentation, clean the code. V1.0 of the X-ARAPUCAs decoder (V1740B digitizers). --- .../XARAPUCA/SBNDXARAPUCADecoder_module.cc | 362 ++++++++++++------ .../Decoders/XARAPUCA/run_xarapucadecoder.fcl | 16 +- .../Decoders/XARAPUCA/xarapucadecoder.fcl | 37 +- 3 files changed, 283 insertions(+), 132 deletions(-) diff --git a/sbndcode/Decoders/XARAPUCA/SBNDXARAPUCADecoder_module.cc b/sbndcode/Decoders/XARAPUCA/SBNDXARAPUCADecoder_module.cc index 7698f8217..461ad5eca 100644 --- a/sbndcode/Decoders/XARAPUCA/SBNDXARAPUCADecoder_module.cc +++ b/sbndcode/Decoders/XARAPUCA/SBNDXARAPUCADecoder_module.cc @@ -2,9 +2,15 @@ // Class: SBNDXARAPUCADecoder // Plugin Type: producer // File: SBNDXARAPUCADecoder_module.cc -// Author Alicia Vázquez-Ramos (aliciavr@ugr.es) +// Author: Alicia Vázquez-Ramos (aliciavr@ugr.es) //////////////////////////////////////////////////////////////////////// +/** + * @file SBNDXARAPUCADecoder_module.cc + * @brief Defines and implements the SBNDXARAPUCADecoder class which inherits from an art::EDProducer + * as the decoder for V1740B digitizers, intended for the X-ARAPUCAs. + */ + #include "art/Framework/Core/EDProducer.h" #include "art/Framework/Core/ModuleMacros.h" #include "art/Framework/Principal/Event.h" @@ -15,9 +21,6 @@ #include "fhiclcpp/ParameterSet.h" #include "messagefacility/MessageLogger/MessageLogger.h" -#include -#include - #include "artdaq-core/Data/Fragment.hh" #include "artdaq-core/Data/ContainerFragment.hh" #include "sbndaq-artdaq-core/Overlays/FragmentType.hh" @@ -28,222 +31,317 @@ #include "art_root_io/TFileService.h" #include "TH1D.h" +#include +#include + + +/** + * @namespace sbndaq + * @brief Contains classes and functions for inside the sbndaq system. + */ namespace sbndaq { class SBNDXARAPUCADecoder; } +/** + * @class SBNDXARAPUCADecoder + * @brief A class providing the V1740B digitizer decoder. It inherits from art::EDProducer and + * creates a vector of raw::OpDetWaveform objects as a product of the decoding. + */ class sbndaq::SBNDXARAPUCADecoder : public art::EDProducer { public: explicit SBNDXARAPUCADecoder(fhicl::ParameterSet const& p); - // The compiler-generated destructor is fine for non-base - // classes without bare pointers or other resource use. - // Plugins should not be copied or assigned. SBNDXARAPUCADecoder(SBNDXARAPUCADecoder const&) = delete; SBNDXARAPUCADecoder(SBNDXARAPUCADecoder&&) = delete; SBNDXARAPUCADecoder& operator=(SBNDXARAPUCADecoder const&) = delete; SBNDXARAPUCADecoder& operator=(SBNDXARAPUCADecoder&&) = delete; - // Required functions. + // Main class method. void produce(art::Event& e) override; private: - // Declare member data here. - uint event_counter; + uint fevent_counter; /**< Event counter. */ + + uint fnum_caen_boards; /**< Maximum number of CAEN boards to be considered. */ + uint ffragment_id_offset; /**< Offset value to get the slot of every CAEN board. */ + std::vector fboard_id_list; /**< Possible CAEN board identifiers based on the slot they are installed. */ + + std::string fcaen_module_label; /**< Label identifying the module where the CAEN fragments come from. */ + std::vector fcaen_fragment_names; /**< Fragments accepted by this decoder. */ - uint fnum_caen_boards; - uint ffragment_id_offset; - std::vector fboard_id_list; + std::string fproduct_instance_name; /**< Name assigned to the product instance generated by this art::EDProducer. */ - std::string fcaen_module_label; - std::vector fcaen_fragment_name; + uint fns_per_sample; /**< Number of nanoseconds per sample. */ + uint16_t fns_per_tick; /**< Number of nanoseconds per trigger time stamp (TTT) tick. */ - std::string fch_instance_name; + uint32_t fsample_bits; /**< Number of bits per sample. */ - float fns_per_sample; - uint16_t fns_per_tick; + art::ServiceHandle tfs; /**< ServiceHandle object to store the histograms in the decoder_hist.root output file. */ - std::stringstream hist_name; - art::ServiceHandle tfs; + bool fdebug_all; /**< If `true` all debug information is printed. */ + bool fdebug_handle; /**< If `true` art::Handle object data is printed. */ + 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 fverbose; /**< If `true` it increases verbosity of console output for detailed processing steps. */ - // Functions. + // Class methods. void add_fragment(artdaq::Fragment& fragment, std::vector >& fragments); - uint16_t get_range(uint64_t buffer, uint32_t msb, uint32_t lsb); + uint16_t get_sample(uint64_t buffer, uint32_t msb, uint32_t lsb); uint32_t read_word(const uint32_t* & data_ptr); uint get_channel_id(uint board, uint board_channel); }; - +/** + * @brief Constructor of the class SBNDXARAPUCADecoder. Given a fhicl::ParameterSet object it gets the configuration needed by this + * art::EDProducer from the FHiCL file. + * @param[in] p A set of parameters containing configuration values for the decoder from the FHiCL file. + * @details This constructor accesses the parameters in the FHiCL configuration file and set the configuration to be run for + * this module. It sets settings for CAEN fragments, board information, timing, debug options, verbosity option and creates an + * instance of the product associated with this module. + */ sbndaq::SBNDXARAPUCADecoder::SBNDXARAPUCADecoder(fhicl::ParameterSet const& p) - : EDProducer{p} // , - // More initializers here. +: EDProducer{p} { - std::cout << "Entering the constructor" << std::endl; - - event_counter = 0; + // Sets the event counter to zero. + fevent_counter = 0; - fnum_caen_boards = p.get ("num_caen_boards"); + // Gets the CAEN fragments information. + fcaen_module_label = p.get ("caen_module_label"); + fcaen_fragment_names = p.get > ("caen_fragment_names"); + + // Gets the CAEN boards information. ffragment_id_offset = p.get ("fragment_id_offset"); - fboard_id_list = p.get > ("board_id_list"); + fnum_caen_boards = p.get ("num_caen_boards"); - fcaen_module_label = p.get ("caen_module_label"); - fcaen_fragment_name = p.get > ("caen_fragment_name"); - - fch_instance_name = p.get ("xarapucaInstanceName"); + // Gets the name of the instance created by this module. + fproduct_instance_name = p.get ("product_instance_name"); - fns_per_sample = p.get("ns_per_sample"); + // Gets timing information. + fns_per_sample = p.get ("ns_per_sample"); fns_per_tick = 8; - - std::cout << event_counter << "\t - xarapucaInstanceName: " << fch_instance_name << "\t - caen module label: " << fcaen_module_label << std::endl; - std::cout << "Num CAEN boards: " << fnum_caen_boards << std::endl; - // Call appropriate produces<>() functions here. - produces > (fch_instance_name); + // Sets the number of bits per sample. + fsample_bits = 12; - // Call appropriate consumes<>() for any products to be retrieved by this module. + // Gets the debug and verbose options. + fdebug_all = p.get ("debug_all"); + fdebug_handle = p.get ("debug_handle"); + fdebug_timing = p.get ("debug_timing"); + fdebug_buffer = p.get ("debug_buffer"); + fdebug_waveforms = p.get ("debug_waveforms"); + fverbose = p.get ("verbose"); + + // Creates the instance product of this module. + produces > (fproduct_instance_name); } +/** + * @brief Main function of the art::EDProducer: the produce function analyzes every event producing waveforms after the decoding. + * @param[in] e The event to be processed. + * @details It is the main function of the art::EDProducer module: + * 1. Iterates over `fcaen_fragment_names` to retrieve each fragment by label. It checks if the fragment handle is valid and + * non-empty. If valid, it updates `found_caen` and processes each fragment based on its type: either as a + * container of fragments or as individual CAEN V1740 fragments. + * 2. Access the data inside the CAEN fragments and extracts header, timing data and the raw waveform. + * 3. 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$. + * 4. The decoded waveforms are dumped into: + * - decoder_hist.root file (waveforms in ROOT histograms format). + * - + */ void sbndaq::SBNDXARAPUCADecoder::produce(art::Event& e) { - std::cout << "Entering the produce function" << std::endl; - // Implementation of required member function here. - event_counter++; + if (fverbose) std::cout << "\n > SBNDXARAPUCADecoder::produce: entering the produce function." << std::endl; - // Initialize output product + + // Advances the event counter. + fevent_counter++; + + // Initializes the output instance product. auto prod_wvfms = std::make_unique > (); + if (fverbose) std::cout << "\n > SBNDXARAPUCADecoder::produce: products initialized." << std::endl; - // Create a vector for all fragments for boards + // Creates a vector for all fragments for boards std::vector > fragments (fnum_caen_boards); + // Flag to track if valid CAEN fragments are found. bool found_caen = false; - for (const std::string &caen_name: fcaen_fragment_name) { + // This loop iterates over the valid CAEN fragments names (`fcaen_fragment_names`) to check + // if the art::Handle object is not empty and has valid CAEN fragments. After this, it extracts + // the CAEN V1740 fragments into a nested std::vector, assigning each fragment to its board. + if (fverbose | fdebug_handle | fdebug_all) std::cout << "\n > SBNDXARAPUCADecoder::produce: searching for V1740 fragments." << std::endl; + for (const std::string &caen_name: fcaen_fragment_names) { art::Handle > fragment_handle; e.getByLabel(fcaen_module_label, caen_name, fragment_handle); - if (!fragment_handle.isValid()) { - std::cout << "\tHandle not valid for " << caen_name << std::endl; + // The art::Handle object is not valid. + if (!fragment_handle.isValid()) { + if (fdebug_handle | fdebug_all) std::cout << "\tHandle not valid for " << caen_name << "." << std::endl; - } else if (fragment_handle->size() == 0) { - std::cout << "\tHandle with size " << fragment_handle->size() << " for " << caen_name << std::endl; + // The art::Handle object is empty. + } else if (fragment_handle->size() == 0) { + if (fdebug_handle | fdebug_all) std::cout << "\tHandle with size " << fragment_handle->size() << " for " << caen_name << "."<< std::endl; - } else { + // The art::Handle object is valid and not empty. + } else { found_caen |= true; - std::cout << "\tHandle valid for " << caen_name << " with size " << fragment_handle->size() << std::endl; + uint frag_handle_size = fragment_handle->size(); + + if (fdebug_handle | fdebug_all) std::cout << "\tHandle valid for " << caen_name << " (" << frag_handle_size << " objects)." << std::endl; - // It is a group of containers containing a group of CAEN V1740 fragments + // It is a group of containers containing a group of CAEN V1740 fragments. if (fragment_handle->front().type() == artdaq::Fragment::ContainerFragmentType){ - std::cout << "\t\tCONTAINER"; - // For every container - for (auto container: *fragment_handle) { + // For every container, + for (size_t c = 0; c < frag_handle_size; c++) { + auto container = fragment_handle->at(c); artdaq::ContainerFragment container_fragment(container); - // Search for all CAEN V1740 fragments inside the container + // it searches for all CAEN V1740 fragments inside the container if it contains CAEN V1740 fragments. if (container_fragment.fragment_type() == sbndaq::detail::FragmentType::CAENV1740) { - for (size_t i = 0; i < container_fragment.block_count(); i++) { - std::cout << "\t\t[container_size: " << container_fragment.block_count() << "]" << std::endl; - artdaq::Fragment fragment = *container_fragment[i].get(); + uint num_caen_fragments = container_fragment.block_count(); + if (fdebug_handle | fdebug_all) std::cout << "\t\tContainerCAENV1740 "<< c << " - CAENV1740 fragments found: " << num_caen_fragments << "." << std::endl; + + for (size_t f = 0; f < num_caen_fragments; f++) { + artdaq::Fragment fragment = *container_fragment[f].get(); add_fragment(fragment, fragments); - } + } // End CAEN V1740 fragments loop. } - } + } // End Container fragments loop. - // It is a group of CAEN V1740 fragments + // It is a group of CAEN V1740 fragments. } else if (fragment_handle->front().type() == sbndaq::detail::FragmentType::CAENV1740) { - std::cout << "\t\tCAENV1740" << std::endl; + if (fdebug_handle | fdebug_all) std::cout << "\t\tCAENV1740 fragments found: " << frag_handle_size << "." << std::endl; - // Search for all CAEN V1740 fragments - for (size_t i = 0; i < fragment_handle->size(); i++) { - artdaq::Fragment fragment = fragment_handle->at(i); + // It searches for all CAEN V1740 fragments. + for (size_t f = 0; f < frag_handle_size; f++) { + artdaq::Fragment fragment = fragment_handle->at(f); add_fragment(fragment, fragments); - } + } // End CAEN V1740 fragments loop. } - } + } // End extracting CAEN V1740 fragments. fragment_handle.removeProduct(); - } + } // End CAEN fragment names loop. + // If no valid CAEN fragments are found it pushes empty waveforms, if (!found_caen) { - std::cout << "\tNo CAEN V1740 fragments of any type found, pushing empty waveforms." << std::endl; - e.put(std::move(prod_wvfms), fch_instance_name); - + e.put(std::move(prod_wvfms), fproduct_instance_name); + if (fverbose) std::cout << "\n > SBNDXARAPUCADecoder::produce: no CAEN V1740 fragments of any type found, pushed empty waveforms." << std::endl; + + // otherwise it starts the decoding of the fragments found. } else { - std::cout << "\tDecoding fragments... " << std::endl; + if (fverbose) std::cout << "\n > SBNDXARAPUCADecoder::produce: decoding V1740 CAEN fragments..." << std::endl; for (size_t b = 0; b < fragments.size(); b++) { for (size_t f = 0; f < fragments[b].size(); f++) { - std::cout << "\t\tCAEN fragment " << f << " from board " << b << std::endl; + if (fverbose) std::cout << "\n > SBNDXARAPUCADecoder::produce: decoding V1740 CAEN fragment " << f << " from the board " << b << "(slot " << fboard_id_list[b] << "):" << std::endl; + // Accesses the metadata of the CAEN fragment. CAENV1740Fragment caen_fragment(fragments[b][f]); CAENV1740FragmentMetadata const* metadata = caen_fragment.Metadata(); uint32_t num_channels = metadata->nChannels; uint32_t num_samples_per_wvfm = metadata->nSamples; uint32_t num_samples_per_group = num_samples_per_wvfm * 8; - std::cout << "\t\t\tNumber of channels: " << num_channels << std::endl; - std::cout << "\t\t\tNumber of samples: " << num_samples_per_wvfm << "(" << num_samples_per_group << " samples per group - 8 channels -)"<< std::endl; + if (fverbose) std::cout << " > SBNDXARAPUCADecoder::produce: number of channels: " << num_channels << std::endl; + if (fverbose) std::cout << " > SBNDXARAPUCADecoder::produce: number of samples: " << num_samples_per_wvfm << " (" << num_samples_per_group << " samples per group - 8 channels -)"<< std::endl; + // Accesses the event and header data of the CAEN fragment. CAENV1740Event const* event = caen_fragment.Event(); CAENV1740EventHeader header = event->Header; - float TTT_end_ns = header.triggerTime() * fns_per_tick; + + // Gets the TTT data of the event. + uint TTT_end_ticks = header.triggerTime(); + float TTT_end_ns = TTT_end_ticks * fns_per_tick; float TTT_ini_ns = TTT_end_ns - num_samples_per_wvfm * fns_per_sample; float TTT_end_us = TTT_end_ns * 1E-3f; float TTT_ini_us = TTT_ini_ns * 1E-3f; - std::cout << std::fixed << std::setprecision(3); - std::cout << "TTT_ini [us]: " << TTT_ini_us << "\tTTT_end [us]: " << TTT_end_us << std::endl; + if (fverbose | fdebug_timing | fdebug_all) { + std::cout << std::fixed << std::setprecision(1); + std::cout << " > SBNDXARAPUCADecoder::produce: time window of " << TTT_end_us - TTT_ini_us << " us: [" << TTT_ini_us << ", " << TTT_end_us << "] us." << std::endl; + } + if (fdebug_timing | fdebug_all) { + std::cout << "\tTTT_end [ticks]: " << TTT_end_ticks << "\tNanoseconds per tick: " << fns_per_tick << " ns." << std::endl; + std::cout << "\tTTT_end [ns]: " << TTT_end_ns << "\tNanoseconds per sample: " << fns_per_sample << " ns." << std::endl; + std::cout << "\tTTT_ini [us]: " << TTT_ini_us << std::endl; + std::cout << "\tTTT_end [us]: " << TTT_end_us << std::endl; + } - //std::cout << "\t\t\tBoard ID (from header): " << header.boardID << std::endl; - + // 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); uint32_t num_words_per_wvfm = (num_words_per_event - num_words_per_header); - - std::cout << "\t\t\tNumber of words per event: " << num_words_per_event << " [Header: " << num_words_per_header << ", Waveform: " << num_words_per_wvfm << "] words" << std::endl; + if (fverbose) std::cout << " > SBNDXARAPUCADecoder::produce: number of words per event: " << num_words_per_event << " (Header: " << num_words_per_header << ", Waveform: " << num_words_per_wvfm << ") words." << std::endl; // =============== Start decoding the waveforms =============== // + if (fverbose) std::cout << " > SBNDXARAPUCADecoder::produce: binary decoding of the waveforms starting... " << std::endl; + std::vector > wvfms(num_channels, std::vector(num_samples_per_wvfm, 0)); - // Absolute sample number + // 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 + // Buffer variables. uint64_t buffer = 0; uint32_t bits_in_buffer = 0; - uint32_t sample_bits = 12; - // Data pointer to the beggining of the waveforms stores in the event. const uint32_t* data_ptr = reinterpret_cast(fragments[b][f].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_wvfm; j++) { uint64_t word = read_word(data_ptr); - //std::cout << buffer << "[word: " << word << "]" << std::endl; + + // Adds the new word to the buffer and increments the number of bits stored in it. + if (fdebug_buffer | fdebug_all) std::cout << buffer << "[word: " << word << "]" << std::endl; buffer |= word << bits_in_buffer; - bits_in_buffer += sizeof(uint32_t) * 8; - //std::cout << " +" << buffer << " [bits in buffer: "<< bits_in_buffer << "]" << std::endl; + bits_in_buffer += sizeof(uint32_t) * 8; // bytes * 8 bits/byte + if (fdebug_buffer | fdebug_all) std::cout << " +" << buffer << " [bits in buffer: "<< bits_in_buffer << "]" << std::endl; - // Get sequences of 12 bits - while (bits_in_buffer >= sample_bits) { + // Obtains 12-bit sequences from the buffer and assigns each sample to the channel and channel sample it belongs to. + while (bits_in_buffer >= fsample_bits) { + // 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 / 3) % 8) + g * 8; // Channel index. uint32_t s = (S % 3) + ((S / 24) * 3) % num_samples_per_wvfm; // Sample/channel index. - uint16_t sample = get_range(buffer, sample_bits - 1, 0); - //std::cout << "\tSample: " << sample << "\tg: " << g << "\tch: " << c << "\ts:" << s << "\tS: " << S << std::endl; + uint16_t sample = get_sample(buffer, fsample_bits - 1, 0); wvfms[c][s] = sample; - buffer >>= sample_bits; - bits_in_buffer -= sample_bits; - //std::cout << " -" << buffer << " [bits in buffer: "<< bits_in_buffer << "]" << std::endl; + if (fdebug_waveforms | fdebug_all) 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 >>= fsample_bits; + bits_in_buffer -= fsample_bits; + if (fdebug_buffer | fdebug_all) std::cout << " -" << buffer << " [bits in buffer: "<< bits_in_buffer << "]" << std::endl; + + // Increments the absolute sample step. S++; } } + // The decoded waveforms are dumped into two products: + if (fverbose) std::cout << " > SBNDXARAPUCADecoder::produce: binary decoding complete, dumping products..." << std::endl; for (size_t ch = 0; ch < wvfms.size(); ch++) { uint channel_id = get_channel_id(b, ch); + // A xarapucadecoder-art.root file with the OpDetWaveforms as the product of this producer for further analysis. raw::OpDetWaveform waveform(TTT_ini_us, channel_id, wvfms[ch]); - //std::cout << "Pushing waveform from board " << b << "(slot " << fboard_id_list[b] << ") channel " << ch << "(ch_id " << channel_id << ")" << std::endl; + if (fdebug_waveforms | fdebug_all) std::cout << "Pushing waveform from board " << b << " (slot " << fboard_id_list[b] << ") channel " << ch << " (ch_id " << channel_id << ")" << std::endl; prod_wvfms->push_back(waveform); - hist_name.str(""); - hist_name << "Event " << event_counter << " CH " << ch << " [frag " << f << ", board " << b << " (slot " << fboard_id_list[b] << ") ] waveform"; + + // - A decoder_hist.root file gathering a waveform histograms. + std::stringstream hist_name(""); + hist_name << "Event " << fevent_counter << " CH " << ch << " [frag " << f << ", board " << b << " (slot " << fboard_id_list[b] << ") ] waveform"; TH1D* hist = tfs->make(hist_name.str().c_str(), hist_name.str().c_str(), wvfms[ch].size(), TTT_ini_us, TTT_end_us); hist->GetYaxis()->SetTitle("ADCs"); hist->GetXaxis()->SetTitle("Time [us]"); @@ -254,12 +352,24 @@ void sbndaq::SBNDXARAPUCADecoder::produce(art::Event& e) } } - e.put(std::move(prod_wvfms), fch_instance_name); + e.put(std::move(prod_wvfms), fproduct_instance_name); + if (fverbose) std::cout << "\n > SBNDXARAPUCADecoder::produce: waveforms for all valid fragments dumped." << std::endl; } - std::cout << "End of producer function." << std::endl; + if (fverbose) std::cout << "\n > SBNDXARAPUCADecoder::produce: end of the producer function.\n\n" << std::endl; } +/** + * @brief Add the fragment given as a parameter to the nested vector of fragments to be processed if it satisfies the ID restrictions. + * @param[in] fragment artdaq::Fragment object containing information related to a CAENV1740 fragment. + * @param[in, out] fragments A nested std::vector of artdaq::Fragment objects to be decoded. + * @details The function check the validity of the fragment ID after subtracting the offset (`ffragment_id_offset`). + * It searches for this adjusted ID in `fboard_id_list`. If found, it calculates the insertion index. + * - If the index is within the valid range `[0, fnum_caen_boards)`, the fragment is added to `fragments` at + * the specified position (this position represents the board to wich it belongs to). + * - If the index is out of range, or if the fragment ID is not found in `fboard_id_list`, the fragment is + * skipped. + */ void sbndaq::SBNDXARAPUCADecoder::add_fragment(artdaq::Fragment& fragment, std::vector >& fragments) { auto fragment_id = fragment.fragmentID() - ffragment_id_offset; auto it = std::find(fboard_id_list.begin(), fboard_id_list.end(), fragment_id); @@ -267,31 +377,63 @@ void sbndaq::SBNDXARAPUCADecoder::add_fragment(artdaq::Fragment& fragment, std:: if (it != fboard_id_list.end()) { uint index = it - fboard_id_list.begin(); if (index < 0 || index >= fnum_caen_boards) { - std::cout << "\t\t\tFragment ID " << fragment_id << " (" << index << ") is out of range. Skipping this fragment..." << std::endl; + if (fverbose) std::cout << " > SBNDXARAPUCADecoder::add_fragment: fragment ID " << fragment_id << " (" << index << ") is out of range. Skipping this fragment..." << std::endl; } else { - std::cout << "\t\t\tGetting a CAENV1740 fragment: [" << fragment_id << " (" << index << ") " << "]" << fragment; + if (fverbose) std::cout << " > SBNDXARAPUCADecoder::add_fragment: getting a CAENV1740 fragment: [" << fragment_id << " (" << index << ")" << "]" << fragment; fragments.at(index).push_back(fragment); } } else { - std::cout << "\t\t\tFragment ID " << fragment_id << " is not valid. Skipping this fragment..." << std::endl; + if (fverbose) std::cout << " > SBNDXARAPUCADecoder::add_fragment: fragment ID " << fragment_id << " is not valid. Skipping this fragment..." << std::endl; } - } -uint16_t sbndaq::SBNDXARAPUCADecoder::get_range(uint64_t buffer, uint32_t msb, uint32_t lsb) { +/** + * @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 + * @return The extracted sample as a 16-bit unsigned integer. + * @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. + */ +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 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. + */ uint sbndaq::SBNDXARAPUCADecoder::get_channel_id(uint board, uint board_channel) { - uint channel_id = fboard_id_list[board] * 1000 + board_channel; + uint channel_id = fboard_id_list[board] * 100 + board_channel; return channel_id; } diff --git a/sbndcode/Decoders/XARAPUCA/run_xarapucadecoder.fcl b/sbndcode/Decoders/XARAPUCA/run_xarapucadecoder.fcl index ccc3cd07c..26ac484c6 100644 --- a/sbndcode/Decoders/XARAPUCA/run_xarapucadecoder.fcl +++ b/sbndcode/Decoders/XARAPUCA/run_xarapucadecoder.fcl @@ -3,25 +3,25 @@ process_name: XARAPUCADecoder services: { - TFileService : {fileName: "decoder_hist.root"} + TFileService : {fileName: "decoder_hist.root"} # Output file containing the histograms with the extracted waveforms. } source: { module_type: RootInput - maxEvents: -1 # Number of events to create + maxEvents: -1 } outputs: { out1: { module_type: RootOutput - fileName: "xarapucadecoder-art.root" + fileName: "xarapucadecoder-art.root" # Output file containing the module products. } } physics: { producers: { - xarapucadecoder: @local::xarapucadecoder + xarapucadecoder: @local::xarapucadecoder } filters:{} @@ -32,14 +32,14 @@ physics: { reco: [xarapucadecoder] - # define the output stream, there could be more than one if using filters + # Defines the output stream, there could be more than one if using filters. stream1: [out1] - # trigger_paths is a keyword and contains the paths that modify the art::event, - # ie filters and producers + # trigger_paths is a keyword and contains the paths that modify the art::Event. + # ie filters and producer. trigger_paths: [reco] # end_paths is a keyword and contains the paths that do not modify the art::Event, - # ie analyzers and output streams. these all run simultaneously + # ie analyzers and output streams. These all run simultaneously. end_paths: [stream1] } \ No newline at end of file diff --git a/sbndcode/Decoders/XARAPUCA/xarapucadecoder.fcl b/sbndcode/Decoders/XARAPUCA/xarapucadecoder.fcl index fa2453423..574d29e91 100644 --- a/sbndcode/Decoders/XARAPUCA/xarapucadecoder.fcl +++ b/sbndcode/Decoders/XARAPUCA/xarapucadecoder.fcl @@ -2,22 +2,31 @@ BEGIN_PROLOG xarapucadecoder: { - module_type: "SBNDXARAPUCADecoder" + # Module name. + module_type: "SBNDXARAPUCADecoder" # The name to be assigne to this art::EDProducer module. - # INPUT configuration - # CAEN Fragments - caen_module_label: "daq" - caen_fragment_name: [ "CAENV1740", "ContainerCAENV1740" ] - # Boards - num_caen_boards: 4 - fragment_id_offset: 40960 - board_id_list: [7, 13, 16, 19] - # Time - ns_per_sample: 16 + # INPUT configuration: + # - CAEN Fragments. + caen_module_label: "daq" # Label identifying the CAEN fragments module. + caen_fragment_names: [ "CAENV1740", "ContainerCAENV1740" ] # Valid CAEN fragments for this decoder. + # - Boards configuration. + num_caen_boards: 4 # Maximum number of boards to be considered. + fragment_id_offset: 40960 # Offset to be applied to the fragment IDs. + board_id_list: [7, 13, 16, 19] # Slots where the boards are installed. + # - Timing configuration. + ns_per_sample: 16 # Nanoseconds per sample. - # OUTPUT configuration - # Output data product instance name - xarapucaInstanceName: "XARAPUCAChannels" + # OUTPUT configuration: + # - Output data product instance name. + product_instance_name: "XARAPUCAChannels" # Name for the instance produt created. + # - Debug options. + debug_all: false # (De)activates all debug options. + debug_handle: false # (De)activates art::Handle 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. + # - Verbose option. + verbose: false # (De)activates verbosity. } END_PROLOG \ No newline at end of file From 4f8c9c001faa2e142599b403c770c033414cb28d Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Alicia=20V=C3=A1zquez-Ramos?= Date: Mon, 4 Nov 2024 10:09:02 -0600 Subject: [PATCH 13/19] Add SBN Document related to the current implementation of the decoder. --- sbndcode/Decoders/XARAPUCA/SBNDXARAPUCADecoder_module.cc | 2 ++ 1 file changed, 2 insertions(+) diff --git a/sbndcode/Decoders/XARAPUCA/SBNDXARAPUCADecoder_module.cc b/sbndcode/Decoders/XARAPUCA/SBNDXARAPUCADecoder_module.cc index 461ad5eca..8418a5642 100644 --- a/sbndcode/Decoders/XARAPUCA/SBNDXARAPUCADecoder_module.cc +++ b/sbndcode/Decoders/XARAPUCA/SBNDXARAPUCADecoder_module.cc @@ -9,6 +9,8 @@ * @file SBNDXARAPUCADecoder_module.cc * @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. */ #include "art/Framework/Core/EDProducer.h" From 630a88cd60a4220e01ac9baba776fcb7c3a039d6 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Alicia=20V=C3=A1zquez-Ramos?= Date: Mon, 4 Nov 2024 11:47:01 -0600 Subject: [PATCH 14/19] Add link in the documentation to the Python binary decoder tool for V1740B digitizers binary decoding --- sbndcode/Decoders/XARAPUCA/SBNDXARAPUCADecoder_module.cc | 2 ++ 1 file changed, 2 insertions(+) diff --git a/sbndcode/Decoders/XARAPUCA/SBNDXARAPUCADecoder_module.cc b/sbndcode/Decoders/XARAPUCA/SBNDXARAPUCADecoder_module.cc index 8418a5642..e0e085719 100644 --- a/sbndcode/Decoders/XARAPUCA/SBNDXARAPUCADecoder_module.cc +++ b/sbndcode/Decoders/XARAPUCA/SBNDXARAPUCADecoder_module.cc @@ -11,6 +11,8 @@ * 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. + * @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). */ #include "art/Framework/Core/EDProducer.h" From c72d80c2e677ec9bcd6b7f26494c96c0d7e69b03 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Alicia=20V=C3=A1zquez-Ramos?= Date: Wed, 27 Nov 2024 09:27:24 -0600 Subject: [PATCH 15/19] Updates the include path for the CAENV1740Fragment.hh and one of the comments fixed. --- sbndcode/Decoders/XARAPUCA/SBNDXARAPUCADecoder_module.cc | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/sbndcode/Decoders/XARAPUCA/SBNDXARAPUCADecoder_module.cc b/sbndcode/Decoders/XARAPUCA/SBNDXARAPUCADecoder_module.cc index e0e085719..4aa6569dd 100644 --- a/sbndcode/Decoders/XARAPUCA/SBNDXARAPUCADecoder_module.cc +++ b/sbndcode/Decoders/XARAPUCA/SBNDXARAPUCADecoder_module.cc @@ -28,7 +28,7 @@ #include "artdaq-core/Data/Fragment.hh" #include "artdaq-core/Data/ContainerFragment.hh" #include "sbndaq-artdaq-core/Overlays/FragmentType.hh" -#include "sbndaq-artdaq-core/Overlays/Common/CAENV1740Fragment.hh" +#include "sbndaq-artdaq-core/Overlays/SBND/CAENV1740Fragment.hh" #include "lardataobj/RawData/OpDetWaveform.h" @@ -166,7 +166,7 @@ sbndaq::SBNDXARAPUCADecoder::SBNDXARAPUCADecoder(fhicl::ParameterSet const& p) * Where the group index is computed as \f$ \frac{S}{s_{g}} \f$. * 4. The decoded waveforms are dumped into: * - decoder_hist.root file (waveforms in ROOT histograms format). - * - + * - xarapucadecoder-art.root file (EDProducer product: a vector of raw::OpDetWaverform). */ void sbndaq::SBNDXARAPUCADecoder::produce(art::Event& e) { From d6cb318023ee42fe2ed2791bcf77c1c17bb7b02a Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Alicia=20V=C3=A1zquez-Ramos?= Date: Thu, 5 Dec 2024 06:02:45 -0600 Subject: [PATCH 16/19] CAEN offset and verbose option updated. --- sbndcode/Decoders/XARAPUCA/SBNDXARAPUCADecoder_module.cc | 2 +- sbndcode/Decoders/XARAPUCA/xarapucadecoder.fcl | 6 +++--- 2 files changed, 4 insertions(+), 4 deletions(-) diff --git a/sbndcode/Decoders/XARAPUCA/SBNDXARAPUCADecoder_module.cc b/sbndcode/Decoders/XARAPUCA/SBNDXARAPUCADecoder_module.cc index 4aa6569dd..03f8d629d 100644 --- a/sbndcode/Decoders/XARAPUCA/SBNDXARAPUCADecoder_module.cc +++ b/sbndcode/Decoders/XARAPUCA/SBNDXARAPUCADecoder_module.cc @@ -253,7 +253,7 @@ void sbndaq::SBNDXARAPUCADecoder::produce(art::Event& e) if (fverbose) std::cout << "\n > SBNDXARAPUCADecoder::produce: decoding V1740 CAEN fragments..." << std::endl; for (size_t b = 0; b < fragments.size(); b++) { for (size_t f = 0; f < fragments[b].size(); f++) { - if (fverbose) std::cout << "\n > SBNDXARAPUCADecoder::produce: decoding V1740 CAEN fragment " << f << " from the board " << b << "(slot " << fboard_id_list[b] << "):" << std::endl; + if (fverbose) std::cout << "\n > SBNDXARAPUCADecoder::produce: decoding V1740 CAEN fragment " << f << " from the board " << b << " (slot " << fboard_id_list[b] << "):" << std::endl; // Accesses the metadata of the CAEN fragment. CAENV1740Fragment caen_fragment(fragments[b][f]); diff --git a/sbndcode/Decoders/XARAPUCA/xarapucadecoder.fcl b/sbndcode/Decoders/XARAPUCA/xarapucadecoder.fcl index 574d29e91..4d902e23d 100644 --- a/sbndcode/Decoders/XARAPUCA/xarapucadecoder.fcl +++ b/sbndcode/Decoders/XARAPUCA/xarapucadecoder.fcl @@ -11,7 +11,7 @@ xarapucadecoder: caen_fragment_names: [ "CAENV1740", "ContainerCAENV1740" ] # Valid CAEN fragments for this decoder. # - Boards configuration. num_caen_boards: 4 # Maximum number of boards to be considered. - fragment_id_offset: 40960 # Offset to be applied to the fragment IDs. + 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. ns_per_sample: 16 # Nanoseconds per sample. @@ -21,12 +21,12 @@ xarapucadecoder: product_instance_name: "XARAPUCAChannels" # Name for the instance produt created. # - Debug options. debug_all: false # (De)activates all debug options. - debug_handle: false # (De)activates art::Handle data printing. + debug_handle: true # (De)activates art::Handle 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. # - Verbose option. - verbose: false # (De)activates verbosity. + verbose: true # (De)activates verbosity. } END_PROLOG \ No newline at end of file From 21d749dd0756fdd8efb64f7d96ef74f4d30ae19d Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Alicia=20V=C3=A1zquez-Ramos?= Date: Tue, 7 Jan 2025 18:29:40 -0600 Subject: [PATCH 17/19] Add option for the number of debug waveforms to store. Comments in the code updated. uint type changed for unsigned int -standard- --- .../XARAPUCA/SBNDXARAPUCADecoder_module.cc | 153 +++++++++++++----- .../Decoders/XARAPUCA/xarapucadecoder.fcl | 7 +- 2 files changed, 120 insertions(+), 40 deletions(-) diff --git a/sbndcode/Decoders/XARAPUCA/SBNDXARAPUCADecoder_module.cc b/sbndcode/Decoders/XARAPUCA/SBNDXARAPUCADecoder_module.cc index 03f8d629d..5c3e8810f 100644 --- a/sbndcode/Decoders/XARAPUCA/SBNDXARAPUCADecoder_module.cc +++ b/sbndcode/Decoders/XARAPUCA/SBNDXARAPUCADecoder_module.cc @@ -28,7 +28,7 @@ #include "artdaq-core/Data/Fragment.hh" #include "artdaq-core/Data/ContainerFragment.hh" #include "sbndaq-artdaq-core/Overlays/FragmentType.hh" -#include "sbndaq-artdaq-core/Overlays/SBND/CAENV1740Fragment.hh" +#include "sbndaq-artdaq-core/Overlays/Common/CAENV1740Fragment.hh" #include "lardataobj/RawData/OpDetWaveform.h" @@ -67,23 +67,24 @@ class sbndaq::SBNDXARAPUCADecoder : public art::EDProducer { private: - uint fevent_counter; /**< Event counter. */ + unsigned int fevent_counter; /**< Event counter. */ - uint fnum_caen_boards; /**< Maximum number of CAEN boards to be considered. */ - uint ffragment_id_offset; /**< Offset value to get the slot of every CAEN board. */ - std::vector fboard_id_list; /**< Possible CAEN board identifiers based on the slot they are installed. */ + unsigned int fnum_caen_boards; /**< Maximum number of CAEN boards to be considered. */ + unsigned int ffragment_id_offset; /**< Offset value to get the slot of every CAEN board. */ + std::vector fboard_id_list; /**< Possible CAEN board identifiers based on the slot they are installed. */ std::string fcaen_module_label; /**< Label identifying the module where the CAEN fragments come from. */ std::vector fcaen_fragment_names; /**< Fragments accepted by this decoder. */ std::string fproduct_instance_name; /**< Name assigned to the product instance generated by this art::EDProducer. */ - uint fns_per_sample; /**< Number of nanoseconds per sample. */ + unsigned int fns_per_sample; /**< Number of nanoseconds per sample. */ uint16_t fns_per_tick; /**< Number of nanoseconds per trigger time stamp (TTT) tick. */ uint32_t fsample_bits; /**< Number of bits per sample. */ 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). */ bool fdebug_all; /**< If `true` all debug information is printed. */ bool fdebug_handle; /**< If `true` art::Handle object data is printed. */ @@ -93,10 +94,12 @@ class sbndaq::SBNDXARAPUCADecoder : public art::EDProducer { bool fverbose; /**< If `true` it increases verbosity of console output for detailed processing steps. */ // Class methods. + void save_prod_wvfm(size_t b, size_t ch, float TTT_ini_us, const std::vector > & wvfms, std::vector & prod_wvfms); + void save_debug_wvfm(size_t b, size_t f, int ch, float TTT_ini_us, float TTT_end_us, const std::vector > & wvfms); void add_fragment(artdaq::Fragment& fragment, std::vector >& fragments); uint16_t get_sample(uint64_t buffer, uint32_t msb, uint32_t lsb); uint32_t read_word(const uint32_t* & data_ptr); - uint get_channel_id(uint board, uint board_channel); + unsigned int get_channel_id(unsigned int board, unsigned int board_channel); }; @@ -119,20 +122,23 @@ sbndaq::SBNDXARAPUCADecoder::SBNDXARAPUCADecoder(fhicl::ParameterSet const& p) fcaen_fragment_names = p.get > ("caen_fragment_names"); // Gets the CAEN boards information. - ffragment_id_offset = p.get ("fragment_id_offset"); - fboard_id_list = p.get > ("board_id_list"); - fnum_caen_boards = p.get ("num_caen_boards"); + ffragment_id_offset = p.get ("fragment_id_offset"); + fboard_id_list = p.get > ("board_id_list"); + fnum_caen_boards = p.get ("num_caen_boards"); // Gets the name of the instance created by this module. fproduct_instance_name = p.get ("product_instance_name"); // Gets timing information. - fns_per_sample = p.get ("ns_per_sample"); + fns_per_sample = p.get ("ns_per_sample"); fns_per_tick = 8; // Sets the number of bits per sample. fsample_bits = 12; + // Gets the number of waveforms to store in the debug output file. + fstore_debug_waveforms = p.get ("store_debug_waveforms", 0); + // Gets the debug and verbose options. fdebug_all = p.get ("debug_all"); fdebug_handle = p.get ("debug_handle"); @@ -172,7 +178,6 @@ void sbndaq::SBNDXARAPUCADecoder::produce(art::Event& e) { if (fverbose) std::cout << "\n > SBNDXARAPUCADecoder::produce: entering the produce function." << std::endl; - // Advances the event counter. fevent_counter++; @@ -205,7 +210,7 @@ void sbndaq::SBNDXARAPUCADecoder::produce(art::Event& e) // The art::Handle object is valid and not empty. } else { found_caen |= true; - uint frag_handle_size = fragment_handle->size(); + size_t frag_handle_size = fragment_handle->size(); if (fdebug_handle | fdebug_all) std::cout << "\tHandle valid for " << caen_name << " (" << frag_handle_size << " objects)." << std::endl; @@ -219,7 +224,7 @@ void sbndaq::SBNDXARAPUCADecoder::produce(art::Event& e) // it searches for all CAEN V1740 fragments inside the container if it contains CAEN V1740 fragments. if (container_fragment.fragment_type() == sbndaq::detail::FragmentType::CAENV1740) { - uint num_caen_fragments = container_fragment.block_count(); + size_t num_caen_fragments = container_fragment.block_count(); if (fdebug_handle | fdebug_all) std::cout << "\t\tContainerCAENV1740 "<< c << " - CAENV1740 fragments found: " << num_caen_fragments << "." << std::endl; for (size_t f = 0; f < num_caen_fragments; f++) { @@ -269,7 +274,7 @@ void sbndaq::SBNDXARAPUCADecoder::produce(art::Event& e) CAENV1740EventHeader header = event->Header; // Gets the TTT data of the event. - uint TTT_end_ticks = header.triggerTime(); + uint32_t TTT_end_ticks = header.triggerTime(); float TTT_end_ns = TTT_end_ticks * fns_per_tick; float TTT_ini_ns = TTT_end_ns - num_samples_per_wvfm * fns_per_sample; float TTT_end_us = TTT_end_ns * 1E-3f; @@ -335,24 +340,29 @@ void sbndaq::SBNDXARAPUCADecoder::produce(art::Event& e) } // 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::produce: binary decoding complete, dumping products..." << std::endl; - for (size_t ch = 0; ch < wvfms.size(); ch++) { - uint channel_id = get_channel_id(b, ch); - // A xarapucadecoder-art.root file with the OpDetWaveforms as the product of this producer for further analysis. - raw::OpDetWaveform waveform(TTT_ini_us, channel_id, wvfms[ch]); - if (fdebug_waveforms | fdebug_all) std::cout << "Pushing waveform from board " << b << " (slot " << fboard_id_list[b] << ") channel " << ch << " (ch_id " << channel_id << ")" << std::endl; - prod_wvfms->push_back(waveform); - - // - A decoder_hist.root file gathering a waveform histograms. - std::stringstream hist_name(""); - hist_name << "Event " << fevent_counter << " CH " << ch << " [frag " << f << ", board " << b << " (slot " << fboard_id_list[b] << ") ] waveform"; - TH1D* hist = tfs->make(hist_name.str().c_str(), hist_name.str().c_str(), wvfms[ch].size(), TTT_ini_us, TTT_end_us); - hist->GetYaxis()->SetTitle("ADCs"); - hist->GetXaxis()->SetTitle("Time [us]"); - for (size_t i = 0; i < wvfms[ch].size(); i++) { - hist->SetBinContent(i+1, wvfms[ch][i]); - } + + 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(b, ch, TTT_ini_us, wvfms, *prod_wvfms); + save_debug_wvfm(b, f, ch, TTT_ini_us, TTT_end_us, wvfms); + } + + for (;ch < num_channels; ch++) { + save_prod_wvfm(b, ch, TTT_ini_us, wvfms, *prod_wvfms); } + } } @@ -363,10 +373,71 @@ void sbndaq::SBNDXARAPUCADecoder::produce(art::Event& e) if (fverbose) std::cout << "\n > SBNDXARAPUCADecoder::produce: end of the producer function.\n\n" << std::endl; } +/** + * @brief Converts a production waveform from raw ADC data into a `raw::OpDetWaveform` object, + * assigning it a global channel ID and timestamp, and appends it to the output collection. + * + * @param[in] b The board index (position in the list of boards). + * @param[in] ch The channel index (channel number from which the waveform is extracted). + * @param[in] TTT_ini_us The initial timestamp of the waveform in microseconds. + * @param[in] wvfms A 2D vector containing the waveforms. Each inner vector corresponds to a channel, + * and each element of the inner vector represents a sample (ADC count). + * @param[out] prod_wvfms A reference to the vector where the produced `raw::OpDetWaveform` objects + * will be stored. + * + * @details + * The function performs the following steps: + * 1. Determines the global channel ID for the specified board and channel using `get_channel_id`. + * 2. Creates a `raw::OpDetWaveform` object with the initial timestamp, global channel ID, and waveform data. + * 3. Appends the `raw::OpDetWaveform` object to the provided `prod_wvfms` collection. + * + * @see raw::OpDetWaveform + */ +void sbndaq::SBNDXARAPUCADecoder::save_prod_wvfm(size_t b, size_t ch, float TTT_ini_us, const std::vector > & wvfms, std::vector & prod_wvfms) { + unsigned int channel_id = get_channel_id(b, ch); + raw::OpDetWaveform waveform(TTT_ini_us, channel_id, wvfms[ch]); + if (fdebug_waveforms | fdebug_all) std::cout << "Pushing waveform from board " << b << " (slot " << fboard_id_list[b] << ") channel " << ch << " (ch_id " << channel_id << ")" << std::endl; + prod_wvfms.push_back(waveform); +} + +/** + * @brief Saves debug waveform as a histogram for debugging purposes, based on the waveform data provided. + * The histogram is labeled with event number, fragment, board slot ID and channel information. + * + * @param[in] b The board index (position in the list of boards). + * @param[in] f The fragment index. + * @param[in] ch The channel index (channel number from which the waveform is extracted). + * @param[in] TTT_ini_us The initial timestamp of the waveform in microseconds. + * @param[in] TTT_end_us The final timestamp of the waveform in microseconds. + * @param[in] wvfms A 2D vector containing the waveforms. Each inner vector corresponds to a channel, + * and each element of the inner vector represents a sample (ADC count). + * + * @details + * The function generates a histogram with: + * - X-axis representing time in microseconds, scaled between `TTT_ini_us` and `TTT_end_us`. + * - Y-axis representing ADC counts. + * The histogram is stored using ROOT's `TFileService`. + * + * @see TH1D, TFileService + */ + +void sbndaq::SBNDXARAPUCADecoder::save_debug_wvfm(size_t b, size_t f, int ch, float TTT_ini_us, float TTT_end_us, const std::vector > & wvfms) { + std::stringstream hist_name(""); + hist_name << "Event " << fevent_counter << " CH " << ch << " [frag " << f << ", board " << b << " (slot " << fboard_id_list[b] << ") ] waveform"; + TH1D* hist = tfs->make(hist_name.str().c_str(), hist_name.str().c_str(), wvfms[ch].size(), TTT_ini_us, TTT_end_us); + hist->GetYaxis()->SetTitle("ADCs"); + hist->GetXaxis()->SetTitle("Time [us]"); + for (size_t i = 0; i < wvfms[ch].size(); i++) { + hist->SetBinContent(i+1, wvfms[ch][i]); + } +} + /** * @brief Add the fragment given as a parameter to the nested vector of fragments to be processed if it satisfies the ID restrictions. + * * @param[in] fragment artdaq::Fragment object containing information related to a CAENV1740 fragment. - * @param[in, out] fragments A nested std::vector of artdaq::Fragment objects to be decoded. + * @param[out] fragments A nested std::vector of artdaq::Fragment objects to be decoded. + * * @details The function check the validity of the fragment ID after subtracting the offset (`ffragment_id_offset`). * It searches for this adjusted ID in `fboard_id_list`. If found, it calculates the insertion index. * - If the index is within the valid range `[0, fnum_caen_boards)`, the fragment is added to `fragments` at @@ -379,7 +450,7 @@ void sbndaq::SBNDXARAPUCADecoder::add_fragment(artdaq::Fragment& fragment, std:: auto it = std::find(fboard_id_list.begin(), fboard_id_list.end(), fragment_id); if (it != fboard_id_list.end()) { - uint index = it - fboard_id_list.begin(); + unsigned int index = it - fboard_id_list.begin(); if (index < 0 || index >= fnum_caen_boards) { if (fverbose) std::cout << " > SBNDXARAPUCADecoder::add_fragment: fragment ID " << fragment_id << " (" << index << ") is out of range. Skipping this fragment..." << std::endl; } else { @@ -393,12 +464,15 @@ void sbndaq::SBNDXARAPUCADecoder::add_fragment(artdaq::Fragment& fragment, std:: /** * @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 - * @return The extracted sample as a 16-bit unsigned integer. + * * @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; @@ -408,9 +482,12 @@ uint16_t sbndaq::SBNDXARAPUCADecoder::get_sample(uint64_t buffer, uint32_t msb, /** * @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) { @@ -420,9 +497,11 @@ uint32_t sbndaq::SBNDXARAPUCADecoder::read_word(const uint32_t* & data_ptr) { } /** - * @brief Generates a unique channel identifier using the board slot and the channel number of that board. + * @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: @@ -436,8 +515,8 @@ uint32_t sbndaq::SBNDXARAPUCADecoder::read_word(const uint32_t* & data_ptr) { * * @return A unique identifier for the specified channel as an unsigned integer. */ -uint sbndaq::SBNDXARAPUCADecoder::get_channel_id(uint board, uint board_channel) { - uint channel_id = fboard_id_list[board] * 100 + board_channel; +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; } diff --git a/sbndcode/Decoders/XARAPUCA/xarapucadecoder.fcl b/sbndcode/Decoders/XARAPUCA/xarapucadecoder.fcl index 4d902e23d..e58fee2ac 100644 --- a/sbndcode/Decoders/XARAPUCA/xarapucadecoder.fcl +++ b/sbndcode/Decoders/XARAPUCA/xarapucadecoder.fcl @@ -18,15 +18,16 @@ xarapucadecoder: # OUTPUT configuration: # - Output data product instance name. - product_instance_name: "XARAPUCAChannels" # Name for the instance produt created. + product_instance_name: "XARAPUCAChannels" # Name for the instance product created. + store_debug_waveforms: 0 # Number of waveforms to store (0: none, -1: all, n: first n waveforms). # - Debug options. debug_all: false # (De)activates all debug options. - debug_handle: true # (De)activates art::Handle data printing. + debug_handle: false # (De)activates art::Handle 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. # - Verbose option. - verbose: true # (De)activates verbosity. + verbose: false # (De)activates verbosity. } END_PROLOG \ No newline at end of file From a55eca387292a75b8173546c9f97b492c734872a Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Alicia=20V=C3=A1zquez-Ramos?= Date: Tue, 7 Jan 2025 18:58:09 -0600 Subject: [PATCH 18/19] Add correction to TFileService ROOT object changing from TH1D to TH1I. Adds default values for FHiCL parameters in the constructor --- .../XARAPUCA/SBNDXARAPUCADecoder_module.cc | 32 +++++++++---------- 1 file changed, 16 insertions(+), 16 deletions(-) diff --git a/sbndcode/Decoders/XARAPUCA/SBNDXARAPUCADecoder_module.cc b/sbndcode/Decoders/XARAPUCA/SBNDXARAPUCADecoder_module.cc index 5c3e8810f..478f5a83a 100644 --- a/sbndcode/Decoders/XARAPUCA/SBNDXARAPUCADecoder_module.cc +++ b/sbndcode/Decoders/XARAPUCA/SBNDXARAPUCADecoder_module.cc @@ -33,7 +33,7 @@ #include "lardataobj/RawData/OpDetWaveform.h" #include "art_root_io/TFileService.h" -#include "TH1D.h" +#include "TH1I.h" #include #include @@ -118,19 +118,19 @@ sbndaq::SBNDXARAPUCADecoder::SBNDXARAPUCADecoder(fhicl::ParameterSet const& p) fevent_counter = 0; // Gets the CAEN fragments information. - fcaen_module_label = p.get ("caen_module_label"); - fcaen_fragment_names = p.get > ("caen_fragment_names"); + fcaen_module_label = p.get ("caen_module_label", "daq"); + fcaen_fragment_names = p.get > ("caen_fragment_names", {"CAENV1740", "ContainerCAENV1740"}); // Gets the CAEN boards information. - ffragment_id_offset = p.get ("fragment_id_offset"); - fboard_id_list = p.get > ("board_id_list"); - fnum_caen_boards = p.get ("num_caen_boards"); + ffragment_id_offset = p.get ("fragment_id_offset", 41216); + fboard_id_list = p.get > ("board_id_list", {7, 13, 16, 19}); + fnum_caen_boards = p.get ("num_caen_boards", 4); // Gets the name of the instance created by this module. - fproduct_instance_name = p.get ("product_instance_name"); + fproduct_instance_name = p.get ("product_instance_name", "XARAPUCAChannels"); // Gets timing information. - fns_per_sample = p.get ("ns_per_sample"); + fns_per_sample = p.get ("ns_per_sample", 16); fns_per_tick = 8; // Sets the number of bits per sample. @@ -140,12 +140,12 @@ sbndaq::SBNDXARAPUCADecoder::SBNDXARAPUCADecoder(fhicl::ParameterSet const& p) fstore_debug_waveforms = p.get ("store_debug_waveforms", 0); // Gets the debug and verbose options. - fdebug_all = p.get ("debug_all"); - fdebug_handle = p.get ("debug_handle"); - fdebug_timing = p.get ("debug_timing"); - fdebug_buffer = p.get ("debug_buffer"); - fdebug_waveforms = p.get ("debug_waveforms"); - fverbose = p.get ("verbose"); + fdebug_all = p.get ("debug_all", false); + fdebug_handle = p.get ("debug_handle", false); + fdebug_timing = p.get ("debug_timing", false); + fdebug_buffer = p.get ("debug_buffer", false); + fdebug_waveforms = p.get ("debug_waveforms", false); + fverbose = p.get ("verbose", false); // Creates the instance product of this module. produces > (fproduct_instance_name); @@ -418,13 +418,13 @@ void sbndaq::SBNDXARAPUCADecoder::save_prod_wvfm(size_t b, size_t ch, float TTT_ * - Y-axis representing ADC counts. * The histogram is stored using ROOT's `TFileService`. * - * @see TH1D, TFileService + * @see TH1I, TFileService */ void sbndaq::SBNDXARAPUCADecoder::save_debug_wvfm(size_t b, size_t f, int ch, float TTT_ini_us, float TTT_end_us, const std::vector > & wvfms) { std::stringstream hist_name(""); hist_name << "Event " << fevent_counter << " CH " << ch << " [frag " << f << ", board " << b << " (slot " << fboard_id_list[b] << ") ] waveform"; - TH1D* hist = tfs->make(hist_name.str().c_str(), hist_name.str().c_str(), wvfms[ch].size(), TTT_ini_us, TTT_end_us); + TH1I* hist = tfs->make(hist_name.str().c_str(), hist_name.str().c_str(), wvfms[ch].size(), TTT_ini_us, TTT_end_us); hist->GetYaxis()->SetTitle("ADCs"); hist->GetXaxis()->SetTitle("Time [us]"); for (size_t i = 0; i < wvfms[ch].size(); i++) { From e19ea3072b4c03604dbe819a5c38560be2d6ee96 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Alicia=20V=C3=A1zquez-Ramos?= Date: Sat, 11 Jan 2025 07:36:46 -0600 Subject: [PATCH 19/19] Read and process every fragment straight out in the reading of the art products --- .../XARAPUCA/SBNDXARAPUCADecoder_module.cc | 344 +++++++++--------- .../Decoders/XARAPUCA/xarapucadecoder.fcl | 2 +- 2 files changed, 171 insertions(+), 175 deletions(-) diff --git a/sbndcode/Decoders/XARAPUCA/SBNDXARAPUCADecoder_module.cc b/sbndcode/Decoders/XARAPUCA/SBNDXARAPUCADecoder_module.cc index 478f5a83a..66808d2da 100644 --- a/sbndcode/Decoders/XARAPUCA/SBNDXARAPUCADecoder_module.cc +++ b/sbndcode/Decoders/XARAPUCA/SBNDXARAPUCADecoder_module.cc @@ -28,7 +28,7 @@ #include "artdaq-core/Data/Fragment.hh" #include "artdaq-core/Data/ContainerFragment.hh" #include "sbndaq-artdaq-core/Overlays/FragmentType.hh" -#include "sbndaq-artdaq-core/Overlays/Common/CAENV1740Fragment.hh" +#include "sbndaq-artdaq-core/Overlays/SBND/CAENV1740Fragment.hh" #include "lardataobj/RawData/OpDetWaveform.h" @@ -84,7 +84,7 @@ class sbndaq::SBNDXARAPUCADecoder : public art::EDProducer { uint32_t fsample_bits; /**< Number of bits per sample. */ 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). */ + 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 fdebug_all; /**< If `true` all debug information is printed. */ bool fdebug_handle; /**< If `true` art::Handle object data is printed. */ @@ -94,9 +94,9 @@ class sbndaq::SBNDXARAPUCADecoder : public art::EDProducer { bool fverbose; /**< If `true` it increases verbosity of console output for detailed processing steps. */ // Class methods. - void save_prod_wvfm(size_t b, size_t ch, float TTT_ini_us, const std::vector > & wvfms, std::vector & prod_wvfms); - void save_debug_wvfm(size_t b, size_t f, int ch, float TTT_ini_us, float TTT_end_us, const std::vector > & wvfms); - void add_fragment(artdaq::Fragment& fragment, std::vector >& fragments); + void decode_fragment(std::vector & fragment_indices, const artdaq::Fragment& fragment, std::vector & prod_wvfms); + void save_prod_wvfm(size_t board_idx, size_t ch, float TTT_ini_us, const std::vector > & wvfms, std::vector & prod_wvfms); + void save_debug_wvfm(size_t board_idx, size_t fragment_idx, int ch, float TTT_ini_us, float TTT_end_us, const std::vector > & wvfms); 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); @@ -159,20 +159,7 @@ sbndaq::SBNDXARAPUCADecoder::SBNDXARAPUCADecoder(fhicl::ParameterSet const& p) * non-empty. If valid, it updates `found_caen` and processes each fragment based on its type: either as a * container of fragments or as individual CAEN V1740 fragments. * 2. Access the data inside the CAEN fragments and extracts header, timing data and the raw waveform. - * 3. 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$. - * 4. The decoded waveforms are dumped into: - * - decoder_hist.root file (waveforms in ROOT histograms format). - * - xarapucadecoder-art.root file (EDProducer product: a vector of raw::OpDetWaverform). + * 3. Decodes the fragment and dumps the products. */ void sbndaq::SBNDXARAPUCADecoder::produce(art::Event& e) { @@ -191,9 +178,8 @@ void sbndaq::SBNDXARAPUCADecoder::produce(art::Event& e) // Flag to track if valid CAEN fragments are found. bool found_caen = false; - // This loop iterates over the valid CAEN fragments names (`fcaen_fragment_names`) to check - // if the art::Handle object is not empty and has valid CAEN fragments. After this, it extracts - // the CAEN V1740 fragments into a nested std::vector, assigning each fragment to its board. + std::vector fragment_indices(fnum_caen_boards, 0); + if (fverbose | fdebug_handle | fdebug_all) std::cout << "\n > SBNDXARAPUCADecoder::produce: searching for V1740 fragments." << std::endl; for (const std::string &caen_name: fcaen_fragment_names) { art::Handle > fragment_handle; @@ -228,8 +214,8 @@ void sbndaq::SBNDXARAPUCADecoder::produce(art::Event& e) if (fdebug_handle | fdebug_all) std::cout << "\t\tContainerCAENV1740 "<< c << " - CAENV1740 fragments found: " << num_caen_fragments << "." << std::endl; for (size_t f = 0; f < num_caen_fragments; f++) { - artdaq::Fragment fragment = *container_fragment[f].get(); - add_fragment(fragment, fragments); + const artdaq::Fragment fragment = *container_fragment[f].get(); + decode_fragment(fragment_indices, fragment, *prod_wvfms); } // End CAEN V1740 fragments loop. } } // End Container fragments loop. @@ -240,137 +226,177 @@ void sbndaq::SBNDXARAPUCADecoder::produce(art::Event& e) // It searches for all CAEN V1740 fragments. for (size_t f = 0; f < frag_handle_size; f++) { - artdaq::Fragment fragment = fragment_handle->at(f); - add_fragment(fragment, fragments); + const artdaq::Fragment fragment = fragment_handle->at(f); + decode_fragment(fragment_indices, fragment, *prod_wvfms); } // End CAEN V1740 fragments loop. } } // End extracting CAEN V1740 fragments. fragment_handle.removeProduct(); } // End CAEN fragment names loop. - // If no valid CAEN fragments are found it pushes empty waveforms, if (!found_caen) { - e.put(std::move(prod_wvfms), fproduct_instance_name); if (fverbose) std::cout << "\n > SBNDXARAPUCADecoder::produce: no CAEN V1740 fragments of any type found, pushed empty waveforms." << std::endl; + } else { + if (fverbose) std::cout << "\n > SBNDXARAPUCADecoder::produce: waveforms for all valid fragments dumped." << std::endl; + } + e.put(std::move(prod_wvfms), fproduct_instance_name); + if (fverbose) std::cout << "\n > SBNDXARAPUCADecoder::produce: end of the producer function.\n\n" << std::endl; +} + +/** + * @brief This function processes a single fragment from a CAEN V1740 and stores the decoded waveforms in the provided product + * container. + * + * @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, samples, and time information. + * - 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. + * + */ +void sbndaq::SBNDXARAPUCADecoder::decode_fragment(std::vector & fragment_indices, const artdaq::Fragment& fragment, std::vector & prod_wvfms) { + 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; - // otherwise it starts the decoding of the fragments found. + 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 << "\n > SBNDXARAPUCADecoder::produce: decoding V1740 CAEN fragments..." << std::endl; - for (size_t b = 0; b < fragments.size(); b++) { - for (size_t f = 0; f < fragments[b].size(); f++) { - if (fverbose) std::cout << "\n > SBNDXARAPUCADecoder::produce: decoding V1740 CAEN fragment " << f << " from the board " << b << " (slot " << fboard_id_list[b] << "):" << std::endl; - - // Accesses the metadata of the CAEN fragment. - CAENV1740Fragment caen_fragment(fragments[b][f]); - CAENV1740FragmentMetadata const* metadata = caen_fragment.Metadata(); - uint32_t num_channels = metadata->nChannels; - uint32_t num_samples_per_wvfm = metadata->nSamples; - uint32_t num_samples_per_group = num_samples_per_wvfm * 8; - if (fverbose) std::cout << " > SBNDXARAPUCADecoder::produce: number of channels: " << num_channels << std::endl; - if (fverbose) std::cout << " > SBNDXARAPUCADecoder::produce: number of samples: " << num_samples_per_wvfm << " (" << num_samples_per_group << " samples per group - 8 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 TTT data of the event. - uint32_t TTT_end_ticks = header.triggerTime(); - float TTT_end_ns = TTT_end_ticks * fns_per_tick; - float TTT_ini_ns = TTT_end_ns - num_samples_per_wvfm * fns_per_sample; - float TTT_end_us = TTT_end_ns * 1E-3f; - float TTT_ini_us = TTT_ini_ns * 1E-3f; - if (fverbose | fdebug_timing | fdebug_all) { - std::cout << std::fixed << std::setprecision(1); - std::cout << " > SBNDXARAPUCADecoder::produce: time window of " << TTT_end_us - TTT_ini_us << " us: [" << TTT_ini_us << ", " << TTT_end_us << "] us." << std::endl; - } - if (fdebug_timing | fdebug_all) { - std::cout << "\tTTT_end [ticks]: " << TTT_end_ticks << "\tNanoseconds per tick: " << fns_per_tick << " ns." << std::endl; - std::cout << "\tTTT_end [ns]: " << TTT_end_ns << "\tNanoseconds per sample: " << fns_per_sample << " ns." << std::endl; - std::cout << "\tTTT_ini [us]: " << TTT_ini_us << std::endl; - std::cout << "\tTTT_end [us]: " << TTT_end_us << std::endl; - } - - // 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); - uint32_t num_words_per_wvfm = (num_words_per_event - num_words_per_header); - if (fverbose) std::cout << " > SBNDXARAPUCADecoder::produce: number of words per event: " << num_words_per_event << " (Header: " << num_words_per_header << ", Waveform: " << num_words_per_wvfm << ") words." << std::endl; - - // =============== Start decoding the waveforms =============== // - if (fverbose) std::cout << " > SBNDXARAPUCADecoder::produce: 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(fragments[b][f].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_wvfm; 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 | fdebug_all) std::cout << buffer << "[word: " << word << "]" << std::endl; - buffer |= word << bits_in_buffer; - bits_in_buffer += sizeof(uint32_t) * 8; // bytes * 8 bits/byte - if (fdebug_buffer | fdebug_all) 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 >= fsample_bits) { - // 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 / 3) % 8) + g * 8; // Channel index. - uint32_t s = (S % 3) + ((S / 24) * 3) % num_samples_per_wvfm; // Sample/channel index. - uint16_t sample = get_sample(buffer, fsample_bits - 1, 0); - wvfms[c][s] = sample; - if (fdebug_waveforms | fdebug_all) 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 >>= fsample_bits; - bits_in_buffer -= fsample_bits; - if (fdebug_buffer | fdebug_all) std::cout << " -" << buffer << " [bits in buffer: "<< bits_in_buffer << "]" << std::endl; - - // Increments the absolute sample step. - S++; - } - } + 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; + + // Accesses the metadata of the CAEN fragment. + CAENV1740Fragment caen_fragment(fragment); + CAENV1740FragmentMetadata const* metadata = caen_fragment.Metadata(); + uint32_t num_channels = metadata->nChannels; + uint32_t num_samples_per_wvfm = metadata->nSamples; + uint32_t num_samples_per_group = num_samples_per_wvfm * 8; + if (fverbose) std::cout << " > SBNDXARAPUCADecoder::decode_fragment: number of channels: " << num_channels << std::endl; + if (fverbose) std::cout << " > SBNDXARAPUCADecoder::decode_fragment: number of samples: " << num_samples_per_wvfm << " (" << num_samples_per_group << " samples per group - 8 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 TTT data of the event. + uint32_t TTT_end_ticks = header.triggerTime(); + float TTT_end_ns = TTT_end_ticks * fns_per_tick; + float TTT_ini_ns = TTT_end_ns - num_samples_per_wvfm * fns_per_sample; + float TTT_end_us = TTT_end_ns * 1E-3f; + float TTT_ini_us = TTT_ini_ns * 1E-3f; + if (fverbose | fdebug_timing | fdebug_all) { + std::cout << std::fixed << std::setprecision(1); + std::cout << " > SBNDXARAPUCADecoder::decode_fragment: time window of " << TTT_end_us - TTT_ini_us << " us: [" << TTT_ini_us << ", " << TTT_end_us << "] us." << std::endl; + } + if (fdebug_timing | fdebug_all) { + std::cout << "\tTTT_end [ticks]: " << TTT_end_ticks << "\tNanoseconds per tick: " << fns_per_tick << " ns." << std::endl; + std::cout << "\tTTT_end [ns]: " << TTT_end_ns << "\tNanoseconds per sample: " << fns_per_sample << " ns." << std::endl; + std::cout << "\tTTT_ini [us]: " << TTT_ini_us << std::endl; + std::cout << "\tTTT_end [us]: " << TTT_end_us << std::endl; + } + + // 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); + uint32_t num_words_per_wvfm = (num_words_per_event - num_words_per_header); + if (fverbose) std::cout << " > SBNDXARAPUCADecoder::decode_fragment: number of words per event: " << num_words_per_event << " (Header: " << num_words_per_header << ", Waveform: " << num_words_per_wvfm << ") words." << 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_wvfm; 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 | fdebug_all) std::cout << buffer << "[word: " << word << "]" << std::endl; + buffer |= word << bits_in_buffer; + bits_in_buffer += sizeof(uint32_t) * 8; // bytes * 8 bits/byte + if (fdebug_buffer | fdebug_all) 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 >= fsample_bits) { + // 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 / 3) % 8) + g * 8; // Channel index. + uint32_t s = (S % 3) + ((S / 24) * 3) % num_samples_per_wvfm; // Sample/channel index. + uint16_t sample = get_sample(buffer, fsample_bits - 1, 0); + wvfms[c][s] = sample; + if (fdebug_waveforms | fdebug_all) std::cout << "\tSample: " << sample << "\tg: " << g << "\tch: " << c << "\ts:" << s << "\tS: " << S << std::endl; - // 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::produce: binary decoding complete, dumping products..." << std::endl; + // Updates the buffer status removing the read bits and decreasing the number of bits stored in it. + buffer >>= fsample_bits; + bits_in_buffer -= fsample_bits; + if (fdebug_buffer | fdebug_all) std::cout << " -" << buffer << " [bits in buffer: "<< bits_in_buffer << "]" << 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); - } + // Increments the absolute sample step. + S++; + } + } + + // 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; - uint32_t ch; + if (fstore_debug_waveforms == -1) { + num_debug_wvfms = num_channels; + } else { + num_debug_wvfms = std::min(num_channels, fstore_debug_waveforms); + } - for (ch = 0; ch < num_debug_wvfms; ch++) { - save_prod_wvfm(b, ch, TTT_ini_us, wvfms, *prod_wvfms); - save_debug_wvfm(b, f, ch, TTT_ini_us, TTT_end_us, wvfms); - } + uint32_t ch; - for (;ch < num_channels; ch++) { - save_prod_wvfm(b, ch, TTT_ini_us, wvfms, *prod_wvfms); - } + for (ch = 0; ch < num_debug_wvfms; ch++) { + save_prod_wvfm(board_idx, ch, TTT_ini_us, wvfms, prod_wvfms); + save_debug_wvfm(board_idx, fragment_indices[board_idx], ch, TTT_ini_us, TTT_end_us, wvfms); + } - } + for (;ch < num_channels; ch++) { + save_prod_wvfm(board_idx, ch, TTT_ini_us, wvfms, prod_wvfms); } - e.put(std::move(prod_wvfms), fproduct_instance_name); - if (fverbose) std::cout << "\n > SBNDXARAPUCADecoder::produce: waveforms for all valid fragments dumped." << std::endl; + fragment_indices[board_idx]++; } - - if (fverbose) std::cout << "\n > SBNDXARAPUCADecoder::produce: end of the producer function.\n\n" << std::endl; } /** @@ -393,10 +419,10 @@ void sbndaq::SBNDXARAPUCADecoder::produce(art::Event& e) * * @see raw::OpDetWaveform */ -void sbndaq::SBNDXARAPUCADecoder::save_prod_wvfm(size_t b, size_t ch, float TTT_ini_us, const std::vector > & wvfms, std::vector & prod_wvfms) { - unsigned int channel_id = get_channel_id(b, ch); +void sbndaq::SBNDXARAPUCADecoder::save_prod_wvfm(size_t board_idx, size_t ch, float TTT_ini_us, const std::vector > & wvfms, std::vector & prod_wvfms) { + unsigned int channel_id = get_channel_id(board_idx, ch); raw::OpDetWaveform waveform(TTT_ini_us, channel_id, wvfms[ch]); - if (fdebug_waveforms | fdebug_all) std::cout << "Pushing waveform from board " << b << " (slot " << fboard_id_list[b] << ") channel " << ch << " (ch_id " << channel_id << ")" << std::endl; + if (fdebug_waveforms | fdebug_all) std::cout << "Pushing waveform from board " << board_idx << " (slot " << fboard_id_list[board_idx] << ") channel " << ch << " (ch_id " << channel_id << ")" << std::endl; prod_wvfms.push_back(waveform); } @@ -404,8 +430,8 @@ void sbndaq::SBNDXARAPUCADecoder::save_prod_wvfm(size_t b, size_t ch, float TTT_ * @brief Saves debug waveform as a histogram for debugging purposes, based on the waveform data provided. * The histogram is labeled with event number, fragment, board slot ID and channel information. * - * @param[in] b The board index (position in the list of boards). - * @param[in] f The fragment index. + * @param[in] board_idx The board index (position in the list of boards). + * @param[in] fragment_idx The fragment index (order in decoding). * @param[in] ch The channel index (channel number from which the waveform is extracted). * @param[in] TTT_ini_us The initial timestamp of the waveform in microseconds. * @param[in] TTT_end_us The final timestamp of the waveform in microseconds. @@ -421,9 +447,9 @@ void sbndaq::SBNDXARAPUCADecoder::save_prod_wvfm(size_t b, size_t ch, float TTT_ * @see TH1I, TFileService */ -void sbndaq::SBNDXARAPUCADecoder::save_debug_wvfm(size_t b, size_t f, int ch, float TTT_ini_us, float TTT_end_us, const std::vector > & wvfms) { +void sbndaq::SBNDXARAPUCADecoder::save_debug_wvfm(size_t board_idx, size_t fragment_idx, int ch, float TTT_ini_us, float TTT_end_us, const std::vector > & wvfms) { std::stringstream hist_name(""); - hist_name << "Event " << fevent_counter << " CH " << ch << " [frag " << f << ", board " << b << " (slot " << fboard_id_list[b] << ") ] waveform"; + hist_name << "Event " << fevent_counter << " CH " << ch << " [frag " << fragment_idx << ", board " << board_idx << " (slot " << fboard_id_list[board_idx] << ") ] waveform"; TH1I* hist = tfs->make(hist_name.str().c_str(), hist_name.str().c_str(), wvfms[ch].size(), TTT_ini_us, TTT_end_us); hist->GetYaxis()->SetTitle("ADCs"); hist->GetXaxis()->SetTitle("Time [us]"); @@ -432,36 +458,6 @@ void sbndaq::SBNDXARAPUCADecoder::save_debug_wvfm(size_t b, size_t f, int ch, fl } } -/** - * @brief Add the fragment given as a parameter to the nested vector of fragments to be processed if it satisfies the ID restrictions. - * - * @param[in] fragment artdaq::Fragment object containing information related to a CAENV1740 fragment. - * @param[out] fragments A nested std::vector of artdaq::Fragment objects to be decoded. - * - * @details The function check the validity of the fragment ID after subtracting the offset (`ffragment_id_offset`). - * It searches for this adjusted ID in `fboard_id_list`. If found, it calculates the insertion index. - * - If the index is within the valid range `[0, fnum_caen_boards)`, the fragment is added to `fragments` at - * the specified position (this position represents the board to wich it belongs to). - * - If the index is out of range, or if the fragment ID is not found in `fboard_id_list`, the fragment is - * skipped. - */ -void sbndaq::SBNDXARAPUCADecoder::add_fragment(artdaq::Fragment& fragment, std::vector >& fragments) { - auto fragment_id = fragment.fragmentID() - ffragment_id_offset; - auto it = std::find(fboard_id_list.begin(), fboard_id_list.end(), fragment_id); - - if (it != fboard_id_list.end()) { - unsigned int index = it - fboard_id_list.begin(); - if (index < 0 || index >= fnum_caen_boards) { - if (fverbose) std::cout << " > SBNDXARAPUCADecoder::add_fragment: fragment ID " << fragment_id << " (" << index << ") is out of range. Skipping this fragment..." << std::endl; - } else { - if (fverbose) std::cout << " > SBNDXARAPUCADecoder::add_fragment: getting a CAENV1740 fragment: [" << fragment_id << " (" << index << ")" << "]" << fragment; - fragments.at(index).push_back(fragment); - } - } else { - if (fverbose) std::cout << " > SBNDXARAPUCADecoder::add_fragment: fragment ID " << fragment_id << " is not valid. Skipping this fragment..." << std::endl; - } -} - /** * @brief Extract a sample from a 64-bit buffer using the specified bit positions. * @@ -496,7 +492,7 @@ uint32_t sbndaq::SBNDXARAPUCADecoder::read_word(const uint32_t* & data_ptr) { 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. diff --git a/sbndcode/Decoders/XARAPUCA/xarapucadecoder.fcl b/sbndcode/Decoders/XARAPUCA/xarapucadecoder.fcl index e58fee2ac..a5bd2d585 100644 --- a/sbndcode/Decoders/XARAPUCA/xarapucadecoder.fcl +++ b/sbndcode/Decoders/XARAPUCA/xarapucadecoder.fcl @@ -19,7 +19,7 @@ xarapucadecoder: # OUTPUT configuration: # - Output data product instance name. product_instance_name: "XARAPUCAChannels" # Name for the instance product created. - store_debug_waveforms: 0 # 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_all: false # (De)activates all debug options. debug_handle: false # (De)activates art::Handle data printing.