artdaq  v3_09_05
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/Provenance/BranchDescription.h"
17 #include "canvas/Persistency/Provenance/BranchKey.h"
18 #include "canvas/Persistency/Provenance/History.h"
19 #include "canvas/Persistency/Provenance/ParentageRegistry.h"
20 #include "canvas/Persistency/Provenance/ProcessConfiguration.h"
21 #include "canvas/Persistency/Provenance/ProcessConfigurationID.h"
22 #include "canvas/Persistency/Provenance/ProcessHistoryID.h"
23 #include "canvas/Persistency/Provenance/ProductList.h"
24 #include "canvas/Persistency/Provenance/ProductProvenance.h"
25 #include "canvas/Persistency/Provenance/RunAuxiliary.h"
26 #include "canvas/Persistency/Provenance/SubRunAuxiliary.h"
27 #include "canvas/Utilities/DebugMacros.h"
28 #include "canvas/Utilities/Exception.h"
29 #include "cetlib/column_width.h"
30 #include "cetlib/lpad.h"
31 #include "cetlib/rpad.h"
32 #include "fhiclcpp/ParameterSet.h"
33 #include "fhiclcpp/ParameterSetID.h"
34 #include "fhiclcpp/ParameterSetRegistry.h"
35 
36 #include "artdaq/DAQdata/Globals.hh"
37 #include "artdaq/DAQdata/NetMonHeader.hh"
38 
39 #include "artdaq-core/Data/Fragment.hh"
40 #include "artdaq-core/Data/RawEvent.hh"
41 #include "artdaq-core/Data/detail/ParentageMap.hh"
42 
43 #include <TBufferFile.h>
44 #include <TClass.h>
45 #include <TList.h>
46 #include <TStreamerInfo.h>
47 
48 #include <unistd.h>
49 #include <algorithm>
50 #include <iomanip>
51 #include <iostream>
52 #include <iterator>
53 #include <memory>
54 #include <sstream>
55 #include <string>
56 #include <vector>
57 
58 #define TLVL_OPENFILE 16
59 #define TLVL_CLOSEFILE 17
60 #define TLVL_RESPONDTOCLOSEINPUTFILE 18
61 #define TLVL_RESPONDTOCLOSEOUTPUTFILE 19
62 #define TLVL_ENDJOB 20
63 #define TLVL_SENDINIT 10
64 #define TLVL_SENDINIT_VERBOSE1 32
65 #define TLVL_SENDINIT_VERBOSE2 33
66 #define TLVL_WRITEDATAPRODUCTS 11
67 #define TLVL_WRITEDATAPRODUCTS_VERBOSE 34
68 #define TLVL_WRITE 12
69 #define TLVL_WRITERUN 13
70 #define TLVL_WRITERUN_VERBOSE 37
71 #define TLVL_WRITESUBRUN 14
72 #define TLVL_WRITESUBRUN_VERBOSE 35
73 #define TLVL_EXTRACTPRODUCTS 15
74 #define TLVL_EXTRACTPRODUCTS_VERBOSE 36
75 
76 namespace art {
77 class ArtdaqOutput;
78 } // namespace art
79 
80 static artdaq::FragmentPtr outputFrag = nullptr;
81 inline char* Fragment_ReAllocChar(char* dataPtr, size_t size, size_t /*oldsize*/)
82 {
83  if (outputFrag != nullptr && dataPtr == reinterpret_cast<char*>(outputFrag->dataBegin())) // NOLINT(cppcoreguidelines-pro-type-reinterpret-cast)
84  {
85  outputFrag->resizeBytes(size);
86 
87  return reinterpret_cast<char*>(outputFrag->dataBegin()); // NOLINT(cppcoreguidelines-pro-type-reinterpret-cast)
88  }
89  return nullptr;
90 }
91 
95 class art::ArtdaqOutput : public art::OutputModule
96 {
97 public:
102  explicit ArtdaqOutput(fhicl::ParameterSet const& ps)
103  : OutputModule(ps), productList_(), raw_data_label_(ps.get<std::string>("raw_data_label", "daq"))
104  {
105  root::setup();
106  }
107 
111  virtual ~ArtdaqOutput() = default;
112 
113 protected:
117  virtual void openFile(FileBlock const&)
118  {
119  TLOG(TLVL_OPENFILE) << "Begin/End: ArtdaqOutput::openFile(const FileBlock&)";
120  }
121 
125  virtual void closeFile() { TLOG(TLVL_CLOSEFILE) << "Begin/End: ArtdaqOutput::closeFile()"; }
126 
130  virtual void respondToCloseInputFile(FileBlock const&)
131  {
132  TLOG(TLVL_RESPONDTOCLOSEINPUTFILE) << "Begin/End: ArtdaqOutput::"
133  "respondToCloseOutputFiles(FileBlock const&)";
134  }
135 
139  virtual void respondToCloseOutputFiles(FileBlock const&)
140  {
141  TLOG(TLVL_RESPONDTOCLOSEOUTPUTFILE) << "Begin/End: ArtdaqOutput::"
142  "respondToCloseOutputFiles(FileBlock const&)";
143  }
144 
148  virtual void endJob()
149  {
150  TLOG(TLVL_ENDJOB) << "Begin/End: ArtdaqOutput::endJob()";
151  }
152 
157  void beginRun(RunPrincipal const& rp) final
158  {
159  extractProducts_(rp);
160  beginRun_(rp);
161  }
165  virtual void beginRun_(RunPrincipal const&) {}
166 
171  void beginSubRun(SubRunPrincipal const& srp) final
172  {
173  extractProducts_(srp);
174  beginSubRun_(srp);
175  }
179  virtual void beginSubRun_(SubRunPrincipal const&) {}
180 
185  void event(EventPrincipal const& ep) final
186  {
187  extractProducts_(ep);
188  event_(ep);
189  }
193  virtual void event_(EventPrincipal const&) {}
194 
199  void write(EventPrincipal& ep) final;
200 
205  void writeRun(RunPrincipal& rp) final;
206 
211  void writeSubRun(SubRunPrincipal& srp) final;
212 
219  void writeDataProducts(std::unique_ptr<TBufferFile>& msg, const Principal& principal, std::vector<BranchKey*>& bkv);
220 
225  void extractProducts_(Principal const& principal);
226 
231  void send_init_message(History const& history);
232 
237  virtual void SendMessage(artdaq::FragmentPtr& msg) = 0;
238 
239 private:
240  ArtdaqOutput(ArtdaqOutput const&) = delete;
241  ArtdaqOutput(ArtdaqOutput&&) = delete;
242  ArtdaqOutput& operator=(ArtdaqOutput const&) = delete;
243  ArtdaqOutput& operator=(ArtdaqOutput&&) = delete;
244 
245  bool initMsgSent_{false};
246  ProductList productList_;
247  size_t last_fragment_size_{10};
248  artdaq::Fragment::sequence_id_t last_sequence_id_{0};
249  artdaq::Fragment::timestamp_t last_timestamp_{0};
250  std::string raw_data_label_;
251 
252  std::unique_ptr<TBufferFile> prepareMessage(artdaq::Fragment::sequence_id_t seqID, artdaq::Fragment::timestamp_t ts, artdaq::Fragment::type_t type)
253  {
255  outputFrag = std::make_unique<artdaq::Fragment>(last_fragment_size_, seqID, my_rank, type, hdr, ts);
256  auto msg = std::make_unique<TBufferFile>(TBuffer::kWrite, last_fragment_size_ * sizeof(artdaq::RawDataType), outputFrag->dataBegin(), kFALSE, &Fragment_ReAllocChar);
257  msg->SetWriteMode();
258 
259  if (seqID > last_sequence_id_) last_sequence_id_ = seqID;
260  if (ts > last_timestamp_) last_timestamp_ = ts;
261 
262  return msg;
263  }
264 
265  void sendMessage(std::unique_ptr<TBufferFile>& msg)
266  {
268  hdr.data_length = static_cast<uint64_t>(msg->Length());
269  outputFrag->updateMetadata(hdr);
270  outputFrag->resizeBytes(hdr.data_length);
271  last_fragment_size_ = std::ceil(msg->Length() / static_cast<double>(sizeof(artdaq::RawDataType)));
272  SendMessage(outputFrag);
273  }
274 };
275 
276 inline void art::ArtdaqOutput::send_init_message(History const& history)
277 {
278  TLOG(TLVL_SENDINIT) << "Begin: ArtdaqOutput::send_init_message()";
279  //
280  // Get the classes we will need.
281  //
282  // static TClass* string_class = TClass::GetClass("std::string");
283  // if (string_class == nullptr) {
284  // throw art::Exception(art::errors::DictionaryNotFound) <<
285  // "ArtdaqOutput static send_init_message(): "
286  // "Could not get TClass for std::string!";
287  //}
288  static TClass* product_list_class = TClass::GetClass("std::map<art::BranchKey,art::BranchDescription>");
289  if (product_list_class == nullptr)
290  {
291  throw art::Exception(art::errors::DictionaryNotFound) << "ArtdaqOutput::send_init_message(): " // NOLINT(cert-err60-cpp)
292  "Could not get TClass for "
293  "map<art::BranchKey,art::BranchDescription>!";
294  }
295  // typedef std::map<const ProcessHistoryID,ProcessHistory> ProcessHistoryMap;
296  // TClass* process_history_map_class = TClass::GetClass(
297  // "std::map<const art::ProcessHistoryID,art::ProcessHistory>");
298  // FIXME: Replace the "2" here with a use of the proper enum value!
299  static TClass* process_history_map_class = TClass::GetClass("std::map<const art::Hash<2>,art::ProcessHistory>");
300  if (process_history_map_class == nullptr)
301  {
302  throw art::Exception(art::errors::DictionaryNotFound) << "ArtdaqOutput::send_init_message(): " // NOLINT(cert-err60-cpp)
303  "Could not get class for "
304  "std::map<const art::Hash<2>,art::ProcessHistory>!";
305  }
306  // static TClass* parentage_map_class = TClass::GetClass(
307  // "std::map<const art::ParentageID,art::Parentage>");
308  static TClass* parentage_map_class = TClass::GetClass("art::ParentageMap");
309  if (parentage_map_class == nullptr)
310  {
311  throw art::Exception(art::errors::DictionaryNotFound) << "ArtdaqOutput::send_init_message(): " // NOLINT(cert-err60-cpp)
312  "Could not get class for ParentageMap.";
313  }
314  TLOG(TLVL_SENDINIT) << "parentage_map_class: " << static_cast<void*>(parentage_map_class);
315 
316  static TClass* history_class = TClass::GetClass("art::History");
317  if (history_class == nullptr)
318  {
319  throw art::Exception(art::errors::DictionaryNotFound) << "ArtdaqOutput::send_init_message(): " // NOLINT(cert-err60-cpp)
320  "Could not get TClass for art::History!";
321  }
322 
323  //
324  // Construct and send the init message.
325  //
326  auto msg = prepareMessage(0, 0, artdaq::Fragment::InitFragmentType);
327  //
328  // Stream the message type code.
329  //
330  TLOG(TLVL_SENDINIT) << "ArtdaqOutput::send_init_message(): Streaming message type code ...";
331  msg->WriteULong(1);
332  TLOG(TLVL_SENDINIT) << "ArtdaqOutput::send_init_message(): Finished streaming message type code.";
333 
334  //
335  // Stream Class info
336  //
337  // 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.
338  TList infos;
339  std::vector<std::string> classNames{"std::map<art::BranchKey,art::BranchDescription>", "std::map<const art::Hash<2>,art::ProcessHistory>", "art::ParentageMap",
340  "art::History", "art::BranchKey", "art::ProductProvenance", "art::RunAuxiliary", "art::SubRunAuxiliary", "art::EventAuxiliary"};
341  for (auto& className : classNames)
342  {
343  TClass* class_ptr = TClass::GetClass(className.c_str());
344  if (class_ptr == nullptr)
345  {
346  throw art::Exception(art::errors::DictionaryNotFound) << "ArtdaqOutput::send_init_message: Could not get TClass for " << className << "!"; // NOLINT(cert-err60-cpp)
347  }
348  infos.Add(class_ptr->GetStreamerInfo());
349  }
350  msg->WriteObject(&infos);
351 
352  //
353  // Stream the ParameterSetRegistry.
354  //
355  ULong_t ps_cnt = fhicl::ParameterSetRegistry::size();
356  TLOG(TLVL_SENDINIT) << "ArtdaqOutput::send_init_message(): parameter set count: " << ps_cnt;
357  msg->WriteULong(ps_cnt);
358  TLOG(TLVL_SENDINIT) << "ArtdaqOutput::send_init_message(): Streaming parameter sets ...";
359  for (auto I = std::begin(fhicl::ParameterSetRegistry::get()), E = std::end(fhicl::ParameterSetRegistry::get());
360  I != E; ++I)
361  {
362  TLOG(TLVL_SENDINIT) << "Pset ID " << I->first << ": " << I->second.to_string();
363  std::string pset_str = I->second.to_string();
364  // msg->WriteObjectAny(&pset_str, string_class);
365  msg->WriteStdString(pset_str);
366  }
367  TLOG(TLVL_SENDINIT) << "ArtdaqOutput::send_init_message(): Finished streaming parameter sets.";
368 
369  //
370  // Stream the MasterProductRegistry.
371  //
372  TLOG(TLVL_SENDINIT) << "ArtdaqOutput::send_init_message(): Streaming Product List sz=" << productList_.size() << "...";
373  msg->WriteObjectAny(&productList_, product_list_class);
374  TLOG(TLVL_SENDINIT) << "ArtdaqOutput::send_init_message(): Finished streaming Product List.";
375 
376  art::ProcessHistoryMap phr;
377  for (auto const& pr : art::ProcessHistoryRegistry::get())
378  {
379  phr.emplace(pr);
380  }
381  //
382  // Dump the ProcessHistoryRegistry.
383  //
384  TLOG(TLVL_SENDINIT_VERBOSE2) << "ArtdaqOutput::send_init_message(): Dumping ProcessHistoryRegistry ...";
385  // typedef std::map<const ProcessHistoryID,ProcessHistory>
386  // ProcessHistoryMap;
387  TLOG(TLVL_SENDINIT_VERBOSE2) << "ArtdaqOutput::send_init_message(): phr: size: " << phr.size();
388  for (auto I = phr.begin(), E = phr.end(); I != E; ++I)
389  {
390  std::ostringstream OS;
391  I->first.print(OS);
392  TLOG(TLVL_SENDINIT_VERBOSE2) << "ArtdaqOutput::send_init_message(): phr: id: '" << OS.str() << "'";
393  }
394  //
395  // Stream the ProcessHistoryRegistry.
396  //
397  TLOG(TLVL_SENDINIT) << "ArtdaqOutput::send_init_message(): Streaming ProcessHistoryRegistry ...";
398  // typedef std::map<const ProcessHistoryID,ProcessHistory>
399  // ProcessHistoryMap;
400  const art::ProcessHistoryMap& phm = phr;
401  TLOG(TLVL_SENDINIT) << "ArtdaqOutput::send_init_message(): phm: size: " << phm.size();
402  msg->WriteObjectAny(&phm, process_history_map_class);
403  TLOG(TLVL_SENDINIT) << "ArtdaqOutput::send_init_message(): Finished streaming ProcessHistoryRegistry.";
404 
405  //
406  // Stream the ParentageRegistry.
407  //
408  TLOG(TLVL_SENDINIT) << "ArtdaqOutput::send_init_message(): Streaming ParentageRegistry ..." << static_cast<void*>(parentage_map_class);
409  art::ParentageMap parentageMap{};
410  for (auto const& pr : art::ParentageRegistry::get())
411  {
412  parentageMap.emplace(pr.first, pr.second);
413  }
414 
415  msg->WriteObjectAny(&parentageMap, parentage_map_class);
416 
417  TLOG(TLVL_SENDINIT) << "ArtdaqOutput::send_init_message(): Finished streaming ParentageRegistry.";
418 
419  TLOG(TLVL_SENDINIT) << "ArtdaqOutput::send_init_message(): Streaming History";
420  msg->WriteObjectAny(&history, history_class);
421  TLOG(TLVL_SENDINIT) << "ArtdaqOutput::send_init_message(): Done streaming History";
422 
423  TLOG(TLVL_SENDINIT) << "ArtdaqOutput::send_init_message(): Sending init message";
424  sendMessage(msg);
425  TLOG(TLVL_SENDINIT) << "ArtdaqOutput::send_init_message(): Done sending init message";
426 
427  TLOG(TLVL_SENDINIT) << "ArtdaqOutput::send_init_message(): END";
428 }
429 
430 inline void art::ArtdaqOutput::writeDataProducts(std::unique_ptr<TBufferFile>& msg, const Principal& principal, std::vector<BranchKey*>& bkv)
431 {
432  TLOG(TLVL_WRITEDATAPRODUCTS) << "Begin: ArtdaqOutput::writeDataProducts(...)";
433  //
434  // Fetch the class dictionaries we need for
435  // writing out the data products.
436  //
437  static TClass* branch_key_class = TClass::GetClass("art::BranchKey");
438  if (branch_key_class == nullptr)
439  {
440  throw art::Exception(art::errors::DictionaryNotFound) << "ArtdaqOutput::writeDataProducts(...): " // NOLINT(cert-err60-cpp)
441  "Could not get TClass for art::BranchKey!";
442  }
443  static TClass* prdprov_class = TClass::GetClass("art::ProductProvenance");
444  if (prdprov_class == nullptr)
445  {
446  throw art::Exception(art::errors::DictionaryNotFound) << "ArtdaqOutput::writeDataProducts(...): " // NOLINT(cert-err60-cpp)
447  "Could not get TClass for art::ProductProvenance!";
448  }
449 
450  //
451  // Calculate the data product count.
452  //
453  ULong_t prd_cnt = 0;
454  // std::map<art::BranchID, std::shared_ptr<art::Group>>::const_iterator
455  for (auto I = principal.begin(), E = principal.end(); I != E; ++I)
456  {
457  auto const& productDescription = I->second->productDescription();
458  auto const& refs = keptProducts()[productDescription.branchType()];
459  bool found = false;
460  for (auto const& ref : refs)
461  {
462 
463  if (ref.second == productDescription)
464  {
465  found = true;
466  break;
467  }
468  }
469  if (!I->second->productAvailable() || !found)
470  {
471  continue;
472  }
473  ++prd_cnt;
474  }
475  //
476  // Write the data product count.
477  //
478  TLOG(TLVL_WRITEDATAPRODUCTS) << "ArtdaqOutput::writeDataProducts(...): Streaming product count: " +
479  std::to_string(prd_cnt);
480  msg->WriteULong(prd_cnt);
481  TLOG(TLVL_WRITEDATAPRODUCTS) << "ArtdaqOutput::writeDataProducts(...): Finished streaming product count.";
482 
483  //
484  // Loop over the groups in the RunPrincipal and
485  // write out the data products.
486  //
487  // Note: We need this vector of keys because the ROOT I/O mechanism
488  // requires that each object inserted in the message has a
489  // unique address, so we force that by holding on to each
490  // branch key manufactured in the loop until after we are
491  // done constructing the message.
492  //
493  bkv.reserve(prd_cnt);
494  // std::map<art::BranchID, std::shared_ptr<art::Group>>::const_iterator
495  for (auto I = principal.begin(), E = principal.end(); I != E; ++I)
496  {
497  auto const& productDescription = I->second->productDescription();
498  auto const& refs = keptProducts()[productDescription.branchType()];
499  bool found = false;
500  for (auto const& ref : refs)
501  {
502  if (ref.second == productDescription)
503  {
504  found = true;
505  break;
506  }
507  }
508  if (!I->second->productAvailable() || !found)
509  {
510  continue;
511  }
512  const BranchDescription& bd(I->second->productDescription());
513  bkv.push_back(new BranchKey(bd));
514  TLOG(TLVL_WRITEDATAPRODUCTS_VERBOSE)
515  << "ArtdaqOutput::writeDataProducts(...): Dumping branch key of class: '"
516  << bkv.back()->friendlyClassName_ << "' modlbl: '" << bkv.back()->moduleLabel_ << "' instnm: '"
517  << bkv.back()->productInstanceName_ << "' procnm: '" << bkv.back()->processName_ << "'";
518  TLOG(TLVL_WRITEDATAPRODUCTS) << "ArtdaqOutput::writeDataProducts(...): "
519  "Streaming branch key of class: '"
520  << bd.producedClassName() << "' modlbl: '" << bd.moduleLabel() << "' instnm: '"
521  << bd.productInstanceName() << "' procnm: '" << bd.processName() << "'";
522  msg->WriteObjectAny(bkv.back(), branch_key_class);
523 
524  TLOG(TLVL_WRITEDATAPRODUCTS) << "ArtdaqOutput::writeDataProducts(...): "
525  "Streaming product of class: '"
526  << bd.producedClassName() << "' modlbl: '" << bd.moduleLabel() << "' instnm: '"
527  << bd.productInstanceName() << "' procnm: '" << bd.processName() << "'";
528 
529  OutputHandle oh = principal.getForOutput(bd.productID(), true);
530  const EDProduct* prd = oh.wrapper();
531  TLOG(TLVL_WRITEDATAPRODUCTS) << "Class for branch " << bd.wrappedName() << " is "
532  << static_cast<void*>(TClass::GetClass(bd.wrappedName().c_str()));
533  msg->WriteObjectAny(prd, TClass::GetClass(bd.wrappedName().c_str()));
534  TLOG(TLVL_WRITEDATAPRODUCTS) << "ArtdaqOutput::writeDataProducts(...): "
535  "Streaming product provenance of class: '"
536  << bd.producedClassName() << "' modlbl: '" << bd.moduleLabel() << "' instnm: '"
537  << bd.productInstanceName() << "' procnm: '" << bd.processName() << "'";
538 
539  const ProductProvenance* prdprov = I->second->productProvenance().get();
540 
541  msg->WriteObjectAny(prdprov, prdprov_class);
542  }
543  TLOG(TLVL_WRITEDATAPRODUCTS) << "End: ArtdaqOutput::writeDataProducts(...)";
544 }
545 
546 inline void art::ArtdaqOutput::write(EventPrincipal& ep)
547 {
548  //
549  // Write an Event message.
550  //
551  TLOG(TLVL_WRITE) << "Begin: ArtdaqOutput::write(const EventPrincipal& ep)";
552  if (!initMsgSent_)
553  {
554  send_init_message(ep.history());
555  initMsgSent_ = true;
556  }
557  //
558  // Get root classes needed for I/O.
559  //
560  static TClass* run_aux_class = TClass::GetClass("art::RunAuxiliary");
561  if (run_aux_class == nullptr)
562  {
563  throw art::Exception(art::errors::DictionaryNotFound) << "ArtdaqOutput::write(const EventPrincipal& ep): " // NOLINT(cert-err60-cpp)
564  "Could not get TClass for art::RunAuxiliary!";
565  }
566  static TClass* subrun_aux_class = TClass::GetClass("art::SubRunAuxiliary");
567  if (subrun_aux_class == nullptr)
568  {
569  throw art::Exception(art::errors::DictionaryNotFound) << "ArtdaqOutput::write(const EventPrincipal& ep): " // NOLINT(cert-err60-cpp)
570  "Could not get TClass for art::SubRunAuxiliary!";
571  }
572  static TClass* event_aux_class = TClass::GetClass("art::EventAuxiliary");
573  if (event_aux_class == nullptr)
574  {
575  throw art::Exception(art::errors::DictionaryNotFound) << "ArtdaqOutput::write(const EventPrincipal& ep): " // NOLINT(cert-err60-cpp)
576  "Could not get TClass for art::EventAuxiliary!";
577  }
578  static TClass* history_class = TClass::GetClass("art::History");
579  if (history_class == nullptr)
580  {
581  throw art::Exception(art::errors::DictionaryNotFound) << "ArtdaqOutput::write(const EventPrincipal& ep): " // NOLINT(cert-err60-cpp)
582  "Could not get TClass for art::History!";
583  }
584 
585  // Subrun number starts at 1
586  TLOG(TLVL_WRITE) << "ArtdaqOutput::write(const EventPrincipal& ep): Setting Output Fragment Header Fields";
587  auto seqID = (static_cast<uint64_t>(ep.eventID().subRun() - 1) << 32) + ep.eventID().event();
588 
589  art::ProcessTag tag("", processName());
590  auto res = ep.getMany(art::ModuleContext::invalid(), art::WrappedTypeID::make<artdaq::detail::RawEventHeader>(), art::MatchAllSelector(), tag);
591 
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:95
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