otsdaq  v2_04_01
ARTDAQAggregatorTable_table.cc
1 #include "otsdaq-core/ConfigurationInterface/ConfigurationManager.h"
2 #include "otsdaq-core/Macros/TablePluginMacros.h"
3 #include "otsdaq-core/TablePlugins/ARTDAQAggregatorTable.h"
4 #include "otsdaq-core/TablePlugins/XDAQContextTable.h"
5 
6 #include <stdio.h>
7 #include <sys/stat.h> //for mkdir
8 #include <fstream> // std::fstream
9 #include <iostream>
10 
11 using namespace ots;
12 
13 #define ARTDAQ_FCL_PATH std::string(__ENV__("USER_DATA")) + "/" + "ARTDAQConfigurations/"
14 #define ARTDAQ_FILE_PREAMBLE "aggregator"
15 
16 // helpers
17 #define OUT out << tabStr << commentStr
18 #define PUSHTAB tabStr += "\t"
19 #define POPTAB tabStr.resize(tabStr.size() - 1)
20 #define PUSHCOMMENT commentStr += "# "
21 #define POPCOMMENT commentStr.resize(commentStr.size() - 2)
22 
23 //========================================================================================================================
24 ARTDAQAggregatorTable::ARTDAQAggregatorTable(void) : TableBase("ARTDAQAggregatorTable")
25 {
27  // WARNING: the names used in C++ MUST match the Table INFO //
29 }
30 
31 //========================================================================================================================
32 ARTDAQAggregatorTable::~ARTDAQAggregatorTable(void) {}
33 
34 //========================================================================================================================
35 void ARTDAQAggregatorTable::init(ConfigurationManager* configManager)
36 {
37  // use isFirstAppInContext to only run once per context, for example to avoid
38  // generating files on local disk multiple times.
39  bool isFirstAppInContext = configManager->isOwnerFirstAppInContext();
40 
41  //__COUTV__(isFirstAppInContext);
42  if(!isFirstAppInContext)
43  return;
44 
45  // make directory just in case
46  mkdir((ARTDAQ_FCL_PATH).c_str(), 0755);
47 
48  __COUT__ << "*&*&*&*&*&*&*&*&*&*&*&*&*&*&*&*&*&*&*&*&*&*" << std::endl;
49  __COUT__ << configManager->__SELF_NODE__ << std::endl;
50 
51  const XDAQContextTable* contextConfig =
52  configManager->__GET_CONFIG__(XDAQContextTable);
53  std::vector<const XDAQContextTable::XDAQContext*> aggContexts =
54  contextConfig->getAggregatorContexts();
55 
56  // for each aggregator context
57  // output associated fcl config file
58  for(auto& aggContext : aggContexts)
59  {
60  ConfigurationTree aggConfigNode = contextConfig->getSupervisorConfigNode(
61  configManager,
62  aggContext->contextUID_,
63  aggContext->applications_[0].applicationUID_);
64 
65  __COUT__ << "Path for this aggregator config is " << aggContext->contextUID_
66  << "/" << aggContext->applications_[0].applicationUID_ << "/"
67  << aggConfigNode.getValueAsString() << std::endl;
68 
69  outputFHICL(
70  configManager,
71  aggConfigNode,
72  contextConfig->getARTDAQAppRank(aggContext->contextUID_),
73  contextConfig->getContextAddress(aggContext->contextUID_),
74  contextConfig->getARTDAQDataPort(configManager, aggContext->contextUID_),
75  contextConfig);
76  }
77 }
78 
79 //========================================================================================================================
80 std::string ARTDAQAggregatorTable::getFHICLFilename(
81  const ConfigurationTree& aggregatorNode)
82 {
83  __COUT__ << "ARTDAQ Aggregator UID: " << aggregatorNode.getValue() << std::endl;
84  std::string filename = ARTDAQ_FCL_PATH + ARTDAQ_FILE_PREAMBLE + "-";
85  std::string uid = aggregatorNode.getValue();
86  for(unsigned int i = 0; i < uid.size(); ++i)
87  if((uid[i] >= 'a' && uid[i] <= 'z') || (uid[i] >= 'A' && uid[i] <= 'Z') ||
88  (uid[i] >= '0' && uid[i] <= '9')) // only allow alpha numeric in file name
89  filename += uid[i];
90 
91  filename += ".fcl";
92 
93  __COUT__ << "fcl: " << filename << std::endl;
94 
95  return filename;
96 }
97 
98 //========================================================================================================================
99 void ARTDAQAggregatorTable::outputFHICL(ConfigurationManager* configManager,
100  const ConfigurationTree& aggregatorNode,
101  unsigned int selfRank,
102  std::string selfHost,
103  unsigned int selfPort,
104  const XDAQContextTable* contextConfig)
105 {
106  /*
107  the file will look something like this:
108 
109  services: {
110  scheduler: {
111  fileMode: NOMERGE
112  errorOnFailureToPut: false
113  }
114  NetMonTransportServiceInterface: {
115  service_provider: NetMonTransportService
116  }
117 
118  #SimpleMemoryCheck: { }
119  }
120 
121  daq: {
122  aggregator: {
123  expected_events_per_bunch: 1
124  print_event_store_stats: true
125  event_queue_depth: 20
126  event_queue_wait_time: 5
127  onmon_event_prescale: 1
128  xmlrpc_client_list:
129  ";http://ironwork.fnal.gov:5205/RPC2,3;http://ironwork.fnal.gov:5206/RPC2,3;http://ironwork.fnal.gov:5235/RPC2,4;http://ironwork.fnal.gov:5236/RPC2,4;http://ironwork.fnal.gov:5265/RPC2,5;http://ironwork.fnal.gov:5266/RPC2,5"
130  file_size_MB: 0.0
131  file_duration: 0
132  file_event_count: 0
133  is_data_logger: true
134 
135  sources: {
136  s2: { transferPluginType: MPI source_rank: 2 max_fragment_size_bytes:
137  2097152} s3: { transferPluginType: MPI source_rank: 3 max_fragment_size_bytes:
138  2097152}
139 
140  }
141  }
142 
143  metrics: {
144  aggFile: {
145  metricPluginType: "file"
146  level: 3
147  fileName: "/tmp/aggregator/agg_%UID%_metrics.log"
148  uniquify: true
149  }
150  # ganglia: {
151  # metricPluginType: "ganglia"
152  # level: %{ganglia_level}
153  # reporting_interval: 15.0
154  #
155  # configFile: "/etc/ganglia/gmond.conf"
156  # group: "ARTDAQ"
157  # }
158  # msgfac: {
159  # level: %{mf_level}
160  # metricPluginType: "msgFacility"
161  # output_message_application_name: "ARTDAQ Metric"
162  # output_message_severity: 0
163  # }
164  # graphite: {
165  # level: %{graphite_level}
166  # metricPluginType: "graphite"
167  # host: "localhost"
168  # port: 20030
169  # namespace: "artdaq."
170  # }
171  }
172 
173  transfer_to_dispatcher: {
174  transferPluginType: Shmem
175  source_rank: 4
176  destination_rank: 5
177  max_fragment_size_bytes: 2097152
178  }
179 
180  }
181 
182  source: {
183  module_type: NetMonInput
184  }
185  outputs: {
186  normalOutput: {
187  module_type: RootOutput
188  fileName: "/tmp/artdaqdemo_r%06r_sr%02s_%to.root"
189  }
190 
191  #normalOutputMod2: {
192  # module_type: RootOutput
193  # fileName: "/tmp/artdaqdemo_r%06r_sr%02s_%to_mod2.root"
194  # SelectEvents: { SelectEvents: [ pmod2 ] }
195  #}
196 
197  #normalOutputMod3: {
198  # module_type: RootOutput
199  # fileName: "/tmp/artdaqdemo_r%06r_sr%02s_%to_mod3.root"
200  # SelectEvents: { SelectEvents: [ pmod3 ] }
201  #}
202 
203  }
204  physics: {
205  analyzers: {
206 
207 
208  checkintegrity: {
209  module_type: CheckIntegrity
210  raw_data_label: daq
211  frag_type: TOY1
212  }
213 
214  }
215 
216  producers: {
217 
218  BuildInfo:
219  {
220  module_type: ArtdaqDemoBuildInfo
221  instance_name: ArtdaqDemo
222  }
223  }
224 
225  filters: {
226 
227  prescaleMod2: {
228  module_type: NthEvent
229  nth: 2
230  }
231 
232  prescaleMod3: {
233  module_type: NthEvent
234  nth: 3
235  }
236  }
237 
238  p2: [ BuildInfo ]
239  pmod2: [ prescaleMod2 ]
240  pmod3: [ prescaleMod3 ]
241 
242  #a1: [ app, wf]
243 
244  my_output_modules: [ normalOutput ]
245  #my_output_modules: [ normalOutputMod2, normalOutputMod3 ]
246  }
247  process_name: DAQAG
248 
249  */
250 
251  std::string filename = getFHICLFilename(aggregatorNode);
252 
253  __COUT__ << "selfRank = " << selfRank << std::endl;
254 
256  // generate xdaq run parameter file
257  std::fstream out;
258 
259  std::string tabStr = "";
260  std::string commentStr = "";
261 
262  out.open(filename, std::fstream::out | std::fstream::trunc);
263  if(out.fail())
264  {
265  __SS__ << "Failed to open ARTDAQ Aggregator fcl file: " << filename << std::endl;
266  __SS_THROW__;
267  }
268 
269  //--------------------------------------
270  // header
271  OUT << "###########################################################" << __E__;
272  OUT << "#" << __E__;
273  OUT << "# artdaq aggregator fcl configuration file produced by otsdaq." << __E__;
274  OUT << "# Creation timestamp: " << StringMacros::getTimestampString() << __E__;
275  OUT << "# Original filename: " << filename << __E__;
276  OUT << "# otsdaq-ARTDAQ Aggregator UID: " << aggregatorNode.getValue() << __E__;
277  OUT << "#" << __E__;
278  OUT << "###########################################################" << __E__;
279  OUT << "\n\n";
280 
281  //--------------------------------------
282  // handle services
283  auto services = aggregatorNode.getNode("servicesLink");
284  if(!services.isDisconnected())
285  {
286  OUT << "services: {\n";
287 
288  // scheduler
289  PUSHTAB;
290  OUT << "scheduler: {\n";
291 
292  PUSHTAB;
293  OUT << "fileMode: " << services.getNode("schedulerFileMode").getValue() << "\n";
294  OUT << "errorOnFailureToPut: "
295  << (services.getNode("schedulerErrorOnFailtureToPut").getValue<bool>()
296  ? "true"
297  : "false")
298  << "\n";
299  POPTAB;
300 
301  OUT << "}\n\n";
302 
303  // NetMonTransportServiceInterface
304  OUT << "NetMonTransportServiceInterface: {\n";
305 
306  PUSHTAB;
307  OUT << "service_provider: " <<
308  // services.getNode("NetMonTrasportServiceInterfaceServiceProvider").getEscapedValue()
309  services.getNode("NetMonTrasportServiceInterfaceServiceProvider").getValue()
310  << "\n";
311 
312  POPTAB;
313  OUT << "}\n\n"; // end NetMonTransportServiceInterface
314 
315  POPTAB;
316  OUT << "}\n\n"; // end services
317  }
318 
319  //--------------------------------------
320  // handle daq
321  auto daq = aggregatorNode.getNode("daqLink");
322  if(!daq.isDisconnected())
323  {
324  OUT << "daq: {\n";
325 
326  // aggregator
327  PUSHTAB;
328  OUT << "aggregator: {\n";
329 
330  PUSHTAB;
331  auto parametersLink = daq.getNode("daqAggregatorParametersLink");
332  if(!parametersLink.isDisconnected())
333  {
334  auto parameters = parametersLink.getChildren();
335  for(auto& parameter : parameters)
336  {
337  if(!parameter.second.getNode(TableViewColumnInfo::COL_NAME_STATUS)
338  .getValue<bool>())
339  PUSHCOMMENT;
340 
341  auto comment =
342  parameter.second.getNode(TableViewColumnInfo::COL_NAME_COMMENT);
343  OUT << parameter.second.getNode("daqParameterKey").getValue() << ": "
344  << parameter.second.getNode("daqParameterValue").getValue()
345  << (comment.isDefaultValue() ? "" : ("\t # " + comment.getValue()))
346  << "\n";
347 
348  if(!parameter.second.getNode(TableViewColumnInfo::COL_NAME_STATUS)
349  .getValue<bool>())
350  POPCOMMENT;
351  }
352  }
353  OUT << "\n"; // end daq aggregator parameters
354 
355  OUT << "sources: {\n";
356 
357  PUSHTAB;
358  auto sourcesGroup = daq.getNode("daqAggregatorSourcesLink");
359  if(!sourcesGroup.isDisconnected())
360  {
361  try
362  {
363  auto sources = sourcesGroup.getChildren();
364  for(auto& source : sources)
365  {
366  std::string sourceContextUID =
367  source.second.getNode("sourceARTDAQContextLink")
368  .getValueAsString();
369 
370  unsigned int sourceRank = -1;
371  try
372  {
373  sourceRank = contextConfig->getARTDAQAppRank(sourceContextUID);
374  }
375  catch(const std::runtime_error& e)
376  {
377  __MCOUT_WARN__("Are the DAQ sources valid? "
378  << "Perhaps a Context has been turned off? "
379  << "Skipping source due to an error looking for "
380  << "Aggregator DAQ source context '"
381  << sourceContextUID << "' for UID '"
382  << aggregatorNode.getValue() << "': " << e.what()
383  << __E__);
384  continue;
385  }
386 
387  std::string host = contextConfig->getContextAddress(sourceContextUID);
388  unsigned int port =
389  contextConfig->getARTDAQDataPort(configManager, sourceContextUID);
390 
391  // open source object
392  OUT << source.second.getNode("sourceKey").getValue() << ": {\n";
393  PUSHTAB;
394 
395  OUT << "transferPluginType: "
396  << source.second.getNode("transferPluginType").getValue()
397  << __E__;
398 
399  OUT << "source_rank: " << sourceRank << __E__;
400 
401  try
402  {
403  auto mfsb =
404  source.second
405  .getNode("ARTDAQGlobalTableLink/maxFragmentSizeBytes")
406  .getValue<unsigned long long>();
407  OUT << "max_fragment_size_bytes: " << mfsb << __E__;
408  OUT << "max_fragment_size_words: " << (mfsb / 8) << __E__;
409  }
410  catch(...)
411  {
412  __SS__ << "The field ARTDAQGlobalTableLink/maxFragmentSizeBytes "
413  "could not be accessed. Make sure the link is valid."
414  << __E__;
415  __SS_THROW__;
416  }
417 
418  OUT << "host_map: [\n";
419  PUSHTAB;
420  OUT << "{\n";
421  PUSHTAB;
422  OUT << "rank: " << sourceRank << __E__;
423  OUT << "host: \"" << host << "\"" << __E__;
424  OUT << "portOffset: " << std::to_string(port) << __E__;
425  POPTAB;
426  OUT << "},\n";
427  OUT << "{\n";
428  PUSHTAB;
429  OUT << "rank: " << selfRank << __E__;
430  OUT << "host: \"" << selfHost << "\"" << __E__;
431  OUT << "portOffset: " << std::to_string(selfPort) << __E__;
432  POPTAB;
433  OUT << "}" << __E__;
434  POPTAB;
435  OUT << "]" << __E__; // close host_map
436 
437  POPTAB;
438  OUT << "}" << __E__; // close source object
439  }
440  }
441  catch(const std::runtime_error& e)
442  {
443  __SS__ << "Are the DAQ sources valid? Error occurred looking for "
444  "Aggregator DAQ sources for UID '"
445  << aggregatorNode.getValue() << "': " << e.what() << std::endl;
446  __COUT_ERR__ << ss.str() << std::endl;
447  __SS_THROW__;
448  }
449  }
450  POPTAB;
451  OUT << "}\n\n"; // end sources
452 
453  POPTAB;
454  OUT << "}\n\n"; // end aggregator
455 
456  OUT << "metrics: {\n";
457 
458  PUSHTAB;
459  auto metricsGroup = daq.getNode("daqMetricsLink");
460  if(!metricsGroup.isDisconnected())
461  {
462  auto metrics = metricsGroup.getChildren();
463 
464  for(auto& metric : metrics)
465  {
466  if(!metric.second.getNode(TableViewColumnInfo::COL_NAME_STATUS)
467  .getValue<bool>())
468  PUSHCOMMENT;
469 
470  OUT << metric.second.getNode("metricKey").getValue() << ": {\n";
471  PUSHTAB;
472 
473  OUT << "metricPluginType: "
474  << metric.second.getNode("metricPluginType").getValue() << "\n";
475  OUT << "level: " << metric.second.getNode("metricLevel").getValue()
476  << "\n";
477 
478  auto metricParametersGroup =
479  metric.second.getNode("metricParametersLink");
480  if(!metricParametersGroup.isDisconnected())
481  {
482  auto metricParameters = metricParametersGroup.getChildren();
483  for(auto& metricParameter : metricParameters)
484  {
485  if(!metricParameter.second
486  .getNode(TableViewColumnInfo::COL_NAME_STATUS)
487  .getValue<bool>())
488  PUSHCOMMENT;
489 
490  auto comment = metricParameter.second.getNode(
491  TableViewColumnInfo::COL_NAME_COMMENT);
492  OUT << metricParameter.second.getNode("metricParameterKey")
493  .getValue()
494  << ": "
495  << metricParameter.second.getNode("metricParameterValue")
496  .getValue()
497  << (comment.isDefaultValue() ? ""
498  : ("\t # " + comment.getValue()))
499  << "\n";
500 
501  if(!metricParameter.second
502  .getNode(TableViewColumnInfo::COL_NAME_STATUS)
503  .getValue<bool>())
504  POPCOMMENT;
505  }
506  }
507  POPTAB;
508  OUT << "}\n\n"; // end metric
509 
510  if(!metric.second.getNode(TableViewColumnInfo::COL_NAME_STATUS)
511  .getValue<bool>())
512  POPCOMMENT;
513  }
514  }
515  POPTAB;
516  OUT << "}\n\n"; // end metrics
517 
518  OUT << "destinations: {\n";
519 
520  PUSHTAB;
521  // other destinations
522  auto destinationsGroup = daq.getNode("daqAggregatorDestinationsLink");
523  if(!destinationsGroup.isDisconnected())
524  {
525  try
526  {
527  auto destinations = destinationsGroup.getChildren();
528  for(auto& destination : destinations)
529  {
530  auto destinationContextUID =
531  destination.second.getNode("destinationARTDAQContextLink")
532  .getValueAsString();
533 
534  unsigned int destinationRank = -1;
535  try
536  {
537  destinationRank =
538  contextConfig->getARTDAQAppRank(destinationContextUID);
539  }
540  catch(const std::runtime_error& e)
541  {
542  __MCOUT_WARN__(
543  "Are the DAQ destinations valid? "
544  << "Perhaps a Context has been turned off? "
545  << "Skipping destination due to an error looking for "
546  << "Aggregator DAQ source context '" << destinationContextUID
547  << "' for UID '" << aggregatorNode.getValue()
548  << "': " << e.what() << __E__);
549  continue;
550  }
551  std::string host =
552  contextConfig->getContextAddress(destinationContextUID);
553  unsigned int port = contextConfig->getARTDAQDataPort(
554  configManager, destinationContextUID);
555 
556  // open destination object
557  OUT << destination.second.getNode("destinationKey").getValue()
558  << ": {\n";
559  PUSHTAB;
560 
561  OUT << "transferPluginType: "
562  << destination.second.getNode("transferPluginType").getValue()
563  << __E__;
564 
565  OUT << "source_rank: " << destinationRank << __E__;
566 
567  try
568  {
569  auto mfsb =
570  destination.second
571  .getNode("ARTDAQGlobalTableLink/maxFragmentSizeBytes")
572  .getValue<unsigned long long>();
573  OUT << "max_fragment_size_bytes: " << mfsb << __E__;
574  OUT << "max_fragment_size_words: " << (mfsb / 8) << __E__;
575  }
576  catch(...)
577  {
578  __SS__ << "The field ARTDAQGlobalTableLink/maxFragmentSizeBytes "
579  "could not be accessed. Make sure the link is valid."
580  << __E__;
581  __SS_THROW__;
582  }
583 
584  OUT << "host_map: [\n";
585  PUSHTAB;
586  OUT << "{\n";
587  PUSHTAB;
588  OUT << "rank: " << destinationRank << __E__;
589  OUT << "host: \"" << host << "\"" << __E__;
590  OUT << "portOffset: " << std::to_string(port) << __E__;
591  POPTAB;
592  OUT << "},\n";
593  OUT << "{\n";
594  PUSHTAB;
595  OUT << "rank: " << selfRank << __E__;
596  OUT << "host: \"" << selfHost << "\"" << __E__;
597  OUT << "portOffset: " << std::to_string(selfPort) << __E__;
598  POPTAB;
599  OUT << "}" << __E__;
600  POPTAB;
601  OUT << "]" << __E__; // close host_map
602 
603  POPTAB;
604  OUT << "}" << __E__; // close source object
605  }
606  }
607  catch(const std::runtime_error& e)
608  {
609  __SS__ << "Are the DAQ destinations valid? Error occurred looking for "
610  "Aggregator DAQ destinations for UID '"
611  << aggregatorNode.getValue() << "': " << e.what() << std::endl;
612  __COUT_ERR__ << ss.str() << std::endl;
613  __SS_THROW__;
614  }
615  }
616  POPTAB;
617  OUT << "}\n\n"; // end destinations
618 
619  POPTAB;
620  OUT << "}\n\n"; // end daq
621  }
622 
623  //--------------------------------------
624  // handle source
625  auto source = aggregatorNode.getNode("sourceLink");
626  if(!source.isDisconnected())
627  {
628  OUT << "source: {\n";
629 
630  PUSHTAB;
631  OUT << "module_type: " << source.getNode("sourceModuleType").getValue() << "\n";
632  POPTAB;
633  OUT << "}\n\n"; // end source
634  }
635 
636  //--------------------------------------
637  // handle outputs
638  auto outputs = aggregatorNode.getNode("outputsLink");
639  if(!outputs.isDisconnected())
640  {
641  OUT << "outputs: {\n";
642 
643  PUSHTAB;
644 
645  auto outputPlugins = outputs.getChildren();
646  for(auto& outputPlugin : outputPlugins)
647  {
648  if(!outputPlugin.second.getNode(TableViewColumnInfo::COL_NAME_STATUS)
649  .getValue<bool>())
650  PUSHCOMMENT;
651 
652  OUT << outputPlugin.second.getNode("outputKey").getValue() << ": {\n";
653  PUSHTAB;
654  OUT << "module_type: "
655  << outputPlugin.second.getNode("outputModuleType").getValue() << "\n";
656  auto pluginParameterLink =
657  outputPlugin.second.getNode("outputModuleParameterLink");
658  if(!pluginParameterLink.isDisconnected())
659  {
660  auto pluginParameters = pluginParameterLink.getChildren();
661  for(auto& pluginParameter : pluginParameters)
662  {
663  if(!pluginParameter.second
664  .getNode(TableViewColumnInfo::COL_NAME_STATUS)
665  .getValue<bool>())
666  PUSHCOMMENT;
667 
668  auto comment = pluginParameter.second.getNode(
669  TableViewColumnInfo::COL_NAME_COMMENT);
670  OUT << pluginParameter.second.getNode("outputParameterKey").getValue()
671  << ": "
672  << pluginParameter.second.getNode("outputParameterValue")
673  .getValue()
674  << (comment.isDefaultValue() ? ""
675  : ("\t # " + comment.getValue()))
676  << "\n";
677 
678  if(!pluginParameter.second
679  .getNode(TableViewColumnInfo::COL_NAME_STATUS)
680  .getValue<bool>())
681  POPCOMMENT;
682  }
683  }
684  POPTAB;
685  OUT << "}\n\n"; // end output module
686 
687  if(!outputPlugin.second.getNode(TableViewColumnInfo::COL_NAME_STATUS)
688  .getValue<bool>())
689  POPCOMMENT;
690  }
691 
692  POPTAB;
693  OUT << "}\n\n"; // end outputs
694  }
695 
696  //--------------------------------------
697  // handle physics
698  auto physics = aggregatorNode.getNode("physicsLink");
699  if(!physics.isDisconnected())
700  {
702  OUT << "physics: {\n";
703 
704  PUSHTAB;
705 
706  auto analyzers = physics.getNode("analyzersLink");
707  if(!analyzers.isDisconnected())
708  {
710  OUT << "analyzers: {\n";
711 
712  PUSHTAB;
713  auto modules = analyzers.getChildren();
714  for(auto& module : modules)
715  {
716  if(!module.second.getNode(TableViewColumnInfo::COL_NAME_STATUS)
717  .getValue<bool>())
718  PUSHCOMMENT;
719 
720  OUT << module.second.getNode("analyzerKey").getValue() << ": {\n";
721  PUSHTAB;
722  OUT << "module_type: "
723  << module.second.getNode("analyzerModuleType").getValue() << "\n";
724  auto moduleParameterLink =
725  module.second.getNode("analyzerModuleParameterLink");
726  if(!moduleParameterLink.isDisconnected())
727  {
728  auto moduleParameters = moduleParameterLink.getChildren();
729  for(auto& moduleParameter : moduleParameters)
730  {
731  if(!moduleParameter.second
732  .getNode(TableViewColumnInfo::COL_NAME_STATUS)
733  .getValue<bool>())
734  PUSHCOMMENT;
735 
736  auto comment = moduleParameter.second.getNode(
737  TableViewColumnInfo::COL_NAME_COMMENT);
738  OUT << moduleParameter.second.getNode("analyzerParameterKey")
739  .getValue()
740  << ": "
741  << moduleParameter.second.getNode("analyzerParameterValue")
742  .getValue()
743  << (comment.isDefaultValue() ? ""
744  : ("\t # " + comment.getValue()))
745  << "\n";
746 
747  if(!moduleParameter.second
748  .getNode(TableViewColumnInfo::COL_NAME_STATUS)
749  .getValue<bool>())
750  POPCOMMENT;
751  }
752  }
753  POPTAB;
754  OUT << "}\n\n"; // end analyzer module
755 
756  if(!module.second.getNode(TableViewColumnInfo::COL_NAME_STATUS)
757  .getValue<bool>())
758  POPCOMMENT;
759  }
760  POPTAB;
761  OUT << "}\n\n"; // end analyzer
762  }
763 
764  auto producers = physics.getNode("producersLink");
765  if(!producers.isDisconnected())
766  {
768  OUT << "producers: {\n";
769 
770  PUSHTAB;
771  auto modules = producers.getChildren();
772  for(auto& module : modules)
773  {
774  if(!module.second.getNode(TableViewColumnInfo::COL_NAME_STATUS)
775  .getValue<bool>())
776  PUSHCOMMENT;
777 
778  OUT << module.second.getNode("producerKey").getValue() << ": {\n";
779  PUSHTAB;
780  OUT << "module_type: "
781  << module.second.getNode("producerModuleType").getValue() << "\n";
782  auto moduleParameterLink =
783  module.second.getNode("producerModuleParameterLink");
784  if(!moduleParameterLink.isDisconnected())
785  {
786  auto moduleParameters = moduleParameterLink.getChildren();
787  for(auto& moduleParameter : moduleParameters)
788  {
789  if(!moduleParameter.second
790  .getNode(TableViewColumnInfo::COL_NAME_STATUS)
791  .getValue<bool>())
792  PUSHCOMMENT;
793 
794  auto comment = moduleParameter.second.getNode(
795  TableViewColumnInfo::COL_NAME_COMMENT);
796  OUT << moduleParameter.second.getNode("producerParameterKey")
797  .getValue()
798  << ":"
799  << moduleParameter.second.getNode("producerParameterValue")
800  .getValue()
801  << (comment.isDefaultValue() ? ""
802  : ("\t # " + comment.getValue()))
803  << "\n";
804 
805  if(!moduleParameter.second
806  .getNode(TableViewColumnInfo::COL_NAME_STATUS)
807  .getValue<bool>())
808  POPCOMMENT;
809  }
810  }
811  POPTAB;
812  OUT << "}\n\n"; // end producer module
813 
814  if(!module.second.getNode(TableViewColumnInfo::COL_NAME_STATUS)
815  .getValue<bool>())
816  POPCOMMENT;
817  }
818  POPTAB;
819  OUT << "}\n\n"; // end producer
820  }
821 
822  auto filters = physics.getNode("filtersLink");
823  if(!filters.isDisconnected())
824  {
826  OUT << "filters: {\n";
827 
828  PUSHTAB;
829  auto modules = filters.getChildren();
830  for(auto& module : modules)
831  {
832  if(!module.second.getNode(TableViewColumnInfo::COL_NAME_STATUS)
833  .getValue<bool>())
834  PUSHCOMMENT;
835 
836  OUT << module.second.getNode("filterKey").getValue() << ": {\n";
837  PUSHTAB;
838  OUT << "module_type: "
839  << module.second.getNode("filterModuleType").getValue() << "\n";
840  auto moduleParameterLink =
841  module.second.getNode("filterModuleParameterLink");
842  if(!moduleParameterLink.isDisconnected())
843  {
844  auto moduleParameters = moduleParameterLink.getChildren();
845  for(auto& moduleParameter : moduleParameters)
846  {
847  if(!moduleParameter.second
848  .getNode(TableViewColumnInfo::COL_NAME_STATUS)
849  .getValue<bool>())
850  PUSHCOMMENT;
851 
852  auto comment = moduleParameter.second.getNode(
853  TableViewColumnInfo::COL_NAME_COMMENT);
854  OUT << moduleParameter.second.getNode("filterParameterKey")
855  .getValue()
856  << ": "
857  << moduleParameter.second.getNode("filterParameterValue")
858  .getValue()
859  << (comment.isDefaultValue() ? ""
860  : ("\t # " + comment.getValue()))
861  << "\n";
862 
863  if(!moduleParameter.second
864  .getNode(TableViewColumnInfo::COL_NAME_STATUS)
865  .getValue<bool>())
866  POPCOMMENT;
867  }
868  }
869  POPTAB;
870  OUT << "}\n\n"; // end filter module
871 
872  if(!module.second.getNode(TableViewColumnInfo::COL_NAME_STATUS)
873  .getValue<bool>())
874  POPCOMMENT;
875  }
876  POPTAB;
877  OUT << "}\n\n"; // end filter
878  }
879 
880  auto otherParameterLink = physics.getNode("physicsOtherParametersLink");
881  if(!otherParameterLink.isDisconnected())
882  {
884  auto physicsParameters = otherParameterLink.getChildren();
885  for(auto& parameter : physicsParameters)
886  {
887  if(!parameter.second.getNode(TableViewColumnInfo::COL_NAME_STATUS)
888  .getValue<bool>())
889  PUSHCOMMENT;
890 
891  auto comment =
892  parameter.second.getNode(TableViewColumnInfo::COL_NAME_COMMENT);
893  OUT << parameter.second.getNode("physicsParameterKey").getValue() << ": "
894  << parameter.second.getNode("physicsParameterValue").getValue()
895  << (comment.isDefaultValue() ? "" : ("\t # " + comment.getValue()))
896  << "\n";
897 
898  if(!parameter.second.getNode(TableViewColumnInfo::COL_NAME_STATUS)
899  .getValue<bool>())
900  POPCOMMENT;
901  }
902  }
903  POPTAB;
904  OUT << "}\n\n"; // end physics
905  }
906 
907  //--------------------------------------
908  // handle process_name
909  try
910  {
911  OUT << "process_name: "
912  << aggregatorNode.getNode(
913  "ARTDAQGlobalTableForProcessNameLink/processNameForAggregators")
914  << "\n";
915  }
916  catch(...)
917  {
918  __SS__ << "The field "
919  "ARTDAQGlobalTableForProcessNameLink/processNameForAggregators could "
920  "not be accessed. "
921  << "Make sure the link is valid from aggregator '"
922  << aggregatorNode.getValue() << ".'" << __E__;
923  __SS_THROW__;
924  }
925 
926  out.close();
927 }
928 
929 DEFINE_OTS_TABLE(ARTDAQAggregatorTable)