artdaq  v3_07_02
ArtdaqOutput.hh
1 
2 #include "art/Framework/Core/OutputModule.h"
3 #include "art/Framework/Principal/EventPrincipal.h"
4 #include "art/Framework/Principal/OutputHandle.h"
5 #include "art/Framework/Principal/RunPrincipal.h"
6 #include "art/Framework/Principal/SubRunPrincipal.h"
7 
8 #include "art/Framework/Core/ModuleMacros.h"
9 #include "art/Framework/Services/Registry/ServiceHandle.h"
10 #include "art/Persistency/Provenance/ProcessHistoryRegistry.h"
11 #if ART_HEX_VERSION < 0x30000
12 #include "art/Persistency/Provenance/ProductMetaData.h"
13 #endif
14 #if ART_HEX_VERSION >= 0x30200
15 #include "art_root_io/setup.h"
16 #endif
17 
18 #include <algorithm>
19 #include <iterator>
20 #include "canvas/Persistency/Provenance/BranchDescription.h"
21 #include "canvas/Persistency/Provenance/BranchKey.h"
22 #include "canvas/Persistency/Provenance/History.h"
23 #include "canvas/Persistency/Provenance/ParentageRegistry.h"
24 #include "canvas/Persistency/Provenance/ProcessConfiguration.h"
25 #include "canvas/Persistency/Provenance/ProcessConfigurationID.h"
26 #include "canvas/Persistency/Provenance/ProcessHistoryID.h"
27 #include "canvas/Persistency/Provenance/ProductList.h"
28 #include "canvas/Persistency/Provenance/ProductProvenance.h"
29 #include "canvas/Persistency/Provenance/RunAuxiliary.h"
30 #include "canvas/Persistency/Provenance/SubRunAuxiliary.h"
31 #include "canvas/Utilities/DebugMacros.h"
32 #include "canvas/Utilities/Exception.h"
33 #include "cetlib/column_width.h"
34 #include "cetlib/lpad.h"
35 #include "cetlib/rpad.h"
36 #include "fhiclcpp/ParameterSet.h"
37 #include "fhiclcpp/ParameterSetID.h"
38 #include "fhiclcpp/ParameterSetRegistry.h"
39 
40 #include "artdaq/DAQdata/Globals.hh"
41 #include "artdaq/DAQdata/NetMonHeader.hh"
42 
43 #include "artdaq-core/Data/Fragment.hh"
44 #include "artdaq-core/Data/detail/ParentageMap.hh"
45 
46 #include <iomanip>
47 #include <iostream>
48 #include <sstream>
49 #include <string>
50 #include <vector>
51 
52 #include <unistd.h>
53 
54 #include <TBufferFile.h>
55 #include <TClass.h>
56 #include <TList.h>
57 #include <TStreamerInfo.h>
58 
59 #define TLVL_OPENFILE 5
60 #define TLVL_CLOSEFILE 6
61 #define TLVL_RESPONDTOCLOSEINPUTFILE 7
62 #define TLVL_RESPONDTOCLOSEOUTPUTFILE 8
63 #define TLVL_ENDJOB 9
64 #define TLVL_SENDINIT 10
65 #define TLVL_SENDINIT_VERBOSE1 32
66 #define TLVL_SENDINIT_VERBOSE2 33
67 #define TLVL_WRITEDATAPRODUCTS 11
68 #define TLVL_WRITEDATAPRODUCTS_VERBOSE 34
69 #define TLVL_WRITE 12
70 #define TLVL_WRITERUN 13
71 #define TLVL_WRITERUN_VERBOSE 37
72 #define TLVL_WRITESUBRUN 14
73 #define TLVL_WRITESUBRUN_VERBOSE 35
74 #define TLVL_EXTRACTPRODUCTS 15
75 #define TLVL_EXTRACTPRODUCTS_VERBOSE 36
76 
77 #if ART_HEX_VERSION < 0x30000
78 #define RUN_AUX aux
79 #define SUBRUN_AUX aux
80 #define EVENT_AUX aux
81 #define RUN_ID id
82 #define SUBRUN_ID id
83 #define EVENT_ID id
84 #else
85 #define RUN_AUX runAux
86 #define SUBRUN_AUX subRunAux
87 #define EVENT_AUX eventAux
88 #define RUN_ID runID
89 #define SUBRUN_ID subRunID
90 #define EVENT_ID eventID
91 #endif
92 
93 namespace art {
94 class ArtdaqOutput;
95 }
96 
97 static artdaq::FragmentPtr outputFrag = nullptr;
98 char* Fragment_ReAllocChar(char* dataPtr, size_t size, size_t /*oldsize*/)
99 {
100  if (outputFrag != nullptr && dataPtr == reinterpret_cast<char*>(outputFrag->dataBegin()))
101  {
102  outputFrag->resizeBytes(size);
103 
104  return reinterpret_cast<char*>(outputFrag->dataBegin());
105  }
106  return nullptr;
107 }
108 
112 class art::ArtdaqOutput : public art::OutputModule
113 {
114 public:
119  explicit ArtdaqOutput(fhicl::ParameterSet const& ps)
120  : OutputModule(ps), initMsgSent_(false), productList_(), last_fragment_size_(10)
121  {
122 #if ART_HEX_VERSION >= 0x30200
123  root::setup();
124 #endif
125  }
126 
130  virtual ~ArtdaqOutput() = default;
131 
132 protected:
136  virtual void openFile(FileBlock const&)
137  {
138  TLOG(TLVL_OPENFILE) << "Begin/End: ArtdaqOutput::openFile(const FileBlock&)";
139  }
140 
144  virtual void closeFile() { TLOG(TLVL_CLOSEFILE) << "Begin/End: ArtdaqOutput::closeFile()"; }
145 
149  virtual void respondToCloseInputFile(FileBlock const&)
150  {
151  TLOG(TLVL_RESPONDTOCLOSEINPUTFILE) << "Begin/End: ArtdaqOutput::"
152  "respondToCloseOutputFiles(FileBlock const&)";
153  }
154 
158  virtual void respondToCloseOutputFiles(FileBlock const&)
159  {
160  TLOG(TLVL_RESPONDTOCLOSEOUTPUTFILE) << "Begin/End: ArtdaqOutput::"
161  "respondToCloseOutputFiles(FileBlock const&)";
162  }
163 
167  virtual void endJob()
168  {
169  TLOG(TLVL_ENDJOB) << "Begin/End: ArtdaqOutput::endJob()";
170  }
171 
176  virtual void beginRun(RunPrincipal const& rp) final
177  {
178  extractProducts_(rp);
179  beginRun_(rp);
180  }
184  virtual void beginRun_(RunPrincipal const&) {}
185 
190  virtual void beginSubRun(SubRunPrincipal const& srp) final
191  {
192  extractProducts_(srp);
193  beginSubRun_(srp);
194  }
198  virtual void beginSubRun_(SubRunPrincipal const&) {}
199 
204  virtual void event(EventPrincipal const& ep) final
205  {
206  extractProducts_(ep);
207  event_(ep);
208  }
212  virtual void event_(EventPrincipal const&) {}
213 
218  virtual void write(EventPrincipal& ep) final;
219 
224  virtual void writeRun(RunPrincipal& rp) final;
225 
230  virtual void writeSubRun(SubRunPrincipal& srp) final;
231 
238  void writeDataProducts(std::unique_ptr<TBufferFile>& msg, const Principal& principal, std::vector<BranchKey*>& bkv);
239 
244  void extractProducts_(Principal const& principal);
245 
250  void send_init_message(History const& history);
251 
256  virtual void SendMessage(artdaq::FragmentPtr& msg) = 0;
257 
258 private:
259  bool initMsgSent_;
260  ProductList productList_;
261  size_t last_fragment_size_;
262 
263  std::unique_ptr<TBufferFile> prepareMessage(artdaq::Fragment::sequence_id_t seqID, artdaq::Fragment::type_t type)
264  {
266  outputFrag.reset(new artdaq::Fragment(last_fragment_size_, seqID, 0, type, hdr));
267  std::unique_ptr<TBufferFile> msg(new TBufferFile(TBuffer::kWrite, last_fragment_size_ * sizeof(artdaq::RawDataType), outputFrag->dataBegin(), kFALSE, &Fragment_ReAllocChar));
268  msg->SetWriteMode();
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 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(): "
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(): "
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(): "
319  "Could not get class for ParentageMap.";
320  }
321  TLOG(TLVL_SENDINIT) << "parentage_map_class: " << (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(): "
327  "Could not get TClass for art::History!";
328  }
329 
330  //
331  // Construct and send the init message.
332  //
333  auto msg = prepareMessage(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 << "!";
354  }
355  infos.Add(class_ptr->GetStreamerInfo());
356  }
357  msg->WriteObject(&infos);
358 
359  //
360  // Stream the ParameterSetRegistry.
361  //
362  unsigned long 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 ..." << (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 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(...): "
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(...): "
454  "Could not get TClass for art::ProductProvenance!";
455  }
456 
457  //
458  // Calculate the data product count.
459  //
460  unsigned long 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 ART_HEX_VERSION < 0x30000
470  if (*ref == productDescription)
471  {
472 #else
473  if (ref.second == productDescription)
474  {
475 #endif
476  found = true;
477  break;
478  }
479  }
480 #if ART_HEX_VERSION < 0x30000
481  if (I->second->productUnavailable() || !found)
482 #else
483  if (!I->second->productAvailable() || !found)
484 #endif
485  {
486  continue;
487  }
488  ++prd_cnt;
489  }
490  //
491  // Write the data product count.
492  //
493  TLOG(TLVL_WRITEDATAPRODUCTS) << "ArtdaqOutput::writeDataProducts(...): Streaming product count: " +
494  std::to_string(prd_cnt);
495  msg->WriteULong(prd_cnt);
496  TLOG(TLVL_WRITEDATAPRODUCTS) << "ArtdaqOutput::writeDataProducts(...): Finished streaming product count.";
497 
498  //
499  // Loop over the groups in the RunPrincipal and
500  // write out the data products.
501  //
502  // Note: We need this vector of keys because the ROOT I/O mechanism
503  // requires that each object inserted in the message has a
504  // unique address, so we force that by holding on to each
505  // branch key manufactured in the loop until after we are
506  // done constructing the message.
507  //
508  bkv.reserve(prd_cnt);
509  // std::map<art::BranchID, std::shared_ptr<art::Group>>::const_iterator
510  for (auto I = principal.begin(), E = principal.end(); I != E; ++I)
511  {
512  auto const& productDescription = I->second->productDescription();
513  auto const& refs = keptProducts()[productDescription.branchType()];
514  bool found = false;
515  for (auto const& ref : refs)
516  {
517 #if ART_HEX_VERSION < 0x30000
518  if (*ref == productDescription)
519  {
520 #else
521  if (ref.second == productDescription)
522  {
523 #endif
524  found = true;
525  break;
526  }
527  }
528 #if ART_HEX_VERSION < 0x30000
529  if (I->second->productUnavailable() || !found)
530 #else
531  if (!I->second->productAvailable() || !found)
532 #endif
533  {
534  continue;
535  }
536  const BranchDescription& bd(I->second->productDescription());
537  bkv.push_back(new BranchKey(bd));
538  TLOG(TLVL_WRITEDATAPRODUCTS_VERBOSE)
539  << "ArtdaqOutput::writeDataProducts(...): Dumping branch key of class: '"
540  << bkv.back()->friendlyClassName_ << "' modlbl: '" << bkv.back()->moduleLabel_ << "' instnm: '"
541  << bkv.back()->productInstanceName_ << "' procnm: '" << bkv.back()->processName_ << "'";
542  TLOG(TLVL_WRITEDATAPRODUCTS) << "ArtdaqOutput::writeDataProducts(...): "
543  "Streaming branch key of class: '"
544  << bd.producedClassName() << "' modlbl: '" << bd.moduleLabel() << "' instnm: '"
545  << bd.productInstanceName() << "' procnm: '" << bd.processName() << "'";
546  msg->WriteObjectAny(bkv.back(), branch_key_class);
547 
548  TLOG(TLVL_WRITEDATAPRODUCTS) << "ArtdaqOutput::writeDataProducts(...): "
549  "Streaming product of class: '"
550  << bd.producedClassName() << "' modlbl: '" << bd.moduleLabel() << "' instnm: '"
551  << bd.productInstanceName() << "' procnm: '" << bd.processName() << "'";
552 
553  OutputHandle oh = principal.getForOutput(bd.productID(), true);
554  const EDProduct* prd = oh.wrapper();
555  TLOG(TLVL_WRITEDATAPRODUCTS) << "Class for branch " << bd.wrappedName() << " is "
556  << (void*)TClass::GetClass(bd.wrappedName().c_str());
557  msg->WriteObjectAny(prd, TClass::GetClass(bd.wrappedName().c_str()));
558  TLOG(TLVL_WRITEDATAPRODUCTS) << "ArtdaqOutput::writeDataProducts(...): "
559  "Streaming product provenance of class: '"
560  << bd.producedClassName() << "' modlbl: '" << bd.moduleLabel() << "' instnm: '"
561  << bd.productInstanceName() << "' procnm: '" << bd.processName() << "'";
562 #if ART_HEX_VERSION < 0x30000
563  const ProductProvenance* prdprov = I->second->productProvenancePtr().get();
564 #else
565  const ProductProvenance* prdprov = I->second->productProvenance().get();
566 #endif
567  msg->WriteObjectAny(prdprov, prdprov_class);
568  }
569  TLOG(TLVL_WRITEDATAPRODUCTS) << "End: ArtdaqOutput::writeDataProducts(...)";
570 }
571 
572 void art::ArtdaqOutput::write(EventPrincipal& ep)
573 {
574  //
575  // Write an Event message.
576  //
577  TLOG(TLVL_WRITE) << "Begin: ArtdaqOutput::write(const EventPrincipal& ep)";
578  if (!initMsgSent_)
579  {
580  send_init_message(ep.history());
581  initMsgSent_ = true;
582  }
583  //
584  // Get root classes needed for I/O.
585  //
586  static TClass* run_aux_class = TClass::GetClass("art::RunAuxiliary");
587  if (run_aux_class == nullptr)
588  {
589  throw art::Exception(art::errors::DictionaryNotFound) << "ArtdaqOutput::write(const EventPrincipal& ep): "
590  "Could not get TClass for art::RunAuxiliary!";
591  }
592  static TClass* subrun_aux_class = TClass::GetClass("art::SubRunAuxiliary");
593  if (subrun_aux_class == nullptr)
594  {
595  throw art::Exception(art::errors::DictionaryNotFound) << "ArtdaqOutput::write(const EventPrincipal& ep): "
596  "Could not get TClass for art::SubRunAuxiliary!";
597  }
598  static TClass* event_aux_class = TClass::GetClass("art::EventAuxiliary");
599  if (event_aux_class == nullptr)
600  {
601  throw art::Exception(art::errors::DictionaryNotFound) << "ArtdaqOutput::write(const EventPrincipal& ep): "
602  "Could not get TClass for art::EventAuxiliary!";
603  }
604  static TClass* history_class = TClass::GetClass("art::History");
605  if (history_class == nullptr)
606  {
607  throw art::Exception(art::errors::DictionaryNotFound) << "ArtdaqOutput::write(const EventPrincipal& ep): "
608  "Could not get TClass for art::History!";
609  }
610  //
611  // Setup message buffer.
612  //
613  auto msg = prepareMessage(ep.EVENT_ID().event(), 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().RUN_AUX(), 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().SUBRUN_AUX(), 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.EVENT_AUX(), 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 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 #if ART_HEX_VERSION < 0x30000
681  send_init_message(art::History());
682 #else
683  send_init_message(rp.history());
684 #endif
685  initMsgSent_ = true;
686  }
687 #if 0
688  //
689  // Fetch the class dictionaries we need for
690  // writing out the auxiliary information.
691  //
692  static TClass* run_aux_class = TClass::GetClass("art::RunAuxiliary");
693  assert(run_aux_class != nullptr && "writeRun: Could not get TClass for art::RunAuxiliary!");
694  //
695  // Begin preparing message.
696  //
697  auto msg = prepareMessage(0, artdaq::Fragment::EndOfRunFragmentType);
698  //
699  // Write message type code.
700  //
701  {
702  TLOG(TLVL_WRITERUN) << "ArtdaqOutput::writeRun: streaming message type code ...";
703  msg->WriteULong(2);
704  TLOG(TLVL_WRITERUN) << "ArtdaqOutput::writeRun: finished streaming message type code.";
705  }
706  //
707  // Write RunAuxiliary.
708  //
709  {
710  TLOG(TLVL_WRITERUN) << "ArtdaqOutput::writeRun: streaming RunAuxiliary ...";
711  msg->WriteObjectAny(&rp.RUN_AUX(), run_aux_class);
712  TLOG(TLVL_WRITERUN) << "ArtdaqOutput::writeRun: streamed RunAuxiliary.";
713  }
714  //
715  // Write data products.
716  //
717  std::vector<BranchKey*> bkv;
718  writeDataProducts(msg, rp, bkv);
719 
720  TLOG(TLVL_WRITERUN) << "ArtdaqOutput::writeRun: Sending message";
721  sendMessage(msg);
722  TLOG(TLVL_WRITERUN) << "ArtdaqOutput::writeRun: Done sending message";
723 
724  for (auto I = bkv.begin(), E = bkv.end(); I != E; ++I)
725  {
726  delete *I;
727  *I = 0;
728  }
729 #endif
730  TLOG(TLVL_WRITERUN) << "End: ArtdaqOutput::writeRun(RunPrincipal& rp)";
731 }
732 void art::ArtdaqOutput::writeSubRun(SubRunPrincipal& srp)
733 { //
734  // Write an EndSubRun message.
735  //
736  TLOG(TLVL_WRITESUBRUN) << "Begin: ArtdaqOutput::writeSubRun(const SubRunPrincipal& srp)";
737  if (!initMsgSent_)
738  {
739 #if ART_HEX_VERSION < 0x30000
740  send_init_message(art::History());
741 #else
742  send_init_message(srp.history());
743 #endif
744  initMsgSent_ = true;
745  }
746  //
747  // Fetch the class dictionaries we need for
748  // writing out the auxiliary information.
749  //
750  static TClass* subrun_aux_class = TClass::GetClass("art::SubRunAuxiliary");
751  if (subrun_aux_class == nullptr)
752  {
753  throw art::Exception(art::errors::DictionaryNotFound) << "ArtdaqOutput::writeSubRun: "
754  "Could not get TClass for art::SubRunAuxiliary!";
755  }
756  //
757  // Begin preparing message.
758  //
759  auto msg = prepareMessage(0, artdaq::Fragment::EndOfSubrunFragmentType);
760  //
761  // Write message type code.
762  //
763  {
764  TLOG(TLVL_WRITESUBRUN) << "ArtdaqOutput::writeSubRun: streaming message type code ...";
765  msg->WriteULong(3);
766  TLOG(TLVL_WRITESUBRUN) << "ArtdaqOutput::writeSubRun: finished streaming message type code.";
767  }
768  //
769  // Write SubRunAuxiliary.
770  //
771  {
772  TLOG(TLVL_WRITESUBRUN) << "ArtdaqOutput::writeSubRun: streaming SubRunAuxiliary ...";
773 
774  TLOG(TLVL_WRITESUBRUN_VERBOSE) << "ArtdaqOutput::writeSubRun: dumping ProcessHistoryRegistry ...";
775  // typedef std::map<const ProcessHistoryID,ProcessHistory>
776  // ProcessHistoryMap;
777  for (auto I = std::begin(art::ProcessHistoryRegistry::get()), E = std::end(art::ProcessHistoryRegistry::get());
778  I != E; ++I)
779  {
780  std::ostringstream OS;
781  I->first.print(OS);
782  TLOG(TLVL_WRITESUBRUN_VERBOSE) << "ArtdaqOutput::writeSubRun: phr: id: '" << OS.str() << "'";
783  OS.str("");
784  TLOG(TLVL_WRITESUBRUN_VERBOSE) << "ArtdaqOutput::writeSubRun: phr: data.size(): " << I->second.data().size();
785  if (I->second.data().size())
786  {
787  I->second.data().back().id().print(OS);
788  TLOG(TLVL_WRITESUBRUN_VERBOSE) << "ArtdaqOutput::writeSubRun: phr: data.back().id(): '" << OS.str() << "'";
789  }
790  }
791  if (!srp.SUBRUN_AUX().processHistoryID().isValid())
792  {
793  TLOG(TLVL_WRITESUBRUN_VERBOSE) << "ArtdaqOutput::writeSubRun: ProcessHistoryID: 'INVALID'";
794  }
795  else
796  {
797  std::ostringstream OS;
798  srp.SUBRUN_AUX().processHistoryID().print(OS);
799  TLOG(TLVL_WRITESUBRUN_VERBOSE) << "ArtdaqOutput::writeSubRun: ProcessHistoryID: '" << OS.str() << "'";
800  OS.str("");
801  ProcessHistory processHistory;
802  ProcessHistoryRegistry::get(srp.SUBRUN_AUX().processHistoryID(), processHistory);
803  if (processHistory.data().size())
804  {
805  // FIXME: Print something special on invalid id() here!
806  processHistory.data().back().id().print(OS);
807  TLOG(TLVL_WRITESUBRUN_VERBOSE) << "ArtdaqOutput::writeSubRun: ProcessConfigurationID: '" << OS.str() << "'";
808  OS.str("");
809  OS << processHistory.data().back();
810  TLOG(TLVL_WRITESUBRUN_VERBOSE) << "ArtdaqOutput::writeSubRun: ProcessConfiguration: '" << OS.str();
811  }
812  }
813  msg->WriteObjectAny(&srp.SUBRUN_AUX(), subrun_aux_class);
814  TLOG(TLVL_WRITESUBRUN) << "ArtdaqOutput::writeSubRun: streamed SubRunAuxiliary.";
815  }
816  //
817  // Write data products.
818  //
819  std::vector<BranchKey*> bkv;
820  writeDataProducts(msg, srp, bkv);
821 
822  TLOG(TLVL_WRITESUBRUN) << "ArtdaqOutput::writeSubRun: Sending message";
823  sendMessage(msg);
824  TLOG(TLVL_WRITESUBRUN) << "ArtdaqOutput::writeSubRun: Done sending message";
825 
826  //
827  // Delete the branch keys we created for the message.
828  //
829  for (auto I = bkv.begin(), E = bkv.end(); I != E; ++I)
830  {
831  delete *I;
832  *I = 0;
833  }
834  TLOG(TLVL_WRITESUBRUN) << "End: ArtdaqOutput::writeSubRun(const SubRunPrincipal& srp)";
835 }
836 
837 void art::ArtdaqOutput::extractProducts_(Principal const& principal [[gnu::unused]])
838 {
839  TLOG(TLVL_EXTRACTPRODUCTS) << "Begin: ArtdaqOutput::extractProducts_(Principal const& principal) sz=" << principal.size();
840 #if ART_HEX_VERSION < 0x30000
841  productList_ = art::ProductMetaData::instance().productList();
842 
843 #else
844  for (auto I = principal.begin(), E = principal.end(); I != E; ++I)
845  {
846  auto const& productDescription = I->second->productDescription();
847  auto const& branchKey = BranchKey(productDescription);
848 
849  if (!productList_.count(branchKey))
850  {
851  TLOG(TLVL_EXTRACTPRODUCTS_VERBOSE) << "ArtdaqOutput::extractProducts_:"
852  << "Adding branch key to productList of class: '"
853  << branchKey.friendlyClassName_ << "' modlbl: '" << branchKey.moduleLabel_ << "' instnm: '"
854  << branchKey.productInstanceName_ << "' procnm: '" << branchKey.processName_ << "'"
855  << ", description: " << productDescription.wrappedName();
856 
857  productList_[branchKey] = productDescription;
858  }
859  }
860 #endif
861 
862  TLOG(TLVL_EXTRACTPRODUCTS) << "End: ArtdaqOutput::extractProducts_(Principal const& principal) Product list sz=" << productList_.size();
863 }
virtual void writeRun(RunPrincipal &rp) final
Write a RunPrincipal to TBufferFile and send
virtual void event(EventPrincipal const &ep) final
Perform actions for each event. Derived classes should implement event_ instead.
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
virtual void beginSubRun(SubRunPrincipal const &srp) final
Perform Begin SubRun actions. Derived classes should implement beginSubRun_ instead.
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
virtual void beginRun(RunPrincipal const &rp) final
Perform Begin Run actions. Derived classes should implement beginRun_ 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...
Header with length information for NetMonTransport messages.
Definition: NetMonHeader.hh:13
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 ...
virtual 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
virtual 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