Line data Source code
1 : /**
2 : * @file HDF5TestDumpRecord.cpp
3 : *
4 : * Demo of HDF5 file reader for TPC fragments: this example demonstrates
5 : * simple 'record-dump' functionality.
6 : *
7 : * This is part of the DUNE DAQ Software Suite, copyright 2020.
8 : * Licensing/copyright details are in the COPYING file that you should have
9 : * received with this code.
10 : */
11 :
12 : #include "hdf5libs/HDF5RawDataFile.hpp"
13 :
14 : #include "daqdataformats/Fragment.hpp"
15 : #include "detdataformats/DetID.hpp"
16 : #include "detdataformats/HSIFrame.hpp"
17 : #include "logging/Logging.hpp"
18 : #include "trgdataformats/TriggerObjectOverlay.hpp"
19 :
20 : #include <bitset>
21 : #include <fstream>
22 : #include <iostream>
23 : #include <sstream>
24 : #include <string>
25 : #include <time.h>
26 : #include <unistd.h>
27 :
28 : using namespace dunedaq::hdf5libs;
29 : using namespace dunedaq::daqdataformats;
30 : using namespace dunedaq::detdataformats;
31 : using namespace dunedaq::trgdataformats;
32 :
33 : void
34 0 : print_usage(const char* appname)
35 : {
36 0 : std::cout << "Usage: " << appname
37 0 : << " [-t] [-n <number of TRs to print>] [-s <number of TRs to skip>] <input_file_name>" << std::endl;
38 0 : std::cout << "Where a negative number of TRs to skip counts backward from the end of the file." << std::endl;
39 0 : std::cout << "And the \'-t\' option causes human-readable times to be printed for selected timestamp values."
40 0 : << std::endl;
41 0 : }
42 :
43 : std::string
44 0 : get_calendar_time_string(timestamp_t timestamp)
45 : {
46 0 : time_t epoch_sec = timestamp / 62500000;
47 0 : tm* gmtm = gmtime(&epoch_sec);
48 0 : std::string time_string = asctime(gmtm);
49 0 : time_string.pop_back(); // removing trailing newline
50 0 : size_t fractional_part = double(timestamp % 62500000) * 10000.0 / 625.0;
51 0 : if (fractional_part != 0 && time_string.length() > 6) {
52 0 : std::string year_string = time_string.substr(time_string.length() - 4);
53 0 : time_string = time_string.substr(0, time_string.length() - 5);
54 0 : std::ostringstream oss;
55 0 : oss << time_string << "." << std::setw(9) << std::setfill('0') << fractional_part << " " << year_string;
56 0 : time_string = oss.str();
57 0 : }
58 0 : return time_string;
59 0 : }
60 :
61 : int
62 0 : main(int argc, char** argv)
63 : {
64 0 : int number_of_trs_to_print = 0x0ffffff;
65 0 : int number_of_trs_to_skip = 0;
66 0 : bool print_calendar_time = false;
67 0 : signed char opt;
68 0 : while ((opt = getopt(argc, argv, "hn:s:t")) != -1) {
69 0 : switch (opt) {
70 0 : case 'h':
71 0 : print_usage(argv[0]);
72 : return 1;
73 0 : case 'n':
74 0 : number_of_trs_to_print = atoi(optarg);
75 0 : break;
76 0 : case 's':
77 0 : number_of_trs_to_skip = atoi(optarg);
78 0 : break;
79 : case 't':
80 : print_calendar_time = true;
81 : break;
82 0 : default: /* '?' */
83 0 : print_usage(argv[0]);
84 : return 1;
85 : }
86 : }
87 :
88 0 : argc -= (optind - 1);
89 0 : argv += (optind - 1);
90 0 : if (argc != 2) {
91 0 : print_usage(argv[0]);
92 0 : return 1;
93 : }
94 :
95 0 : const std::string ifile_name = std::string(argv[1]);
96 :
97 : // open our file reading
98 0 : HDF5RawDataFile h5_raw_data_file(ifile_name);
99 0 : std::ostringstream ss;
100 :
101 0 : ss << "\nFile name: " << h5_raw_data_file.get_file_name();
102 0 : ss << "\n\tRecorded size: " << h5_raw_data_file.get_recorded_size();
103 0 : size_t uncompressed_raw_data_size = h5_raw_data_file.get_attribute_if_exists<size_t>("uncompressed_raw_data_size", h5_raw_data_file.get_recorded_size());
104 0 : ss << "\n\tUncompressed raw data size: " << uncompressed_raw_data_size;
105 :
106 0 : auto record_type = h5_raw_data_file.get_record_type();
107 0 : ss << "\nRecord type = " << record_type;
108 :
109 0 : TLOG() << ss.str();
110 0 : ss.str("");
111 :
112 : // get some file attributes
113 0 : auto run_number = h5_raw_data_file.get_attribute<unsigned int>("run_number");
114 0 : auto file_index = h5_raw_data_file.get_attribute<unsigned int>("file_index");
115 0 : auto app_name = h5_raw_data_file.get_attribute<std::string>("application_name");
116 0 : auto compression_level = h5_raw_data_file.get_attribute_if_exists<unsigned>("compression_level", 0);
117 :
118 0 : ss << "\n\tRun number: " << run_number;
119 0 : ss << "\n\tFile index: " << file_index;
120 0 : if (h5_raw_data_file.get_file_layout().get_version() >= 6) {
121 0 : auto creation_timestamp = h5_raw_data_file.get_attribute<size_t>("creation_timestamp");
122 0 : ss << "\n\tCreation timestamp: " << creation_timestamp;
123 : } else {
124 0 : auto creation_timestamp = h5_raw_data_file.get_attribute<std::string>("creation_timestamp");
125 0 : ss << "\n\tCreation timestamp: " << creation_timestamp;
126 0 : }
127 0 : ss << "\n\tWriter app name: " << app_name;
128 0 : ss << "\n\tCompression level: " << compression_level;
129 :
130 0 : TLOG() << ss.str();
131 0 : ss.str("");
132 :
133 0 : auto records = h5_raw_data_file.get_all_record_ids();
134 0 : ss << "\nNumber of records: " << records.size();
135 0 : if (records.empty()) {
136 0 : ss << "\n\nNO TRIGGER RECORDS FOUND";
137 0 : TLOG() << ss.str();
138 0 : return 0;
139 : }
140 0 : auto first_rec = *(records.begin());
141 0 : auto last_rec = *(std::next(records.begin(), records.size() - 1));
142 :
143 0 : ss << "\n\tFirst record: " << first_rec.first << "," << first_rec.second;
144 0 : ss << "\n\tLast record: " << last_rec.first << "," << last_rec.second;
145 :
146 0 : TLOG() << ss.str();
147 0 : ss.str("");
148 :
149 0 : if (number_of_trs_to_skip < 0) {
150 0 : number_of_trs_to_skip += records.size();
151 : }
152 0 : int tr_count = 0;
153 0 : int trs_printed = 0;
154 :
155 0 : for (auto const& record_id : records) {
156 0 : ++tr_count;
157 0 : if (number_of_trs_to_skip > 0 && tr_count <= number_of_trs_to_skip) {
158 0 : continue;
159 : }
160 :
161 0 : if (trs_printed >= number_of_trs_to_print) {
162 : break;
163 : }
164 :
165 0 : if (h5_raw_data_file.is_timeslice_type()) {
166 0 : auto tsh_ptr = h5_raw_data_file.get_tsh_ptr(record_id);
167 0 : ss << "\n\tTimeSliceHeader: " << *tsh_ptr;
168 0 : } else {
169 0 : auto trh_ptr = h5_raw_data_file.get_trh_ptr(record_id);
170 0 : if (trh_ptr->get_header().version != TriggerRecordHeaderData::s_trigger_record_header_version) {
171 0 : std::cout << std::endl;
172 0 : std::cout << "ERROR: The specified data file was written with a version of the DUNE-DAQ software that "
173 0 : << "used a different version" << std::endl
174 : << " of the TriggerRecordHeader "
175 0 : << "than this application (built with the current version of the software) is expecting."
176 0 : << std::endl;
177 0 : std::cout << "Please use a version of the software that is compatible with the data file." << std::endl;
178 0 : std::cout << "(Expected TRH version " << TriggerRecordHeaderData::s_trigger_record_header_version
179 0 : << " and found version " << trh_ptr->get_header().version << ".)" << std::endl;
180 0 : std::exit(1);
181 : }
182 0 : ss << "\n\tTriggerRecordHeader: " << trh_ptr->get_header();
183 0 : if (print_calendar_time) {
184 0 : std::string trigger_timestamp_string = get_calendar_time_string(trh_ptr->get_header().trigger_timestamp);
185 0 : ss << "\n\t\t"
186 0 : << "Trigger timestamp corresponds to UTC " << trigger_timestamp_string;
187 0 : }
188 0 : }
189 0 : TLOG() << ss.str();
190 0 : ss.str("");
191 0 : bool first_frag = true;
192 0 : std::set<SourceID> frag_sid_list = h5_raw_data_file.get_fragment_source_ids(record_id);
193 0 : for (auto const& source_id : frag_sid_list) {
194 0 : if (first_frag) {
195 : first_frag = false;
196 : } else {
197 0 : ss << "\n";
198 : }
199 0 : auto frag_ptr = h5_raw_data_file.get_frag_ptr(record_id, source_id);
200 0 : ss << "\t" << fragment_type_to_string(frag_ptr->get_fragment_type()) << " fragment with SourceID "
201 0 : << frag_ptr->get_element_id().to_string() << " from subdetector "
202 0 : << DetID::subdetector_to_string(static_cast<DetID::Subdetector>(frag_ptr->get_detector_id()))
203 0 : << " has size = " << frag_ptr->get_size() << " -----";
204 0 : if (h5_raw_data_file.is_trigger_record_type()) {
205 0 : try {
206 0 : auto trh_ptr = h5_raw_data_file.get_trh_ptr(record_id);
207 0 : ComponentRequest cr = trh_ptr->get_component_for_source_id(frag_ptr->get_element_id());
208 0 : int64_t begin_diff = cr.window_begin;
209 0 : begin_diff -= trh_ptr->get_trigger_timestamp();
210 0 : int64_t end_diff = cr.window_end;
211 0 : end_diff -= trh_ptr->get_trigger_timestamp();
212 0 : ss << "\n\t\t"
213 0 : << "Readout window begin = " << begin_diff << ", end = " << end_diff
214 0 : << " (relative to the trigger_timestamp)";
215 0 : if (print_calendar_time) {
216 0 : std::string window_begin_string = get_calendar_time_string(cr.window_begin);
217 0 : std::string window_end_string = get_calendar_time_string(cr.window_end);
218 0 : ss << "\n\t\t\t"
219 0 : << "Readout window times corresponds to UTC " << window_begin_string << " and " << window_end_string;
220 0 : }
221 0 : } catch (std::exception const& excpt) {
222 0 : ss << "\n\t\t"
223 0 : << "Unable to determine readout window, exception was \"" << excpt.what() << "\"";
224 0 : }
225 : }
226 0 : if (h5_raw_data_file.is_timeslice_type()) {
227 0 : ss << "\n\t\tFragment window begin time = " << frag_ptr->get_window_begin()
228 0 : << ", window end time = " << frag_ptr->get_window_end();
229 0 : if (print_calendar_time) {
230 0 : std::string window_begin_string = get_calendar_time_string(frag_ptr->get_window_begin());
231 0 : std::string window_end_string = get_calendar_time_string(frag_ptr->get_window_end());
232 0 : ss << "\n\t\t\t"
233 0 : << "Fragment window times corresponds to UTC " << window_begin_string << " and " << window_end_string;
234 0 : }
235 : }
236 0 : if (frag_ptr->get_element_id().subsystem == SourceID::Subsystem::kDetectorReadout) {
237 0 : ss << "\n\t\t"
238 0 : << "It may contain data from the following detector components:";
239 0 : std::vector<uint64_t> geo_id_list = h5_raw_data_file.get_geo_ids_for_source_id(record_id, source_id);
240 0 : for (auto const& geo_id : geo_id_list) {
241 : // FIXME
242 : // GeoInfo = HardwareMapService::parse_geo_id(geo_id);
243 0 : uint16_t det_id = geo_id & 0xffff;
244 0 : uint16_t crate_id = (geo_id >> 16) & 0xffff;
245 0 : uint16_t slot_id = (geo_id >> 32) & 0xffff;
246 0 : uint16_t link_id = (geo_id >> 48) & 0xffff;
247 0 : ss << "\n\t\t\t"
248 0 : << "subdetector " << DetID::subdetector_to_string(static_cast<DetID::Subdetector>(det_id)) << " ("
249 0 : << det_id << ")"
250 0 : << ", crate " << crate_id << ", slot " << slot_id << ", link " << link_id;
251 : }
252 0 : }
253 0 : if (frag_ptr->get_data_size() == 0) {
254 0 : ss << "\n\t\t"
255 0 : << "*** Empty fragment! Moving to next fragment. ***";
256 0 : continue;
257 : }
258 0 : if (frag_ptr->get_fragment_type() == FragmentType::kTriggerCandidate) {
259 0 : size_t payload_size = frag_ptr->get_size() - sizeof(FragmentHeader);
260 0 : size_t offset = 0;
261 0 : int number_of_TCs = 0;
262 0 : int number_of_referenced_TAs = 0;
263 0 : while ((offset + sizeof(TriggerCandidateData)) < payload_size) {
264 0 : ++number_of_TCs;
265 0 : TriggerCandidate* tmp_tcptr =
266 0 : reinterpret_cast<TriggerCandidate*>(offset + reinterpret_cast<uint8_t*>(frag_ptr->get_data()));
267 0 : offset += sizeof(TriggerCandidateData) + sizeof(tmp_tcptr->n_inputs);
268 0 : offset += (tmp_tcptr->n_inputs * sizeof(TriggerActivityData));
269 0 : number_of_referenced_TAs += tmp_tcptr->n_inputs;
270 : }
271 0 : TriggerCandidate* tcptr = static_cast<TriggerCandidate*>(frag_ptr->get_data());
272 0 : ss << "\n\t\t"
273 0 : << "Number of TCs in this fragment=" << number_of_TCs
274 0 : << ", overall number of referenced TAs=" << number_of_referenced_TAs
275 0 : << ", size of TC data=" << (sizeof(TriggerCandidateData) + sizeof(tcptr->n_inputs));
276 0 : ss << "\n\t\t"
277 0 : << "First TC type = " << get_trigger_candidate_type_names()[tcptr->data.type] << " ("
278 0 : << static_cast<int>(tcptr->data.type) << "), TC algorithm = " << static_cast<int>(tcptr->data.algorithm)
279 0 : << ", number of TAs = " << tcptr->n_inputs;
280 0 : ss << "\n\t\t"
281 0 : << "First TC start time=" << tcptr->data.time_start << ", end time=" << tcptr->data.time_end
282 0 : << ", and candidate time=" << tcptr->data.time_candidate;
283 0 : if (number_of_TCs >= 2) {
284 0 : offset = sizeof(TriggerCandidateData) + sizeof(tcptr->n_inputs);
285 0 : offset += (tcptr->n_inputs * sizeof(TriggerActivityData));
286 0 : TriggerCandidate* tmp_tcptr =
287 0 : reinterpret_cast<TriggerCandidate*>(offset+reinterpret_cast<uint8_t*>(frag_ptr->get_data()));
288 0 : ss << "\n\t\t" << "Second TC type = " << get_trigger_candidate_type_names()[tmp_tcptr->data.type]
289 0 : << " (" << static_cast<int>(tmp_tcptr->data.type) << "), TC algorithm = "
290 0 : << static_cast<int>(tmp_tcptr->data.algorithm) << ", number of TAs = " << tmp_tcptr->n_inputs;
291 0 : ss << "\n\t\t" << "Second TC start time=" << tmp_tcptr->data.time_start << ", end time=" << tmp_tcptr->data.time_end
292 0 : << ", and candidate time=" << tmp_tcptr->data.time_candidate;
293 : }
294 : }
295 0 : if (frag_ptr->get_fragment_type() == FragmentType::kTriggerActivity) {
296 0 : size_t payload_size = frag_ptr->get_size() - sizeof(FragmentHeader);
297 0 : size_t offset = 0;
298 0 : int number_of_TAs = 0;
299 0 : int number_of_referenced_TPs = 0;
300 0 : while ((offset + sizeof(TriggerActivityData)) < payload_size) {
301 0 : ++number_of_TAs;
302 0 : TriggerActivity* tmp_taptr =
303 0 : reinterpret_cast<TriggerActivity*>(offset + reinterpret_cast<uint8_t*>(frag_ptr->get_data()));
304 0 : offset += sizeof(TriggerActivityData) + sizeof(tmp_taptr->n_inputs);
305 0 : offset += (tmp_taptr->n_inputs * sizeof(TriggerPrimitive));
306 0 : number_of_referenced_TPs += tmp_taptr->n_inputs;
307 : }
308 0 : TriggerActivity* taptr = static_cast<TriggerActivity*>(frag_ptr->get_data());
309 0 : ss << "\n\t\t"
310 0 : << "Number of TAs in this fragment=" << number_of_TAs
311 0 : << ", overall number of referenced TPs=" << number_of_referenced_TPs
312 0 : << ", size of TA data=" << (sizeof(TriggerActivityData) + sizeof(taptr->n_inputs));
313 0 : ss << "\n\t\t"
314 0 : << "First TA type = " << static_cast<int>(taptr->data.type)
315 0 : << ", TA algorithm = " << static_cast<int>(taptr->data.algorithm) << ", number of TPs = " << taptr->n_inputs;
316 0 : ss << "\n\t\t"
317 0 : << "First TA start time=" << taptr->data.time_start << ", end time=" << taptr->data.time_end
318 0 : << ", and activity time=" << taptr->data.time_activity;
319 0 : if (number_of_TAs >= 2) {
320 0 : offset = sizeof(TriggerActivityData) + sizeof(taptr->n_inputs);
321 0 : offset += (taptr->n_inputs * sizeof(TriggerPrimitive));
322 0 : TriggerActivity* tmp_taptr =
323 0 : reinterpret_cast<TriggerActivity*>(offset+reinterpret_cast<uint8_t*>(frag_ptr->get_data()));
324 0 : ss << "\n\t\t" << "Second TA type = " << static_cast<int>(tmp_taptr->data.type) << ", TA algorithm = "
325 0 : << static_cast<int>(tmp_taptr->data.algorithm) << ", number of TPs = " << tmp_taptr->n_inputs;
326 0 : ss << "\n\t\t" << "Second TA start time=" << tmp_taptr->data.time_start << ", end time=" << tmp_taptr->data.time_end
327 0 : << ", and activity time=" << tmp_taptr->data.time_activity;
328 : }
329 : }
330 0 : if (frag_ptr->get_fragment_type() == FragmentType::kTriggerPrimitive) {
331 0 : TriggerPrimitive* tpptr = static_cast<TriggerPrimitive*>(frag_ptr->get_data());
332 0 : if (tpptr->version != TriggerPrimitive::s_trigger_primitive_version) {
333 0 : std::cout << std::endl;
334 0 : std::cout << "ERROR: The specified data file was written with a version of the DUNE-DAQ software that "
335 0 : << std::endl
336 0 : << " used a different version of the TriggerPrimitive data structure than this "
337 0 : << std::endl
338 0 : << " application (built with the current version of the software) is expecting."
339 0 : << std::endl;
340 0 : std::cout << "Please use a version of the software that is compatible with the data file." << std::endl;
341 0 : std::cout << "(Expected TP version " << static_cast<int>(TriggerPrimitive::s_trigger_primitive_version)
342 0 : << " and found version " << tpptr->version << ".)" << std::endl;
343 0 : std::exit(1);
344 : }
345 0 : ss << "\n\t\t"
346 0 : << "Number of TPs in this fragment="
347 0 : << ((frag_ptr->get_size() - sizeof(FragmentHeader)) / sizeof(TriggerPrimitive))
348 0 : << ", size of TP data structure=" << sizeof(TriggerPrimitive)
349 0 : << ", size of Fragment Header=" << sizeof(FragmentHeader);
350 0 : ss << "\n\t\t"
351 0 : << "First TP flag = " << static_cast<int>(tpptr->flag)
352 0 : << ", TP detid = " << static_cast<int>(tpptr->detid);
353 0 : ss << "\n\t\t"
354 0 : << "First TP start time=" << tpptr->time_start << ", samples to peak=" << tpptr->samples_to_peak
355 0 : << ", and samples over threshold=" << tpptr->samples_over_threshold;
356 0 : if (print_calendar_time) {
357 0 : std::string time_string = get_calendar_time_string(tpptr->time_start);
358 0 : ss << "\n\t\t\t"
359 0 : << "First TP start time corresponds to UTC " << time_string;
360 0 : }
361 : }
362 0 : if (frag_ptr->get_fragment_type() == FragmentType::kHardwareSignal) {
363 0 : HSIFrame* hsi_ptr = static_cast<HSIFrame*>(frag_ptr->get_data());
364 0 : ss << "\n\t\t"
365 0 : << "Detector ID = " << hsi_ptr->detector_id << ", Crate = " << hsi_ptr->crate << ", Slot = " << hsi_ptr->slot
366 0 : << ", Link = " << hsi_ptr->link;
367 0 : ss << ",\n\t\t"
368 0 : << "Sequence = " << hsi_ptr->sequence << ", Trigger = " << hsi_ptr->trigger
369 0 : << ", Version = " << hsi_ptr->version;
370 0 : ss << ",\n\t\t"
371 0 : << "Timestamp = " << hsi_ptr->get_timestamp();
372 :
373 : // Finding the bit positions for input_low and input_high
374 0 : uint32_t bit_pos, bit_sniff;
375 0 : uint32_t input_low = hsi_ptr->input_low;
376 0 : std::bitset<32> low_bits{ input_low };
377 0 : size_t num_bits = low_bits.count();
378 0 : ss << ",\n\t\t"
379 0 : << "Input Low Bitmap = " << input_low;
380 0 : if (input_low != 0) { // Skip printing the positions if the value is 0.
381 0 : ss << ", Input Low Bit Positions = ";
382 : bit_sniff = 1;
383 0 : for (bit_pos = 0; bit_pos < 32 && num_bits > 0; bit_pos++) {
384 0 : if (input_low & bit_sniff) {
385 0 : if (num_bits == 1)
386 0 : ss << bit_pos;
387 : else
388 0 : ss << bit_pos << ", ";
389 0 : num_bits--;
390 : }
391 0 : bit_sniff = bit_sniff << 1;
392 : }
393 : }
394 :
395 0 : uint32_t input_high = hsi_ptr->input_high;
396 0 : std::bitset<32> high_bits{ input_high };
397 0 : num_bits = high_bits.count();
398 0 : ss << ",\n\t\t"
399 0 : << "Input High Bitmap = " << input_high;
400 0 : if (input_high != 0) {
401 0 : ss << ", Input High Bit Positions = ";
402 : bit_sniff = 1;
403 0 : for (bit_pos = 0; bit_pos < 32 && num_bits > 0; bit_pos++) {
404 0 : if (input_high & bit_sniff) {
405 0 : if (num_bits == 1)
406 0 : ss << bit_pos;
407 : else
408 0 : ss << bit_pos << ", ";
409 0 : num_bits--;
410 : }
411 0 : bit_sniff = bit_sniff << 1;
412 : }
413 : }
414 0 : ss << "."; // Finishes the HSI section.
415 : }
416 0 : }
417 0 : std::cout << ss.str() << std::endl;
418 0 : ss.str("");
419 :
420 0 : ++trs_printed;
421 0 : }
422 :
423 0 : return 0;
424 : } // NOLINT
|