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