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