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