artdaq  v3_09_06a
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  if (ref.second == productDescription)
463  {
464  found = true;
465  break;
466  }
467  }
468  if (!I->second->productAvailable() || !found)
469  {
470  continue;
471  }
472  ++prd_cnt;
473  }
474  //
475  // Write the data product count.
476  //
477  TLOG(TLVL_WRITEDATAPRODUCTS) << "ArtdaqOutput::writeDataProducts(...): Streaming product count: " +
478  std::to_string(prd_cnt);
479  msg->WriteULong(prd_cnt);
480  TLOG(TLVL_WRITEDATAPRODUCTS) << "ArtdaqOutput::writeDataProducts(...): Finished streaming product count.";
481 
482  //
483  // Loop over the groups in the RunPrincipal and
484  // write out the data products.
485  //
486  // Note: We need this vector of keys because the ROOT I/O mechanism
487  // requires that each object inserted in the message has a
488  // unique address, so we force that by holding on to each
489  // branch key manufactured in the loop until after we are
490  // done constructing the message.
491  //
492  bkv.reserve(prd_cnt);
493  // std::map<art::BranchID, std::shared_ptr<art::Group>>::const_iterator
494  for (auto I = principal.begin(), E = principal.end(); I != E; ++I)
495  {
496  auto const& productDescription = I->second->productDescription();
497  auto const& refs = keptProducts()[productDescription.branchType()];
498  bool found = false;
499  for (auto const& ref : refs)
500  {
501  if (ref.second == productDescription)
502  {
503  found = true;
504  break;
505  }
506  }
507  if (!I->second->productAvailable() || !found)
508  {
509  continue;
510  }
511  const BranchDescription& bd(I->second->productDescription());
512  bkv.push_back(new BranchKey(bd));
513  TLOG(TLVL_WRITEDATAPRODUCTS_VERBOSE)
514  << "ArtdaqOutput::writeDataProducts(...): Dumping branch key of class: '"
515  << bkv.back()->friendlyClassName_ << "' modlbl: '" << bkv.back()->moduleLabel_ << "' instnm: '"
516  << bkv.back()->productInstanceName_ << "' procnm: '" << bkv.back()->processName_ << "'";
517  TLOG(TLVL_WRITEDATAPRODUCTS) << "ArtdaqOutput::writeDataProducts(...): "
518  "Streaming branch key of class: '"
519  << bd.producedClassName() << "' modlbl: '" << bd.moduleLabel() << "' instnm: '"
520  << bd.productInstanceName() << "' procnm: '" << bd.processName() << "'";
521  msg->WriteObjectAny(bkv.back(), branch_key_class);
522 
523  TLOG(TLVL_WRITEDATAPRODUCTS) << "ArtdaqOutput::writeDataProducts(...): "
524  "Streaming product of class: '"
525  << bd.producedClassName() << "' modlbl: '" << bd.moduleLabel() << "' instnm: '"
526  << bd.productInstanceName() << "' procnm: '" << bd.processName() << "'";
527 
528  OutputHandle oh = principal.getForOutput(bd.productID(), true);
529  const EDProduct* prd = oh.wrapper();
530  TLOG(TLVL_WRITEDATAPRODUCTS) << "Class for branch " << bd.wrappedName() << " is "
531  << static_cast<void*>(TClass::GetClass(bd.wrappedName().c_str()));
532  msg->WriteObjectAny(prd, TClass::GetClass(bd.wrappedName().c_str()));
533  TLOG(TLVL_WRITEDATAPRODUCTS) << "ArtdaqOutput::writeDataProducts(...): "
534  "Streaming product provenance of class: '"
535  << bd.producedClassName() << "' modlbl: '" << bd.moduleLabel() << "' instnm: '"
536  << bd.productInstanceName() << "' procnm: '" << bd.processName() << "'";
537 
538  const ProductProvenance* prdprov = I->second->productProvenance().get();
539 
540  msg->WriteObjectAny(prdprov, prdprov_class);
541  }
542  TLOG(TLVL_WRITEDATAPRODUCTS) << "End: ArtdaqOutput::writeDataProducts(...)";
543 }
544 
545 inline void art::ArtdaqOutput::write(EventPrincipal& ep)
546 {
547  //
548  // Write an Event message.
549  //
550  TLOG(TLVL_WRITE) << "Begin: ArtdaqOutput::write(const EventPrincipal& ep)";
551  if (!initMsgSent_)
552  {
553  send_init_message(ep.history());
554  initMsgSent_ = true;
555  }
556  //
557  // Get root classes needed for I/O.
558  //
559  static TClass* run_aux_class = TClass::GetClass("art::RunAuxiliary");
560  if (run_aux_class == nullptr)
561  {
562  throw art::Exception(art::errors::DictionaryNotFound) << "ArtdaqOutput::write(const EventPrincipal& ep): " // NOLINT(cert-err60-cpp)
563  "Could not get TClass for art::RunAuxiliary!";
564  }
565  static TClass* subrun_aux_class = TClass::GetClass("art::SubRunAuxiliary");
566  if (subrun_aux_class == nullptr)
567  {
568  throw art::Exception(art::errors::DictionaryNotFound) << "ArtdaqOutput::write(const EventPrincipal& ep): " // NOLINT(cert-err60-cpp)
569  "Could not get TClass for art::SubRunAuxiliary!";
570  }
571  static TClass* event_aux_class = TClass::GetClass("art::EventAuxiliary");
572  if (event_aux_class == nullptr)
573  {
574  throw art::Exception(art::errors::DictionaryNotFound) << "ArtdaqOutput::write(const EventPrincipal& ep): " // NOLINT(cert-err60-cpp)
575  "Could not get TClass for art::EventAuxiliary!";
576  }
577  static TClass* history_class = TClass::GetClass("art::History");
578  if (history_class == nullptr)
579  {
580  throw art::Exception(art::errors::DictionaryNotFound) << "ArtdaqOutput::write(const EventPrincipal& ep): " // NOLINT(cert-err60-cpp)
581  "Could not get TClass for art::History!";
582  }
583 
584  // Subrun number starts at 1
585  TLOG(TLVL_WRITE) << "ArtdaqOutput::write(const EventPrincipal& ep): Setting Output Fragment Header Fields";
586  auto seqID = (static_cast<uint64_t>(ep.eventID().subRun() - 1) << 32) + ep.eventID().event();
587 
588  art::ProcessTag tag("", processName());
589  auto res = ep.getMany(art::ModuleContext::invalid(), art::WrappedTypeID::make<artdaq::detail::RawEventHeader>(), art::MatchAllSelector(), tag);
590 
591  artdaq::Fragment::timestamp_t ts = 0;
592 
593  for (auto const& qr : res)
594  {
595  Handle<artdaq::detail::RawEventHeader> handle{qr};
596  if (handle.isValid())
597  {
598  if (handle->timestamp > ts) ts = handle->timestamp;
599  }
600  }
601  TLOG(TLVL_WRITE) << "ArtdaqOutput::write(const EventPrincipal& ep): Data Fragment Header Fields: SeqID: " << seqID << ", timestamp: " << ts;
602 
603  //
604  // Setup message buffer.
605  //
606  auto msg = prepareMessage(seqID, ts, artdaq::Fragment::DataFragmentType);
607  //
608  // Write message type code.
609  //
610  TLOG(TLVL_WRITE) << "ArtdaqOutput::write(const EventPrincipal& ep): Streaming message type code ...";
611  msg->WriteULong(4);
612  TLOG(TLVL_WRITE) << "ArtdaqOutput::write(const EventPrincipal& ep): Finished streaming message type code.";
613 
614  //
615  // Write RunAuxiliary.
616  //
617  TLOG(TLVL_WRITE) << "ArtdaqOutput::write(const EventPrincipal& ep): Streaming RunAuxiliary ...";
618  msg->WriteObjectAny(&ep.subRunPrincipal().runPrincipal().runAux(), run_aux_class);
619  TLOG(TLVL_WRITE) << "ArtdaqOutput::write(const EventPrincipal& ep): Finished streaming RunAuxiliary.";
620 
621  //
622  // Write SubRunAuxiliary.
623  //
624  TLOG(TLVL_WRITE) << "ArtdaqOutput::write(const EventPrincipal& ep): Streaming SubRunAuxiliary ...";
625  msg->WriteObjectAny(&ep.subRunPrincipal().subRunAux(), subrun_aux_class);
626  TLOG(TLVL_WRITE) << "ArtdaqOutput::write(const EventPrincipal& ep): Finished streaming SubRunAuxiliary.";
627 
628  //
629  // Write EventAuxiliary.
630  //
631  {
632  TLOG(TLVL_WRITE) << "ArtdaqOutput::write(const EventPrincipal& ep): Streaming EventAuxiliary ...";
633  msg->WriteObjectAny(&ep.eventAux(), event_aux_class);
634  TLOG(TLVL_WRITE) << "ArtdaqOutput::write(const EventPrincipal& ep): Finished streaming EventAuxiliary.";
635  }
636  //
637  // Write History.
638  //
639  {
640  TLOG(TLVL_WRITE) << "ArtdaqOutput::write(const EventPrincipal& ep): Streaming History ...";
641  msg->WriteObjectAny(&ep.history(), history_class);
642  TLOG(TLVL_WRITE) << "ArtdaqOutput::write(const EventPrincipal& ep): Finished streaming History.";
643  }
644  //
645  // Write data products.
646  //
647  std::vector<BranchKey*> bkv;
648  writeDataProducts(msg, ep, bkv);
649 
650  TLOG(TLVL_WRITE) << "ArtdaqOutput::write: Sending message";
651  sendMessage(msg);
652  TLOG(TLVL_WRITE) << "ArtdaqOutput::write: Done sending message";
653 
654  //
655  // Delete the branch keys we created for the message.
656  //
657  for (auto I = bkv.begin(), E = bkv.end(); I != E; ++I)
658  {
659  delete *I;
660  *I = 0;
661  }
662  TLOG(TLVL_WRITE) << "End: ArtdaqOutput::write(const EventPrincipal& ep)";
663 }
664 
665 inline void art::ArtdaqOutput::writeRun(RunPrincipal& rp)
666 { //
667  // Write an EndRun message.
668  //
669  TLOG(TLVL_WRITERUN) << "Begin: ArtdaqOutput::writeRun(const RunPrincipal& rp)";
670  (void)rp;
671  if (!initMsgSent_)
672  {
673  send_init_message(rp.history());
674  initMsgSent_ = true;
675  }
676 #if 0
677  //
678  // Fetch the class dictionaries we need for
679  // writing out the auxiliary information.
680  //
681  static TClass* run_aux_class = TClass::GetClass("art::RunAuxiliary");
682  assert(run_aux_class != nullptr && "writeRun: Could not get TClass for art::RunAuxiliary!");
683  //
684  // Begin preparing message.
685  //
686  auto msg = prepareMessage(last_sequence_id_ + 1,rp.run() + 1, artdaq::Fragment::EndOfRunFragmentType);
687  //
688  // Write message type code.
689  //
690  {
691  TLOG(TLVL_WRITERUN) << "ArtdaqOutput::writeRun: streaming message type code ...";
692  msg->WriteULong(2);
693  TLOG(TLVL_WRITERUN) << "ArtdaqOutput::writeRun: finished streaming message type code.";
694  }
695  //
696  // Write RunAuxiliary.
697  //
698  {
699  TLOG(TLVL_WRITERUN) << "ArtdaqOutput::writeRun: streaming RunAuxiliary ...";
700  msg->WriteObjectAny(&rp.runAux(), run_aux_class);
701  TLOG(TLVL_WRITERUN) << "ArtdaqOutput::writeRun: streamed RunAuxiliary.";
702  }
703  //
704  // Write data products.
705  //
706  std::vector<BranchKey*> bkv;
707  writeDataProducts(msg, rp, bkv);
708 
709  TLOG(TLVL_WRITERUN) << "ArtdaqOutput::writeRun: Sending message";
710  sendMessage(msg);
711  TLOG(TLVL_WRITERUN) << "ArtdaqOutput::writeRun: Done sending message";
712 
713  for (auto I = bkv.begin(), E = bkv.end(); I != E; ++I)
714  {
715  delete *I;
716  *I = 0;
717  }
718 #endif
719  TLOG(TLVL_WRITERUN) << "End: ArtdaqOutput::writeRun(RunPrincipal& rp)";
720 }
721 inline void art::ArtdaqOutput::writeSubRun(SubRunPrincipal& srp)
722 { //
723  // Write an EndSubRun message.
724  //
725  TLOG(TLVL_WRITESUBRUN) << "Begin: ArtdaqOutput::writeSubRun(const SubRunPrincipal& srp)";
726  if (!initMsgSent_)
727  {
728  send_init_message(srp.history());
729  initMsgSent_ = true;
730  }
731  //
732  // Fetch the class dictionaries we need for
733  // writing out the auxiliary information.
734  //
735  static TClass* subrun_aux_class = TClass::GetClass("art::SubRunAuxiliary");
736  if (subrun_aux_class == nullptr)
737  {
738  throw art::Exception(art::errors::DictionaryNotFound) << "ArtdaqOutput::writeSubRun: " // NOLINT(cert-err60-cpp)
739  "Could not get TClass for art::SubRunAuxiliary!";
740  }
741  //
742  // Begin preparing message.
743  //
744  auto msg = prepareMessage(last_sequence_id_ + 1, srp.subRun() + 1, artdaq::Fragment::EndOfSubrunFragmentType);
745  //
746  // Write message type code.
747  //
748  {
749  TLOG(TLVL_WRITESUBRUN) << "ArtdaqOutput::writeSubRun: streaming message type code ...";
750  msg->WriteULong(3);
751  TLOG(TLVL_WRITESUBRUN) << "ArtdaqOutput::writeSubRun: finished streaming message type code.";
752  }
753  //
754  // Write SubRunAuxiliary.
755  //
756  {
757  TLOG(TLVL_WRITESUBRUN) << "ArtdaqOutput::writeSubRun: streaming SubRunAuxiliary ...";
758 
759  TLOG(TLVL_WRITESUBRUN_VERBOSE) << "ArtdaqOutput::writeSubRun: dumping ProcessHistoryRegistry ...";
760  // typedef std::map<const ProcessHistoryID,ProcessHistory>
761  // ProcessHistoryMap;
762  for (auto I = std::begin(art::ProcessHistoryRegistry::get()), E = std::end(art::ProcessHistoryRegistry::get());
763  I != E; ++I)
764  {
765  std::ostringstream OS;
766  I->first.print(OS);
767  TLOG(TLVL_WRITESUBRUN_VERBOSE) << "ArtdaqOutput::writeSubRun: phr: id: '" << OS.str() << "'";
768  OS.str("");
769  TLOG(TLVL_WRITESUBRUN_VERBOSE) << "ArtdaqOutput::writeSubRun: phr: data.size(): " << I->second.data().size();
770  if (!I->second.data().empty())
771  {
772  I->second.data().back().id().print(OS);
773  TLOG(TLVL_WRITESUBRUN_VERBOSE) << "ArtdaqOutput::writeSubRun: phr: data.back().id(): '" << OS.str() << "'";
774  }
775  }
776  if (!srp.subRunAux().processHistoryID().isValid())
777  {
778  TLOG(TLVL_WRITESUBRUN_VERBOSE) << "ArtdaqOutput::writeSubRun: ProcessHistoryID: 'INVALID'";
779  }
780  else
781  {
782  std::ostringstream OS;
783  srp.subRunAux().processHistoryID().print(OS);
784  TLOG(TLVL_WRITESUBRUN_VERBOSE) << "ArtdaqOutput::writeSubRun: ProcessHistoryID: '" << OS.str() << "'";
785  OS.str("");
786  ProcessHistory processHistory;
787  ProcessHistoryRegistry::get(srp.subRunAux().processHistoryID(), processHistory);
788  if (!processHistory.data().empty())
789  {
790  // FIXME: Print something special on invalid id() here!
791  processHistory.data().back().id().print(OS);
792  TLOG(TLVL_WRITESUBRUN_VERBOSE) << "ArtdaqOutput::writeSubRun: ProcessConfigurationID: '" << OS.str() << "'";
793  OS.str("");
794  OS << processHistory.data().back();
795  TLOG(TLVL_WRITESUBRUN_VERBOSE) << "ArtdaqOutput::writeSubRun: ProcessConfiguration: '" << OS.str();
796  }
797  }
798  msg->WriteObjectAny(&srp.subRunAux(), subrun_aux_class);
799  TLOG(TLVL_WRITESUBRUN) << "ArtdaqOutput::writeSubRun: streamed SubRunAuxiliary.";
800  }
801  //
802  // Write data products.
803  //
804  std::vector<BranchKey*> bkv;
805  writeDataProducts(msg, srp, bkv);
806 
807  TLOG(TLVL_WRITESUBRUN) << "ArtdaqOutput::writeSubRun: Sending message";
808  sendMessage(msg);
809  TLOG(TLVL_WRITESUBRUN) << "ArtdaqOutput::writeSubRun: Done sending message";
810 
811  //
812  // Delete the branch keys we created for the message.
813  //
814  for (auto I = bkv.begin(), E = bkv.end(); I != E; ++I)
815  {
816  delete *I;
817  *I = 0;
818  }
819  TLOG(TLVL_WRITESUBRUN) << "End: ArtdaqOutput::writeSubRun(const SubRunPrincipal& srp)";
820 }
821 
822 inline void art::ArtdaqOutput::extractProducts_(Principal const& principal [[gnu::unused]])
823 {
824  TLOG(TLVL_EXTRACTPRODUCTS) << "Begin: ArtdaqOutput::extractProducts_(Principal const& principal) sz=" << principal.size();
825 
826  for (auto I = principal.begin(), E = principal.end(); I != E; ++I)
827  {
828  auto const& productDescription = I->second->productDescription();
829  auto const& branchKey = BranchKey(productDescription);
830 
831  if (!productList_.count(branchKey))
832  {
833  TLOG(TLVL_EXTRACTPRODUCTS_VERBOSE) << "ArtdaqOutput::extractProducts_:"
834  << "Adding branch key to productList of class: '"
835  << branchKey.friendlyClassName_ << "' modlbl: '" << branchKey.moduleLabel_ << "' instnm: '"
836  << branchKey.productInstanceName_ << "' procnm: '" << branchKey.processName_ << "'"
837  << ", description: " << productDescription.wrappedName();
838 
839  productList_[branchKey] = productDescription;
840  }
841  }
842 
843  TLOG(TLVL_EXTRACTPRODUCTS) << "End: ArtdaqOutput::extractProducts_(Principal const& principal) Product list sz=" << productList_.size();
844 }
845 
846 #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