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
|