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