artdaq  v3_11_02
ArtdaqOutput.hh
1 #ifndef ARTDAQ_ARTDAQ_ARTMODULES_ARTDAQOUTPUT_HH_
2 #define ARTDAQ_ARTDAQ_ARTMODULES_ARTDAQOUTPUT_HH_
3 
4 #include "art/Framework/Core/OutputModule.h"
5 #include "art/Framework/Principal/EventPrincipal.h"
6 #include "art/Framework/Principal/OutputHandle.h"
7 #include "art/Framework/Principal/RunPrincipal.h"
8 #include "art/Framework/Principal/SubRunPrincipal.h"
9 
10 #include "art/Framework/Core/ModuleMacros.h"
11 #include "art/Framework/Services/Registry/ServiceHandle.h"
12 #include "art/Persistency/Provenance/ModuleContext.h"
13 #include "art/Persistency/Provenance/ProcessHistoryRegistry.h"
14 
15 #include "art_root_io/setup.h"
16 
17 #include "canvas/Persistency/Common/Wrapper.h"
18 #include "canvas/Persistency/Provenance/BranchDescription.h"
19 #include "canvas/Persistency/Provenance/BranchKey.h"
20 #include "canvas/Persistency/Provenance/ParentageRegistry.h"
21 #include "canvas/Persistency/Provenance/ProcessConfiguration.h"
22 #include "canvas/Persistency/Provenance/ProcessConfigurationID.h"
23 #include "canvas/Persistency/Provenance/ProcessHistoryID.h"
24 #include "canvas/Persistency/Provenance/ProductList.h"
25 #include "canvas/Persistency/Provenance/ProductProvenance.h"
26 #include "canvas/Persistency/Provenance/RunAuxiliary.h"
27 #include "canvas/Persistency/Provenance/SubRunAuxiliary.h"
28 #include "canvas/Utilities/DebugMacros.h"
29 #include "canvas/Utilities/Exception.h"
30 #if ART_HEX_VERSION < 0x30901
31 #include "canvas/Utilities/WrappedTypeID.h"
32 #else
33 #include "canvas/Persistency/Common/WrappedTypeID.h"
34 #endif
35 #include "cetlib/column_width.h"
36 #include "cetlib/lpad.h"
37 #include "cetlib/rpad.h"
38 #include "fhiclcpp/ParameterSet.h"
39 #include "fhiclcpp/ParameterSetID.h"
40 #include "fhiclcpp/ParameterSetRegistry.h"
41 
42 #include "artdaq/DAQdata/Globals.hh"
43 #include "artdaq/DAQdata/NetMonHeader.hh"
44 
45 #include "artdaq-core/Data/Fragment.hh"
46 #include "artdaq-core/Data/RawEvent.hh"
47 #include "artdaq-core/Data/detail/ParentageMap.hh"
48 
49 #include <TBufferFile.h>
50 #include <TClass.h>
51 #include <TList.h>
52 #include <TStreamerInfo.h>
53 
54 #include <unistd.h>
55 #include <algorithm>
56 #include <iomanip>
57 #include <iostream>
58 #include <iterator>
59 #include <memory>
60 #include <sstream>
61 #include <string>
62 #include <vector>
63 
64 #define TLVL_OPENFILE 34
65 #define TLVL_CLOSEFILE 35
66 #define TLVL_RESPONDTOCLOSEINPUTFILE 36
67 #define TLVL_RESPONDTOCLOSEOUTPUTFILE 37
68 #define TLVL_ENDJOB 38
69 #define TLVL_SENDINIT 39
70 #define TLVL_SENDINIT_VERBOSE1 40
71 #define TLVL_SENDINIT_VERBOSE2 41
72 #define TLVL_WRITEDATAPRODUCTS 42
73 #define TLVL_WRITEDATAPRODUCTS_VERBOSE 43
74 #define TLVL_WRITE 44
75 #define TLVL_WRITERUN 45
76 #define TLVL_WRITERUN_VERBOSE 46
77 #define TLVL_WRITESUBRUN 47
78 #define TLVL_WRITESUBRUN_VERBOSE 48
79 #define TLVL_EXTRACTPRODUCTS 49
80 #define TLVL_EXTRACTPRODUCTS_VERBOSE 50
81 
82 namespace art {
83 class ArtdaqOutput;
84 } // namespace art
85 
86 static artdaq::FragmentPtr outputFrag = nullptr;
87 inline char* Fragment_ReAllocChar(char* dataPtr, size_t size, size_t /*oldsize*/)
88 {
89  if (outputFrag != nullptr && dataPtr == reinterpret_cast<char*>(outputFrag->dataBegin())) // NOLINT(cppcoreguidelines-pro-type-reinterpret-cast)
90  {
91  outputFrag->resizeBytes(size);
92 
93  return reinterpret_cast<char*>(outputFrag->dataBegin()); // NOLINT(cppcoreguidelines-pro-type-reinterpret-cast)
94  }
95  return nullptr;
96 }
97 
101 class art::ArtdaqOutput : public art::OutputModule
102 {
103 public:
108  explicit ArtdaqOutput(fhicl::ParameterSet const& ps)
109  : OutputModule(ps), productList_(), raw_data_label_(ps.get<std::string>("raw_data_label", "daq"))
110  {
111  root::setup();
112  }
113 
117  virtual ~ArtdaqOutput() = default;
118 
119 protected:
123  virtual void openFile(FileBlock const&)
124  {
125  TLOG(TLVL_OPENFILE) << "Begin/End: ArtdaqOutput::openFile(const FileBlock&)";
126  }
127 
131  virtual void closeFile() { TLOG(TLVL_CLOSEFILE) << "Begin/End: ArtdaqOutput::closeFile()"; }
132 
136  virtual void respondToCloseInputFile(FileBlock const&)
137  {
138  TLOG(TLVL_RESPONDTOCLOSEINPUTFILE) << "Begin/End: ArtdaqOutput::"
139  "respondToCloseOutputFiles(FileBlock const&)";
140  }
141 
145  virtual void respondToCloseOutputFiles(FileBlock const&)
146  {
147  TLOG(TLVL_RESPONDTOCLOSEOUTPUTFILE) << "Begin/End: ArtdaqOutput::"
148  "respondToCloseOutputFiles(FileBlock const&)";
149  }
150 
154  virtual void endJob()
155  {
156  TLOG(TLVL_ENDJOB) << "Begin/End: ArtdaqOutput::endJob()";
157  }
158 
163  void beginRun(RunPrincipal const& rp) final
164  {
165  extractProducts_(rp);
166  beginRun_(rp);
167  }
171  virtual void beginRun_(RunPrincipal const&) {}
172 
177  void beginSubRun(SubRunPrincipal const& srp) final
178  {
179  extractProducts_(srp);
180  beginSubRun_(srp);
181  }
185  virtual void beginSubRun_(SubRunPrincipal const&) {}
186 
191  void event(EventPrincipal const& ep) final
192  {
193  extractProducts_(ep);
194  event_(ep);
195  }
199  virtual void event_(EventPrincipal const&) {}
200 
205  void write(EventPrincipal& ep) final;
206 
211  void writeRun(RunPrincipal& rp) final;
212 
217  void writeSubRun(SubRunPrincipal& srp) final;
218 
225  void writeDataProducts(std::unique_ptr<TBufferFile>& msg, const Principal& principal, std::vector<BranchKey*>& bkv);
226 
231  void extractProducts_(Principal const& principal);
232 
236  void send_init_message();
237 
242  virtual void SendMessage(artdaq::FragmentPtr& msg) = 0;
243 
244 private:
245  ArtdaqOutput(ArtdaqOutput const&) = delete;
246  ArtdaqOutput(ArtdaqOutput&&) = delete;
247  ArtdaqOutput& operator=(ArtdaqOutput const&) = delete;
248  ArtdaqOutput& operator=(ArtdaqOutput&&) = delete;
249 
250  bool initMsgSent_{false};
251  ProductList productList_;
252  size_t last_fragment_size_{10};
253  artdaq::Fragment::sequence_id_t last_sequence_id_{0};
254  artdaq::Fragment::timestamp_t last_timestamp_{0};
255  std::string raw_data_label_;
256 
257  std::unique_ptr<TBufferFile> prepareMessage(artdaq::Fragment::sequence_id_t seqID, artdaq::Fragment::timestamp_t ts, artdaq::Fragment::type_t type)
258  {
260  outputFrag = std::make_unique<artdaq::Fragment>(last_fragment_size_, seqID, my_rank, type, hdr, ts);
261  auto msg = std::make_unique<TBufferFile>(TBuffer::kWrite, last_fragment_size_ * sizeof(artdaq::RawDataType), outputFrag->dataBegin(), kFALSE, &Fragment_ReAllocChar);
262  msg->SetWriteMode();
263 
264  if (seqID > last_sequence_id_) last_sequence_id_ = seqID;
265  if (ts > last_timestamp_) last_timestamp_ = ts;
266 
267  return msg;
268  }
269 
270  void sendMessage(std::unique_ptr<TBufferFile>& msg)
271  {
273  hdr.data_length = static_cast<uint64_t>(msg->Length());
274  outputFrag->updateMetadata(hdr);
275  outputFrag->resizeBytes(hdr.data_length);
276  last_fragment_size_ = std::ceil(msg->Length() / static_cast<double>(sizeof(artdaq::RawDataType)));
277  SendMessage(outputFrag);
278  }
279 };
280 
282 {
283  TLOG(TLVL_SENDINIT) << "Begin: ArtdaqOutput::send_init_message()";
284  //
285  // Get the classes we will need.
286  //
287  // static TClass* string_class = TClass::GetClass("std::string");
288  // if (string_class == nullptr) {
289  // throw art::Exception(art::errors::DictionaryNotFound) <<
290  // "ArtdaqOutput static send_init_message(): "
291  // "Could not get TClass for std::string!";
292  //}
293  static TClass* product_list_class = TClass::GetClass("std::map<art::BranchKey,art::BranchDescription>");
294  if (product_list_class == nullptr)
295  {
296  throw art::Exception(art::errors::DictionaryNotFound) << "ArtdaqOutput::send_init_message(): " // NOLINT(cert-err60-cpp)
297  "Could not get TClass for "
298  "map<art::BranchKey,art::BranchDescription>!";
299  }
300  // typedef std::map<const ProcessHistoryID,ProcessHistory> ProcessHistoryMap;
301  // TClass* process_history_map_class = TClass::GetClass(
302  // "std::map<const art::ProcessHistoryID,art::ProcessHistory>");
303  // FIXME: Replace the "2" here with a use of the proper enum value!
304  static TClass* process_history_map_class = TClass::GetClass("std::map<const art::Hash<2>,art::ProcessHistory>");
305  if (process_history_map_class == nullptr)
306  {
307  throw art::Exception(art::errors::DictionaryNotFound) << "ArtdaqOutput::send_init_message(): " // NOLINT(cert-err60-cpp)
308  "Could not get class for "
309  "std::map<const art::Hash<2>,art::ProcessHistory>!";
310  }
311  // static TClass* parentage_map_class = TClass::GetClass(
312  // "std::map<const art::ParentageID,art::Parentage>");
313  static TClass* parentage_map_class = TClass::GetClass("art::ParentageMap");
314  if (parentage_map_class == nullptr)
315  {
316  throw art::Exception(art::errors::DictionaryNotFound) << "ArtdaqOutput::send_init_message(): " // NOLINT(cert-err60-cpp)
317  "Could not get class for ParentageMap.";
318  }
319  TLOG(TLVL_SENDINIT) << "parentage_map_class: " << static_cast<void*>(parentage_map_class);
320 
321  //
322  // Construct and send the init message.
323  //
324  auto msg = prepareMessage(0, 0, artdaq::Fragment::InitFragmentType);
325  //
326  // Stream the message type code.
327  //
328  TLOG(TLVL_SENDINIT) << "ArtdaqOutput::send_init_message(): Streaming message type code ...";
329  msg->WriteULong(1);
330  TLOG(TLVL_SENDINIT) << "ArtdaqOutput::send_init_message(): Finished streaming message type code.";
331 
332  //
333  // Stream Class info
334  //
335  // ELF: 6/11/2019: This is being done so that if the receiver is a newer version of art/ROOT, it can still understand our version.
336  TList infos;
337  std::vector<std::string> classNames{"std::map<art::BranchKey,art::BranchDescription>", "std::map<const art::Hash<2>,art::ProcessHistory>", "art::ParentageMap",
338  "art::BranchKey", "art::ProductProvenance", "art::RunAuxiliary", "art::SubRunAuxiliary", "art::EventAuxiliary"};
339  for (auto& className : classNames)
340  {
341  TClass* class_ptr = TClass::GetClass(className.c_str());
342  if (class_ptr == nullptr)
343  {
344  throw art::Exception(art::errors::DictionaryNotFound) << "ArtdaqOutput::send_init_message: Could not get TClass for " << className << "!"; // NOLINT(cert-err60-cpp)
345  }
346  infos.Add(class_ptr->GetStreamerInfo());
347  }
348  msg->WriteObject(&infos);
349 
350  //
351  // Stream the ParameterSetRegistry.
352  //
353  ULong_t ps_cnt = fhicl::ParameterSetRegistry::size();
354  TLOG(TLVL_SENDINIT) << "ArtdaqOutput::send_init_message(): parameter set count: " << ps_cnt;
355  msg->WriteULong(ps_cnt);
356  TLOG(TLVL_SENDINIT) << "ArtdaqOutput::send_init_message(): Streaming parameter sets ...";
357  for (auto I = std::begin(fhicl::ParameterSetRegistry::get()), E = std::end(fhicl::ParameterSetRegistry::get());
358  I != E; ++I)
359  {
360  TLOG(TLVL_SENDINIT) << "Pset ID " << I->first << ": " << I->second.to_string();
361  std::string pset_str = I->second.to_string();
362  // msg->WriteObjectAny(&pset_str, string_class);
363  msg->WriteStdString(pset_str);
364  }
365  TLOG(TLVL_SENDINIT) << "ArtdaqOutput::send_init_message(): Finished streaming parameter sets.";
366 
367  //
368  // Stream the MasterProductRegistry.
369  //
370  TLOG(TLVL_SENDINIT) << "ArtdaqOutput::send_init_message(): Streaming Product List sz=" << productList_.size() << "...";
371  msg->WriteObjectAny(&productList_, product_list_class);
372  TLOG(TLVL_SENDINIT) << "ArtdaqOutput::send_init_message(): Finished streaming Product List.";
373 
374  art::ProcessHistoryMap phr;
375  for (auto const& pr : art::ProcessHistoryRegistry::get())
376  {
377  phr.emplace(pr);
378  }
379  //
380  // Dump the ProcessHistoryRegistry.
381  //
382  TLOG(TLVL_SENDINIT_VERBOSE2) << "ArtdaqOutput::send_init_message(): Dumping ProcessHistoryRegistry ...";
383  // typedef std::map<const ProcessHistoryID,ProcessHistory>
384  // ProcessHistoryMap;
385  TLOG(TLVL_SENDINIT_VERBOSE2) << "ArtdaqOutput::send_init_message(): phr: size: " << phr.size();
386  for (auto I = phr.begin(), E = phr.end(); I != E; ++I)
387  {
388  std::ostringstream OS;
389  I->first.print(OS);
390  TLOG(TLVL_SENDINIT_VERBOSE2) << "ArtdaqOutput::send_init_message(): phr: id: '" << OS.str() << "'";
391  }
392  //
393  // Stream the ProcessHistoryRegistry.
394  //
395  TLOG(TLVL_SENDINIT) << "ArtdaqOutput::send_init_message(): Streaming ProcessHistoryRegistry ...";
396  // typedef std::map<const ProcessHistoryID,ProcessHistory>
397  // ProcessHistoryMap;
398  const art::ProcessHistoryMap& phm = phr;
399  TLOG(TLVL_SENDINIT) << "ArtdaqOutput::send_init_message(): phm: size: " << phm.size();
400  msg->WriteObjectAny(&phm, process_history_map_class);
401  TLOG(TLVL_SENDINIT) << "ArtdaqOutput::send_init_message(): Finished streaming ProcessHistoryRegistry.";
402 
403  //
404  // Stream the ParentageRegistry.
405  //
406  TLOG(TLVL_SENDINIT) << "ArtdaqOutput::send_init_message(): Streaming ParentageRegistry ..." << static_cast<void*>(parentage_map_class);
407  art::ParentageMap parentageMap{};
408  for (auto const& pr : art::ParentageRegistry::get())
409  {
410  parentageMap.emplace(pr.first, pr.second);
411  }
412 
413  msg->WriteObjectAny(&parentageMap, parentage_map_class);
414 
415  TLOG(TLVL_SENDINIT) << "ArtdaqOutput::send_init_message(): Finished streaming ParentageRegistry.";
416 
417  TLOG(TLVL_SENDINIT) << "ArtdaqOutput::send_init_message(): Sending init message";
418  sendMessage(msg);
419  TLOG(TLVL_SENDINIT) << "ArtdaqOutput::send_init_message(): Done sending init message";
420 
421  TLOG(TLVL_SENDINIT) << "ArtdaqOutput::send_init_message(): END";
422 }
423 
424 inline void art::ArtdaqOutput::writeDataProducts(std::unique_ptr<TBufferFile>& msg, const Principal& principal, std::vector<BranchKey*>& bkv)
425 {
426  TLOG(TLVL_WRITEDATAPRODUCTS) << "Begin: ArtdaqOutput::writeDataProducts(...)";
427  //
428  // Fetch the class dictionaries we need for
429  // writing out the data products.
430  //
431  static TClass* branch_key_class = TClass::GetClass("art::BranchKey");
432  if (branch_key_class == nullptr)
433  {
434  throw art::Exception(art::errors::DictionaryNotFound) << "ArtdaqOutput::writeDataProducts(...): " // NOLINT(cert-err60-cpp)
435  "Could not get TClass for art::BranchKey!";
436  }
437  static TClass* prdprov_class = TClass::GetClass("art::ProductProvenance");
438  if (prdprov_class == nullptr)
439  {
440  throw art::Exception(art::errors::DictionaryNotFound) << "ArtdaqOutput::writeDataProducts(...): " // NOLINT(cert-err60-cpp)
441  "Could not get TClass for art::ProductProvenance!";
442  }
443 
444  //
445  // Calculate the data product count.
446  //
447  ULong_t prd_cnt = 0;
448  // std::map<art::BranchID, std::shared_ptr<art::Group>>::const_iterator
449  for (auto I = principal.begin(), E = principal.end(); I != E; ++I)
450  {
451  auto const& productDescription = I->second->productDescription();
452  auto const& refs = keptProducts()[productDescription.branchType()];
453  bool found = false;
454  for (auto const& ref : refs)
455  {
456  if (ref.second == productDescription)
457  {
458  found = true;
459  break;
460  }
461  }
462  if (!I->second->productAvailable() || !found)
463  {
464  continue;
465  }
466  ++prd_cnt;
467  }
468  //
469  // Write the data product count.
470  //
471  TLOG(TLVL_WRITEDATAPRODUCTS) << "ArtdaqOutput::writeDataProducts(...): Streaming product count: " +
472  std::to_string(prd_cnt);
473  msg->WriteULong(prd_cnt);
474  TLOG(TLVL_WRITEDATAPRODUCTS) << "ArtdaqOutput::writeDataProducts(...): Finished streaming product count.";
475 
476  //
477  // Loop over the groups in the RunPrincipal and
478  // write out the data products.
479  //
480  // Note: We need this vector of keys because the ROOT I/O mechanism
481  // requires that each object inserted in the message has a
482  // unique address, so we force that by holding on to each
483  // branch key manufactured in the loop until after we are
484  // done constructing the message.
485  //
486  bkv.reserve(prd_cnt);
487  // std::map<art::BranchID, std::shared_ptr<art::Group>>::const_iterator
488  for (auto I = principal.begin(), E = principal.end(); I != E; ++I)
489  {
490  auto const& productDescription = I->second->productDescription();
491  auto const& refs = keptProducts()[productDescription.branchType()];
492  bool found = false;
493  for (auto const& ref : refs)
494  {
495  if (ref.second == productDescription)
496  {
497  found = true;
498  break;
499  }
500  }
501  if (!I->second->productAvailable() || !found)
502  {
503  continue;
504  }
505  const BranchDescription& bd(I->second->productDescription());
506  bkv.push_back(new BranchKey(bd));
507  TLOG(TLVL_WRITEDATAPRODUCTS_VERBOSE)
508  << "ArtdaqOutput::writeDataProducts(...): Dumping branch key of class: '"
509  << bkv.back()->friendlyClassName_ << "' modlbl: '" << bkv.back()->moduleLabel_ << "' instnm: '"
510  << bkv.back()->productInstanceName_ << "' procnm: '" << bkv.back()->processName_ << "'";
511  TLOG(TLVL_WRITEDATAPRODUCTS) << "ArtdaqOutput::writeDataProducts(...): "
512  "Streaming branch key of class: '"
513  << bd.producedClassName() << "' modlbl: '" << bd.moduleLabel() << "' instnm: '"
514  << bd.productInstanceName() << "' procnm: '" << bd.processName() << "'";
515  msg->WriteObjectAny(bkv.back(), branch_key_class);
516 
517  TLOG(TLVL_WRITEDATAPRODUCTS) << "ArtdaqOutput::writeDataProducts(...): "
518  "Streaming product of class: '"
519  << bd.producedClassName() << "' modlbl: '" << bd.moduleLabel() << "' instnm: '"
520  << bd.productInstanceName() << "' procnm: '" << bd.processName() << "'";
521 
522  OutputHandle oh = principal.getForOutput(bd.productID(), true);
523  const EDProduct* prd = oh.wrapper();
524  TLOG(TLVL_WRITEDATAPRODUCTS) << "Class for branch " << bd.wrappedName() << " is "
525  << static_cast<void*>(TClass::GetClass(bd.wrappedName().c_str()));
526  msg->WriteObjectAny(prd, TClass::GetClass(bd.wrappedName().c_str()));
527  TLOG(TLVL_WRITEDATAPRODUCTS) << "ArtdaqOutput::writeDataProducts(...): "
528  "Streaming product provenance of class: '"
529  << bd.producedClassName() << "' modlbl: '" << bd.moduleLabel() << "' instnm: '"
530  << bd.productInstanceName() << "' procnm: '" << bd.processName() << "'";
531 
532  const ProductProvenance* prdprov = I->second->productProvenance().get();
533 
534  msg->WriteObjectAny(prdprov, prdprov_class);
535  }
536  TLOG(TLVL_WRITEDATAPRODUCTS) << "End: ArtdaqOutput::writeDataProducts(...)";
537 }
538 
539 inline void art::ArtdaqOutput::write(EventPrincipal& ep)
540 {
541  //
542  // Write an Event message.
543  //
544  TLOG(TLVL_WRITE) << "Begin: ArtdaqOutput::write(const EventPrincipal& ep)";
545  if (!initMsgSent_)
546  {
547  send_init_message();
548  initMsgSent_ = true;
549  }
550  //
551  // Get root classes needed for I/O.
552  //
553  static TClass* run_aux_class = TClass::GetClass("art::RunAuxiliary");
554  if (run_aux_class == nullptr)
555  {
556  throw art::Exception(art::errors::DictionaryNotFound) << "ArtdaqOutput::write(const EventPrincipal& ep): " // NOLINT(cert-err60-cpp)
557  "Could not get TClass for art::RunAuxiliary!";
558  }
559  static TClass* subrun_aux_class = TClass::GetClass("art::SubRunAuxiliary");
560  if (subrun_aux_class == nullptr)
561  {
562  throw art::Exception(art::errors::DictionaryNotFound) << "ArtdaqOutput::write(const EventPrincipal& ep): " // NOLINT(cert-err60-cpp)
563  "Could not get TClass for art::SubRunAuxiliary!";
564  }
565  static TClass* event_aux_class = TClass::GetClass("art::EventAuxiliary");
566  if (event_aux_class == nullptr)
567  {
568  throw art::Exception(art::errors::DictionaryNotFound) << "ArtdaqOutput::write(const EventPrincipal& ep): " // NOLINT(cert-err60-cpp)
569  "Could not get TClass for art::EventAuxiliary!";
570  }
571 
572  // Subrun number starts at 1
573  TLOG(TLVL_WRITE) << "ArtdaqOutput::write(const EventPrincipal& ep): Setting Output Fragment Header Fields";
574  auto seqID = (static_cast<uint64_t>(ep.eventID().subRun() - 1) << 32) + ep.eventID().event();
575 
576  art::ProcessTag tag("", processName());
577  auto res = ep.getMany(art::ModuleContext::invalid(), art::WrappedTypeID::make<artdaq::detail::RawEventHeader>(), art::MatchAllSelector(), tag);
578 
579  artdaq::Fragment::timestamp_t ts = 0;
580 
581  for (auto const& qr : res)
582  {
583  Handle<artdaq::detail::RawEventHeader> handle{qr};
584  if (handle.isValid())
585  {
586  if (handle->timestamp > ts) ts = handle->timestamp;
587  }
588  }
589  TLOG(TLVL_WRITE) << "ArtdaqOutput::write(const EventPrincipal& ep): Data Fragment Header Fields: SeqID: " << seqID << ", timestamp: " << ts;
590 
591  //
592  // Setup message buffer.
593  //
594  auto msg = prepareMessage(seqID, ts, artdaq::Fragment::DataFragmentType);
595  //
596  // Write message type code.
597  //
598  TLOG(TLVL_WRITE) << "ArtdaqOutput::write(const EventPrincipal& ep): Streaming message type code ...";
599  msg->WriteULong(4);
600  TLOG(TLVL_WRITE) << "ArtdaqOutput::write(const EventPrincipal& ep): Finished streaming message type code.";
601 
602  //
603  // Write RunAuxiliary.
604  //
605  TLOG(TLVL_WRITE) << "ArtdaqOutput::write(const EventPrincipal& ep): Streaming RunAuxiliary ...";
606  msg->WriteObjectAny(&ep.subRunPrincipal().runPrincipal().runAux(), run_aux_class);
607  TLOG(TLVL_WRITE) << "ArtdaqOutput::write(const EventPrincipal& ep): Finished streaming RunAuxiliary.";
608 
609  //
610  // Write SubRunAuxiliary.
611  //
612  TLOG(TLVL_WRITE) << "ArtdaqOutput::write(const EventPrincipal& ep): Streaming SubRunAuxiliary ...";
613  msg->WriteObjectAny(&ep.subRunPrincipal().subRunAux(), subrun_aux_class);
614  TLOG(TLVL_WRITE) << "ArtdaqOutput::write(const EventPrincipal& ep): Finished streaming SubRunAuxiliary.";
615 
616  //
617  // Write EventAuxiliary.
618  //
619  {
620  TLOG(TLVL_WRITE) << "ArtdaqOutput::write(const EventPrincipal& ep): Streaming EventAuxiliary ...";
621  msg->WriteObjectAny(&ep.eventAux(), event_aux_class);
622  TLOG(TLVL_WRITE) << "ArtdaqOutput::write(const EventPrincipal& ep): Finished streaming EventAuxiliary.";
623  }
624 
625  //
626  // Write data products.
627  //
628  std::vector<BranchKey*> bkv;
629  writeDataProducts(msg, ep, bkv);
630 
631  TLOG(TLVL_WRITE) << "ArtdaqOutput::write: Sending message";
632  sendMessage(msg);
633  TLOG(TLVL_WRITE) << "ArtdaqOutput::write: Done sending message";
634 
635  //
636  // Delete the branch keys we created for the message.
637  //
638  for (auto I = bkv.begin(), E = bkv.end(); I != E; ++I)
639  {
640  delete *I;
641  *I = 0;
642  }
643  TLOG(TLVL_WRITE) << "End: ArtdaqOutput::write(const EventPrincipal& ep)";
644 }
645 
646 inline void art::ArtdaqOutput::writeRun(RunPrincipal& rp)
647 { //
648  // Write an EndRun message.
649  //
650  TLOG(TLVL_WRITERUN) << "Begin: ArtdaqOutput::writeRun(const RunPrincipal& rp)";
651  (void)rp;
652  if (!initMsgSent_)
653  {
654  send_init_message();
655  initMsgSent_ = true;
656  }
657 #if 0
658  //
659  // Fetch the class dictionaries we need for
660  // writing out the auxiliary information.
661  //
662  static TClass* run_aux_class = TClass::GetClass("art::RunAuxiliary");
663  assert(run_aux_class != nullptr && "writeRun: Could not get TClass for art::RunAuxiliary!");
664  //
665  // Begin preparing message.
666  //
667  auto msg = prepareMessage(last_sequence_id_ + 1,rp.run() + 1, artdaq::Fragment::EndOfRunFragmentType);
668  //
669  // Write message type code.
670  //
671  {
672  TLOG(TLVL_WRITERUN) << "ArtdaqOutput::writeRun: streaming message type code ...";
673  msg->WriteULong(2);
674  TLOG(TLVL_WRITERUN) << "ArtdaqOutput::writeRun: finished streaming message type code.";
675  }
676  //
677  // Write RunAuxiliary.
678  //
679  {
680  TLOG(TLVL_WRITERUN) << "ArtdaqOutput::writeRun: streaming RunAuxiliary ...";
681  msg->WriteObjectAny(&rp.runAux(), run_aux_class);
682  TLOG(TLVL_WRITERUN) << "ArtdaqOutput::writeRun: streamed RunAuxiliary.";
683  }
684  //
685  // Write data products.
686  //
687  std::vector<BranchKey*> bkv;
688  writeDataProducts(msg, rp, bkv);
689 
690  TLOG(TLVL_WRITERUN) << "ArtdaqOutput::writeRun: Sending message";
691  sendMessage(msg);
692  TLOG(TLVL_WRITERUN) << "ArtdaqOutput::writeRun: Done sending message";
693 
694  for (auto I = bkv.begin(), E = bkv.end(); I != E; ++I)
695  {
696  delete *I;
697  *I = 0;
698  }
699 #endif
700  TLOG(TLVL_WRITERUN) << "End: ArtdaqOutput::writeRun(RunPrincipal& rp)";
701 }
702 inline void art::ArtdaqOutput::writeSubRun(SubRunPrincipal& srp)
703 { //
704  // Write an EndSubRun message.
705  //
706  TLOG(TLVL_WRITESUBRUN) << "Begin: ArtdaqOutput::writeSubRun(const SubRunPrincipal& srp)";
707  if (!initMsgSent_)
708  {
709  send_init_message();
710  initMsgSent_ = true;
711  }
712  //
713  // Fetch the class dictionaries we need for
714  // writing out the auxiliary information.
715  //
716  static TClass* subrun_aux_class = TClass::GetClass("art::SubRunAuxiliary");
717  if (subrun_aux_class == nullptr)
718  {
719  throw art::Exception(art::errors::DictionaryNotFound) << "ArtdaqOutput::writeSubRun: " // NOLINT(cert-err60-cpp)
720  "Could not get TClass for art::SubRunAuxiliary!";
721  }
722  //
723  // Begin preparing message.
724  //
725  auto msg = prepareMessage(last_sequence_id_ + 1, srp.subRun() + 1, artdaq::Fragment::EndOfSubrunFragmentType);
726  //
727  // Write message type code.
728  //
729  {
730  TLOG(TLVL_WRITESUBRUN) << "ArtdaqOutput::writeSubRun: streaming message type code ...";
731  msg->WriteULong(3);
732  TLOG(TLVL_WRITESUBRUN) << "ArtdaqOutput::writeSubRun: finished streaming message type code.";
733  }
734  //
735  // Write SubRunAuxiliary.
736  //
737  {
738  TLOG(TLVL_WRITESUBRUN) << "ArtdaqOutput::writeSubRun: streaming SubRunAuxiliary ...";
739 
740  TLOG(TLVL_WRITESUBRUN_VERBOSE) << "ArtdaqOutput::writeSubRun: dumping ProcessHistoryRegistry ...";
741  // typedef std::map<const ProcessHistoryID,ProcessHistory>
742  // ProcessHistoryMap;
743  for (auto I = std::begin(art::ProcessHistoryRegistry::get()), E = std::end(art::ProcessHistoryRegistry::get());
744  I != E; ++I)
745  {
746  std::ostringstream OS;
747  I->first.print(OS);
748  TLOG(TLVL_WRITESUBRUN_VERBOSE) << "ArtdaqOutput::writeSubRun: phr: id: '" << OS.str() << "'";
749  OS.str("");
750  TLOG(TLVL_WRITESUBRUN_VERBOSE) << "ArtdaqOutput::writeSubRun: phr: data.size(): " << I->second.data().size();
751  if (!I->second.data().empty())
752  {
753  I->second.data().back().id().print(OS);
754  TLOG(TLVL_WRITESUBRUN_VERBOSE) << "ArtdaqOutput::writeSubRun: phr: data.back().id(): '" << OS.str() << "'";
755  }
756  }
757  if (!srp.subRunAux().processHistoryID().isValid())
758  {
759  TLOG(TLVL_WRITESUBRUN_VERBOSE) << "ArtdaqOutput::writeSubRun: ProcessHistoryID: 'INVALID'";
760  }
761  else
762  {
763  std::ostringstream OS;
764  srp.subRunAux().processHistoryID().print(OS);
765  TLOG(TLVL_WRITESUBRUN_VERBOSE) << "ArtdaqOutput::writeSubRun: ProcessHistoryID: '" << OS.str() << "'";
766  OS.str("");
767  ProcessHistory processHistory;
768  ProcessHistoryRegistry::get(srp.subRunAux().processHistoryID(), processHistory);
769  if (!processHistory.data().empty())
770  {
771  // FIXME: Print something special on invalid id() here!
772  processHistory.data().back().id().print(OS);
773  TLOG(TLVL_WRITESUBRUN_VERBOSE) << "ArtdaqOutput::writeSubRun: ProcessConfigurationID: '" << OS.str() << "'";
774  OS.str("");
775  OS << processHistory.data().back();
776  TLOG(TLVL_WRITESUBRUN_VERBOSE) << "ArtdaqOutput::writeSubRun: ProcessConfiguration: '" << OS.str();
777  }
778  }
779  msg->WriteObjectAny(&srp.subRunAux(), subrun_aux_class);
780  TLOG(TLVL_WRITESUBRUN) << "ArtdaqOutput::writeSubRun: streamed SubRunAuxiliary.";
781  }
782  //
783  // Write data products.
784  //
785  std::vector<BranchKey*> bkv;
786  writeDataProducts(msg, srp, bkv);
787 
788  TLOG(TLVL_WRITESUBRUN) << "ArtdaqOutput::writeSubRun: Sending message";
789  sendMessage(msg);
790  TLOG(TLVL_WRITESUBRUN) << "ArtdaqOutput::writeSubRun: Done sending message";
791 
792  //
793  // Delete the branch keys we created for the message.
794  //
795  for (auto I = bkv.begin(), E = bkv.end(); I != E; ++I)
796  {
797  delete *I;
798  *I = 0;
799  }
800  TLOG(TLVL_WRITESUBRUN) << "End: ArtdaqOutput::writeSubRun(const SubRunPrincipal& srp)";
801 }
802 
803 inline void art::ArtdaqOutput::extractProducts_(Principal const& principal [[gnu::unused]])
804 {
805  TLOG(TLVL_EXTRACTPRODUCTS) << "Begin: ArtdaqOutput::extractProducts_(Principal const& principal) sz=" << principal.size();
806 
807  for (auto I = principal.begin(), E = principal.end(); I != E; ++I)
808  {
809  auto const& productDescription = I->second->productDescription();
810  auto const& branchKey = BranchKey(productDescription);
811 
812  if (!productList_.count(branchKey))
813  {
814  TLOG(TLVL_EXTRACTPRODUCTS_VERBOSE) << "ArtdaqOutput::extractProducts_:"
815  << "Adding branch key to productList of class: '"
816  << branchKey.friendlyClassName_ << "' modlbl: '" << branchKey.moduleLabel_ << "' instnm: '"
817  << branchKey.productInstanceName_ << "' procnm: '" << branchKey.processName_ << "'"
818  << ", description: " << productDescription.wrappedName();
819 
820  productList_[branchKey] = productDescription;
821  }
822  }
823 
824  TLOG(TLVL_EXTRACTPRODUCTS) << "End: ArtdaqOutput::extractProducts_(Principal const& principal) Product list sz=" << productList_.size();
825 }
826 
827 #endif // ARTDAQ_ARTDAQ_ARTMODULES_ARTDAQOUTPUT_HH_
void writeRun(RunPrincipal &rp) final
Write a RunPrincipal to TBufferFile and send
virtual void event_(EventPrincipal const &)
Perform actions for each event. No-op, but derived classes may override
void extractProducts_(Principal const &principal)
Extract the list of Products from the given Principal
This is the base class for artdaq OutputModules, providing the serialization interface for art Events...
virtual void beginSubRun_(SubRunPrincipal const &)
Perform Begin SubRun actions. No-op, but derived classes may override
virtual ~ArtdaqOutput()=default
Destructor
void event(EventPrincipal const &ep) final
Perform actions for each event. Derived classes should implement event_ instead.
void send_init_message()
Send an init message downstream.
virtual void openFile(FileBlock const &)
Perform actions necessary for opening files. No-op, but derived classes may override ...
virtual void endJob()
Perform End-of-Job actions. No-op, but derived classes may override
virtual void SendMessage(artdaq::FragmentPtr &msg)=0
Send the serialized art Event downstream. Artdaq output modules should define this function...
void beginRun(RunPrincipal const &rp) final
Perform Begin Run actions. Derived classes should implement beginRun_ instead.
Header with length information for NetMonTransport messages.
Definition: NetMonHeader.hh:13
void beginSubRun(SubRunPrincipal const &srp) final
Perform Begin SubRun actions. Derived classes should implement beginSubRun_ instead.
virtual void closeFile()
Perform actions necessary for closing files. No-op, but derived classes may override ...
ArtdaqOutput(fhicl::ParameterSet const &ps)
ArtdaqOutput Constructor
virtual void respondToCloseOutputFiles(FileBlock const &)
Perform actions necessary after closing the output file(s). No-op, but derived classes may override ...
void writeSubRun(SubRunPrincipal &srp) final
Write a SubRunPrincipal to TBufferFile and send
virtual void respondToCloseInputFile(FileBlock const &)
Perform actions nesessary after closing the input file. No-op, but derived classes may override ...
virtual void beginRun_(RunPrincipal const &)
Perform Begin Run actions. No-op, but derived classes may override
uint64_t data_length
The length of the message.
Definition: NetMonHeader.hh:15
void write(EventPrincipal &ep) final
Write an EventPrincipal to TBufferFile and send
void writeDataProducts(std::unique_ptr< TBufferFile > &msg, const Principal &principal, std::vector< BranchKey * > &bkv)
Extract the data products from a Principal and write them to the TBufferFile