LCOV - code coverage report
Current view: top level - hdf5libs/src - HDF5RawDataFile.cpp (source / functions) Coverage Total Hit
Test: code.result Lines: 58.9 % 616 363
Test Date: 2026-10-11 15:05:20 Functions: 52.2 % 69 36

            Line data    Source code
       1              : /**
       2              :  * This is part of the DUNE DAQ Application Framework, copyright 2020.
       3              :  * Licensing/copyright details are in the COPYING file that you should have
       4              :  * received with this code.
       5              :  *
       6              :  */
       7              : 
       8              : #include "hdf5libs/HDF5RawDataFile.hpp"
       9              : 
      10              : #include "logging/Logging.hpp"
      11              : 
      12              : #include <algorithm>
      13              : #include <filesystem>
      14              : #include <map>
      15              : #include <memory>
      16              : #include <set>
      17              : #include <sstream>
      18              : #include <string>
      19              : #include <utility>
      20              : #include <vector>
      21              : 
      22              : namespace dunedaq {
      23              : namespace hdf5libs {
      24              : 
      25              : constexpr uint32_t MAX_FILELAYOUT_VERSION = 4294967295; // NOLINT(build/unsigned)
      26              : 
      27              : /**
      28              :  * @brief Constructor for writing a new file
      29              :  */
      30           30 : HDF5RawDataFile::HDF5RawDataFile(const std::string file_name,
      31              :                                  const daqdataformats::run_number_t run_number,
      32              :                                  const size_t file_index,
      33              :                                  const std::string application_name,
      34              :                                  const HDF5FileLayoutParameters fl_params,
      35              :                                  const HDF5SourceIDHandler::source_id_geo_id_map_t srcid_geoid_map,
      36              :                                  const unsigned compression_level,
      37              :                                  const std::string inprogress_filename_suffix,
      38           30 :                                  const unsigned open_flags)
      39           30 :   : m_bare_file_name(file_name)
      40           30 :   , m_compression_level(compression_level)
      41           60 :   , m_open_flags(open_flags)
      42              : {
      43              : 
      44              :   // check and make sure that the file isn't ReadOnly
      45           30 :   if (m_open_flags == HighFive::File::ReadOnly) {
      46            0 :     throw IncompatibleOpenFlags(ERS_HERE, file_name, m_open_flags);
      47              :   }
      48              : 
      49           30 :   auto filename_to_open = m_bare_file_name + inprogress_filename_suffix;
      50              : 
      51              :   // do the file open
      52           30 :   try {
      53           30 :     m_file_ptr.reset(new HighFive::File(filename_to_open, m_open_flags));
      54            0 :   } catch (std::exception const& excpt) {
      55            0 :     throw FileOpenFailed(ERS_HERE, filename_to_open, excpt.what());
      56            0 :   }
      57              : 
      58           30 :   m_recorded_size = 0;
      59           30 :   m_uncompressed_raw_data_size = 0;
      60           30 :   m_total_file_size = 0;
      61              : 
      62           30 :   size_t file_creation_timestamp =
      63           30 :     std::chrono::duration_cast<std::chrono::milliseconds>(system_clock::now().time_since_epoch()).count();
      64              : 
      65           30 :   TLOG_DEBUG(TLVL_BASIC) << "Created HDF5 file (" << file_name << ") at time " << file_creation_timestamp << " .";
      66              : 
      67              :   // write some file attributes
      68           30 :   write_attribute("run_number", run_number);
      69           30 :   write_attribute("file_index", file_index);
      70           30 :   write_attribute("creation_timestamp", file_creation_timestamp);
      71           30 :   write_attribute("application_name", application_name);
      72              : 
      73              :   // set the file layout contents
      74           30 :   m_file_layout_ptr.reset(new HDF5FileLayout(fl_params));
      75           30 :   write_file_layout();
      76              : 
      77              :   // write the SourceID-related attributes
      78              :   // HDF5SourceIDHandler::populate_source_id_geo_id_map(srcid_geoid_map, m_file_level_source_id_geo_id_map);
      79           30 :   m_file_level_source_id_geo_id_map = srcid_geoid_map;
      80           30 :   HDF5SourceIDHandler::store_file_level_geo_id_info(*m_file_ptr, m_file_level_source_id_geo_id_map);
      81              : 
      82              :   // write the record type
      83           30 :   m_record_type = fl_params.record_name_prefix;
      84           30 :   write_attribute("record_type", m_record_type);
      85              : 
      86              :   // write the compression level
      87           30 :   write_attribute("compression_level", m_compression_level);
      88           30 : }
      89              : 
      90           44 : HDF5RawDataFile::~HDF5RawDataFile()
      91              : {
      92           44 :   if (m_file_ptr.get() != nullptr && m_open_flags != HighFive::File::ReadOnly) {
      93           30 :     if (!m_file_ptr->hasAttribute("recorded_size")) {
      94           30 :       write_attribute("recorded_size", m_recorded_size);
      95              :     }
      96              : 
      97           30 :     if (!m_file_ptr->hasAttribute("uncompressed_raw_data_size")) {
      98           30 :       write_attribute("uncompressed_raw_data_size", m_uncompressed_raw_data_size);
      99              :     }
     100              : 
     101           30 :     if (!m_file_ptr->hasAttribute("total_file_size")) {
     102           30 :       write_attribute("total_file_size", m_total_file_size);
     103              :     }
     104              : 
     105           30 :     if (!m_file_ptr->hasAttribute("closing_timestamp")) {
     106           30 :       size_t file_closing_timestamp =
     107           30 :         std::chrono::duration_cast<std::chrono::milliseconds>(system_clock::now().time_since_epoch()).count();
     108           30 :       write_attribute("closing_timestamp", file_closing_timestamp);
     109              :     }
     110              : 
     111           30 :     m_file_ptr->flush();
     112              : 
     113              :     // rename file to the bare name, if needed
     114           30 :     if (m_file_ptr->getName() != m_bare_file_name) {
     115           30 :       std::filesystem::rename(m_file_ptr->getName(), m_bare_file_name);
     116              :     }
     117              :   }
     118              : 
     119              :   // explicit destruction; not really needed, but nice to be clear...
     120           44 :   m_file_ptr.reset();
     121           44 :   m_file_layout_ptr.reset();
     122           44 : }
     123              : 
     124              : /**
     125              :  * @brief Fetch the list of all file-level Attribute names.
     126              :  */
     127              : std::vector<std::string>
     128            0 : HDF5RawDataFile::HDF5RawDataFile::get_attribute_names()
     129              : {
     130            0 :   return m_file_ptr->listAttributeNames();
     131              : }
     132              : 
     133              : /**
     134              :  * @brief Write a TriggerRecord to the file.
     135              :  */
     136              : void
     137           75 : HDF5RawDataFile::write(const daqdataformats::TriggerRecord& tr)
     138              : {
     139              :   // the source_id_path map that we will build up as we write the TR header
     140              :   // and fragments (and then write the map into the HDF5 TR_record Group)
     141           75 :   HDF5SourceIDHandler::source_id_path_map_t source_id_path_map;
     142              : 
     143              :   // the map of fragment types to SourceIDS
     144           75 :   HDF5SourceIDHandler::fragment_type_source_id_map_t fragment_type_source_id_map;
     145              : 
     146              :   // the map of subdetectors to SourceIDS
     147           75 :   HDF5SourceIDHandler::subdetector_source_id_map_t subdetector_source_id_map;
     148              : 
     149              :   // write the record header into the HDF5 file/group
     150           75 :   HighFive::Group record_level_group = write(tr.get_header_ref(), source_id_path_map);
     151              : 
     152              :   // store the SourceID of the record header in the HDF5 file/group
     153              :   // (since there should only be one entry in the map at this point, we'll take advantage of that...)
     154          150 :   for (auto const& source_id_path : source_id_path_map) {
     155           75 :     HDF5SourceIDHandler::store_record_header_source_id(record_level_group, source_id_path.first);
     156              :   }
     157              : 
     158              :   // write all of the fragments into the HDF5 file/group
     159         1415 :   for (auto const& frag_ptr : tr.get_fragments_ref()) {
     160         1340 :     write(*frag_ptr, source_id_path_map);
     161         1340 :     HDF5SourceIDHandler::add_fragment_type_source_id_to_map(
     162         1340 :       fragment_type_source_id_map, frag_ptr->get_fragment_type(), frag_ptr->get_element_id());
     163         1340 :     HDF5SourceIDHandler::add_subdetector_source_id_to_map(
     164              :       subdetector_source_id_map,
     165         1340 :       static_cast<detdataformats::DetID::Subdetector>(frag_ptr->get_detector_id()),
     166         1340 :       frag_ptr->get_element_id());
     167              :   }
     168              : 
     169              :   // store all of the record-level maps in the HDF5 file/group
     170           75 :   HDF5SourceIDHandler::store_record_level_path_info(record_level_group, source_id_path_map);
     171           75 :   HDF5SourceIDHandler::store_record_level_fragment_type_map(record_level_group, fragment_type_source_id_map);
     172           75 :   HDF5SourceIDHandler::store_record_level_subdetector_map(record_level_group, subdetector_source_id_map);
     173           75 : }
     174              : 
     175              : /**
     176              :  * @brief Write a TimeSlice to the file.
     177              :  */
     178              : void
     179           31 : HDF5RawDataFile::write(const daqdataformats::TimeSlice& ts)
     180              : {
     181              :   // the source_id_path map that we will build up as we write the TR header
     182              :   // and fragments (and then write the map into the HDF5 TR_record Group)
     183           31 :   HDF5SourceIDHandler::source_id_path_map_t source_id_path_map;
     184              : 
     185              :   // the map of fragment types to SourceIDS
     186           31 :   HDF5SourceIDHandler::fragment_type_source_id_map_t fragment_type_source_id_map;
     187              : 
     188              :   // the map of subdetectors to SourceIDS
     189           31 :   HDF5SourceIDHandler::subdetector_source_id_map_t subdetector_source_id_map;
     190              : 
     191              :   // write the record header into the HDF5 file/group
     192           31 :   HighFive::Group record_level_group = write(ts.get_header(), source_id_path_map);
     193              : 
     194              :   // store the SourceID of the record header in the HDF5 file/group
     195              :   // (since there should only be one entry in the map at this point, we'll take advantage of that...)
     196           62 :   for (auto const& source_id_path : source_id_path_map) {
     197           31 :     HDF5SourceIDHandler::store_record_header_source_id(record_level_group, source_id_path.first);
     198              :   }
     199              : 
     200              :   // write all of the fragments into the HDF5 file/group
     201          271 :   for (auto const& frag_ptr : ts.get_fragments_ref()) {
     202          240 :     write(*frag_ptr, source_id_path_map);
     203          240 :     HDF5SourceIDHandler::add_fragment_type_source_id_to_map(
     204          240 :       fragment_type_source_id_map, frag_ptr->get_fragment_type(), frag_ptr->get_element_id());
     205          240 :     HDF5SourceIDHandler::add_subdetector_source_id_to_map(
     206              :       subdetector_source_id_map,
     207          240 :       static_cast<detdataformats::DetID::Subdetector>(frag_ptr->get_detector_id()),
     208          240 :       frag_ptr->get_element_id());
     209              :   }
     210              : 
     211              :   // store all of the record-level maps in the HDF5 file/group
     212           31 :   HDF5SourceIDHandler::store_record_level_path_info(record_level_group, source_id_path_map);
     213           31 :   HDF5SourceIDHandler::store_record_level_fragment_type_map(record_level_group, fragment_type_source_id_map);
     214           31 :   HDF5SourceIDHandler::store_record_level_subdetector_map(record_level_group, subdetector_source_id_map);
     215           31 : }
     216              : 
     217              : /**
     218              :  * @brief Write a TriggerRecordHeader to the file.
     219              :  */
     220              : HighFive::Group
     221           75 : HDF5RawDataFile::write(const daqdataformats::TriggerRecordHeader& trh,
     222              :                        HDF5SourceIDHandler::source_id_path_map_t& path_map)
     223              : {
     224           75 :   std::tuple<size_t, std::string, HighFive::Group> write_results =
     225           75 :     do_write(m_file_layout_ptr->get_path_elements(trh),
     226           75 :              static_cast<const char*>(trh.get_storage_location()),
     227              :              trh.get_total_size_bytes(),
     228           75 :              m_compression_level);
     229           75 :   m_recorded_size += std::get<0>(write_results);
     230           75 :   HDF5SourceIDHandler::add_source_id_path_to_map(path_map, trh.get_header().element_id, std::get<1>(write_results));
     231          150 :   return std::get<2>(write_results);
     232           75 : }
     233              : 
     234              : /**
     235              :  * @brief Write a TimeSliceHeader to the file.
     236              :  */
     237              : HighFive::Group
     238           31 : HDF5RawDataFile::write(const daqdataformats::TimeSliceHeader& tsh, HDF5SourceIDHandler::source_id_path_map_t& path_map)
     239              : {
     240           31 :   std::tuple<size_t, std::string, HighFive::Group> write_results = do_write(m_file_layout_ptr->get_path_elements(tsh),
     241              :                                                                             (const char*)(&tsh),
     242              :                                                                             sizeof(daqdataformats::TimeSliceHeader),
     243           31 :                                                                             m_compression_level);
     244           31 :   m_recorded_size += std::get<0>(write_results);
     245           31 :   HDF5SourceIDHandler::add_source_id_path_to_map(path_map, tsh.element_id, std::get<1>(write_results));
     246           62 :   return std::get<2>(write_results);
     247           31 : }
     248              : 
     249              : /**
     250              :  * @brief Write a Fragment to the file.
     251              :  */
     252              : void
     253         1580 : HDF5RawDataFile::write(const daqdataformats::Fragment& frag, HDF5SourceIDHandler::source_id_path_map_t& path_map)
     254              : {
     255         1580 :   std::tuple<size_t, std::string, HighFive::Group> write_results =
     256         1580 :     do_write(m_file_layout_ptr->get_path_elements(frag.get_header()),
     257         1580 :              static_cast<const char*>(frag.get_storage_location()),
     258              :              frag.get_size(),
     259         1580 :              m_compression_level);
     260         1580 :   m_recorded_size += std::get<0>(write_results);
     261              : 
     262         1580 :   daqdataformats::SourceID source_id = frag.get_element_id();
     263         1580 :   HDF5SourceIDHandler::add_source_id_path_to_map(path_map, source_id, std::get<1>(write_results));
     264         1580 : }
     265              : 
     266              : /**
     267              :  * @brief write the file layout
     268              :  */
     269              : void
     270           30 : HDF5RawDataFile::write_file_layout()
     271              : {
     272           30 :   auto fl_json = m_file_layout_ptr->get_file_layout_params().to_json();
     273           30 :   write_attribute("filelayout_params", fl_json.dump());
     274           30 :   write_attribute("filelayout_version", m_file_layout_ptr->get_version());
     275           30 : }
     276              : 
     277              : /**
     278              :  * @brief write bytes to a dataset in the file, at the appropriate path
     279              :  */
     280              : std::tuple<size_t, std::string, HighFive::Group>
     281         1686 : HDF5RawDataFile::do_write(std::vector<std::string> const& group_and_dataset_path_elements,
     282              :                           const char* raw_data_ptr,
     283              :                           size_t raw_data_size_bytes,
     284              :                           unsigned compression_level)
     285              : {
     286         1686 :   const std::string dataset_name = group_and_dataset_path_elements.back();
     287              : 
     288              :   // create top level group if needed
     289         1686 :   std::string const& top_level_group_name = group_and_dataset_path_elements.at(0);
     290         1686 :   if (!m_file_ptr->exist(top_level_group_name))
     291          106 :     m_file_ptr->createGroup(top_level_group_name);
     292              : 
     293              :   // setup sub_group to work with
     294         1686 :   HighFive::Group sub_group = m_file_ptr->getGroup(top_level_group_name);
     295         1686 :   if (!sub_group.isValid()) {
     296            0 :     throw InvalidHDF5Group(ERS_HERE, top_level_group_name);
     297              :   }
     298         1686 :   HighFive::Group top_level_group = sub_group;
     299              : 
     300              :   // Create the remaining subgroups
     301         3372 :   for (size_t idx = 1; idx < group_and_dataset_path_elements.size() - 1; ++idx) {
     302              :     // group_dataset.size()-1 because the last element is the dataset
     303         1686 :     std::string const& child_group_name = group_and_dataset_path_elements[idx];
     304         1686 :     if (child_group_name.empty()) {
     305            0 :       throw InvalidHDF5Group(ERS_HERE, child_group_name);
     306              :     }
     307         1686 :     if (!sub_group.exist(child_group_name)) {
     308          106 :       sub_group.createGroup(child_group_name);
     309              :     }
     310         1686 :     HighFive::Group child_group = sub_group.getGroup(child_group_name);
     311         1686 :     if (!child_group.isValid()) {
     312            0 :       throw InvalidHDF5Group(ERS_HERE, child_group_name);
     313              :     }
     314         1686 :     sub_group = child_group;
     315         1686 :   }
     316              : 
     317              :   // Create dataset
     318         1686 :   HighFive::DataSpace data_space = HighFive::DataSpace({ raw_data_size_bytes, 1 });
     319         1686 :   HighFive::DataSetCreateProps data_set_create_props;
     320         1686 :   HighFive::DataSetAccessProps data_set_access_props;
     321              : 
     322         1686 :   if (compression_level > 0) {
     323          415 :     std::vector<hsize_t> chunk_size = { raw_data_size_bytes, 1 };
     324          415 :     data_set_create_props.add(HighFive::Chunking(chunk_size));
     325          415 :     data_set_create_props.add(HighFive::Deflate(compression_level));
     326          415 :   }
     327              : 
     328         1686 :   m_uncompressed_raw_data_size += raw_data_size_bytes;
     329              : 
     330         1686 :   auto data_set = sub_group.createDataSet<char>(dataset_name, data_space, data_set_create_props, data_set_access_props);
     331              : 
     332         1686 :   if (data_set.isValid()) {
     333         1686 :     data_set.write_raw(raw_data_ptr);
     334         1686 :     m_total_file_size = m_file_ptr->getFileSize();
     335         1686 :     m_file_ptr->flush();
     336         3372 :     return std::make_tuple(data_set.getStorageSize(), data_set.getPath(), top_level_group);
     337              :   } else {
     338            0 :     throw InvalidHDF5Dataset(ERS_HERE, dataset_name, m_file_ptr->getName());
     339              :   }
     340         1686 : }
     341              : 
     342              : /**
     343              :  * @brief Constructor for reading (and optionally writing) a file
     344              :  */
     345           14 : HDF5RawDataFile::HDF5RawDataFile(const std::string& file_name, bool allow_writing)
     346           14 :   : m_open_flags(HighFive::File::ReadOnly)
     347              : {
     348           14 :   if (allow_writing) {
     349            0 :     m_open_flags = HighFive::File::ReadWrite;
     350              :   }
     351           14 :   m_bare_file_name = file_name;
     352           14 :   size_t pos = m_bare_file_name.rfind(s_inprogress_suffix);
     353           14 :   if (pos != std::string::npos) {
     354            0 :     m_bare_file_name.erase(pos);
     355              :   }
     356              : 
     357              :   // do the file open
     358           14 :   try {
     359           14 :     m_file_ptr = std::make_unique<HighFive::File>(file_name, m_open_flags);
     360            0 :   } catch (std::exception const& excpt) {
     361            0 :     throw FileOpenFailed(ERS_HERE, file_name, excpt.what());
     362            0 :   }
     363              : 
     364           14 :   if (m_file_ptr->hasAttribute("recorded_size"))
     365           14 :     m_recorded_size = get_attribute<size_t>("recorded_size");
     366              :   else
     367            0 :     m_recorded_size = 0;
     368              : 
     369           14 :   if (m_file_ptr->hasAttribute("uncompressed_raw_data_size"))
     370           14 :     m_uncompressed_raw_data_size = get_attribute<size_t>("uncompressed_raw_data_size");
     371              :   else
     372            0 :     m_uncompressed_raw_data_size = 0;
     373              : 
     374           14 :   if (m_file_ptr->hasAttribute("total_file_size"))
     375           14 :     m_total_file_size = get_attribute<size_t>("total_file_size");
     376              :   else
     377            0 :     m_total_file_size = 0;
     378              : 
     379           14 :   if (m_file_ptr->hasAttribute("compression_level"))
     380           14 :     m_compression_level = get_attribute<unsigned>("compression_level");
     381              :   else
     382            0 :     m_compression_level = 0;
     383              : 
     384           14 :   read_file_layout();
     385              : 
     386           14 :   if (m_file_ptr->hasAttribute("record_type"))
     387           14 :     m_record_type = get_attribute<std::string>("record_type");
     388              :   else
     389            0 :     m_record_type = m_file_layout_ptr->get_record_name_prefix();
     390              : 
     391           14 :   check_file_layout();
     392              : 
     393              :   // HDF5SourceIDHandler operations need to come *after* read_file_layout()
     394              :   // because they count on the filelayout_version, which is set in read_file_layout().
     395           14 :   HDF5SourceIDHandler sid_handler(get_version());
     396           14 :   sid_handler.fetch_file_level_geo_id_info(*m_file_ptr, m_file_level_source_id_geo_id_map);
     397           14 : }
     398              : 
     399              : void
     400           14 : HDF5RawDataFile::read_file_layout()
     401              : {
     402           14 :   HDF5FileLayoutParameters fl_params;
     403           14 :   uint32_t version = 0; // NOLINT(build/unsigned)
     404              : 
     405           14 :   std::string fl_str;
     406           14 :   try {
     407           14 :     fl_str = get_attribute<std::string>("filelayout_params");
     408           14 :     nlohmann::json fl_json = nlohmann::json::parse(fl_str);
     409           14 :     fl_params = HDF5FileLayoutParameters(fl_json);
     410              : 
     411           14 :     version = get_attribute<uint32_t>("filelayout_version"); // NOLINT(build/unsigned)
     412              : 
     413           14 :   } catch (InvalidHDF5Attribute const&) {
     414            0 :     ers::info(MissingFileLayout(ERS_HERE, version));
     415            0 :   }
     416              : 
     417              :   // now reset the HDF5Filelayout object
     418           14 :   m_file_layout_ptr.reset(new HDF5FileLayout(fl_params, version));
     419           14 : }
     420              : 
     421              : void
     422           14 : HDF5RawDataFile::check_file_layout()
     423              : {
     424           14 :   if (get_version() < 2)
     425            0 :     return;
     426              : 
     427           14 :   std::string record_type = get_attribute<std::string>("record_type");
     428           14 :   if (record_type.compare(m_file_layout_ptr->get_record_name_prefix()) != 0)
     429            0 :     throw BadRecordType(ERS_HERE, record_type, m_file_layout_ptr->get_record_name_prefix());
     430           14 : }
     431              : 
     432              : void
     433           18 : HDF5RawDataFile::check_record_type(std::string rt_name)
     434              : {
     435           18 :   if (get_version() < 2)
     436              :     return;
     437              : 
     438           18 :   if (m_file_layout_ptr->get_record_name_prefix().compare(rt_name) != 0)
     439            0 :     throw WrongRecordTypeRequested(ERS_HERE, rt_name, m_file_layout_ptr->get_record_name_prefix());
     440              : }
     441              : 
     442              : // HDF5 Utility function to recursively traverse a file
     443              : void
     444          176 : HDF5RawDataFile::explore_subgroup(const HighFive::Group& parent_group,
     445              :                                   std::string relative_path,
     446              :                                   std::vector<std::string>& path_list)
     447              : {
     448          176 :   if (relative_path.size() > 0 && relative_path.compare(relative_path.size() - 1, 1, "/") == 0)
     449           16 :     relative_path.pop_back();
     450              : 
     451          176 :   std::vector<std::string> childNames = parent_group.listObjectNames();
     452              : 
     453         1256 :   for (auto& child_name : childNames) {
     454         1080 :     std::string full_path = relative_path + "/" + child_name;
     455         1080 :     HighFive::ObjectType child_type = parent_group.getObjectType(child_name);
     456              : 
     457         1080 :     if (child_type == HighFive::ObjectType::Dataset) {
     458          920 :       path_list.push_back(full_path);
     459          160 :     } else if (child_type == HighFive::ObjectType::Group) {
     460          160 :       HighFive::Group child_group = parent_group.getGroup(child_name);
     461              :       // start the recusion
     462          160 :       std::string new_path = relative_path + "/" + child_name;
     463          160 :       explore_subgroup(child_group, new_path, path_list);
     464          160 :     }
     465         1080 :   }
     466          176 : }
     467              : 
     468              : void
     469           72 : HDF5RawDataFile::add_record_level_info_to_caches_if_needed(record_id_t rid)
     470              : {
     471              :   // we should probably check that all relevant caches have an entry for the
     472              :   // specified record ID, but we will just check one, in the interest of
     473              :   // performance, and trust the "else" part of this routine to fill in *all*
     474              :   // of the appropriate caches
     475           72 :   if (m_source_id_path_cache.count(rid) != 0) {
     476           32 :     return;
     477              :   }
     478              : 
     479              :   // create the handler to do the work
     480           40 :   HDF5SourceIDHandler sid_handler(get_version());
     481              : 
     482              :   // determine the HDF5 Group that corresponds to the specified record
     483           40 :   std::string record_level_group_name = m_file_layout_ptr->get_record_number_string(rid.first, rid.second);
     484           40 :   HighFive::Group record_group = m_file_ptr->getGroup(record_level_group_name);
     485           40 :   if (!record_group.isValid()) {
     486            0 :     throw InvalidHDF5Group(ERS_HERE, record_level_group_name);
     487              :   }
     488              : 
     489              :   // start with a copy of the file-level source-id-to-geo-id map and give the
     490              :   // handler an opportunity to add any record-level additions
     491           40 :   HDF5SourceIDHandler::source_id_geo_id_map_t local_source_id_geo_id_map = m_file_level_source_id_geo_id_map;
     492           40 :   sid_handler.fetch_record_level_geo_id_info(record_group, local_source_id_geo_id_map);
     493              : 
     494              :   // fetch the record-level source-id-to-path map
     495           40 :   HDF5SourceIDHandler::source_id_path_map_t source_id_path_map;
     496           40 :   sid_handler.fetch_source_id_path_info(record_group, source_id_path_map);
     497              : 
     498              :   // fetch the record-level fragment-type-to-source-id map
     499           40 :   HDF5SourceIDHandler::fragment_type_source_id_map_t fragment_type_source_id_map;
     500           40 :   sid_handler.fetch_fragment_type_source_id_info(record_group, fragment_type_source_id_map);
     501              : 
     502              :   // fetch the record-level subdetector-to-source-id map
     503           40 :   HDF5SourceIDHandler::subdetector_source_id_map_t subdetector_source_id_map;
     504           40 :   sid_handler.fetch_subdetector_source_id_info(record_group, subdetector_source_id_map);
     505              : 
     506              :   // loop through the source-id-to-path map to create various lists of SourceIDs in the record
     507           40 :   daqdataformats::SourceID rh_sid = sid_handler.fetch_record_header_source_id(record_group);
     508           40 :   std::set<daqdataformats::SourceID> full_source_id_set;
     509           40 :   std::set<daqdataformats::SourceID> fragment_source_id_set;
     510           40 :   HDF5SourceIDHandler::subsystem_source_id_map_t subsystem_source_id_map;
     511          500 :   for (auto const& source_id_path : source_id_path_map) {
     512          460 :     full_source_id_set.insert(source_id_path.first);
     513          460 :     if (source_id_path.first != rh_sid) {
     514          420 :       fragment_source_id_set.insert(source_id_path.first);
     515              :     }
     516          460 :     HDF5SourceIDHandler::add_subsystem_source_id_to_map(
     517          460 :       subsystem_source_id_map, source_id_path.first.subsystem, source_id_path.first);
     518              :   }
     519              : 
     520              :   // note that even if the "fetch" methods above fail to add anything to the specified
     521              :   // maps, the maps will still be valid (though, possibly empty), and once we add them
     522              :   // to the caches here, we will be assured that lookups from the caches will not fail.
     523           40 :   m_source_id_cache[rid] = full_source_id_set;
     524           40 :   m_record_header_source_id_cache[rid] = rh_sid;
     525           40 :   m_fragment_source_id_cache[rid] = fragment_source_id_set;
     526           40 :   m_source_id_geo_id_cache[rid] = local_source_id_geo_id_map;
     527           40 :   m_source_id_path_cache[rid] = source_id_path_map;
     528           40 :   m_subsystem_source_id_cache[rid] = subsystem_source_id_map;
     529           40 :   m_fragment_type_source_id_cache[rid] = fragment_type_source_id_map;
     530           40 :   m_subdetector_source_id_cache[rid] = subdetector_source_id_map;
     531           40 : }
     532              : 
     533              : /**
     534              :  * @brief Return a vector of dataset names
     535              :  */
     536              : std::vector<std::string>
     537           16 : HDF5RawDataFile::get_dataset_paths(std::string top_level_group_name)
     538              : {
     539           16 :   if (top_level_group_name.empty())
     540           16 :     top_level_group_name = m_file_ptr->getPath();
     541              : 
     542              :   // Vector containing the path list to the HDF5 datasets
     543           16 :   std::vector<std::string> path_list;
     544              : 
     545           16 :   HighFive::Group parent_group = m_file_ptr->getGroup(top_level_group_name);
     546           16 :   if (!parent_group.isValid())
     547            0 :     throw InvalidHDF5Group(ERS_HERE, top_level_group_name);
     548              : 
     549           16 :   explore_subgroup(parent_group, top_level_group_name, path_list);
     550              : 
     551           16 :   return path_list;
     552           16 : }
     553              : 
     554              : /**
     555              :  * @brief Return all of the record numbers in the file.
     556              :  */
     557              : HDF5RawDataFile::record_id_set // NOLINT(build/unsigned)
     558          242 : HDF5RawDataFile::get_all_record_ids()
     559              : {
     560          242 :   if (!m_all_record_ids_in_file.empty())
     561          232 :     return m_all_record_ids_in_file;
     562              : 
     563              :   // records are at the top level
     564              : 
     565           10 :   HighFive::Group parent_group = m_file_ptr->getGroup(m_file_ptr->getPath());
     566              : 
     567           10 :   std::vector<std::string> childNames = parent_group.listObjectNames();
     568           10 :   const std::string record_prefix = m_file_layout_ptr->get_record_name_prefix();
     569           10 :   const size_t record_prefix_size = record_prefix.size();
     570              : 
     571           60 :   for (auto const& name : childNames) {
     572           50 :     auto loc = name.find(record_prefix);
     573              : 
     574           50 :     if (loc == std::string::npos)
     575            0 :       continue;
     576              : 
     577           50 :     auto rec_num_string = name.substr(loc + record_prefix_size);
     578              : 
     579           50 :     loc = rec_num_string.find(".");
     580           50 :     if (loc == std::string::npos) {
     581           20 :       m_all_record_ids_in_file.insert(std::make_pair(std::stoll(rec_num_string), 0));
     582              :     } else {
     583           30 :       auto seq_num_string = rec_num_string.substr(loc + 1);
     584           30 :       rec_num_string.resize(loc); // remove anything from '.' onwards
     585           30 :       m_all_record_ids_in_file.insert(std::make_pair(std::stoll(rec_num_string), std::stoi(seq_num_string)));
     586           30 :     }
     587              : 
     588           50 :   } // end loop over childNames
     589              : 
     590           10 :   return m_all_record_ids_in_file;
     591           10 : }
     592              : 
     593              : std::set<uint64_t>
     594            4 : HDF5RawDataFile::get_all_record_numbers() // NOLINT(build/unsigned)
     595              : {
     596           12 :   ers::warning(DeprecatedUsage(ERS_HERE,
     597              :                                "get_all_record_numbers()",
     598           12 :                                "Use get_all_record_ids(), which returns a record_number,sequence_number pair."));
     599              : 
     600            4 :   std::set<uint64_t> record_numbers; // NOLINT(build/unsigned)
     601           24 :   for (auto const& rid : get_all_record_ids())
     602           24 :     record_numbers.insert(rid.first);
     603              : 
     604            4 :   return record_numbers;
     605            0 : }
     606              : 
     607              : HDF5RawDataFile::record_id_set
     608            6 : HDF5RawDataFile::get_all_trigger_record_ids()
     609              : {
     610            6 :   check_record_type("TriggerRecord");
     611            6 :   return get_all_record_ids();
     612              : }
     613              : 
     614              : std::set<daqdataformats::trigger_number_t>
     615            0 : HDF5RawDataFile::get_all_trigger_record_numbers()
     616              : {
     617            0 :   ers::warning(
     618            0 :     DeprecatedUsage(ERS_HERE,
     619              :                     "get_all_trigger_record_numbers()",
     620            0 :                     "Use get_all_trigger_record_ids(), which returns a record_number,sequence_number pair."));
     621              : 
     622            0 :   return get_all_record_numbers();
     623              : }
     624              : 
     625              : HDF5RawDataFile::record_id_set
     626            0 : HDF5RawDataFile::get_all_timeslice_ids()
     627              : {
     628            0 :   check_record_type("TimeSlice");
     629            0 :   return get_all_record_ids();
     630              : }
     631              : 
     632              : std::set<daqdataformats::timeslice_number_t>
     633            4 : HDF5RawDataFile::get_all_timeslice_numbers()
     634              : {
     635            4 :   check_record_type("TimeSlice");
     636            4 :   return get_all_record_numbers();
     637              : }
     638              : 
     639              : /**
     640              :  * @brief Return a vector of dataset names that correspond to record headers
     641              :  */
     642              : std::vector<std::string>
     643            8 : HDF5RawDataFile::get_record_header_dataset_paths()
     644              : {
     645              : 
     646            8 :   std::vector<std::string> rec_paths;
     647              : 
     648            8 :   if (get_version() >= 2) {
     649           48 :     for (auto const& rec_id : get_all_record_ids())
     650           48 :       rec_paths.push_back(get_record_header_dataset_path(rec_id));
     651              :   } else {
     652            0 :     for (auto const& path : get_dataset_paths()) {
     653            0 :       if (path.find(m_file_layout_ptr->get_record_header_dataset_name()) != std::string::npos) {
     654            0 :         rec_paths.push_back(path);
     655              :       }
     656            0 :     }
     657              :   }
     658              : 
     659            8 :   return rec_paths;
     660            0 : }
     661              : 
     662              : std::vector<std::string>
     663            4 : HDF5RawDataFile::get_trigger_record_header_dataset_paths()
     664              : {
     665            4 :   check_record_type("TriggerRecord");
     666            4 :   return get_record_header_dataset_paths();
     667              : }
     668              : 
     669              : std::vector<std::string>
     670            4 : HDF5RawDataFile::get_timeslice_header_dataset_paths()
     671              : {
     672            4 :   check_record_type("TimeSlice");
     673            4 :   return get_record_header_dataset_paths();
     674              : }
     675              : 
     676              : std::string
     677           40 : HDF5RawDataFile::get_record_header_dataset_path(const record_id_t& rid)
     678              : {
     679           40 :   auto rec_id = get_all_record_ids().find(rid);
     680           40 :   if (rec_id == get_all_record_ids().end())
     681            0 :     throw RecordIDNotFound(ERS_HERE, rid.first, rid.second);
     682              : 
     683           40 :   if (get_version() <= 2) {
     684            0 :     return (m_file_ptr->getPath() + m_file_layout_ptr->get_record_header_path(rid.first, rid.second));
     685              :   } else {
     686           40 :     daqdataformats::SourceID source_id = get_record_header_source_id(rid);
     687           40 :     return m_source_id_path_cache[rid][source_id];
     688              :   }
     689              : }
     690              : 
     691              : std::string
     692            0 : HDF5RawDataFile::get_record_header_dataset_path(const uint64_t rec_num, // NOLINT (build/unsigned)
     693              :                                                 const daqdataformats::sequence_number_t seq_num)
     694              : {
     695            0 :   return get_record_header_dataset_path(std::make_pair(rec_num, seq_num));
     696              : }
     697              : 
     698              : std::string
     699            0 : HDF5RawDataFile::get_trigger_record_header_dataset_path(const record_id_t& rid)
     700              : {
     701            0 :   check_record_type("TriggerRecord");
     702            0 :   return get_record_header_dataset_path(rid);
     703              : }
     704              : 
     705              : std::string
     706            0 : HDF5RawDataFile::get_trigger_record_header_dataset_path(const daqdataformats::trigger_number_t trig_num,
     707              :                                                         const daqdataformats::sequence_number_t seq_num)
     708              : {
     709            0 :   check_record_type("TriggerRecord");
     710            0 :   return get_record_header_dataset_path(trig_num, seq_num);
     711              : }
     712              : 
     713              : std::string
     714            0 : HDF5RawDataFile::get_timeslice_header_dataset_path(const record_id_t& rid)
     715              : {
     716            0 :   check_record_type("TimeSlice");
     717            0 :   return get_record_header_dataset_path(rid.first, 0);
     718              : }
     719              : 
     720              : std::string
     721            0 : HDF5RawDataFile::get_timeslice_header_dataset_path(const daqdataformats::timeslice_number_t ts_num)
     722              : {
     723            0 :   check_record_type("TimeSlice");
     724            0 :   return get_record_header_dataset_path(ts_num);
     725              : }
     726              : 
     727              : /**
     728              :  * @brief Return a vector of dataset names that correspond to Fragemnts
     729              :  * Note: this gets all datsets, and then removes those that look like TriggerRecordHeader ones
     730              :  *       one could instead loop through all system types and ask for appropriate datsets in those
     731              :  *       however, probably that's more time consuming
     732              :  */
     733              : std::vector<std::string>
     734            8 : HDF5RawDataFile::get_all_fragment_dataset_paths()
     735              : {
     736            8 :   std::vector<std::string> frag_paths;
     737              : 
     738          468 :   for (auto const& path : get_dataset_paths()) {
     739          460 :     if (path.find(m_file_layout_ptr->get_record_header_dataset_name()) == std::string::npos)
     740          420 :       frag_paths.push_back(path);
     741            8 :   }
     742              : 
     743            8 :   return frag_paths;
     744            0 : }
     745              : 
     746              : // get all fragment dataset paths for given record ID
     747              : std::vector<std::string>
     748            0 : HDF5RawDataFile::get_fragment_dataset_paths(const record_id_t& rid)
     749              : {
     750            0 :   auto rec_id = get_all_record_ids().find(rid);
     751            0 :   if (rec_id == get_all_record_ids().end())
     752            0 :     throw RecordIDNotFound(ERS_HERE, rid.first, rid.second);
     753              : 
     754            0 :   std::vector<std::string> frag_paths;
     755            0 :   if (get_version() <= 2) {
     756            0 :     std::string record_group_path =
     757            0 :       m_file_ptr->getPath() + m_file_layout_ptr->get_record_number_string(rid.first, rid.second);
     758              : 
     759            0 :     for (auto const& path : get_dataset_paths(record_group_path)) {
     760            0 :       if (path.find(m_file_layout_ptr->get_record_header_dataset_name()) == std::string::npos)
     761            0 :         frag_paths.push_back(path);
     762            0 :     }
     763            0 :   } else {
     764            0 :     std::set<daqdataformats::SourceID> source_id_list = get_fragment_source_ids(rid);
     765            0 :     for (auto const& source_id : source_id_list) {
     766            0 :       frag_paths.push_back(m_source_id_path_cache[rid][source_id]);
     767              :     }
     768            0 :   }
     769            0 :   return frag_paths;
     770            0 : }
     771              : 
     772              : // get all fragment dataset paths for given record ID
     773              : std::vector<std::string>
     774            0 : HDF5RawDataFile::get_fragment_dataset_paths(const uint64_t rec_num, // NOLINT (build/unsigned)
     775              :                                             const daqdataformats::sequence_number_t seq_num)
     776              : {
     777            0 :   return get_fragment_dataset_paths(std::make_pair(rec_num, seq_num));
     778              : }
     779              : 
     780              : // get all fragment dataset paths for a Subsystem
     781              : std::vector<std::string>
     782            0 : HDF5RawDataFile::get_fragment_dataset_paths(const daqdataformats::SourceID::Subsystem subsystem)
     783              : {
     784            0 :   std::vector<std::string> frag_paths;
     785            0 :   for (auto const& rid : get_all_record_ids()) {
     786            0 :     if (get_version() <= 2) {
     787            0 :       auto datasets = get_dataset_paths(m_file_ptr->getPath() +
     788            0 :                                         m_file_layout_ptr->get_fragment_type_path(rid.first, rid.second, subsystem));
     789            0 :       frag_paths.insert(frag_paths.end(), datasets.begin(), datasets.end());
     790            0 :     } else {
     791            0 :       std::set<daqdataformats::SourceID> source_id_list = get_source_ids_for_subsystem(rid, subsystem);
     792            0 :       for (auto const& source_id : source_id_list) {
     793            0 :         frag_paths.push_back(m_source_id_path_cache[rid][source_id]);
     794              :       }
     795            0 :     }
     796            0 :   }
     797            0 :   return frag_paths;
     798            0 : }
     799              : 
     800              : std::vector<std::string>
     801            0 : HDF5RawDataFile::get_fragment_dataset_paths(const std::string& subsystem_name)
     802              : {
     803            0 :   daqdataformats::SourceID::Subsystem subsystem = daqdataformats::SourceID::string_to_subsystem(subsystem_name);
     804            0 :   return get_fragment_dataset_paths(subsystem);
     805              : }
     806              : 
     807              : std::vector<std::string>
     808            0 : HDF5RawDataFile::get_fragment_dataset_paths(const record_id_t& rid, const daqdataformats::SourceID::Subsystem subsystem)
     809              : {
     810            0 :   auto rec_id = get_all_record_ids().find(rid);
     811            0 :   if (rec_id == get_all_record_ids().end())
     812            0 :     throw RecordIDNotFound(ERS_HERE, rid.first, rid.second);
     813              : 
     814            0 :   if (get_version() <= 2) {
     815            0 :     return get_dataset_paths(m_file_ptr->getPath() +
     816            0 :                              m_file_layout_ptr->get_fragment_type_path(rid.first, rid.second, subsystem));
     817              :   } else {
     818            0 :     std::vector<std::string> frag_paths;
     819            0 :     std::set<daqdataformats::SourceID> source_id_list = get_source_ids_for_subsystem(rid, subsystem);
     820            0 :     for (auto const& source_id : source_id_list) {
     821            0 :       frag_paths.push_back(m_source_id_path_cache[rid][source_id]);
     822              :     }
     823            0 :     return frag_paths;
     824            0 :   }
     825              : }
     826              : 
     827              : std::vector<std::string>
     828            0 : HDF5RawDataFile::get_fragment_dataset_paths(const record_id_t& rid, const std::string& subsystem_name)
     829              : {
     830            0 :   daqdataformats::SourceID::Subsystem subsystem = daqdataformats::SourceID::string_to_subsystem(subsystem_name);
     831            0 :   return get_fragment_dataset_paths(rid, subsystem);
     832              : }
     833              : 
     834              : #if 0
     835              : // get all fragment dataset paths for a SourceID
     836              : std::vector<std::string>
     837              : HDF5RawDataFile::get_fragment_dataset_paths(const daqdataformats::SourceID& source_id)
     838              : {
     839              :   std::vector<std::string> frag_paths;
     840              : 
     841              :   for (auto const& rid : get_all_record_ids())
     842              :     frag_paths.push_back(m_file_ptr->getPath() +
     843              :                          m_file_layout_ptr->get_fragment_path(rid.first, rid.second, source_id));
     844              : 
     845              :   return frag_paths;
     846              : }
     847              : 
     848              : std::vector<std::string>
     849              : HDF5RawDataFile::get_fragment_dataset_paths(const daqdataformats::SourceID::Subsystem type,
     850              :                                                const uint32_t id) // NOLINT(build/unsigned)
     851              : {
     852              :   return get_fragment_dataset_paths(daqdataformats::SourceID(type, source_id));
     853              : }
     854              : std::vector<std::string>
     855              : HDF5RawDataFile::get_fragment_dataset_paths(const std::string& typestring,
     856              :                                                const uint32_t id) // NOLINT(build/unsigned)
     857              : {
     858              :   return get_fragment_dataset_paths(
     859              :     daqdataformats::SourceID(daqdataformats::SourceID::string_to_subsystem(typestring), source_id));
     860              : }
     861              : 
     862              : std::set<daqdataformats::SourceID>
     863              : HDF5RawDataFile::get_source_ids(std::vector<std::string> const& frag_dataset_paths)
     864              : {
     865              :   std::set<daqdataformats::SourceID> source_ids;
     866              :   std::vector<std::string> path_elements;
     867              :   std::string s;
     868              :   for (auto const& frag_dataset : frag_dataset_paths) {
     869              :     path_elements.clear();
     870              :     std::istringstream iss(frag_dataset);
     871              :     while (std::getline(iss, s, '/')) {
     872              :       if (s.size() > 0)
     873              :         path_elements.push_back(s);
     874              :     }
     875              :     source_ids.insert(m_file_layout_ptr->get_source_id_from_path_elements(path_elements));
     876              :   }
     877              : 
     878              :   return source_ids;
     879              : }
     880              : #endif
     881              : 
     882              : HDF5SourceIDHandler::source_id_geo_id_map_t
     883            0 : HDF5RawDataFile::get_srcid_geoid_map() const
     884              : {
     885              : 
     886            0 :   return m_file_level_source_id_geo_id_map;
     887              : }
     888              : 
     889              : std::set<uint64_t> // NOLINT(build/unsigned)
     890            0 : HDF5RawDataFile::get_all_geo_ids() const
     891              : {
     892            0 :   std::set<uint64_t> set_of_geo_ids;
     893              :   // 13-Sep-2022, KAB
     894              :   // It would be safer, but slower, to fetch all of the geo_ids from the
     895              :   // individual records, and we'll go with faster, for now.  If/when we
     896              :   // change the way that we determine the file-level and record-level
     897              :   // source_id-to-geo_id maps, we may need to change this code.
     898            0 :   for (auto const& map_entry : m_file_level_source_id_geo_id_map) {
     899            0 :     for (auto const& geo_id : map_entry.second) {
     900            0 :       set_of_geo_ids.insert(geo_id);
     901              :     }
     902              :   }
     903            0 :   return set_of_geo_ids;
     904            0 : }
     905              : 
     906              : std::set<uint64_t> // NOLINT(build/unsigned)
     907            0 : HDF5RawDataFile::get_geo_ids(const record_id_t& rid)
     908              : {
     909            0 :   auto rec_id = get_all_record_ids().find(rid);
     910            0 :   if (rec_id == get_all_record_ids().end())
     911            0 :     throw RecordIDNotFound(ERS_HERE, rid.first, rid.second);
     912              : 
     913            0 :   add_record_level_info_to_caches_if_needed(rid);
     914              : 
     915            0 :   std::set<uint64_t> set_of_geo_ids;
     916            0 :   for (auto const& map_entry : m_source_id_geo_id_cache[rid]) {
     917            0 :     for (auto const& geo_id : map_entry.second) {
     918            0 :       set_of_geo_ids.insert(geo_id);
     919              :     }
     920              :   }
     921            0 :   return set_of_geo_ids;
     922            0 : }
     923              : 
     924              : std::set<uint64_t> // NOLINT(build/unsigned)
     925            0 : HDF5RawDataFile::get_geo_ids_for_subdetector(const record_id_t& rid, const detdataformats::DetID::Subdetector subdet)
     926              : {
     927            0 :   auto rec_id = get_all_record_ids().find(rid);
     928            0 :   if (rec_id == get_all_record_ids().end())
     929            0 :     throw RecordIDNotFound(ERS_HERE, rid.first, rid.second);
     930              : 
     931            0 :   add_record_level_info_to_caches_if_needed(rid);
     932              : 
     933            0 :   std::set<uint64_t> set_of_geo_ids;
     934            0 :   for (auto const& map_entry : m_source_id_geo_id_cache[rid]) {
     935            0 :     for (auto const& geo_id : map_entry.second) {
     936              :       // FIXME: replace with a proper coder/decoder
     937              : 
     938            0 :       uint16_t det_id = 0xffff & geo_id;
     939            0 :       if (det_id == static_cast<uint16_t>(subdet)) {
     940            0 :         set_of_geo_ids.insert(geo_id);
     941              :       }
     942              :     }
     943              :   }
     944            0 :   return set_of_geo_ids;
     945            0 : }
     946              : 
     947              : // get all SourceIDs for given record ID
     948              : std::set<daqdataformats::SourceID>
     949            0 : HDF5RawDataFile::get_source_ids(const record_id_t& rid)
     950              : {
     951            0 :   auto rec_id = get_all_record_ids().find(rid);
     952            0 :   if (rec_id == get_all_record_ids().end())
     953            0 :     throw RecordIDNotFound(ERS_HERE, rid.first, rid.second);
     954              : 
     955            0 :   add_record_level_info_to_caches_if_needed(rid);
     956              : 
     957            0 :   return m_source_id_cache[rid];
     958              : }
     959              : 
     960              : daqdataformats::SourceID
     961           40 : HDF5RawDataFile::get_record_header_source_id(const record_id_t& rid)
     962              : {
     963           40 :   auto rec_id = get_all_record_ids().find(rid);
     964           40 :   if (rec_id == get_all_record_ids().end())
     965            0 :     throw RecordIDNotFound(ERS_HERE, rid.first, rid.second);
     966              : 
     967           40 :   add_record_level_info_to_caches_if_needed(rid);
     968              : 
     969           40 :   return m_record_header_source_id_cache[rid];
     970              : }
     971              : 
     972              : std::set<daqdataformats::SourceID>
     973            0 : HDF5RawDataFile::get_fragment_source_ids(const record_id_t& rid)
     974              : {
     975            0 :   auto rec_id = get_all_record_ids().find(rid);
     976            0 :   if (rec_id == get_all_record_ids().end())
     977            0 :     throw RecordIDNotFound(ERS_HERE, rid.first, rid.second);
     978              : 
     979            0 :   add_record_level_info_to_caches_if_needed(rid);
     980              : 
     981            0 :   return m_fragment_source_id_cache[rid];
     982              : }
     983              : 
     984              : std::set<daqdataformats::SourceID>
     985            0 : HDF5RawDataFile::get_source_ids_for_subsystem(const record_id_t& rid,
     986              :                                               const daqdataformats::SourceID::Subsystem subsystem)
     987              : {
     988            0 :   auto rec_id = get_all_record_ids().find(rid);
     989            0 :   if (rec_id == get_all_record_ids().end())
     990            0 :     throw RecordIDNotFound(ERS_HERE, rid.first, rid.second);
     991              : 
     992            0 :   add_record_level_info_to_caches_if_needed(rid);
     993              : 
     994            0 :   return m_subsystem_source_id_cache[rid][subsystem];
     995              : }
     996              : 
     997              : std::set<daqdataformats::SourceID>
     998            0 : HDF5RawDataFile::get_source_ids_for_fragment_type(const record_id_t& rid, const daqdataformats::FragmentType frag_type)
     999              : {
    1000            0 :   auto rec_id = get_all_record_ids().find(rid);
    1001            0 :   if (rec_id == get_all_record_ids().end())
    1002            0 :     throw RecordIDNotFound(ERS_HERE, rid.first, rid.second);
    1003              : 
    1004            0 :   add_record_level_info_to_caches_if_needed(rid);
    1005              : 
    1006            0 :   return m_fragment_type_source_id_cache[rid][frag_type];
    1007              : }
    1008              : 
    1009              : std::set<daqdataformats::SourceID>
    1010            0 : HDF5RawDataFile::get_source_ids_for_fragtype_and_subdetector(const record_id_t& rid,
    1011              :                                                              const std::string& frag_type_name,
    1012              :                                                              const std::string& subdet_name)
    1013              : {
    1014            0 :   daqdataformats::FragmentType frag_type = daqdataformats::string_to_fragment_type(frag_type_name);
    1015            0 :   if (frag_type == daqdataformats::FragmentType::kUnknown)
    1016            0 :     throw InvalidFragmentTypeString(ERS_HERE, frag_type_name);
    1017            0 :   detdataformats::DetID::Subdetector subdet = detdataformats::DetID::string_to_subdetector(subdet_name);
    1018            0 :   if (subdet == detdataformats::DetID::Subdetector::kUnknown)
    1019            0 :     throw InvalidSubdetectorString(ERS_HERE, subdet_name);
    1020              : 
    1021            0 :   auto rec_id = get_all_record_ids().find(rid);
    1022            0 :   if (rec_id == get_all_record_ids().end())
    1023            0 :     throw RecordIDNotFound(ERS_HERE, rid.first, rid.second);
    1024              : 
    1025            0 :   add_record_level_info_to_caches_if_needed(rid);
    1026              : 
    1027            0 :   std::set<daqdataformats::SourceID> fragtype_match_sids = m_fragment_type_source_id_cache[rid][frag_type];
    1028            0 :   std::set<daqdataformats::SourceID> detid_match_sids = m_subdetector_source_id_cache[rid][subdet];
    1029            0 :   std::set<daqdataformats::SourceID> combined_set_sids;
    1030            0 :   for (auto ftsid : fragtype_match_sids) {
    1031            0 :     if (detid_match_sids.contains(ftsid)) {
    1032            0 :       combined_set_sids.insert(ftsid);
    1033              :     }
    1034              :   }
    1035            0 :   return combined_set_sids;
    1036            0 : }
    1037              : 
    1038              : std::set<daqdataformats::SourceID>
    1039            0 : HDF5RawDataFile::get_source_ids_for_subdetector(const record_id_t& rid, const detdataformats::DetID::Subdetector subdet)
    1040              : {
    1041            0 :   auto rec_id = get_all_record_ids().find(rid);
    1042            0 :   if (rec_id == get_all_record_ids().end())
    1043            0 :     throw RecordIDNotFound(ERS_HERE, rid.first, rid.second);
    1044              : 
    1045            0 :   add_record_level_info_to_caches_if_needed(rid);
    1046              : 
    1047            0 :   return m_subdetector_source_id_cache[rid][subdet];
    1048              : }
    1049              : 
    1050              : std::unique_ptr<char[]>
    1051           48 : HDF5RawDataFile::get_dataset_raw_data(const std::string& dataset_path)
    1052              : {
    1053           48 :   HighFive::Group parent_group = m_file_ptr->getGroup("/");
    1054           48 :   HighFive::DataSet data_set = parent_group.getDataSet(dataset_path);
    1055              : 
    1056           48 :   if (!data_set.isValid())
    1057            0 :     throw InvalidHDF5Dataset(ERS_HERE, dataset_path, get_file_name());
    1058              : 
    1059           48 :   size_t data_size = data_set.getSpace().getElementCount() * sizeof(char);
    1060              : 
    1061           48 :   auto membuffer = std::make_unique<char[]>(data_size);
    1062              : 
    1063           48 :   data_set.read(membuffer.get());
    1064           48 :   return membuffer;
    1065           48 : }
    1066              : 
    1067              : std::unique_ptr<daqdataformats::Fragment>
    1068           32 : HDF5RawDataFile::get_frag_ptr(const std::string& dataset_name)
    1069              : {
    1070           32 :   auto membuffer = get_dataset_raw_data(dataset_name);
    1071           32 :   auto frag_ptr = std::make_unique<daqdataformats::Fragment>(
    1072           32 :     membuffer.release(), dunedaq::daqdataformats::Fragment::BufferAdoptionMode::kTakeOverBuffer);
    1073           32 :   return frag_ptr;
    1074           32 : }
    1075              : 
    1076              : std::unique_ptr<daqdataformats::Fragment>
    1077           24 : HDF5RawDataFile::get_frag_ptr(const record_id_t& rid, const daqdataformats::SourceID& source_id)
    1078              : {
    1079           24 :   if (get_version() < 2)
    1080            0 :     throw IncompatibleFileLayoutVersion(ERS_HERE, get_version(), 2, MAX_FILELAYOUT_VERSION);
    1081              : 
    1082           24 :   auto rec_id = get_all_record_ids().find(rid);
    1083           24 :   if (rec_id == get_all_record_ids().end())
    1084            0 :     throw RecordIDNotFound(ERS_HERE, rid.first, rid.second);
    1085              : 
    1086           24 :   add_record_level_info_to_caches_if_needed(rid);
    1087              : 
    1088           24 :   return get_frag_ptr(m_source_id_path_cache[rid][source_id]);
    1089              : }
    1090              : 
    1091              : std::unique_ptr<daqdataformats::Fragment>
    1092            8 : HDF5RawDataFile::get_frag_ptr(const uint64_t rec_num, // NOLINT(build/unsigned)
    1093              :                               const daqdataformats::sequence_number_t seq_num,
    1094              :                               const daqdataformats::SourceID& source_id)
    1095              : {
    1096            8 :   record_id_t rid = std::make_pair(rec_num, seq_num);
    1097            8 :   return get_frag_ptr(rid, source_id);
    1098              : }
    1099              : 
    1100              : std::unique_ptr<daqdataformats::Fragment>
    1101            0 : HDF5RawDataFile::get_frag_ptr(const record_id_t& rid,
    1102              :                               const daqdataformats::SourceID::Subsystem type,
    1103              :                               const uint32_t id) // NOLINT(build/unsigned)
    1104              : {
    1105            0 :   daqdataformats::SourceID source_id(type, id);
    1106            0 :   return get_frag_ptr(rid, source_id);
    1107              : }
    1108              : 
    1109              : std::unique_ptr<daqdataformats::Fragment>
    1110            0 : HDF5RawDataFile::get_frag_ptr(const uint64_t rec_num, // NOLINT(build/unsigned)
    1111              :                               const daqdataformats::sequence_number_t seq_num,
    1112              :                               const daqdataformats::SourceID::Subsystem type,
    1113              :                               const uint32_t id) // NOLINT(build/unsigned)
    1114              : {
    1115            0 :   record_id_t rid = std::make_pair(rec_num, seq_num);
    1116            0 :   daqdataformats::SourceID source_id(type, id);
    1117            0 :   return get_frag_ptr(rid, source_id);
    1118              : }
    1119              : 
    1120              : std::unique_ptr<daqdataformats::Fragment>
    1121            0 : HDF5RawDataFile::get_frag_ptr(const record_id_t& rid,
    1122              :                               const std::string& typestring,
    1123              :                               const uint32_t id) // NOLINT(build/unsigned)
    1124              : {
    1125            0 :   daqdataformats::SourceID source_id(daqdataformats::SourceID::string_to_subsystem(typestring), id);
    1126            0 :   return get_frag_ptr(rid, source_id);
    1127              : }
    1128              : 
    1129              : std::unique_ptr<daqdataformats::Fragment>
    1130           16 : HDF5RawDataFile::get_frag_ptr(const uint64_t rec_num, // NOLINT(build/unsigned)
    1131              :                               const daqdataformats::sequence_number_t seq_num,
    1132              :                               const std::string& typestring,
    1133              :                               const uint32_t id) // NOLINT(build/unsigned)
    1134              : {
    1135           16 :   record_id_t rid = std::make_pair(rec_num, seq_num);
    1136           16 :   daqdataformats::SourceID source_id(daqdataformats::SourceID::string_to_subsystem(typestring), id);
    1137           16 :   return get_frag_ptr(rid, source_id);
    1138              : }
    1139              : 
    1140              : std::unique_ptr<daqdataformats::Fragment>
    1141            0 : HDF5RawDataFile::get_frag_ptr(const record_id_t& rid,
    1142              :                               const uint64_t geo_id) // NOLINT(build/unsigned)
    1143              : {
    1144            0 :   daqdataformats::SourceID sid = get_source_id_for_geo_id(rid, geo_id);
    1145            0 :   return get_frag_ptr(rid, sid);
    1146              : }
    1147              : 
    1148              : std::unique_ptr<daqdataformats::Fragment>
    1149            0 : HDF5RawDataFile::get_frag_ptr(const uint64_t rec_num, // NOLINT(build/unsigned)
    1150              :                               const daqdataformats::sequence_number_t seq_num,
    1151              :                               const uint64_t geo_id) // NOLINT(build/unsigned)
    1152              : {
    1153            0 :   record_id_t rid = std::make_pair(rec_num, seq_num);
    1154            0 :   return get_frag_ptr(rid, geo_id);
    1155              : }
    1156              : 
    1157              : std::unique_ptr<daqdataformats::TriggerRecordHeader>
    1158            8 : HDF5RawDataFile::get_trh_ptr(const std::string& dataset_name)
    1159              : {
    1160            8 :   auto membuffer = get_dataset_raw_data(dataset_name);
    1161            8 :   auto trh_ptr = std::make_unique<daqdataformats::TriggerRecordHeader>(membuffer.release(), true);
    1162            8 :   return trh_ptr;
    1163            8 : }
    1164              : 
    1165              : std::unique_ptr<daqdataformats::TriggerRecordHeader>
    1166            4 : HDF5RawDataFile::get_trh_ptr(const record_id_t& rid)
    1167              : {
    1168            4 :   if (get_version() < 2)
    1169            0 :     throw IncompatibleFileLayoutVersion(ERS_HERE, get_version(), 2, MAX_FILELAYOUT_VERSION);
    1170              : 
    1171            4 :   auto rec_id = get_all_record_ids().find(rid);
    1172            4 :   if (rec_id == get_all_record_ids().end())
    1173            0 :     throw RecordIDNotFound(ERS_HERE, rid.first, rid.second);
    1174              : 
    1175            4 :   add_record_level_info_to_caches_if_needed(rid);
    1176              : 
    1177            4 :   daqdataformats::SourceID rh_source_id = m_record_header_source_id_cache[rid];
    1178            4 :   return get_trh_ptr(m_source_id_path_cache[rid][rh_source_id]);
    1179              : }
    1180              : 
    1181              : std::unique_ptr<daqdataformats::TimeSliceHeader>
    1182            8 : HDF5RawDataFile::get_tsh_ptr(const std::string& dataset_name)
    1183              : {
    1184            8 :   auto membuffer = get_dataset_raw_data(dataset_name);
    1185            8 :   auto tsh_ptr = std::make_unique<daqdataformats::TimeSliceHeader>(
    1186            8 :     *(reinterpret_cast<daqdataformats::TimeSliceHeader*>(membuffer.release()))); // NOLINT
    1187            8 :   return tsh_ptr;
    1188            8 : }
    1189              : 
    1190              : std::unique_ptr<daqdataformats::TimeSliceHeader>
    1191            4 : HDF5RawDataFile::get_tsh_ptr(const record_id_t& rid)
    1192              : {
    1193            4 :   if (get_version() < 2)
    1194            0 :     throw IncompatibleFileLayoutVersion(ERS_HERE, get_version(), 2, MAX_FILELAYOUT_VERSION);
    1195              : 
    1196            4 :   auto rec_id = get_all_record_ids().find(rid);
    1197            4 :   if (rec_id == get_all_record_ids().end())
    1198            0 :     throw RecordIDNotFound(ERS_HERE, rid.first, rid.second);
    1199              : 
    1200            4 :   add_record_level_info_to_caches_if_needed(rid);
    1201              : 
    1202            4 :   daqdataformats::SourceID rh_source_id = m_record_header_source_id_cache[rid];
    1203            4 :   return get_tsh_ptr(m_source_id_path_cache[rid][rh_source_id]);
    1204              : }
    1205              : 
    1206              : daqdataformats::TriggerRecord
    1207            0 : HDF5RawDataFile::get_trigger_record(const record_id_t& rid)
    1208              : {
    1209            0 :   daqdataformats::TriggerRecord trigger_record(*get_trh_ptr(rid));
    1210            0 :   for (auto const& frag_path : get_fragment_dataset_paths(rid)) {
    1211            0 :     trigger_record.add_fragment(get_frag_ptr(frag_path));
    1212            0 :   }
    1213              : 
    1214            0 :   return trigger_record;
    1215            0 : }
    1216              : 
    1217              : daqdataformats::TimeSlice
    1218            0 : HDF5RawDataFile::get_timeslice(const daqdataformats::timeslice_number_t ts_num)
    1219              : {
    1220            0 :   daqdataformats::TimeSlice timeslice(*get_tsh_ptr(ts_num));
    1221            0 :   for (auto const& frag_path : get_fragment_dataset_paths(ts_num)) {
    1222            0 :     timeslice.add_fragment(get_frag_ptr(frag_path));
    1223            0 :   }
    1224              : 
    1225            0 :   return timeslice;
    1226            0 : }
    1227              : 
    1228              : std::vector<uint64_t> // NOLINT(build/unsigned)
    1229            0 : HDF5RawDataFile::get_geo_ids_for_source_id(const record_id_t& rid, const daqdataformats::SourceID& source_id)
    1230              : {
    1231            0 :   auto rec_id = get_all_record_ids().find(rid);
    1232            0 :   if (rec_id == get_all_record_ids().end())
    1233            0 :     throw RecordIDNotFound(ERS_HERE, rid.first, rid.second);
    1234              : 
    1235            0 :   add_record_level_info_to_caches_if_needed(rid);
    1236              : 
    1237            0 :   return m_source_id_geo_id_cache[rid][source_id];
    1238              : }
    1239              : 
    1240              : daqdataformats::SourceID
    1241            0 : HDF5RawDataFile::get_source_id_for_geo_id(const record_id_t& rid,
    1242              :                                           const uint64_t requested_geo_id) // NOLINT(build/unsigned)
    1243              : {
    1244            0 :   auto rec_id = get_all_record_ids().find(rid);
    1245            0 :   if (rec_id == get_all_record_ids().end())
    1246            0 :     throw RecordIDNotFound(ERS_HERE, rid.first, rid.second);
    1247              : 
    1248            0 :   add_record_level_info_to_caches_if_needed(rid);
    1249              : 
    1250              :   // if we want to make this faster, we could build a reverse lookup cache in
    1251              :   // add_record_level_info_to_caches_if_needed() and just look up the requested geo_id here
    1252            0 :   for (auto const& map_entry : m_source_id_geo_id_cache[rid]) {
    1253            0 :     auto geoid_list = map_entry.second;
    1254            0 :     for (auto const& geoid_from_list : geoid_list) {
    1255            0 :       if (geoid_from_list == requested_geo_id) {
    1256            0 :         return map_entry.first;
    1257              :       }
    1258              :     }
    1259            0 :   }
    1260              : 
    1261            0 :   daqdataformats::SourceID empty_sid;
    1262            0 :   return empty_sid;
    1263              : }
    1264              : 
    1265              : } // namespace hdf5libs
    1266              : } // namespace dunedaq
        

Generated by: LCOV version 2.0-1