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