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

Generated by: LCOV version 2.0-1