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