artdaq_demo_hdf5  v1_04_01
highFiveGroupedDataset_dataset.cc
1 #include "tracemf.h"
2 #define TRACE_NAME "HighFiveGroupedDataset"
3 #define TLVL_INSERTONE 6
4 #define TLVL_INSERTHEADER 7
5 #define TLVL_WRITEFRAGMENT 8
6 #define TLVL_WRITEFRAGMENT_V 9
7 #define TLVL_READNEXTEVENT 10
8 #define TLVL_READNEXTEVENT_V 11
9 #define TLVL_READFRAGMENT 12
10 #define TLVL_READFRAGMENT_V 13
11 #define TLVL_GETEVENTHEADER 14
12 
13 #include <memory>
14 #include <unordered_map>
15 #include "artdaq-core/Data/ContainerFragmentLoader.hh"
16 #include "artdaq-demo-hdf5/HDF5/FragmentDataset.hh"
17 #include "artdaq-demo-hdf5/HDF5/highFive/HighFive/include/highfive/H5File.hpp"
18 
19 namespace artdaq {
20 namespace hdf5 {
28 {
29 public:
38  HighFiveGroupedDataset(fhicl::ParameterSet const& ps);
42  ~HighFiveGroupedDataset() noexcept override;
43 
51  void insertOne(artdaq::Fragment const& frag) override;
56  void insertMany(artdaq::Fragments const& frags) override;
63  void insertHeader(artdaq::detail::RawEventHeader const& hdr) override;
68  std::unordered_map<artdaq::Fragment::type_t, std::unique_ptr<artdaq::Fragments>> readNextEvent() override;
74  std::unique_ptr<artdaq::detail::RawEventHeader> getEventHeader(artdaq::Fragment::sequence_id_t const& seqID) override;
75 
76 private:
79  HighFiveGroupedDataset& operator=(HighFiveGroupedDataset const&) = delete;
80  HighFiveGroupedDataset& operator=(HighFiveGroupedDataset&&) = delete;
81 
82  std::unique_ptr<HighFive::File> file_;
83  size_t eventIndex_;
84  HighFive::DataSetCreateProps fragmentCProps_;
85  HighFive::DataSetAccessProps fragmentAProps_;
86 
87  void writeFragment_(HighFive::Group& group, artdaq::Fragment const& frag);
88  artdaq::FragmentPtr readFragment_(HighFive::DataSet const& dataset);
89 };
90 } // namespace hdf5
91 } // namespace artdaq
92 
94  : FragmentDataset(ps, ps.get<std::string>("mode", "write")), file_(nullptr), eventIndex_(0)
95 {
96  TLOG(TLVL_DEBUG) << "HighFiveGroupedDataset CONSTRUCTOR BEGIN";
97  if (mode_ == FragmentDatasetMode::Read)
98  {
99  file_ = std::make_unique<HighFive::File>(ps.get<std::string>("fileName"), HighFive::File::ReadOnly);
100  }
101  else
102  {
103  file_ = std::make_unique<HighFive::File>(ps.get<std::string>("fileName"), HighFive::File::OpenOrCreate | HighFive::File::Truncate);
104  }
105 
106  TLOG(TLVL_DEBUG) << "HighFiveGroupedDataset CONSTRUCTOR END";
107 }
108 
110 {
111  TLOG(TLVL_DEBUG) << "~HighFiveGroupedDataset Begin/End ";
112  // file_->flush();
113 }
114 
115 void artdaq::hdf5::HighFiveGroupedDataset::insertOne(artdaq::Fragment const& frag)
116 {
117  TLOG(TLVL_TRACE) << "insertOne BEGIN";
118  if (!file_->exist(std::to_string(frag.sequenceID())))
119  {
120  TLOG(TLVL_INSERTONE) << "insertOne: Creating group for sequence ID " << frag.sequenceID();
121  file_->createGroup(std::to_string(frag.sequenceID()));
122  }
123  auto eventGroup = file_->getGroup(std::to_string(frag.sequenceID()));
124 
125  if (frag.type() == Fragment::ContainerFragmentType)
126  {
127  TLOG(TLVL_INSERTONE) << "insertOne: Processing ContainerFragment";
128  ContainerFragment cf(frag);
129  if (cf.block_count() > 0)
130  {
131  TLOG(TLVL_INSERTONE) << "insertOne: Getting Fragment type name";
132  auto fragPtr = cf.at(0);
133  auto typeName = nameHelper_->GetInstanceNameForFragment(*fragPtr).second;
134 
135  if (!eventGroup.exist(typeName))
136  {
137  TLOG(TLVL_INSERTONE) << "insertOne: Creating group for type " << typeName;
138  eventGroup.createGroup(typeName);
139  }
140 
141  TLOG(TLVL_INSERTONE) << "insertOne: Creating group and setting attributes";
142  auto typeGroup = eventGroup.getGroup(typeName);
143  auto containerGroup = typeGroup.createGroup("Container_" + std::to_string(frag.fragmentID()));
144  containerGroup.createAttribute("version", frag.version());
145  containerGroup.createAttribute("type", frag.type());
146  containerGroup.createAttribute("sequence_id", frag.sequenceID());
147  containerGroup.createAttribute("fragment_id", frag.fragmentID());
148  containerGroup.createAttribute("timestamp", frag.timestamp());
149 
150  containerGroup.createAttribute("container_block_count", cf.block_count());
151  containerGroup.createAttribute("container_fragment_type", cf.fragment_type());
152  containerGroup.createAttribute("container_version", cf.metadata()->version);
153  containerGroup.createAttribute("container_missing_data", cf.missing_data());
154 
155  TLOG(TLVL_INSERTONE) << "insertOne: Writing Container contained Fragments";
156  for (size_t ii = 0; ii < cf.block_count(); ++ii)
157  {
158  if (ii != 0)
159  {
160  fragPtr = cf.at(ii);
161  }
162  writeFragment_(containerGroup, *fragPtr);
163  }
164  }
165  else
166  {
167  TLOG(TLVL_INSERTONE) << "insertOne: Writing Empty Container Fragment as standard Fragment";
168  auto typeName = nameHelper_->GetInstanceNameForFragment(frag).second;
169  if (!eventGroup.exist(typeName))
170  {
171  TLOG(TLVL_INSERTONE) << "insertOne: Creating group for type " << typeName;
172  eventGroup.createGroup(typeName);
173  }
174  auto typeGroup = eventGroup.getGroup(typeName);
175 
176  writeFragment_(typeGroup, frag);
177  }
178  }
179  else
180  {
181  TLOG(TLVL_INSERTONE) << "insertOne: Writing non-Container Fragment";
182  auto typeName = nameHelper_->GetInstanceNameForFragment(frag).second;
183  if (!eventGroup.exist(typeName))
184  {
185  TLOG(TLVL_INSERTONE) << "insertOne: Creating group for type " << typeName;
186  eventGroup.createGroup(typeName);
187  }
188  auto typeGroup = eventGroup.getGroup(typeName);
189 
190  writeFragment_(typeGroup, frag);
191  }
192  TLOG(TLVL_TRACE) << "insertOne END";
193 }
194 
195 void artdaq::hdf5::HighFiveGroupedDataset::insertMany(artdaq::Fragments const& fs)
196 {
197  TLOG(TLVL_TRACE) << "insertMany BEGIN";
198  for (auto& f : fs) insertOne(f);
199  TLOG(TLVL_TRACE) << "insertMany END";
200 }
201 
202 void artdaq::hdf5::HighFiveGroupedDataset::insertHeader(artdaq::detail::RawEventHeader const& hdr)
203 {
204  TLOG(TLVL_TRACE) << "insertHeader BEGIN";
205  if (!file_->exist(std::to_string(hdr.sequence_id)))
206  {
207  TLOG(TLVL_INSERTHEADER) << "insertHeader: Creating group for event " << hdr.sequence_id;
208  file_->createGroup(std::to_string(hdr.sequence_id));
209  }
210  auto eventGroup = file_->getGroup(std::to_string(hdr.sequence_id));
211  eventGroup.createAttribute("run_id", hdr.run_id);
212  eventGroup.createAttribute("subrun_id", hdr.subrun_id);
213  eventGroup.createAttribute("event_id", hdr.event_id);
214  eventGroup.createAttribute("timestamp", hdr.timestamp);
215  eventGroup.createAttribute("is_complete", hdr.is_complete);
216  TLOG(TLVL_TRACE) << "insertHeader END";
217 }
218 
219 std::unordered_map<artdaq::Fragment::type_t, std::unique_ptr<artdaq::Fragments>> artdaq::hdf5::HighFiveGroupedDataset::readNextEvent()
220 {
221  TLOG(TLVL_DEBUG) << "readNextEvent BEGIN";
222  std::unordered_map<artdaq::Fragment::type_t, std::unique_ptr<artdaq::Fragments>> output;
223 
224  TLOG(TLVL_READNEXTEVENT) << "readNextEvent: Finding next event group in file";
225  auto groupNames = file_->listObjectNames();
226  while (eventIndex_ < groupNames.size() && file_->getObjectType(groupNames[eventIndex_]) != HighFive::ObjectType::Group)
227  {
228  eventIndex_++;
229  }
230 
231  if (groupNames.size() <= eventIndex_)
232  {
233  TLOG(TLVL_INFO) << "readNextEvent: No more events in file!";
234  }
235  else
236  {
237  TLOG(TLVL_READNEXTEVENT) << "readNextEvent: Getting event group " << groupNames[eventIndex_];
238  auto event_group = file_->getGroup(groupNames[eventIndex_]);
239  auto fragment_type_names = event_group.listObjectNames();
240 
241  for (auto& fragment_type : fragment_type_names)
242  {
243  if (event_group.getObjectType(fragment_type) != HighFive::ObjectType::Group)
244  {
245  continue;
246  }
247  TLOG(TLVL_READNEXTEVENT) << "readNextEvent: Reading Fragment type " << fragment_type;
248  auto type_group = event_group.getGroup(fragment_type);
249  auto fragment_names = type_group.listObjectNames();
250 
251  for (auto& fragment_name : fragment_names)
252  {
253  TLOG(TLVL_READNEXTEVENT) << "readNextEvent: Reading Fragment " << fragment_name;
254  auto node_type = type_group.getObjectType(fragment_name);
255  if (node_type == HighFive::ObjectType::Group)
256  {
257  TLOG(TLVL_READNEXTEVENT) << "readNextEvent: Fragment " << fragment_name << " is a Container";
258  auto container_group = type_group.getGroup(fragment_name);
259  Fragment::type_t type;
260  container_group.getAttribute("type").read<Fragment::type_t>(type);
261  Fragment::sequence_id_t seqID;
262  container_group.getAttribute("sequence_id").read(seqID);
263  Fragment::timestamp_t timestamp;
264  container_group.getAttribute("timestamp").read(timestamp);
265  Fragment::fragment_id_t fragID;
266  container_group.getAttribute("fragment_id").read(fragID);
267  if (output.count(type) == 0u)
268  {
269  output[type] = std::make_unique<Fragments>();
270  }
271  output[type]->emplace_back(seqID, fragID);
272  output[type]->back().setTimestamp(timestamp);
273  output[type]->back().setSystemType(type);
274 
275  TLOG(TLVL_READNEXTEVENT) << "readNextEvent: Creating ContainerFragmentLoader for reading Container Fragments";
276  ContainerFragmentLoader cfl(output[type]->back());
277 
278  Fragment::type_t container_fragment_type;
279  int missing_data;
280  container_group.getAttribute("container_fragment_type").read(container_fragment_type);
281  container_group.getAttribute("container_missing_data").read(missing_data);
282 
283  cfl.set_fragment_type(container_fragment_type);
284  cfl.set_missing_data(missing_data != 0);
285 
286  TLOG(TLVL_READNEXTEVENT) << "readNextEvent: Reading ContainerFragment Fragments";
287  auto fragments = container_group.listObjectNames();
288  for (auto& fragname : fragments)
289  {
290  if (container_group.getObjectType(fragname) != HighFive::ObjectType::Dataset)
291  {
292  continue;
293  }
294  TLOG(TLVL_READNEXTEVENT_V) << "readNextEvent: Calling readFragment_ BEGIN";
295  auto frag = readFragment_(container_group.getDataSet(fragname, fragmentAProps_));
296  TLOG(TLVL_READNEXTEVENT_V) << "readNextEvent: Calling readFragment_ END";
297 
298  TLOG(TLVL_READNEXTEVENT_V) << "readNextEvent: Calling addFragment BEGIN";
299  cfl.addFragment(frag);
300  TLOG(TLVL_READNEXTEVENT_V) << "readNextEvent: addFragment END";
301  }
302  }
303  else if (node_type == HighFive::ObjectType::Dataset)
304  {
305  TLOG(TLVL_READNEXTEVENT_V) << "readNextEvent: Calling readFragment_ BEGIN";
306  auto frag = readFragment_(type_group.getDataSet(fragment_name, fragmentAProps_));
307  TLOG(TLVL_READNEXTEVENT_V) << "readNextEvent: Calling readFragment_ END";
308 
309  TLOG(TLVL_READNEXTEVENT) << "readNextEvent: Adding Fragment to output";
310  if (output.count(frag->type()) == 0u)
311  {
312  output[frag->type()] = std::make_unique<artdaq::Fragments>();
313  }
314  output[frag->type()]->push_back(*frag.release());
315  }
316  }
317  }
318  }
319  ++eventIndex_;
320 
321  TLOG(TLVL_DEBUG)
322  << "readNextEvent END output.size() = " << output.size();
323  return output;
324 }
325 
326 std::unique_ptr<artdaq::detail::RawEventHeader> artdaq::hdf5::HighFiveGroupedDataset::getEventHeader(artdaq::Fragment::sequence_id_t const& seqID)
327 {
328  TLOG(TLVL_TRACE) << "GetEventHeader BEGIN seqID=" << seqID;
329  if (!file_->exist(std::to_string(seqID)))
330  {
331  TLOG(TLVL_ERROR) << "Sequence ID " << seqID << " not found in input file!";
332  return nullptr;
333  }
334  auto seqIDGroup = file_->getGroup(std::to_string(seqID));
335 
336  uint32_t runID, subrunID, eventID;
337  uint64_t timestamp;
338  seqIDGroup.getAttribute("run_id").read(runID);
339  seqIDGroup.getAttribute("subrun_id").read(subrunID);
340  seqIDGroup.getAttribute("event_id").read(eventID);
341  seqIDGroup.getAttribute("timestamp").read(timestamp);
342 
343  TLOG(TLVL_GETEVENTHEADER) << "Creating EventHeader with runID " << runID << ", subrunID " << subrunID << ", eventID " << eventID << " (seqID " << seqID << ")";
344  artdaq::detail::RawEventHeader hdr(runID, subrunID, eventID, seqID, timestamp);
345  seqIDGroup.getAttribute("is_complete").read(hdr.is_complete);
346 
347  TLOG(TLVL_TRACE) << "GetEventHeader END";
348  return std::make_unique<artdaq::detail::RawEventHeader>(hdr);
349 }
350 
351 void artdaq::hdf5::HighFiveGroupedDataset::writeFragment_(HighFive::Group& group, artdaq::Fragment const& frag)
352 {
353  TLOG(TLVL_TRACE) << "writeFragment_ BEGIN";
354 
355  auto datasetNameBase = "Fragment_" + std::to_string(frag.fragmentID());
356  auto datasetName = datasetNameBase + ";1";
357  int counter = 2;
358  while (group.exist(datasetName))
359  {
360  TLOG(TLVL_WRITEFRAGMENT) << "writeFragment_: Duplicate Fragment ID " << frag.fragmentID() << " detected. If this is a ContainerFragment, this is expected, otherwise check configuration!";
361  datasetName = datasetNameBase + ";" + std::to_string(counter);
362  counter++;
363  }
364 
365  TLOG(TLVL_WRITEFRAGMENT) << "writeFragment_: Creating DataSpace";
366  HighFive::DataSpace fragmentSpace = HighFive::DataSpace({frag.size() - frag.headerSizeWords(), 1});
367  auto fragDset = group.createDataSet<RawDataType>(datasetName, fragmentSpace, fragmentCProps_, fragmentAProps_);
368 
369  TLOG(TLVL_WRITEFRAGMENT) << "writeFragment_: Creating Attributes from Fragment Header";
370  auto fragHdr = frag.fragmentHeader();
371  fragDset.createAttribute("word_count", fragHdr.word_count);
372  fragDset.createAttribute("fragment_data_size", frag.size() - frag.headerSizeWords());
373  fragDset.createAttribute("version", fragHdr.version);
374  fragDset.createAttribute("type", fragHdr.type);
375  fragDset.createAttribute("metadata_word_count", fragHdr.metadata_word_count);
376 
377  fragDset.createAttribute("sequence_id", fragHdr.sequence_id);
378  fragDset.createAttribute("fragment_id", fragHdr.fragment_id);
379 
380  fragDset.createAttribute("timestamp", fragHdr.timestamp);
381 
382  fragDset.createAttribute("valid", fragHdr.valid);
383  fragDset.createAttribute("complete", fragHdr.complete);
384  fragDset.createAttribute("atime_ns", fragHdr.atime_ns);
385  fragDset.createAttribute("atime_s", fragHdr.atime_s);
386 
387  TLOG(TLVL_WRITEFRAGMENT_V) << "writeFragment_: Writing Fragment payload START";
388  fragDset.write(frag.headerBegin() + frag.headerSizeWords());
389  TLOG(TLVL_WRITEFRAGMENT_V) << "writeFragment_: Writing Fragment payload DONE";
390  TLOG(TLVL_TRACE) << "writeFragment_ END";
391 }
392 
393 artdaq::FragmentPtr artdaq::hdf5::HighFiveGroupedDataset::readFragment_(HighFive::DataSet const& dataset)
394 {
395  TLOG(TLVL_TRACE) << "readFragment_ BEGIN";
396  size_t fragSize;
397  dataset.getAttribute("fragment_data_size").read(fragSize);
398  TLOG(TLVL_READFRAGMENT) << "readFragment_: Fragment size " << fragSize << ", dataset size " << dataset.getDimensions()[0];
399 
400  artdaq::FragmentPtr frag(new Fragment(fragSize));
401 
402  artdaq::Fragment::type_t type;
403  size_t metadata_size;
404  artdaq::Fragment::sequence_id_t seqID;
405  artdaq::Fragment::fragment_id_t fragID;
406  artdaq::Fragment::timestamp_t timestamp;
407  int valid, complete, atime_ns, atime_s;
408 
409  TLOG(TLVL_READFRAGMENT) << "readFragment_: Reading Fragment header fields from dataset attributes";
410  dataset.getAttribute("type").read(type);
411  dataset.getAttribute("metadata_word_count").read(metadata_size);
412 
413  dataset.getAttribute("sequence_id").read(seqID);
414  dataset.getAttribute("fragment_id").read(fragID);
415 
416  dataset.getAttribute("timestamp").read(timestamp);
417 
418  dataset.getAttribute("valid").read(valid);
419  dataset.getAttribute("complete").read(complete);
420  dataset.getAttribute("atime_ns").read(atime_ns);
421  dataset.getAttribute("atime_s").read(atime_s);
422 
423  auto fragHdr = frag->fragmentHeader();
424  fragHdr.type = type;
425  fragHdr.metadata_word_count = metadata_size;
426 
427  fragHdr.sequence_id = seqID;
428  fragHdr.fragment_id = fragID;
429 
430  fragHdr.timestamp = timestamp;
431 
432  fragHdr.valid = valid;
433  fragHdr.complete = complete;
434  fragHdr.atime_ns = atime_ns;
435  fragHdr.atime_s = atime_s;
436 
437  TLOG(TLVL_READFRAGMENT) << "readFragment_: Copying header into Fragment";
438  memcpy(frag->headerAddress(), &fragHdr, sizeof(fragHdr));
439 
440  TLOG(TLVL_READFRAGMENT_V) << "readFragment_: Reading payload data into Fragment BEGIN";
441  dataset.read(frag->headerAddress() + frag->headerSizeWords()); // NOLINT(cppcoreguidelines-pro-bounds-pointer-arithmetic)
442  TLOG(TLVL_READFRAGMENT_V) << "readFragment_: Reading payload data into Fragment END";
443 
444  TLOG(TLVL_TRACE) << "readFragment_ END";
445  return frag;
446 }
447 
448 DEFINE_ARTDAQ_DATASET_PLUGIN(artdaq::hdf5::HighFiveGroupedDataset)
std::unordered_map< artdaq::Fragment::type_t, std::unique_ptr< artdaq::Fragments > > readNextEvent() override
Read the next event from the Dataset (HDF5 file)
std::unique_ptr< artdaq::detail::RawEventHeader > getEventHeader(artdaq::Fragment::sequence_id_t const &seqID) override
Read a RawEventHeader from the Dataset (HDF5 file)
A FragmentDataset implementation which produces files where each event is a Group, and each Fragment_id_t within the group is either a dataset or a group if it is a ContainerFragment.
void insertOne(artdaq::Fragment const &frag) override
Insert a Fragment into the Dataset (write it to the HDF5 file)
HighFiveGroupedDataset(fhicl::ParameterSet const &ps)
HighFiveGroupedDataset Constructor.
~HighFiveGroupedDataset() noexceptoverride
HighFiveGroupedDataset Destructor.
void insertHeader(artdaq::detail::RawEventHeader const &hdr) override
Insert a RawEventHeader into the Dataset (write it to the HDF5 file)
FragmentDatasetMode mode_
Mode of this FragmentDataset, either FragmentDatasetMode::Write or FragmentDatasetMode::Read.
Base class that defines methods for reading and writing to HDF5 files via various implementation plug...
void insertMany(artdaq::Fragments const &frags) override
Insert several Fragments into the Dataset (write them to the HDF5 file)