LCOV - code coverage report
Current view: top level - hdf5libs/src - HDF5FileLayout.cpp (source / functions) Coverage Total Hit
Test: code.result Lines: 41.7 % 144 60
Test Date: 2026-10-11 15:05:20 Functions: 47.6 % 21 10

            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/HDF5FileLayout.hpp"
       9              : 
      10              : #include <stdexcept>
      11              : #include <string>
      12              : #include <vector>
      13              : 
      14              : namespace dunedaq {
      15              : namespace hdf5libs {
      16              : 
      17           44 : HDF5FileLayout::HDF5FileLayout(HDF5FileLayoutParameters conf,
      18           44 :                                uint32_t version) // NOLINT(build/unsigned)
      19           44 :   : m_conf_params(conf)
      20           44 :   , m_version(version)
      21              : {
      22           44 :   if (m_version < 2)
      23            0 :     m_conf_params = get_v0_file_layout_params();
      24              : 
      25           44 :   fill_path_params_maps(m_conf_params);
      26              : 
      27           44 :   check_config();
      28           44 : }
      29              : 
      30              : void
      31           44 : HDF5FileLayout::check_config()
      32              : {
      33              :   // for now, don't do additional config checks for old versions
      34           44 :   if (m_version < 2)
      35              :     return;
      36              : 
      37           44 :   if (m_conf_params.record_name_prefix.compare("TriggerRecord") == 0) {
      38           32 :     if (m_conf_params.digits_for_sequence_number == 0) {
      39            0 :       ers::error(FileLayoutSequenceIDsCannotBeZero(ERS_HERE, 4));
      40            0 :       m_conf_params.digits_for_sequence_number = 4;
      41              :     }
      42           12 :   } else if (m_conf_params.record_name_prefix.compare("TimeSlice") == 0) {
      43           12 :     if (m_conf_params.digits_for_sequence_number != 0) {
      44            0 :       ers::warning(InvalidSequenceDigits(ERS_HERE, m_conf_params.record_name_prefix, 0));
      45            0 :       m_conf_params.digits_for_sequence_number = 0;
      46              :     }
      47              :   } else {
      48            0 :     throw InvalidRecordName(ERS_HERE, m_conf_params.record_name_prefix);
      49              :   }
      50              : }
      51              : 
      52              : HDF5PathParameters
      53            0 : HDF5FileLayout::get_path_params(daqdataformats::SourceID::Subsystem type) const
      54              : {
      55            0 :   try {
      56            0 :     return m_path_params_map.at(type);
      57            0 :   } catch (std::out_of_range&) {
      58            0 :     throw FileLayoutUnconfiguredSubsystem(ERS_HERE, type, daqdataformats::SourceID::subsystem_to_string(type));
      59            0 :   }
      60              : }
      61              : 
      62              : std::string
      63         1728 : HDF5FileLayout::get_record_number_string(uint64_t record_number, // NOLINT(build/unsigned)
      64              :                                          daqdataformats::sequence_number_t seq_num) const
      65              : {
      66         1728 :   std::ostringstream record_number_string;
      67              : 
      68         1728 :   int width = m_conf_params.digits_for_record_number;
      69         1728 :   record_number_string << m_conf_params.record_name_prefix << std::setw(width) << std::setfill('0') << record_number;
      70              : 
      71         1728 :   if (m_conf_params.digits_for_sequence_number > 0) {
      72              : 
      73         1438 :     width = m_conf_params.digits_for_sequence_number;
      74         1438 :     record_number_string << "." << std::setw(width) << std::setfill('0') << seq_num;
      75              :   }
      76              : 
      77         3456 :   return record_number_string.str();
      78         1728 : }
      79              : 
      80              : std::string
      81         1655 : HDF5FileLayout::get_trigger_number_string(daqdataformats::trigger_number_t trig_num,
      82              :                                           daqdataformats::sequence_number_t seq_num) const
      83              : {
      84         1655 :   return get_record_number_string(trig_num, seq_num);
      85              : }
      86              : 
      87              : std::string
      88           33 : HDF5FileLayout::get_timeslice_number_string(daqdataformats::timeslice_number_t ts_num) const
      89              : {
      90           33 :   return get_record_number_string(ts_num);
      91              : }
      92              : 
      93              : /**
      94              :  * @brief get the correct path for the TriggerRecordHeader
      95              :  */
      96              : std::vector<std::string>
      97           75 : HDF5FileLayout::get_path_elements(const daqdataformats::TriggerRecordHeader& trh) const
      98              : {
      99              : 
     100           75 :   std::vector<std::string> path_elements;
     101              : 
     102              :   // first the Trigger string
     103           75 :   path_elements.push_back(get_trigger_number_string(trh.get_trigger_number(), trh.get_sequence_number()));
     104              : 
     105              :   // then the RawData group name
     106           75 :   path_elements.push_back(m_conf_params.raw_data_group_name);
     107              : 
     108              :   // then the SourceID plus record header name
     109           75 :   path_elements.push_back(trh.get_header().element_id.to_string() + "_" + m_conf_params.record_header_dataset_name);
     110              : 
     111           75 :   return path_elements;
     112            0 : }
     113              : 
     114              : /**
     115              :  * @brief get the correct path for the TimeSliceHeader
     116              :  */
     117              : std::vector<std::string>
     118           31 : HDF5FileLayout::get_path_elements(const daqdataformats::TimeSliceHeader& tsh) const
     119              : {
     120              : 
     121           31 :   std::vector<std::string> path_elements;
     122              : 
     123              :   // first the Trigger string
     124           31 :   path_elements.push_back(get_timeslice_number_string(tsh.timeslice_number));
     125              : 
     126              :   // then the RawData group name
     127           31 :   path_elements.push_back(m_conf_params.raw_data_group_name);
     128              : 
     129              :   // then the SourceID plus record header name
     130           31 :   path_elements.push_back(tsh.element_id.to_string() + "_" + m_conf_params.record_header_dataset_name);
     131              : 
     132           31 :   return path_elements;
     133            0 : }
     134              : 
     135              : /**
     136              :  * @brief get the correct path for the Fragment
     137              :  */
     138              : std::vector<std::string>
     139         1580 : HDF5FileLayout::get_path_elements(const daqdataformats::FragmentHeader& fh) const
     140              : {
     141              : 
     142         1580 :   std::vector<std::string> path_elements;
     143              : 
     144              :   // first the Trigger string
     145              :   // note, this still works for TimeSlices through enforced proper configuration of layout parameters
     146         1580 :   path_elements.push_back(get_trigger_number_string(fh.trigger_number, fh.sequence_number));
     147              : 
     148              :   // then the RawData group name
     149         1580 :   path_elements.push_back(m_conf_params.raw_data_group_name);
     150              : 
     151              :   // then the SourceID plus FragmentType
     152         1580 :   path_elements.push_back(
     153         3160 :     fh.element_id.to_string() + "_" +
     154         4740 :     daqdataformats::fragment_type_to_string(static_cast<daqdataformats::FragmentType>(fh.fragment_type)));
     155              : 
     156         1580 :   return path_elements;
     157            0 : }
     158              : 
     159              : /**
     160              :  * @brief get the path for the TimeSliceHeader as a single string
     161              :  */
     162              : std::string
     163            2 : HDF5FileLayout::get_path_string(const daqdataformats::TimeSliceHeader& tsh) const
     164              : {
     165            2 :   std::ostringstream path_string;
     166            2 :   path_string << "/" << get_timeslice_number_string(tsh.timeslice_number) << "/" << m_conf_params.raw_data_group_name
     167            4 :               << "/" << tsh.element_id.to_string() << "_" << m_conf_params.record_header_dataset_name;
     168            4 :   return path_string.str();
     169            2 : }
     170              : 
     171              : /**
     172              :  * @brief get the full path for a record header dataset based on trig/seq number
     173              :  */
     174              : std::string
     175            0 : HDF5FileLayout::get_record_header_path(uint64_t rec_num, // NOLINT (build/unsigned)
     176              :                                        daqdataformats::sequence_number_t seq_num) const
     177              : {
     178            0 :   return get_record_number_string(rec_num, seq_num) + "/" + m_conf_params.record_header_dataset_name;
     179              : }
     180              : 
     181              : /**
     182              :  * @brief get the full path for a TriggerRecordHeader dataset based on trig/seq number
     183              :  */
     184              : std::string
     185            0 : HDF5FileLayout::get_trigger_record_header_path(daqdataformats::trigger_number_t trig_num,
     186              :                                                daqdataformats::sequence_number_t seq_num) const
     187              : {
     188            0 :   return get_trigger_number_string(trig_num, seq_num) + "/" + m_conf_params.record_header_dataset_name;
     189              : }
     190              : 
     191              : /**
     192              :  * @brief get the full path for a TimeSliceHeader dataset based on ts number
     193              :  */
     194              : std::string
     195            0 : HDF5FileLayout::get_timeslice_header_path(daqdataformats::timeslice_number_t ts_num) const
     196              : {
     197            0 :   return get_timeslice_number_string(ts_num) + "/" + m_conf_params.record_header_dataset_name;
     198              : }
     199              : 
     200              : /**
     201              :  * @brief get the full path for a Fragment dataset based on trig/seq number and element ID
     202              :  */
     203              : std::string
     204            0 : HDF5FileLayout::get_fragment_path(uint64_t trig_num, // NOLINT(build/unsigned)
     205              :                                   daqdataformats::sequence_number_t seq_num,
     206              :                                   daqdataformats::SourceID element_id) const
     207              : {
     208              : 
     209            0 :   auto const& path_params = get_path_params(element_id.subsystem);
     210              : 
     211            0 :   std::ostringstream path_string;
     212            0 :   path_string << get_trigger_number_string(trig_num, seq_num) << "/" << path_params.detector_group_name << "/"
     213            0 :               << path_params.element_name_prefix << std::setw(path_params.digits_for_element_number)
     214            0 :               << std::setfill('0') << element_id.id;
     215            0 :   return path_string.str();
     216            0 : }
     217              : 
     218              : /**
     219              :  * @brief get the full path for a Fragment dataset based on trig/seq number, give element_id pieces
     220              :  */
     221              : std::string
     222            0 : HDF5FileLayout::get_fragment_path(uint64_t trig_num, // NOLINT(build/unsigned)
     223              :                                   daqdataformats::sequence_number_t seq_num,
     224              :                                   daqdataformats::SourceID::Subsystem type,
     225              :                                   uint32_t element_id) const // NOLINT(build/unsigned)
     226              : {
     227            0 :   daqdataformats::SourceID sid{ type, element_id };
     228            0 :   return get_fragment_path(trig_num, seq_num, sid);
     229              : }
     230              : 
     231              : /**
     232              :  * @brief get the full path for a Fragment dataset based on trig/seq number, give element_id pieces
     233              :  */
     234              : std::string
     235            0 : HDF5FileLayout::get_fragment_path(uint64_t trig_num, // NOLINT(build/unsigned)
     236              :                                   daqdataformats::sequence_number_t seq_num,
     237              :                                   const std::string& typestring,
     238              :                                   uint32_t element_id) const // NOLINT(build/unsigned)
     239              : {
     240            0 :   daqdataformats::SourceID sid{ daqdataformats::SourceID::string_to_subsystem(typestring), element_id };
     241            0 :   return get_fragment_path(trig_num, seq_num, sid);
     242              : }
     243              : 
     244              : /**
     245              :  * @brief get the path for a Fragment type group based on trig/seq number and type
     246              :  */
     247              : std::string
     248            0 : HDF5FileLayout::get_fragment_type_path(uint64_t trig_num, // NOLINT(build/unsigned)
     249              :                                        daqdataformats::sequence_number_t seq_num,
     250              :                                        daqdataformats::SourceID::Subsystem type) const
     251              : {
     252            0 :   auto const& path_params = get_path_params(type);
     253              : 
     254            0 :   std::ostringstream path_string;
     255            0 :   path_string << get_trigger_number_string(trig_num, seq_num) << "/" << path_params.detector_group_name;
     256            0 :   return path_string.str();
     257            0 : }
     258              : 
     259              : /**
     260              :  * @brief get the path for a Fragment type group based on trig/seq number and type
     261              :  */
     262              : std::string
     263            0 : HDF5FileLayout::get_fragment_type_path(uint64_t trig_num, // NOLINT(build/unsigned)
     264              :                                        daqdataformats::sequence_number_t seq_num,
     265              :                                        std::string typestring) const
     266              : {
     267            0 :   return get_fragment_type_path(trig_num, seq_num, daqdataformats::SourceID::string_to_subsystem(typestring));
     268              : }
     269              : 
     270              : daqdataformats::SourceID
     271            0 : HDF5FileLayout::get_source_id_from_path_elements(std::vector<std::string> const& path_elements) const
     272              : {
     273              :   // ignore first path element, which is for the record group
     274              :   // second path element is detector name.
     275            0 :   daqdataformats::SourceID::Subsystem systype = m_detector_group_name_to_type_map.at(path_elements[1]);
     276              : 
     277              :   // get back the path parameters for this system type from the file layout
     278            0 :   auto path_params = get_path_params(systype);
     279              : 
     280              :   // fourth path element is element. remove prefix and translate to numbers
     281            0 :   auto ele_id = std::stoi(path_elements[3].substr(path_params.element_name_prefix.size()));
     282              : 
     283            0 :   return daqdataformats::SourceID(systype, ele_id);
     284            0 : }
     285              : 
     286              : void
     287           44 : HDF5FileLayout::fill_path_params_maps(HDF5FileLayoutParameters const& flp)
     288              : {
     289           88 :   for (auto const& path_param : flp.path_params_list) {
     290           44 :     auto sys_type = daqdataformats::SourceID::string_to_subsystem(path_param.detector_group_type);
     291              : 
     292           44 :     if (sys_type == daqdataformats::SourceID::Subsystem::kUnknown)
     293            0 :       throw FileLayoutInvalidSubsystem(ERS_HERE, path_param.detector_group_type);
     294              : 
     295           44 :     m_path_params_map[sys_type] = path_param;
     296           44 :     m_detector_group_name_to_type_map[path_param.detector_group_name] = sys_type;
     297              :   }
     298           44 : }
     299              : 
     300              : /**
     301              :  * @brief Version0 FileLayout parameters, for backward compatibility
     302              :  */
     303              : HDF5FileLayoutParameters
     304            0 : HDF5FileLayout::get_v0_file_layout_params()
     305              : {
     306            0 :   HDF5FileLayoutParameters flp;
     307            0 :   flp.record_name_prefix = "TriggerRecord";
     308            0 :   flp.digits_for_record_number = 6;
     309            0 :   flp.digits_for_sequence_number = 0;
     310            0 :   flp.record_header_dataset_name = "TriggerRecordHeader";
     311              : 
     312            0 :   HDF5PathParameters pp;
     313              : 
     314            0 :   pp.detector_group_type = "TPC";
     315            0 :   pp.detector_group_name = "TPC";
     316            0 :   pp.element_name_prefix = "Link";
     317            0 :   pp.digits_for_element_number = 2;
     318            0 :   flp.path_params_list.push_back(pp);
     319              : 
     320            0 :   pp.detector_group_type = "PDS";
     321            0 :   pp.detector_group_name = "PDS";
     322            0 :   pp.element_name_prefix = "Element";
     323            0 :   pp.digits_for_element_number = 2;
     324            0 :   flp.path_params_list.push_back(pp);
     325              : 
     326            0 :   pp.detector_group_type = "NDLArTPC";
     327            0 :   pp.detector_group_name = "NDLArTPC";
     328            0 :   pp.element_name_prefix = "Element";
     329            0 :   pp.digits_for_element_number = 2;
     330            0 :   flp.path_params_list.push_back(pp);
     331              : 
     332            0 :   pp.detector_group_type = "NDLArPDS";
     333            0 :   pp.detector_group_name = "NDLArPDS";
     334            0 :   pp.element_name_prefix = "Element";
     335            0 :   pp.digits_for_element_number = 2;
     336            0 :   flp.path_params_list.push_back(pp);
     337              : 
     338            0 :   pp.detector_group_type = "DataSelection";
     339            0 :   pp.detector_group_name = "Trigger";
     340            0 :   pp.element_name_prefix = "Element";
     341            0 :   pp.digits_for_element_number = 2;
     342            0 :   flp.path_params_list.push_back(pp);
     343              : 
     344            0 :   return flp;
     345            0 : }
     346              : 
     347              : } // namespace hdf5libs
     348              : } // namespace dunedaq
        

Generated by: LCOV version 2.0-1