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