artdaq  v3_07_01
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 
42 #include "artdaq-core/Data/Fragment.hh"
43 #include "artdaq-core/Data/detail/ParentageMap.hh"
44 
45 #include <iomanip>
46 #include <iostream>
47 #include <sstream>
48 #include <string>
49 #include <vector>
50 
51 #include <unistd.h>
52 
53 #include <TBufferFile.h>
54 #include <TClass.h>
55 #include <TList.h>
56 #include <TStreamerInfo.h>
57 
58 #define TLVL_OPENFILE 5
59 #define TLVL_CLOSEFILE 6
60 #define TLVL_RESPONDTOCLOSEINPUTFILE 7
61 #define TLVL_RESPONDTOCLOSEOUTPUTFILE 8
62 #define TLVL_ENDJOB 9
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 #if ART_HEX_VERSION < 0x30000
77 #define RUN_AUX aux
78 #define SUBRUN_AUX aux
79 #define EVENT_AUX aux
80 #define RUN_ID id
81 #define SUBRUN_ID id
82 #define EVENT_ID id
83 #else
84 #define RUN_AUX runAux
85 #define SUBRUN_AUX subRunAux
86 #define EVENT_AUX eventAux
87 #define RUN_ID runID
88 #define SUBRUN_ID subRunID
89 #define EVENT_ID eventID
90 #endif
91 
92 namespace art {
93 class ArtdaqOutput;
94 }
95 
99 class art::ArtdaqOutput : public art::OutputModule
100 {
101 public:
106  explicit ArtdaqOutput(fhicl::ParameterSet const& ps)
107  : OutputModule(ps), initMsgSent_(false), productList_()
108  {
109 #if ART_HEX_VERSION >= 0x30200
110  root::setup();
111 #endif
112  }
113 
117  virtual ~ArtdaqOutput() = default;
118 
119 protected:
123  virtual void openFile(FileBlock const&)
124  {
125  TLOG(TLVL_OPENFILE) << "Begin/End: ArtdaqOutput::openFile(const FileBlock&)";
126  }
127 
131  virtual void closeFile() { TLOG(TLVL_CLOSEFILE) << "Begin/End: ArtdaqOutput::closeFile()"; }
132 
136  virtual void respondToCloseInputFile(FileBlock const&)
137  {
138  TLOG(TLVL_RESPONDTOCLOSEINPUTFILE) << "Begin/End: ArtdaqOutput::"
139  "respondToCloseOutputFiles(FileBlock const&)";
140  }
141 
145  virtual void respondToCloseOutputFiles(FileBlock const&)
146  {
147  TLOG(TLVL_RESPONDTOCLOSEOUTPUTFILE) << "Begin/End: ArtdaqOutput::"
148  "respondToCloseOutputFiles(FileBlock const&)";
149  }
150 
154  virtual void endJob()
155  {
156  TLOG(TLVL_ENDJOB) << "Begin/End: ArtdaqOutput::endJob()";
157  }
158 
163  virtual void beginRun(RunPrincipal const& rp) final
164  {
165  extractProducts_(rp);
166  beginRun_(rp);
167  }
171  virtual void beginRun_(RunPrincipal const&) {}
172 
177  virtual void beginSubRun(SubRunPrincipal const& srp) final
178  {
179  extractProducts_(srp);
180  beginSubRun_(srp);
181  }
185  virtual void beginSubRun_(SubRunPrincipal const&) {}
186 
191  virtual void event(EventPrincipal const& ep) final
192  {
193  extractProducts_(ep);
194  event_(ep);
195  }
199  virtual void event_(EventPrincipal const&) {}
200 
205  virtual void write(EventPrincipal& ep) final;
206 
211  virtual void writeRun(RunPrincipal& rp) final;
212 
217  virtual void writeSubRun(SubRunPrincipal& srp) final;
218 
225  void writeDataProducts(TBufferFile& msg, const Principal& principal, std::vector<BranchKey*>& bkv);
226 
231  void extractProducts_(Principal const& principal);
232 
237  void send_init_message(History const& history);
238 
245  virtual void SendMessage(artdaq::Fragment::sequence_id_t sequenceId, artdaq::Fragment::type_t messageType, TBufferFile& msg) = 0;
246 
247 private:
248  bool initMsgSent_;
249  ProductList productList_;
250 };
251 
252 void art::ArtdaqOutput::send_init_message(History const& history)
253 {
254  TLOG(TLVL_SENDINIT) << "Begin: ArtdaqOutput::send_init_message()";
255  //
256  // Get the classes we will need.
257  //
258  // static TClass* string_class = TClass::GetClass("std::string");
259  // if (string_class == nullptr) {
260  // throw art::Exception(art::errors::DictionaryNotFound) <<
261  // "ArtdaqOutput static send_init_message(): "
262  // "Could not get TClass for std::string!";
263  //}
264  static TClass* product_list_class = TClass::GetClass("std::map<art::BranchKey,art::BranchDescription>");
265  if (product_list_class == nullptr)
266  {
267  throw art::Exception(art::errors::DictionaryNotFound) << "ArtdaqOutput::send_init_message(): "
268  "Could not get TClass for "
269  "map<art::BranchKey,art::BranchDescription>!";
270  }
271  // typedef std::map<const ProcessHistoryID,ProcessHistory> ProcessHistoryMap;
272  // TClass* process_history_map_class = TClass::GetClass(
273  // "std::map<const art::ProcessHistoryID,art::ProcessHistory>");
274  // FIXME: Replace the "2" here with a use of the proper enum value!
275  static TClass* process_history_map_class = TClass::GetClass("std::map<const art::Hash<2>,art::ProcessHistory>");
276  if (process_history_map_class == nullptr)
277  {
278  throw art::Exception(art::errors::DictionaryNotFound) << "ArtdaqOutput::send_init_message(): "
279  "Could not get class for "
280  "std::map<const art::Hash<2>,art::ProcessHistory>!";
281  }
282  // static TClass* parentage_map_class = TClass::GetClass(
283  // "std::map<const art::ParentageID,art::Parentage>");
284  static TClass* parentage_map_class = TClass::GetClass("art::ParentageMap");
285  if (parentage_map_class == nullptr)
286  {
287  throw art::Exception(art::errors::DictionaryNotFound) << "ArtdaqOutput::send_init_message(): "
288  "Could not get class for ParentageMap.";
289  }
290  TLOG(TLVL_SENDINIT) << "parentage_map_class: " << (void*)parentage_map_class;
291 
292  static TClass* history_class = TClass::GetClass("art::History");
293  if (history_class == nullptr)
294  {
295  throw art::Exception(art::errors::DictionaryNotFound) << "ArtdaqOutput::send_init_message(): "
296  "Could not get TClass for art::History!";
297  }
298 
299  //
300  // Construct and send the init message.
301  //
302  TBufferFile msg(TBuffer::kWrite);
303  msg.SetWriteMode();
304  //
305  // Stream the message type code.
306  //
307  TLOG(TLVL_SENDINIT) << "ArtdaqOutput::send_init_message(): Streaming message type code ...";
308  msg.WriteULong(1);
309  TLOG(TLVL_SENDINIT) << "ArtdaqOutput::send_init_message(): Finished streaming message type code.";
310 
311  //
312  // Stream Class info
313  //
314  // 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.
315  TList infos;
316  std::vector<std::string> classNames{"std::map<art::BranchKey,art::BranchDescription>", "std::map<const art::Hash<2>,art::ProcessHistory>", "art::ParentageMap",
317  "art::History", "art::BranchKey", "art::ProductProvenance", "art::RunAuxiliary", "art::SubRunAuxiliary", "art::EventAuxiliary"};
318  for (auto& className : classNames)
319  {
320  TClass* class_ptr = TClass::GetClass(className.c_str());
321  if (class_ptr == nullptr)
322  {
323  throw art::Exception(art::errors::DictionaryNotFound) << "ArtdaqOutput::send_init_message: Could not get TClass for " << className << "!";
324  }
325  infos.Add(class_ptr->GetStreamerInfo());
326  }
327  msg.WriteObject(&infos);
328 
329  //
330  // Stream the ParameterSetRegistry.
331  //
332  unsigned long ps_cnt = fhicl::ParameterSetRegistry::size();
333  TLOG(TLVL_SENDINIT) << "ArtdaqOutput::send_init_message(): parameter set count: " << ps_cnt;
334  msg.WriteULong(ps_cnt);
335  TLOG(TLVL_SENDINIT) << "ArtdaqOutput::send_init_message(): Streaming parameter sets ...";
336  for (auto I = std::begin(fhicl::ParameterSetRegistry::get()), E = std::end(fhicl::ParameterSetRegistry::get());
337  I != E; ++I)
338  {
339  TLOG(TLVL_SENDINIT) << "Pset ID " << I->first << ": " << I->second.to_string();
340  std::string pset_str = I->second.to_string();
341  // msg.WriteObjectAny(&pset_str, string_class);
342  msg.WriteStdString(pset_str);
343  }
344  TLOG(TLVL_SENDINIT) << "ArtdaqOutput::send_init_message(): Finished streaming parameter sets.";
345 
346  //
347  // Stream the MasterProductRegistry.
348  //
349  TLOG(TLVL_SENDINIT) << "ArtdaqOutput::send_init_message(): Streaming Product List sz=" << productList_.size() << "...";
350  msg.WriteObjectAny(&productList_, product_list_class);
351  TLOG(TLVL_SENDINIT) << "ArtdaqOutput::send_init_message(): Finished streaming Product List.";
352 
353  art::ProcessHistoryMap phr;
354  for (auto const& pr : art::ProcessHistoryRegistry::get())
355  {
356  phr.emplace(pr);
357  }
358  //
359  // Dump the ProcessHistoryRegistry.
360  //
361  TLOG(TLVL_SENDINIT_VERBOSE2) << "ArtdaqOutput::send_init_message(): Dumping ProcessHistoryRegistry ...";
362  // typedef std::map<const ProcessHistoryID,ProcessHistory>
363  // ProcessHistoryMap;
364  TLOG(TLVL_SENDINIT_VERBOSE2) << "ArtdaqOutput::send_init_message(): phr: size: " << phr.size();
365  for (auto I = phr.begin(), E = phr.end(); I != E; ++I)
366  {
367  std::ostringstream OS;
368  I->first.print(OS);
369  TLOG(TLVL_SENDINIT_VERBOSE2) << "ArtdaqOutput::send_init_message(): phr: id: '" << OS.str() << "'";
370  }
371  //
372  // Stream the ProcessHistoryRegistry.
373  //
374  TLOG(TLVL_SENDINIT) << "ArtdaqOutput::send_init_message(): Streaming ProcessHistoryRegistry ...";
375  // typedef std::map<const ProcessHistoryID,ProcessHistory>
376  // ProcessHistoryMap;
377  const art::ProcessHistoryMap& phm = phr;
378  TLOG(TLVL_SENDINIT) << "ArtdaqOutput::send_init_message(): phm: size: " << phm.size();
379  msg.WriteObjectAny(&phm, process_history_map_class);
380  TLOG(TLVL_SENDINIT) << "ArtdaqOutput::send_init_message(): Finished streaming ProcessHistoryRegistry.";
381 
382  //
383  // Stream the ParentageRegistry.
384  //
385  TLOG(TLVL_SENDINIT) << "ArtdaqOutput::send_init_message(): Streaming ParentageRegistry ..." << (void*)parentage_map_class;
386  art::ParentageMap parentageMap{};
387  for (auto const& pr : art::ParentageRegistry::get())
388  {
389  parentageMap.emplace(pr.first, pr.second);
390  }
391 
392  msg.WriteObjectAny(&parentageMap, parentage_map_class);
393 
394  TLOG(TLVL_SENDINIT) << "ArtdaqOutput::send_init_message(): Finished streaming ParentageRegistry.";
395 
396  TLOG(TLVL_SENDINIT) << "ArtdaqOutput::send_init_message(): Streaming History";
397  msg.WriteObjectAny(&history, history_class);
398  TLOG(TLVL_SENDINIT) << "ArtdaqOutput::send_init_message(): Done streaming History";
399 
400  TLOG(TLVL_SENDINIT) << "ArtdaqOutput::send_init_message(): Sending init message";
401  SendMessage(0, artdaq::Fragment::InitFragmentType, msg);
402  TLOG(TLVL_SENDINIT) << "ArtdaqOutput::send_init_message(): Done sending init message";
403 
404  TLOG(TLVL_SENDINIT) << "ArtdaqOutput::send_init_message(): END";
405 }
406 
407 void art::ArtdaqOutput::writeDataProducts(TBufferFile& msg, const Principal& principal, std::vector<BranchKey*>& bkv)
408 {
409  TLOG(TLVL_WRITEDATAPRODUCTS) << "Begin: ArtdaqOutput::writeDataProducts(...)";
410  //
411  // Fetch the class dictionaries we need for
412  // writing out the data products.
413  //
414  static TClass* branch_key_class = TClass::GetClass("art::BranchKey");
415  if (branch_key_class == nullptr)
416  {
417  throw art::Exception(art::errors::DictionaryNotFound) << "ArtdaqOutput::writeDataProducts(...): "
418  "Could not get TClass for art::BranchKey!";
419  }
420  static TClass* prdprov_class = TClass::GetClass("art::ProductProvenance");
421  if (prdprov_class == nullptr)
422  {
423  throw art::Exception(art::errors::DictionaryNotFound) << "ArtdaqOutput::writeDataProducts(...): "
424  "Could not get TClass for art::ProductProvenance!";
425  }
426 
427  //
428  // Calculate the data product count.
429  //
430  unsigned long prd_cnt = 0;
431  // std::map<art::BranchID, std::shared_ptr<art::Group>>::const_iterator
432  for (auto I = principal.begin(), E = principal.end(); I != E; ++I)
433  {
434  auto const& productDescription = I->second->productDescription();
435  auto const& refs = keptProducts()[productDescription.branchType()];
436  bool found = false;
437  for (auto const& ref : refs)
438  {
439 #if ART_HEX_VERSION < 0x30000
440  if (*ref == productDescription)
441  {
442 #else
443  if (ref.second == productDescription)
444  {
445 #endif
446  found = true;
447  break;
448  }
449  }
450 #if ART_HEX_VERSION < 0x30000
451  if (I->second->productUnavailable() || !found)
452 #else
453  if (!I->second->productAvailable() || !found)
454 #endif
455  {
456  continue;
457  }
458  ++prd_cnt;
459  }
460  //
461  // Write the data product count.
462  //
463  TLOG(TLVL_WRITEDATAPRODUCTS) << "ArtdaqOutput::writeDataProducts(...): Streaming product count: " +
464  std::to_string(prd_cnt);
465  msg.WriteULong(prd_cnt);
466  TLOG(TLVL_WRITEDATAPRODUCTS) << "ArtdaqOutput::writeDataProducts(...): Finished streaming product count.";
467 
468  //
469  // Loop over the groups in the RunPrincipal and
470  // write out the data products.
471  //
472  // Note: We need this vector of keys because the ROOT I/O mechanism
473  // requires that each object inserted in the message has a
474  // unique address, so we force that by holding on to each
475  // branch key manufactured in the loop until after we are
476  // done constructing the message.
477  //
478  bkv.reserve(prd_cnt);
479  // std::map<art::BranchID, std::shared_ptr<art::Group>>::const_iterator
480  for (auto I = principal.begin(), E = principal.end(); I != E; ++I)
481  {
482  auto const& productDescription = I->second->productDescription();
483  auto const& refs = keptProducts()[productDescription.branchType()];
484  bool found = false;
485  for (auto const& ref : refs)
486  {
487 #if ART_HEX_VERSION < 0x30000
488  if (*ref == productDescription)
489  {
490 #else
491  if (ref.second == productDescription)
492  {
493 #endif
494  found = true;
495  break;
496  }
497  }
498 #if ART_HEX_VERSION < 0x30000
499  if (I->second->productUnavailable() || !found)
500 #else
501  if (!I->second->productAvailable() || !found)
502 #endif
503  {
504  continue;
505  }
506  const BranchDescription& bd(I->second->productDescription());
507  bkv.push_back(new BranchKey(bd));
508  TLOG(TLVL_WRITEDATAPRODUCTS_VERBOSE)
509  << "ArtdaqOutput::writeDataProducts(...): Dumping branch key of class: '"
510  << bkv.back()->friendlyClassName_ << "' modlbl: '" << bkv.back()->moduleLabel_ << "' instnm: '"
511  << bkv.back()->productInstanceName_ << "' procnm: '" << bkv.back()->processName_ << "'";
512  TLOG(TLVL_WRITEDATAPRODUCTS) << "ArtdaqOutput::writeDataProducts(...): "
513  "Streaming branch key of class: '"
514  << bd.producedClassName() << "' modlbl: '" << bd.moduleLabel() << "' instnm: '"
515  << bd.productInstanceName() << "' procnm: '" << bd.processName() << "'";
516  msg.WriteObjectAny(bkv.back(), branch_key_class);
517 
518  TLOG(TLVL_WRITEDATAPRODUCTS) << "ArtdaqOutput::writeDataProducts(...): "
519  "Streaming product of class: '"
520  << bd.producedClassName() << "' modlbl: '" << bd.moduleLabel() << "' instnm: '"
521  << bd.productInstanceName() << "' procnm: '" << bd.processName() << "'";
522 
523  OutputHandle oh = principal.getForOutput(bd.productID(), true);
524  const EDProduct* prd = oh.wrapper();
525  TLOG(TLVL_WRITEDATAPRODUCTS) << "Class for branch " << bd.wrappedName() << " is "
526  << (void*)TClass::GetClass(bd.wrappedName().c_str());
527  msg.WriteObjectAny(prd, TClass::GetClass(bd.wrappedName().c_str()));
528  TLOG(TLVL_WRITEDATAPRODUCTS) << "ArtdaqOutput::writeDataProducts(...): "
529  "Streaming product provenance of class: '"
530  << bd.producedClassName() << "' modlbl: '" << bd.moduleLabel() << "' instnm: '"
531  << bd.productInstanceName() << "' procnm: '" << bd.processName() << "'";
532 #if ART_HEX_VERSION < 0x30000
533  const ProductProvenance* prdprov = I->second->productProvenancePtr().get();
534 #else
535  const ProductProvenance* prdprov = I->second->productProvenance().get();
536 #endif
537  msg.WriteObjectAny(prdprov, prdprov_class);
538  }
539  TLOG(TLVL_WRITEDATAPRODUCTS) << "End: ArtdaqOutput::writeDataProducts(...)";
540 }
541 
542 void art::ArtdaqOutput::write(EventPrincipal& ep)
543 {
544  //
545  // Write an Event message.
546  //
547  TLOG(TLVL_WRITE) << "Begin: ArtdaqOutput::write(const EventPrincipal& ep)";
548  if (!initMsgSent_)
549  {
550  send_init_message(ep.history());
551  initMsgSent_ = true;
552  }
553  //
554  // Get root classes needed for I/O.
555  //
556  static TClass* run_aux_class = TClass::GetClass("art::RunAuxiliary");
557  if (run_aux_class == nullptr)
558  {
559  throw art::Exception(art::errors::DictionaryNotFound) << "ArtdaqOutput::write(const EventPrincipal& ep): "
560  "Could not get TClass for art::RunAuxiliary!";
561  }
562  static TClass* subrun_aux_class = TClass::GetClass("art::SubRunAuxiliary");
563  if (subrun_aux_class == nullptr)
564  {
565  throw art::Exception(art::errors::DictionaryNotFound) << "ArtdaqOutput::write(const EventPrincipal& ep): "
566  "Could not get TClass for art::SubRunAuxiliary!";
567  }
568  static TClass* event_aux_class = TClass::GetClass("art::EventAuxiliary");
569  if (event_aux_class == nullptr)
570  {
571  throw art::Exception(art::errors::DictionaryNotFound) << "ArtdaqOutput::write(const EventPrincipal& ep): "
572  "Could not get TClass for art::EventAuxiliary!";
573  }
574  static TClass* history_class = TClass::GetClass("art::History");
575  if (history_class == nullptr)
576  {
577  throw art::Exception(art::errors::DictionaryNotFound) << "ArtdaqOutput::write(const EventPrincipal& ep): "
578  "Could not get TClass for art::History!";
579  }
580  //
581  // Setup message buffer.
582  //
583  TBufferFile msg(TBuffer::kWrite);
584  msg.SetWriteMode();
585  //
586  // Write message type code.
587  //
588  TLOG(TLVL_WRITE) << "ArtdaqOutput::write(const EventPrincipal& ep): Streaming message type code ...";
589  msg.WriteULong(4);
590  TLOG(TLVL_WRITE) << "ArtdaqOutput::write(const EventPrincipal& ep): Finished streaming message type code.";
591 
592  //
593  // Write RunAuxiliary.
594  //
595  TLOG(TLVL_WRITE) << "ArtdaqOutput::write(const EventPrincipal& ep): Streaming RunAuxiliary ...";
596  msg.WriteObjectAny(&ep.subRunPrincipal().runPrincipal().RUN_AUX(), run_aux_class);
597  TLOG(TLVL_WRITE) << "ArtdaqOutput::write(const EventPrincipal& ep): Finished streaming RunAuxiliary.";
598 
599  //
600  // Write SubRunAuxiliary.
601  //
602  TLOG(TLVL_WRITE) << "ArtdaqOutput::write(const EventPrincipal& ep): Streaming SubRunAuxiliary ...";
603  msg.WriteObjectAny(&ep.subRunPrincipal().SUBRUN_AUX(), subrun_aux_class);
604  TLOG(TLVL_WRITE) << "ArtdaqOutput::write(const EventPrincipal& ep): Finished streaming SubRunAuxiliary.";
605 
606  //
607  // Write EventAuxiliary.
608  //
609  {
610  TLOG(TLVL_WRITE) << "ArtdaqOutput::write(const EventPrincipal& ep): Streaming EventAuxiliary ...";
611  msg.WriteObjectAny(&ep.EVENT_AUX(), event_aux_class);
612  TLOG(TLVL_WRITE) << "ArtdaqOutput::write(const EventPrincipal& ep): Finished streaming EventAuxiliary.";
613  }
614  //
615  // Write History.
616  //
617  {
618  TLOG(TLVL_WRITE) << "ArtdaqOutput::write(const EventPrincipal& ep): Streaming History ...";
619  msg.WriteObjectAny(&ep.history(), history_class);
620  TLOG(TLVL_WRITE) << "ArtdaqOutput::write(const EventPrincipal& ep): Finished streaming History.";
621  }
622  //
623  // Write data products.
624  //
625  std::vector<BranchKey*> bkv;
626  writeDataProducts(msg, ep, bkv);
627 
628  TLOG(TLVL_WRITE) << "ArtdaqOutput::write: Sending message";
629  SendMessage(ep.EVENT_ID().event(), artdaq::Fragment::DataFragmentType, msg);
630  TLOG(TLVL_WRITE) << "ArtdaqOutput::write: Done sending message";
631 
632  //
633  // Delete the branch keys we created for the message.
634  //
635  for (auto I = bkv.begin(), E = bkv.end(); I != E; ++I)
636  {
637  delete *I;
638  *I = 0;
639  }
640  TLOG(TLVL_WRITE) << "End: ArtdaqOutput::write(const EventPrincipal& ep)";
641 }
642 
643 void art::ArtdaqOutput::writeRun(RunPrincipal& rp)
644 { //
645  // Write an EndRun message.
646  //
647  TLOG(TLVL_WRITERUN) << "Begin: ArtdaqOutput::writeRun(const RunPrincipal& rp)";
648  (void)rp;
649  if (!initMsgSent_)
650  {
651 #if ART_HEX_VERSION < 0x30000
652  send_init_message(art::History());
653 #else
654  send_init_message(rp.history());
655 #endif
656  initMsgSent_ = true;
657  }
658 #if 0
659  //
660  // Fetch the class dictionaries we need for
661  // writing out the auxiliary information.
662  //
663  static TClass* run_aux_class = TClass::GetClass("art::RunAuxiliary");
664  assert(run_aux_class != nullptr && "writeRun: Could not get TClass for art::RunAuxiliary!");
665  //
666  // Begin preparing message.
667  //
668  TBufferFile msg(TBuffer::kWrite);
669  msg.SetWriteMode();
670  //
671  // Write message type code.
672  //
673  {
674  TLOG(TLVL_WRITERUN) << "ArtdaqOutput::writeRun: streaming message type code ...";
675  msg.WriteULong(2);
676  TLOG(TLVL_WRITERUN) << "ArtdaqOutput::writeRun: finished streaming message type code.";
677  }
678  //
679  // Write RunAuxiliary.
680  //
681  {
682  TLOG(TLVL_WRITERUN) << "ArtdaqOutput::writeRun: streaming RunAuxiliary ...";
683  msg.WriteObjectAny(&rp.RUN_AUX(), run_aux_class);
684  TLOG(TLVL_WRITERUN) << "ArtdaqOutput::writeRun: streamed RunAuxiliary.";
685  }
686  //
687  // Write data products.
688  //
689  std::vector<BranchKey*> bkv;
690  writeDataProducts(msg, rp, bkv);
691 
692  TLOG(TLVL_WRITERUN) << "ArtdaqOutput::writeRun: Sending message";
693  SendMessage(0, artdaq::Fragment::EndOfRunFragmentType, msg);
694  TLOG(TLVL_WRITERUN) << "ArtdaqOutput::writeRun: Done sending message";
695 
696  for (auto I = bkv.begin(), E = bkv.end(); I != E; ++I)
697  {
698  delete *I;
699  *I = 0;
700  }
701 #endif
702  TLOG(TLVL_WRITERUN) << "End: ArtdaqOutput::writeRun(RunPrincipal& rp)";
703 }
704 void art::ArtdaqOutput::writeSubRun(SubRunPrincipal& srp)
705 { //
706  // Write an EndSubRun message.
707  //
708  TLOG(TLVL_WRITESUBRUN) << "Begin: ArtdaqOutput::writeSubRun(const SubRunPrincipal& srp)";
709  if (!initMsgSent_)
710  {
711 #if ART_HEX_VERSION < 0x30000
712  send_init_message(art::History());
713 #else
714  send_init_message(srp.history());
715 #endif
716  initMsgSent_ = true;
717  }
718  //
719  // Fetch the class dictionaries we need for
720  // writing out the auxiliary information.
721  //
722  static TClass* subrun_aux_class = TClass::GetClass("art::SubRunAuxiliary");
723  if (subrun_aux_class == nullptr)
724  {
725  throw art::Exception(art::errors::DictionaryNotFound) << "ArtdaqOutput::writeSubRun: "
726  "Could not get TClass for art::SubRunAuxiliary!";
727  }
728  //
729  // Begin preparing message.
730  //
731  TBufferFile msg(TBuffer::kWrite);
732  msg.SetWriteMode();
733  //
734  // Write message type code.
735  //
736  {
737  TLOG(TLVL_WRITESUBRUN) << "ArtdaqOutput::writeSubRun: streaming message type code ...";
738  msg.WriteULong(3);
739  TLOG(TLVL_WRITESUBRUN) << "ArtdaqOutput::writeSubRun: finished streaming message type code.";
740  }
741  //
742  // Write SubRunAuxiliary.
743  //
744  {
745  TLOG(TLVL_WRITESUBRUN) << "ArtdaqOutput::writeSubRun: streaming SubRunAuxiliary ...";
746 
747  TLOG(TLVL_WRITESUBRUN_VERBOSE) << "ArtdaqOutput::writeSubRun: dumping ProcessHistoryRegistry ...";
748  // typedef std::map<const ProcessHistoryID,ProcessHistory>
749  // ProcessHistoryMap;
750  for (auto I = std::begin(art::ProcessHistoryRegistry::get()), E = std::end(art::ProcessHistoryRegistry::get());
751  I != E; ++I)
752  {
753  std::ostringstream OS;
754  I->first.print(OS);
755  TLOG(TLVL_WRITESUBRUN_VERBOSE) << "ArtdaqOutput::writeSubRun: phr: id: '" << OS.str() << "'";
756  OS.str("");
757  TLOG(TLVL_WRITESUBRUN_VERBOSE) << "ArtdaqOutput::writeSubRun: phr: data.size(): " << I->second.data().size();
758  if (I->second.data().size())
759  {
760  I->second.data().back().id().print(OS);
761  TLOG(TLVL_WRITESUBRUN_VERBOSE) << "ArtdaqOutput::writeSubRun: phr: data.back().id(): '" << OS.str() << "'";
762  }
763  }
764  if (!srp.SUBRUN_AUX().processHistoryID().isValid())
765  {
766  TLOG(TLVL_WRITESUBRUN_VERBOSE) << "ArtdaqOutput::writeSubRun: ProcessHistoryID: 'INVALID'";
767  }
768  else
769  {
770  std::ostringstream OS;
771  srp.SUBRUN_AUX().processHistoryID().print(OS);
772  TLOG(TLVL_WRITESUBRUN_VERBOSE) << "ArtdaqOutput::writeSubRun: ProcessHistoryID: '" << OS.str() << "'";
773  OS.str("");
774  ProcessHistory processHistory;
775  ProcessHistoryRegistry::get(srp.SUBRUN_AUX().processHistoryID(), processHistory);
776  if (processHistory.data().size())
777  {
778  // FIXME: Print something special on invalid id() here!
779  processHistory.data().back().id().print(OS);
780  TLOG(TLVL_WRITESUBRUN_VERBOSE) << "ArtdaqOutput::writeSubRun: ProcessConfigurationID: '" << OS.str() << "'";
781  OS.str("");
782  OS << processHistory.data().back();
783  TLOG(TLVL_WRITESUBRUN_VERBOSE) << "ArtdaqOutput::writeSubRun: ProcessConfiguration: '" << OS.str();
784  }
785  }
786  msg.WriteObjectAny(&srp.SUBRUN_AUX(), subrun_aux_class);
787  TLOG(TLVL_WRITESUBRUN) << "ArtdaqOutput::writeSubRun: streamed SubRunAuxiliary.";
788  }
789  //
790  // Write data products.
791  //
792  std::vector<BranchKey*> bkv;
793  writeDataProducts(msg, srp, bkv);
794 
795  TLOG(TLVL_WRITESUBRUN) << "ArtdaqOutput::writeSubRun: Sending message";
796  SendMessage(0, artdaq::Fragment::EndOfSubrunFragmentType, msg);
797  TLOG(TLVL_WRITESUBRUN) << "ArtdaqOutput::writeSubRun: Done sending message";
798 
799  //
800  // Delete the branch keys we created for the message.
801  //
802  for (auto I = bkv.begin(), E = bkv.end(); I != E; ++I)
803  {
804  delete *I;
805  *I = 0;
806  }
807  TLOG(TLVL_WRITESUBRUN) << "End: ArtdaqOutput::writeSubRun(const SubRunPrincipal& srp)";
808 }
809 
810 void art::ArtdaqOutput::extractProducts_(Principal const& principal [[gnu::unused]])
811 {
812  TLOG(TLVL_EXTRACTPRODUCTS) << "Begin: ArtdaqOutput::extractProducts_(Principal const& principal) sz=" << principal.size();
813 #if ART_HEX_VERSION < 0x30000
814  productList_ = art::ProductMetaData::instance().productList();
815 
816 #else
817  for (auto I = principal.begin(), E = principal.end(); I != E; ++I)
818  {
819  auto const& productDescription = I->second->productDescription();
820  auto const& branchKey = BranchKey(productDescription);
821 
822  if (!productList_.count(branchKey))
823  {
824  TLOG(TLVL_EXTRACTPRODUCTS_VERBOSE) << "ArtdaqOutput::extractProducts_:"
825  << "Adding branch key to productList of class: '"
826  << branchKey.friendlyClassName_ << "' modlbl: '" << branchKey.moduleLabel_ << "' instnm: '"
827  << branchKey.productInstanceName_ << "' procnm: '" << branchKey.processName_ << "'"
828  << ", description: " << productDescription.wrappedName();
829 
830  productList_[branchKey] = productDescription;
831  }
832  }
833 #endif
834 
835  TLOG(TLVL_EXTRACTPRODUCTS) << "End: ArtdaqOutput::extractProducts_(Principal const& principal) Product list sz=" << productList_.size();
836 }
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...
Definition: ArtdaqOutput.hh:99
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 SendMessage(artdaq::Fragment::sequence_id_t sequenceId, artdaq::Fragment::type_t messageType, TBufferFile &msg)=0
Send the serialized art Event downstream. Artdaq output modules should define this function...
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 closeFile()
Perform actions necessary for closing files. No-op, but derived classes may override ...
ArtdaqOutput(fhicl::ParameterSet const &ps)
ArtdaqOutput Constructor
void writeDataProducts(TBufferFile &msg, const Principal &principal, std::vector< BranchKey * > &bkv)
Extract the data products from a Principal and write them to the TBufferFile
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
virtual void write(EventPrincipal &ep) final
Write an EventPrincipal to TBufferFile and send