tdaq-develop-2025-02-12
ARTDAQTableBase.cc
1 #include "otsdaq/TablePlugins/ARTDAQTableBase/ARTDAQTableBase.h"
2 
3 #include <fstream> // for std::ofstream
4 #include <iostream> // std::cout
5 #include <typeinfo>
6 
7 #include "otsdaq/Macros/CoutMacros.h"
8 #define TRACE_NAME "ARTDAQTableBase"
9 
10 #include <fhiclcpp/ParameterSet.h>
11 #include <fhiclcpp/detail/print_mode.h>
12 #include <fhiclcpp/intermediate_table.h>
13 #include <fhiclcpp/parse.h>
14 
15 #include "otsdaq/ProgressBar/ProgressBar.h"
16 #include "otsdaq/TablePlugins/XDAQContextTable/XDAQContextTable.h"
17 
18 using namespace ots;
19 
20 #undef __MF_SUBJECT__
21 #define __MF_SUBJECT__ "ARTDAQTableBase"
22 
23 // clang-format off
24 
25 const std::string ARTDAQTableBase::ARTDAQ_FCL_PATH = std::string(__ENV__("USER_DATA")) + "/" + "ARTDAQConfigurations/";
26 
27 const std::string ARTDAQTableBase::ARTDAQ_SUPERVISOR_CLASS = "ots::ARTDAQSupervisor";
28 const std::string ARTDAQTableBase::ARTDAQ_SUPERVISOR_TABLE = "ARTDAQSupervisorTable";
29 
30 const std::string ARTDAQTableBase::ARTDAQ_READER_TABLE = "ARTDAQBoardReaderTable";
31 const std::string ARTDAQTableBase::ARTDAQ_BUILDER_TABLE = "ARTDAQEventBuilderTable";
32 const std::string ARTDAQTableBase::ARTDAQ_LOGGER_TABLE = "ARTDAQDataLoggerTable";
33 const std::string ARTDAQTableBase::ARTDAQ_DISPATCHER_TABLE = "ARTDAQDispatcherTable";
34 const std::string ARTDAQTableBase::ARTDAQ_MONITOR_TABLE = "ARTDAQMonitorTable";
35 const std::string ARTDAQTableBase::ARTDAQ_ROUTER_TABLE = "ARTDAQRoutingManagerTable";
36 
37 const std::string ARTDAQTableBase::ARTDAQ_SUBSYSTEM_TABLE = "ARTDAQSubsystemTable";
38 const std::string ARTDAQTableBase::ARTDAQ_DAQ_TABLE = "ARTDAQDaqTable";
39 const std::string ARTDAQTableBase::ARTDAQ_DAQ_PARAMETER_TABLE = "ARTDAQDaqParameterTable";
40 
41 const std::string ARTDAQTableBase::ARTDAQ_TYPE_TABLE_HOSTNAME = "ExecutionHostname";
42 const std::string ARTDAQTableBase::ARTDAQ_TYPE_TABLE_ALLOWED_PROCESSORS = "AllowedProcessors";
43 const std::string ARTDAQTableBase::ARTDAQ_TYPE_TABLE_SUBSYSTEM_LINK = "SubsystemLink";
44 const std::string ARTDAQTableBase::ARTDAQ_TYPE_TABLE_SUBSYSTEM_LINK_UID = "SubsystemLinkUID";
45 
46 
47 const int ARTDAQTableBase::NULL_SUBSYSTEM_DESTINATION = 0;
48 const std::string ARTDAQTableBase::NULL_SUBSYSTEM_DESTINATION_LABEL = "nullDestinationSubsystem";
49 
50 ARTDAQTableBase::ARTDAQInfo ARTDAQTableBase::info_;
51 
52 ARTDAQTableBase::ColARTDAQSupervisor ARTDAQTableBase::colARTDAQSupervisor_;
53 ARTDAQTableBase::ColARTDAQSubsystem ARTDAQTableBase::colARTDAQSubsystem_;
54 ARTDAQTableBase::ColARTDAQReader ARTDAQTableBase::colARTDAQReader_;
55 ARTDAQTableBase::ColARTDAQNotReader ARTDAQTableBase::colARTDAQNotReader_;
56 ARTDAQTableBase::ColARTDAQDaq ARTDAQTableBase::colARTDAQDaq_;
57 ARTDAQTableBase::ColARTDAQDaqParameter ARTDAQTableBase::colARTDAQDaqParameter_;
58 
61 
62 // clang-format on
63 
64 //==============================================================================
70 ARTDAQTableBase::ARTDAQTableBase(std::string tableName,
71  std::string* accumulatedExceptions /* =0 */)
72  : TableBase(tableName, accumulatedExceptions)
73 {
74  // make directory just in case
75  mkdir((ARTDAQ_FCL_PATH).c_str(), 0755);
76 
77  // December 2021 started seeing an issue where traceTID is found to be cleared to 0
78  // which crashes TRACE if __COUT__ is used in a Table plugin constructor
79  // This check and re-initialization seems to cover up the issue for now.
80  // Why it is cleared to 0 after the constructor sets it to -1 is still unknown.
81  // Note: it seems to only happen on the first alphabetially ARTDAQ Configure Table plugin.
82  if(traceTID == 0)
83  {
84  std::cout << "ARTDAQTableBase Before traceTID=" << traceTID << __E__;
85  char buf[40];
86  traceInit(trace_name(TRACE_NAME, __TRACE_FILE__, buf, sizeof(buf)), 0);
87  std::cout << "ARTDAQTableBase After traceTID=" << traceTID << __E__;
88  __COUT__ << "ARTDAQTableBase TRACE reinit and Constructed." << __E__;
89  }
90 
91 } // end constuctor()
92 
93 //==============================================================================
96 ARTDAQTableBase::ARTDAQTableBase(void) : TableBase("ARTDAQTableBase")
97 {
98  __SS__ << "Should not call void constructor, table type is lost!" << __E__;
99  __SS_THROW__;
100 } // end illegal default constructor()
101 
102 //==============================================================================
103 ARTDAQTableBase::~ARTDAQTableBase(void) {} // end destructor()
104 
105 //==============================================================================
106 const std::string& ARTDAQTableBase::getTypeString(ARTDAQAppType type)
107 {
108  switch(type)
109  {
110  case ARTDAQAppType::EventBuilder:
111  return processTypes_.BUILDER;
112  case ARTDAQAppType::DataLogger:
113  return processTypes_.LOGGER;
114  case ARTDAQAppType::Dispatcher:
115  return processTypes_.DISPATCHER;
116  case ARTDAQAppType::BoardReader:
117  return processTypes_.READER;
118  case ARTDAQAppType::Monitor:
119  return processTypes_.MONITOR;
120  case ARTDAQAppType::RoutingManager:
121  return processTypes_.ROUTER;
122  }
123  // return "UNKNOWN";
124  __SS__ << "Illegal translation attempt for type '" << (unsigned int)type << "'"
125  << __E__;
126  __SS_THROW__;
127 } // end getTypeString()
128 
129 //==============================================================================
130 std::string ARTDAQTableBase::getFHICLFilename(ARTDAQAppType type, const std::string& name)
131 {
132  //__COUT__ << "Type: " << getTypeString(type) << " Name: " << name
133  //<< __E__;
134  std::string filename = ARTDAQ_FCL_PATH + getTypeString(type) + "-";
135  std::string uid = name;
136  for(unsigned int i = 0; i < uid.size(); ++i)
137  if((uid[i] >= 'a' && uid[i] <= 'z') || (uid[i] >= 'A' && uid[i] <= 'Z') ||
138  (uid[i] >= '0' && uid[i] <= '9')) // only allow alpha numeric in file name
139  filename += uid[i];
140 
141  filename += ".fcl";
142 
143  //__COUT__ << "fcl: " << filename << __E__;
144 
145  return filename;
146 } // end getFHICLFilename()
147 
148 //==============================================================================
149 std::string ARTDAQTableBase::getFlatFHICLFilename(ARTDAQAppType type,
150  const std::string& name)
151 {
152  //__COUT__ << "Type: " << getTypeString(type) << " Name: " << name
153  // << __E__;
154  std::string filename = ARTDAQ_FCL_PATH + getTypeString(type) + "-";
155  std::string uid = name;
156  for(unsigned int i = 0; i < uid.size(); ++i)
157  if((uid[i] >= 'a' && uid[i] <= 'z') || (uid[i] >= 'A' && uid[i] <= 'Z') ||
158  (uid[i] >= '0' && uid[i] <= '9')) // only allow alpha numeric in file name
159  filename += uid[i];
160 
161  filename += "_flattened.fcl";
162 
163  //__COUT__ << "fcl: " << filename << __E__;
164 
165  return filename;
166 } // end getFlatFHICLFilename()
167 
168 //==============================================================================
169 void ARTDAQTableBase::flattenFHICL(ARTDAQAppType type, const std::string& name)
170 {
171  std::chrono::steady_clock::time_point startClock = std::chrono::steady_clock::now();
172  //__COUT__ << "flattenFHICL()" << __ENV__("FHICL_FILE_PATH") << __E__;
173 
174  std::string inFile = getFHICLFilename(type, name);
175  std::string outFile = getFlatFHICLFilename(type, name);
176 
177  //__COUTV__(inFile);
178  //__COUTV__(outFile);
179 
180  cet::filepath_lookup_nonabsolute policy("FHICL_FILE_PATH");
181  fhicl::ParameterSet pset;
182 
183  try
184  {
185  TLOG(TLVL_INFO) << "parsing document: " << inFile;
186  // tbl = fhicl::parse_document(inFile, policy);
187  // pset = fhicl::ParameterSet::make(tbl);
188  pset = fhicl::ParameterSet::make(inFile, policy);
189  TLOG(TLVL_TRACE) << "document: " << inFile << " parsed";
190  TLOG(TLVL_TRACE) << "got pset from table:";
191 
192  std::ofstream ofs{outFile};
193  ofs << pset.to_indented_string(
194  0); // , fhicl::detail::print_mode::annotated); // Only really useful for debugging
195  __COUTT__ << name << " Flatten Clock time = "
196  << artdaq::TimeUtils::GetElapsedTime(startClock) << __E__;
197  }
198  catch(cet::exception const& e)
199  {
200  __SS__ << "Failed to parse fhicl: " << e.what() << __E__;
201  __SS_THROW__;
202  }
203 } // end flattenFHICL()
204 
205 //==============================================================================
212 void ARTDAQTableBase::insertParameters(std::ostream& out,
213  std::string& tabStr,
214  std::string& commentStr,
215  ConfigurationTree parameterGroupLink,
216  const std::string& parameterPreamble,
217  bool onlyInsertAtTableParameters /*=false*/,
218  bool includeAtTableParameters /*=false*/)
219 {
220  // skip if link is disconnected
221  if(!parameterGroupLink.isDisconnected())
222  {
224  auto otherParameters = parameterGroupLink.getChildren();
225 
226  std::string key;
227  //__COUTV__(otherParameters.size());
228  for(auto& parameter : otherParameters)
229  {
230  key = parameter.second.getNode(parameterPreamble + "Key").getValue();
231 
232  // handle special keyword @table:: (which imports full tables, usually as
233  // defaults)
234  if(key.find("@table::") != std::string::npos)
235  {
236  // include @table::
237  if(onlyInsertAtTableParameters || includeAtTableParameters)
238  {
239  if(!parameter.second.status())
240  PUSHCOMMENT;
241 
242  OUT << key;
243 
244  // skip connecting : if special keywords found
245  OUT << parameter.second.getNode(parameterPreamble + "Value")
246  .getValue()
247  << "\n";
248 
249  if(!parameter.second.status())
250  POPCOMMENT;
251  }
252  // else skip it
253 
254  continue;
255  }
256  // else NOT @table:: keyword parameter
257 
258  if(onlyInsertAtTableParameters)
259  continue; // skip all other types
260 
261  if(!parameter.second.status())
262  PUSHCOMMENT;
263 
264  OUT << key;
265 
266  // skip connecting : if special keywords found
267  if(key.find("#include") == std::string::npos)
268  OUT << ":";
269  OUT << parameter.second.getNode(parameterPreamble + "Value").getValue()
270  << "\n";
271 
272  if(!parameter.second.status())
273  POPCOMMENT;
274  }
275  }
276  // else
277  // __COUT__ << "No parameters found" << __E__;
278 
279 } // end insertParameters()
280 
281 //==============================================================================
284 std::string ARTDAQTableBase::insertModuleType(std::ostream& out,
285  std::string& tabStr,
286  std::string& commentStr,
287  ConfigurationTree moduleTypeNode)
288 {
289  std::string value = moduleTypeNode.getValue();
290 
291  OUT;
292  if(value.find("@table::") == std::string::npos)
293  out << "module_type: ";
294  out << value << "\n";
295 
296  return value;
297 } // end insertModuleType()
298 
299 //==============================================================================
301 void ARTDAQTableBase::insertMetricsBlock(std::ostream& out,
302  std::string& tabStr,
303  std::string& commentStr,
304  ConfigurationTree daqNode)
305 {
306  OUT << "\n\nmetrics: {\n";
307 
308  PUSHTAB;
309  auto metricsGroup = daqNode.getNode("daqMetricsLink");
310  if(!metricsGroup.isDisconnected())
311  {
312  auto metrics = metricsGroup.getChildren();
313 
314  for(auto& metric : metrics)
315  {
316  if(!metric.second.status())
317  PUSHCOMMENT;
318 
319  OUT << metric.second.getNode("metricKey").getValue() << ": {\n";
320  PUSHTAB;
321 
322  OUT << "metricPluginType: "
323  << metric.second.getNode("metricPluginType").getValue() << "\n";
324  OUT << "level: " << metric.second.getNode("metricLevel").getValue() << "\n";
325 
326  auto metricParametersGroup = metric.second.getNode("metricParametersLink");
327  if(!metricParametersGroup.isDisconnected())
328  {
329  auto metricParameters = metricParametersGroup.getChildren();
330  for(auto& metricParameter : metricParameters)
331  {
332  if(!metricParameter.second.status())
333  PUSHCOMMENT;
334 
335  OUT << metricParameter.second.getNode("metricParameterKey").getValue()
336  << ": "
337  << metricParameter.second.getNode("metricParameterValue")
338  .getValue()
339  << "\n";
340 
341  if(!metricParameter.second.status())
342  POPCOMMENT;
343  }
344  }
345  POPTAB;
346  OUT << "}\n\n"; // end metric
347 
348  if(!metric.second.status())
349  POPCOMMENT;
350  }
351  }
352  POPTAB;
353  OUT << "}\n\n"; // end metrics
354 } // end insertMetricsBlock()
355 
356 //==============================================================================
357 void ARTDAQTableBase::outputBoardReaderFHICL(
358  const ConfigurationTree& boardReaderNode,
359  size_t /*maxFragmentSizeBytes */ /* = DEFAULT_MAX_FRAGMENT_SIZE */,
360  size_t routingTimeoutMs /* = DEFAULT_ROUTING_TIMEOUT_MS */,
361  size_t routingRetryCount /* = DEFAULT_ROUTING_RETRY_COUNT */)
362 {
363  /*
364  the file will look something like this:
365 
366  daq: {
367  fragment_receiver: {
368  mpi_sync_interval: 50
369 
370  # CommandableFragmentGenerator Table:
371  fragment_ids: []
372  fragment_id: -99 # Please define only one of these
373 
374  sleep_on_stop_us: 0
375 
376  requests_enabled: false # Whether to set up the socket for listening for
377  trigger messages request_mode: "Ignored" # Possible values are: Ignored, Single,
378  Buffer, Window
379 
380  data_buffer_depth_fragments: 1000
381  data_buffer_depth_mb: 1000
382 
383  request_port: 3001
384  request_address: "227.128.12.26" # Multicast request address
385 
386  request_window_offset: 0 # Request message contains tzero. Window will be from
387  tzero - offset to tzero + width request_window_width: 0 stale_request_timeout:
388  "0xFFFFFFFF" # How long to wait before discarding request messages that are outside
389  the available data request_windows_are_unique: true # If request windows are
390  unique, avoids a copy operation, but the same data point cannot be used for two
391  requests. If this is not anticipated, leave set to "true"
392 
393  separate_data_thread: false # MUST be true for triggers to be applied! If
394  triggering is not desired, but a separate readout thread is, set this to true,
395  triggers_enabled to false and trigger_mode to ignored. separate_monitoring_thread:
396  false # Whether a thread should be started which periodically calls checkHWStatus_,
397  a user-defined function which should be used to check hardware status registers and
398  report to MetricMan. poll_hardware_status: false # Whether checkHWStatus_ will be
399  called, either through the thread or at the start of getNext
400  hardware_poll_interval_us: 1000000 # If hardware monitoring thread is enabled,
401  how often should it call checkHWStatus_
402 
403 
404  # Generated Parameters:
405  generator: ToySimulator
406  fragment_type: TOY1
407  fragment_id: 0
408  board_id: 0
409  starting_fragment_id: 0
410  random_seed: 5780
411  sleep_on_stop_us: 500000
412 
413  # Generator-Specific Table:
414 
415  nADCcounts: 40
416 
417  throttle_usecs: 100000
418 
419  distribution_type: 1
420 
421  timestamp_scale_factor: 1
422 
423 
424  destinations: {
425  d2: { transferPluginType: MPI
426  destination_rank: 2
427  max_fragment_size_bytes: 2097152
428  host_map: [
429  {
430  host: "mu2edaq01.fnal.gov"
431  rank: 0
432  },
433  {
434  host: "mu2edaq01.fnal.gov"
435  rank: 1
436  }]
437  }
438  d3: { transferPluginType: MPI
439  destination_rank: 3
440  max_fragment_size_bytes: 2097152
441  host_map: [
442  {
443  host: "mu2edaq01.fnal.gov"
444  rank: 0
445  },
446  {
447  host: "mu2edaq01.fnal.gov"
448  rank: 1
449  }]
450  }
451 
452  }
453  }
454 
455  metrics: {
456  brFile: {
457  metricPluginType: "file"
458  level: 3
459  fileName: "/tmp/boardreader/br_%UID%_metrics.log"
460  uniquify: true
461  }
462  # ganglia: {
463  # metricPluginType: "ganglia"
464  # level: %{ganglia_level}
465  # reporting_interval: 15.0
466  #
467  # configFile: "/etc/ganglia/gmond.conf"
468  # group: "ARTDAQ"
469  # }
470  # msgfac: {
471  # level: %{mf_level}
472  # metricPluginType: "msgFacility"
473  # output_message_application_name: "ARTDAQ Metric"
474  # output_message_severity: 0
475  # }
476  # graphite: {
477  # level: %{graphite_level}
478  # metricPluginType: "graphite"
479  # host: "localhost"
480  # port: 20030
481  # namespace: "artdaq."
482  # }
483  }
484  }
485 
486  */
487 
488  std::string filename =
489  getFHICLFilename(ARTDAQAppType::BoardReader, boardReaderNode.getValue());
490 
492  // generate xdaq run parameter file
493  std::fstream out;
494 
495  std::string tabStr = "";
496  std::string commentStr = "";
497 
498  out.open(filename, std::fstream::out | std::fstream::trunc);
499  if(out.fail())
500  {
501  __SS__ << "Failed to open ARTDAQ BoardReader fcl file: " << filename << __E__;
502  __SS_THROW__;
503  }
504 
505  //--------------------------------------
506  // header
507  OUT << "###########################################################" << __E__;
508  OUT << "#" << __E__;
509  OUT << "# artdaq reader fcl configuration file produced by otsdaq." << __E__;
510  OUT << "# Creation time: \t" << StringMacros::getTimestampString()
511  << __E__;
512  OUT << "# Original filename: \t" << filename << __E__;
513  OUT << "# otsdaq-ARTDAQ Reader UID:\t" << boardReaderNode.getValue() << __E__;
514  OUT << "#" << __E__;
515  OUT << "###########################################################" << __E__;
516  OUT << "\n\n";
517 
518  // no primary link to table tree for reader node!
519  try
520  {
521  if(boardReaderNode.isDisconnected())
522  {
523  // create empty fcl
524  OUT << "{}\n\n";
525  out.close();
526  return;
527  }
528  }
529  catch(const std::runtime_error&)
530  {
531  //__COUT__ << "Ignoring error, assume this a valid UID node." << __E__;
532  // error is expected here for UIDs.. so just ignore
533  // this check is valuable if source node is a unique-Link node, rather than UID
534  }
535 
536  //--------------------------------------
537  // handle preamble parameters
538  //_COUT__ << "Inserting preamble parameters..." << __E__;
539  insertParameters(out,
540  tabStr,
541  commentStr,
542  boardReaderNode.getNode("preambleParametersLink"),
543  "daqParameter" /*parameterType*/,
544  false /*onlyInsertAtTableParameters*/,
545  true /*includeAtTableParameters*/);
546 
547  //--------------------------------------
548  // handle daq
549  OUT << "daq: {\n";
550 
551  // fragment_receiver
552  PUSHTAB;
553  OUT << "fragment_receiver: {\n";
554 
555  PUSHTAB;
556  {
557  // plugin type and fragment data-type
558  OUT << "generator"
559  << ": " << boardReaderNode.getNode("daqGeneratorPluginType").getValue()
560  << ("\t #daq generator plug-in type") << "\n";
561  OUT << "fragment_type"
562  << ": " << boardReaderNode.getNode("daqGeneratorFragmentType").getValue()
563  << ("\t #generator data fragment type") << "\n\n";
564 
565  // shared and unique parameters
566  auto parametersLink = boardReaderNode.getNode("daqParametersLink");
567  if(!parametersLink.isDisconnected())
568  {
569  auto parameters = parametersLink.getChildren();
570  for(auto& parameter : parameters)
571  {
572  if(!parameter.second.status())
573  PUSHCOMMENT;
574 
575  // __COUT__ <<
576  // parameter.second.getNode("daqParameterKey").getValue() <<
577  // ": " <<
578  // parameter.second.getNode("daqParameterValue").getValue()
579  // <<
580  // "\n";
581 
582  auto comment =
583  parameter.second.getNode(TableViewColumnInfo::COL_NAME_COMMENT);
584  OUT << parameter.second.getNode("daqParameterKey").getValue() << ": "
585  << parameter.second.getNode("daqParameterValue").getValue()
586  << (comment.isDefaultValue() ? "" : ("\t # " + comment.getValue()))
587  << "\n";
588 
589  if(!parameter.second.status())
590  POPCOMMENT;
591  }
592  }
593  OUT << "\n"; // end daq board reader parameters
594  }
595 
596  OUT << "destinations: {\n";
597 
598  OUT << "}\n\n"; // end destinations
599 
600  OUT << "routing_table_config: {\n";
601  PUSHTAB;
602 
603  auto readerSubsystemID = 1;
604  auto readerSubsystemLink = boardReaderNode.getNode("SubsystemLink");
605  if(!readerSubsystemLink.isDisconnected())
606  {
607  readerSubsystemID = getSubsytemId(readerSubsystemLink);
608  }
609  if(info_.subsystems[readerSubsystemID].hasRoutingManager)
610  {
611  OUT << "use_routing_manager: true\n";
612  OUT << "routing_manager_hostname: \""
613  << info_.subsystems[readerSubsystemID].routingManagerHost << "\"\n";
614  OUT << "table_update_port: 0\n";
615  OUT << "table_update_address: \"0.0.0.0\"\n";
616  OUT << "table_update_multicast_interface: \"0.0.0.0\"\n";
617  OUT << "table_acknowledge_port : 0\n";
618  OUT << "routing_timeout_ms: " << routingTimeoutMs << "\n";
619  OUT << "routing_retry_count: " << routingRetryCount << "\n";
620  }
621  else
622  {
623  OUT << "use_routing_manager: false\n";
624  }
625 
626  POPTAB;
627  OUT << "}\n"; // end routing_table_config
628 
629  POPTAB;
630  OUT << "}\n\n"; // end fragment_receiver
631 
632  insertMetricsBlock(OUT, tabStr, commentStr, boardReaderNode);
633 
634  POPTAB;
635  OUT << "}\n\n"; // end daq
636 
637  //--------------------------------------
638  // handle ALL add-on parameters
639  //__COUT__ << "Inserting add-on parameters" << __E__;
640  insertParameters(out,
641  tabStr,
642  commentStr,
643  boardReaderNode.getNode("addOnParametersLink"),
644  "daqParameter" /*parameterType*/,
645  false /*onlyInsertAtTableParameters*/,
646  true /*includeAtTableParameters*/);
647 
648  out.close();
649 } // end outputReaderFHICL()
650 
651 //==============================================================================
655  const ConfigurationTree& receiverNode,
656  ARTDAQAppType appType,
657  size_t /*maxFragmentSizeBytes */ /* = DEFAULT_MAX_FRAGMENT_SIZE */,
658  size_t routingTimeoutMs /* = DEFAULT_ROUTING_TIMEOUT_MS */,
659  size_t routingRetryCount /* = DEFAULT_ROUTING_RETRY_COUNT */)
660 {
661  std::string filename = getFHICLFilename(appType, receiverNode.getValue());
662 
664  // generate xdaq run parameter file
665  std::fstream out;
666 
667  std::string tabStr = "";
668  std::string commentStr = "";
669 
670  out.open(filename, std::fstream::out | std::fstream::trunc);
671  if(out.fail())
672  {
673  __SS__ << "Failed to open ARTDAQ fcl file: " << filename << __E__;
674  __SS_THROW__;
675  }
676 
677  //--------------------------------------
678  // header
679  OUT << "###########################################################" << __E__;
680  OUT << "#" << __E__;
681  OUT << "# artdaq " << getTypeString(appType)
682  << " fcl configuration file produced by otsdaq." << __E__;
683  OUT << "# Creation time: \t" << StringMacros::getTimestampString()
684  << __E__;
685  OUT << "# Original filename: \t" << filename << __E__;
686  OUT << "# otsdaq-ARTDAQ " << getTypeString(appType) << " UID:\t"
687  << receiverNode.getValue() << __E__;
688  OUT << "#" << __E__;
689  OUT << "###########################################################" << __E__;
690  OUT << "\n\n";
691 
692  // no primary link to table tree for data receiver node!
693  try
694  {
695  if(receiverNode.isDisconnected())
696  {
697  // create empty fcl
698  OUT << "{}\n\n";
699  out.close();
700  return;
701  }
702  }
703  catch(const std::runtime_error&)
704  {
705  //__COUT__ << "Ignoring error, assume this a valid UID node." << __E__;
706  // error is expected here for UIDs.. so just ignore
707  // this check is valuable if source node is a unique-Link node, rather than UID
708  }
709 
710  //--------------------------------------
711  // handle preamble parameters
712  //_COUT__ << "Inserting preamble parameters..." << __E__;
713  insertParameters(out,
714  tabStr,
715  commentStr,
716  receiverNode.getNode("preambleParametersLink"),
717  "daqParameter" /*parameterType*/,
718  false /*onlyInsertAtTableParameters*/,
719  true /*includeAtTableParameters*/);
720 
721  //--------------------------------------
722  // handle daq
723  //__COUT__ << "Generating daq block..." << __E__;
724  auto daq = receiverNode.getNode("daqLink");
725  if(!daq.isDisconnected())
726  {
728  OUT << "daq: {\n";
729 
730  PUSHTAB;
731  if(appType == ARTDAQAppType::EventBuilder)
732  {
733  // event_builder
734  OUT << "event_builder: {\n";
735  }
736  else
737  {
738  // both datalogger and dispatcher use aggregator for now
739  OUT << "aggregator: {\n";
740  }
741 
742  PUSHTAB;
743 
744  if(appType == ARTDAQAppType::DataLogger)
745  {
746  OUT << "is_datalogger: true\n";
747  }
748  else if(appType == ARTDAQAppType::Dispatcher)
749  {
750  OUT << "is_dispatcher: true\n";
751  }
752 
753  //--------------------------------------
754  // handle ALL daq parameters
755  //__COUT__ << "Inserting DAQ Parameters..." << __E__;
756  insertParameters(out,
757  tabStr,
758  commentStr,
759  daq.getNode("daqParametersLink"),
760  "daqParameter" /*parameterType*/,
761  false /*onlyInsertAtTableParameters*/,
762  true /*includeAtTableParameters*/);
763 
764  if(appType == ARTDAQAppType::EventBuilder)
765  {
766  OUT << "routing_token_config: {\n";
767  PUSHTAB;
768 
769  auto builderSubsystemID = 1;
770  auto builderSubsystemLink = receiverNode.getNode("SubsystemLink");
771  if(!builderSubsystemLink.isDisconnected())
772  {
773  builderSubsystemID = getSubsytemId(builderSubsystemLink);
774  }
775 
776  if(info_.subsystems[builderSubsystemID].hasRoutingManager)
777  {
778  OUT << "use_routing_manager: true\n";
779  OUT << "routing_manager_hostname: \""
780  << info_.subsystems[builderSubsystemID].routingManagerHost << "\"\n";
781  OUT << "routing_token_port: 0\n";
782  }
783  else
784  {
785  OUT << "use_routing_manager: false\n";
786  }
787  POPTAB;
788  OUT << "}\n"; // end routing_token_config
789  }
790 
791  //__COUT__ << "Adding sources placeholder" << __E__;
792  OUT << "sources: {\n"
793  << "}\n\n"; // end sources
794 
795  POPTAB;
796  OUT << "}\n\n"; // end event builder
797 
798  insertMetricsBlock(OUT, tabStr, commentStr, daq);
799 
800  POPTAB;
801  OUT << "}\n\n"; // end daq
802  }
803 
804  //--------------------------------------
805  // handle art
806  //__COUT__ << "Filling art block..." << __E__;
807  auto art = receiverNode.getNode("artLink");
808  if(!art.isDisconnected())
809  {
810  OUT << "art: {\n";
811 
812  PUSHTAB;
813 
815  tabStr,
816  commentStr,
817  art,
818  receiverNode.getNode("SubsystemLink"),
819  routingTimeoutMs,
820  routingRetryCount);
821 
822  POPTAB;
823  OUT << "}\n\n"; // end art
824  }
825 
826  //--------------------------------------
827  // handle ALL add-on parameters
828  //__COUT__ << "Inserting add-on parameters" << __E__;
829  insertParameters(out,
830  tabStr,
831  commentStr,
832  receiverNode.getNode("addOnParametersLink"),
833  "daqParameter" /*parameterType*/,
834  false /*onlyInsertAtTableParameters*/,
835  true /*includeAtTableParameters*/);
836 
837  //__COUT__ << "outputDataReceiverFHICL DONE" << __E__;
838  out.close();
839 } // end outputDataReceiverFHICL()
840 
841 //==============================================================================
845 {
846  std::string filename =
847  getFHICLFilename(ARTDAQAppType::Monitor, monitorNode.getValue());
848 
850  // generate xdaq run parameter file
851  std::fstream out;
852 
853  std::string tabStr = "";
854  std::string commentStr = "";
855 
856  out.open(filename, std::fstream::out | std::fstream::trunc);
857  if(out.fail())
858  {
859  __SS__ << "Failed to open ARTDAQ fcl file: " << filename << __E__;
860  __SS_THROW__;
861  }
862 
863  //--------------------------------------
864  // header
865  OUT << "###########################################################" << __E__;
866  OUT << "#" << __E__;
867  OUT << "# artdaq " << getTypeString(ARTDAQAppType::Monitor)
868  << " fcl configuration file produced by otsdaq." << __E__;
869  OUT << "# Creation time: \t" << StringMacros::getTimestampString()
870  << __E__;
871  OUT << "# Original filename: \t" << filename << __E__;
872  OUT << "# otsdaq-ARTDAQ " << getTypeString(ARTDAQAppType::Monitor) << " UID:\t"
873  << monitorNode.getValue() << __E__;
874  OUT << "#" << __E__;
875  OUT << "###########################################################" << __E__;
876  OUT << "\n\n";
877 
878  // no primary link to table tree for data receiver node!
879  try
880  {
881  if(monitorNode.isDisconnected())
882  {
883  // create empty fcl
884  OUT << "{}\n\n";
885  out.close();
886  return;
887  }
888  }
889  catch(const std::runtime_error&)
890  {
891  //__COUT__ << "Ignoring error, assume this a valid UID node." << __E__;
892  // error is expected here for UIDs.. so just ignore
893  // this check is valuable if source node is a unique-Link node, rather than UID
894  }
895 
896  //--------------------------------------
897  // handle preamble parameters
898  //_COUT__ << "Inserting preamble parameters..." << __E__;
899  insertParameters(out,
900  tabStr,
901  commentStr,
902  monitorNode.getNode("preambleParametersLink"),
903  "daqParameter" /*parameterType*/,
904  false /*onlyInsertAtTableParameters*/,
905  true /*includeAtTableParameters*/);
906 
907  //--------------------------------------
908  // handle art
909  //__COUT__ << "Filling art block..." << __E__;
910  auto art = monitorNode.getNode("artLink");
911  if(!art.isDisconnected())
912  {
913  insertArtProcessBlock(out, tabStr, commentStr, art);
914  OUT << "services.message: { "
915  << artdaq::generateMessageFacilityConfiguration(
916  mf::GetApplicationName().c_str(), true, false)
917  << "}\n";
918  OUT << "services.message.destinations.file: {type: \"GenFile\" threshold: "
919  "\"INFO\" seperator: \"-\""
920  << " pattern: \"" << monitorNode.getValue() << "-%?H%t-%p.log"
921  << "\""
922  << " timestamp_pattern: \"%Y%m%d%H%M%S\""
923  << " directory: \"" << __ENV__("OTSDAQ_LOG_ROOT") << "/"
924  << monitorNode.getValue() << "\""
925  << " append : false }\n";
926  }
927 
928  auto dispatcherLink = monitorNode.getNode("dispatcherLink");
929  if(!dispatcherLink.isDisconnected())
930  {
931  std::string monitorHost =
932  monitorNode.getNode(ARTDAQTableBase::ARTDAQ_TYPE_TABLE_HOSTNAME)
933  .getValueWithDefault("localhost");
934  std::string dispatcherHost =
935  dispatcherLink.getNode(ARTDAQTableBase::ARTDAQ_TYPE_TABLE_HOSTNAME)
936  .getValueWithDefault("localhost");
937  OUT << "source.dispatcherHost: \"" << dispatcherHost << "\"\n";
938  int dispatcherPort = dispatcherLink.getNode("DispatcherPort").getValue<int>();
939  OUT << "source.dispatcherPort: " << dispatcherPort << "\n";
940  OUT << "source.commanderPluginType: xmlrpc\n";
941 
942  int om_rank = monitorNode.getNode("MonitorID").getValue<int>();
943  int disp_fake_rank =
944  dispatcherLink.getNode("DispatcherID").getValueWithDefault<int>(200);
945 
946  size_t max_fragment_size =
947  monitorNode.getNode("max_fragment_size_words").getValueWithDefault(0x100000);
948  std::string transfer_plugin_type =
949  monitorNode.getNode("transfer_plugin_type").getValueWithDefault("Autodetect");
950 
951  OUT << "TransferPluginConfig: {\n";
952  PUSHTAB;
953  OUT << "transferPluginType: " << transfer_plugin_type << "\n";
954  OUT << "host_map: [{ rank: " << disp_fake_rank << " host: \"" << dispatcherHost
955  << "\"}, { rank: " << om_rank << " host: \"" << monitorHost << "\"}]\n";
956  OUT << "max_fragment_size_words: " << max_fragment_size << "\n";
957  OUT << "source_rank: " << disp_fake_rank << "\n";
958  OUT << "destination_rank: " << om_rank << "\n";
959  OUT << "unique_label: " << monitorNode.getValue() << "_to_"
960  << dispatcherLink.getValue() << "\n";
961  POPTAB;
962  OUT << "}\n";
963  OUT << "source.transfer_plugin: @local::TransferPluginConfig \n";
964  auto dispatcherArt = monitorNode.getNode("dispatcherArtLink");
965  if(!dispatcherArt.isDisconnected())
966  {
967  OUT << "source.dispatcher_config: {\n";
968 
969  PUSHTAB;
970 
971  OUT << "path: " << monitorNode.getNode("dispatcher_path").getValue() << "\n";
972  OUT << "filter_paths: [\n";
973 
974  PUSHTAB;
975 
976  auto filterPathsLink = monitorNode.getNode("filterPathsLink");
977  if(!filterPathsLink.isDisconnected())
978  {
980  auto filterPaths = filterPathsLink.getChildren();
981  bool first = true;
982 
983  //__COUTV__(otherParameters.size());
984  for(auto& filterPath : filterPaths)
985  {
986  if(!first)
987  OUT << ",";
988  OUT << "{ ";
989 
990  if(!filterPath.second.status())
991  PUSHCOMMENT;
992 
993  OUT << "name: " << filterPath.second.getNode("Name").getValue()
994  << " ";
995  OUT << "path: " << filterPath.second.getNode("Path").getValue()
996  << " ";
997 
998  OUT << "}\n";
999  if(!filterPath.second.status())
1000  POPCOMMENT;
1001  first = false;
1002  }
1003  }
1004 
1005  POPTAB;
1006 
1007  OUT << "]\n";
1008  OUT << "unique_label: " << monitorNode.getValue() << "\n";
1009  insertArtProcessBlock(out, tabStr, commentStr, dispatcherArt);
1010 
1011  POPTAB;
1012  OUT << "}\n\n"; // end art
1013  }
1014  }
1015 
1016  //--------------------------------------
1017  // handle ALL add-on parameters
1018  //__COUT__ << "Inserting add-on parameters" << __E__;
1019  insertParameters(out,
1020  tabStr,
1021  commentStr,
1022  monitorNode.getNode("addOnParametersLink"),
1023  "daqParameter" /*parameterType*/,
1024  false /*onlyInsertAtTableParameters*/,
1025  true /*includeAtTableParameters*/);
1026 
1027  //__COUT__ << "outputDataReceiverFHICL DONE" << __E__;
1028  out.close();
1029 } // end outputDataReceiverFHICL()
1030 
1031 //==============================================================================
1035  std::string& tabStr,
1036  std::string& commentStr,
1037  ConfigurationTree art,
1038  ConfigurationTree subsystemLink,
1039  size_t routingTimeoutMs,
1040  size_t routingRetryCount)
1041 {
1042  //--------------------------------------
1043  // handle services
1044  //__COUT__ << "Filling art.services" << __E__;
1045  auto services = art.getNode("servicesLink");
1046  if(!services.isDisconnected())
1047  {
1048  OUT << "services: {\n";
1049 
1050  PUSHTAB;
1051 
1052  //--------------------------------------
1053  // handle services @table:: parameters
1054  insertParameters(out,
1055  tabStr,
1056  commentStr,
1057  services.getNode("ServicesParametersLink"),
1058  "daqParameter" /*parameterType*/,
1059  true /*onlyInsertAtTableParameters*/,
1060  false /*includeAtTableParameters*/);
1061 
1062  OUT << "ArtdaqSharedMemoryServiceInterface: { service_provider: "
1063  "ArtdaqSharedMemoryService \n";
1064 
1065  OUT << "waiting_time: " << services.getNode("sharedMemoryWaitingTime").getValue()
1066  << "\n";
1067  OUT << "resume_after_timeout: "
1068  << (services.getNode("sharedMemoryResumeAfterTimeout").getValue<bool>()
1069  ? "true"
1070  : "false")
1071  << "\n";
1072  OUT << "}\n\n";
1073 
1074  OUT << "ArtdaqFragmentNamingServiceInterface: { service_provider: "
1075  "ArtdaqFragmentNamingService helper_plugin: "
1076  << (services.getNode("fragmentNamingServiceProvider").getValue<std::string>())
1077  << "}\n\n";
1078 
1079  //--------------------------------------
1080  // handle services NOT @table:: parameters
1081  insertParameters(out,
1082  tabStr,
1083  commentStr,
1084  services.getNode("ServicesParametersLink"),
1085  "daqParameter" /*parameterType*/,
1086  false /*onlyInsertAtTableParameters*/,
1087  false /*includeAtTableParameters*/);
1088 
1089  POPTAB;
1090  OUT << "}\n\n"; // end services
1091  }
1092 
1093  //--------------------------------------
1094  // handle outputs
1095  //__COUT__ << "Filling art.outputs" << __E__;
1096  auto outputs = art.getNode("outputsLink");
1097  if(!outputs.isDisconnected())
1098  {
1099  OUT << "outputs: {\n";
1100 
1101  PUSHTAB;
1102 
1103  auto outputPlugins = outputs.getChildren();
1104  for(auto& outputPlugin : outputPlugins)
1105  {
1106  if(!outputPlugin.second.status())
1107  PUSHCOMMENT;
1108 
1109  OUT << outputPlugin.second.getNode("outputKey").getValue() << ": {\n";
1110  PUSHTAB;
1111 
1112  std::string moduleType = insertModuleType(
1113  out, tabStr, commentStr, outputPlugin.second.getNode("outputModuleType"));
1114 
1115  //--------------------------------------
1116  // handle ALL output parameters
1117  insertParameters(out,
1118  tabStr,
1119  commentStr,
1120  outputPlugin.second.getNode("outputModuleParameterLink"),
1121  "outputParameter" /*parameterType*/,
1122  false /*onlyInsertAtTableParameters*/,
1123  true /*includeAtTableParameters*/);
1124 
1125  if(outputPlugin.second.getNode("outputModuleType").getValue() ==
1126  "BinaryNetOutput" ||
1127  outputPlugin.second.getNode("outputModuleType").getValue() ==
1128  "RootNetOutput")
1129  {
1130  OUT << "destinations: {\n";
1131  OUT << "}\n\n"; // end destinations
1132  OUT << "routing_table_config: {\n";
1133  PUSHTAB;
1134 
1135  auto mySubsystemID = 1;
1136  auto destinationSubsystemID = 1;
1137  if(!subsystemLink.isDisconnected())
1138  {
1139  mySubsystemID = getSubsytemId(subsystemLink);
1140  }
1141  destinationSubsystemID = info_.subsystems[mySubsystemID].destination;
1142  if(info_.subsystems[destinationSubsystemID].hasRoutingManager)
1143  {
1144  OUT << "use_routing_manager: true\n";
1145  OUT << "routing_manager_hostname: \""
1146  << info_.subsystems[destinationSubsystemID].routingManagerHost
1147  << "\"\n";
1148  OUT << "table_update_port: 0\n";
1149  OUT << "table_update_address: \"0.0.0.0\"\n";
1150  OUT << "table_update_multicast_interface: \"0.0.0.0\"\n";
1151  OUT << "table_acknowledge_port : 0\n";
1152  OUT << "routing_timeout_ms: " << routingTimeoutMs << "\n";
1153  OUT << "routing_retry_count: " << routingRetryCount << "\n";
1154  }
1155  else
1156  {
1157  OUT << "use_routing_manager: false\n";
1158  }
1159 
1160  if(outputPlugin.second.getNode("outputModuleType").getValue() ==
1161  "RootNetOutput")
1162  {
1163  info_.subsystems[mySubsystemID].eventMode = true;
1164  }
1165 
1166  POPTAB;
1167  OUT << "}\n"; // end routing_table_config
1168  }
1169  if(outputPlugin.second.getNode("outputModuleType").getValue() ==
1170  "TransferOutput" ||
1171  outputPlugin.second.getNode("outputModuleType").getValue() ==
1172  "TransferOutputReliable")
1173  {
1174  OUT << "transfer_plugin: @local::TransferPluginConfig \n";
1175  }
1176 
1177  POPTAB;
1178  OUT << "}\n\n"; // end output module
1179 
1180  if(!outputPlugin.second.status())
1181  POPCOMMENT;
1182  }
1183 
1184  POPTAB;
1185  OUT << "}\n\n"; // end outputs
1186  }
1187 
1188  //--------------------------------------
1189  // handle physics
1190  //__COUT__ << "Filling art.physics" << __E__;
1191  auto physics = art.getNode("physicsLink");
1192  if(!physics.isDisconnected())
1193  {
1195  OUT << "physics: {\n";
1196 
1197  PUSHTAB;
1198 
1199  //--------------------------------------
1200  // handle only @table:: physics parameters
1201  insertParameters(out,
1202  tabStr,
1203  commentStr,
1204  physics.getNode("physicsOtherParametersLink"),
1205  "physicsParameter" /*parameterType*/,
1206  true /*onlyInsertAtTableParameters*/,
1207  false /*includeAtTableParameters*/);
1208 
1209  auto analyzers = physics.getNode("analyzersLink");
1210  if(!analyzers.isDisconnected())
1211  {
1213  OUT << "analyzers: {\n";
1214 
1215  PUSHTAB;
1216 
1217  auto modules = analyzers.getChildren();
1218  for(auto& module : modules)
1219  {
1220  if(!module.second.status())
1221  PUSHCOMMENT;
1222 
1223  //--------------------------------------
1224  // handle only @table:: analyzer parameters
1225  insertParameters(out,
1226  tabStr,
1227  commentStr,
1228  module.second.getNode("analyzerModuleParameterLink"),
1229  "analyzerParameter" /*parameterType*/,
1230  true /*onlyInsertAtTableParameters*/,
1231  false /*includeAtTableParameters*/);
1232 
1233  OUT << module.second.getNode("analyzerKey").getValue() << ": {\n";
1234  PUSHTAB;
1236  out, tabStr, commentStr, module.second.getNode("analyzerModuleType"));
1237 
1238  //--------------------------------------
1239  // handle NOT @table:: producer parameters
1240  insertParameters(out,
1241  tabStr,
1242  commentStr,
1243  module.second.getNode("analyzerModuleParameterLink"),
1244  "analyzerParameter" /*parameterType*/,
1245  false /*onlyInsertAtTableParameters*/,
1246  false /*includeAtTableParameters*/);
1247 
1248  POPTAB;
1249  OUT << "}\n\n"; // end analyzer module
1250 
1251  if(!module.second.status())
1252  POPCOMMENT;
1253  }
1254  POPTAB;
1255  OUT << "}\n\n"; // end analyzer
1256  }
1257 
1258  auto producers = physics.getNode("producersLink");
1259  if(!producers.isDisconnected())
1260  {
1262  OUT << "producers: {\n";
1263 
1264  PUSHTAB;
1265 
1266  auto modules = producers.getChildren();
1267  for(auto& module : modules)
1268  {
1269  if(!module.second.status())
1270  PUSHCOMMENT;
1271 
1272  //--------------------------------------
1273  // handle only @table:: producer parameters
1274  insertParameters(out,
1275  tabStr,
1276  commentStr,
1277  module.second.getNode("producerModuleParameterLink"),
1278  "producerParameter" /*parameterType*/,
1279  true /*onlyInsertAtTableParameters*/,
1280  false /*includeAtTableParameters*/);
1281 
1282  if(module.second.status() &&
1283  module.second.getNode("producerModuleType").getValue() == "")
1284  continue;
1285  OUT << module.second.getNode("producerKey").getValue() << ": {\n";
1286  PUSHTAB;
1287 
1289  out, tabStr, commentStr, module.second.getNode("producerModuleType"));
1290 
1291  //--------------------------------------
1292  // handle NOT @table:: producer parameters
1293  insertParameters(out,
1294  tabStr,
1295  commentStr,
1296  module.second.getNode("producerModuleParameterLink"),
1297  "producerParameter" /*parameterType*/,
1298  false /*onlyInsertAtTableParameters*/,
1299  false /*includeAtTableParameters*/);
1300 
1301  POPTAB;
1302  OUT << "}\n\n"; // end producer module
1303 
1304  if(!module.second.status())
1305  POPCOMMENT;
1306  }
1307  POPTAB;
1308  OUT << "}\n\n"; // end producer
1309  }
1310 
1311  auto filters = physics.getNode("filtersLink");
1312  if(!filters.isDisconnected())
1313  {
1315  OUT << "filters: {\n";
1316 
1317  PUSHTAB;
1318 
1319  auto modules = filters.getChildren();
1320  for(auto& module : modules)
1321  {
1322  if(!module.second.status())
1323  PUSHCOMMENT;
1324 
1325  //--------------------------------------
1326  // handle only @table:: filter parameters
1327  insertParameters(out,
1328  tabStr,
1329  commentStr,
1330  module.second.getNode("filterModuleParameterLink"),
1331  "filterParameter" /*parameterType*/,
1332  true /*onlyInsertAtTableParameters*/,
1333  false /*includeAtTableParameters*/);
1334  if(module.second.status() &&
1335  module.second.getNode("filterModuleType").getValue() == "")
1336  continue;
1337  OUT << module.second.getNode("filterKey").getValue() << ": {\n";
1338  PUSHTAB;
1339 
1341  out, tabStr, commentStr, module.second.getNode("filterModuleType"));
1342 
1343  //--------------------------------------
1344  // handle NOT @table:: filter parameters
1345  insertParameters(out,
1346  tabStr,
1347  commentStr,
1348  module.second.getNode("filterModuleParameterLink"),
1349  "filterParameter" /*parameterType*/,
1350  false /*onlyInsertAtTableParameters*/,
1351  false /*includeAtTableParameters*/);
1352 
1353  POPTAB;
1354  OUT << "}\n\n"; // end filter module
1355 
1356  if(!module.second.status())
1357  POPCOMMENT;
1358  }
1359  POPTAB;
1360  OUT << "}\n\n"; // end filter
1361  }
1362 
1363  //--------------------------------------
1364  // handle NOT @table:: physics parameters
1365  insertParameters(out,
1366  tabStr,
1367  commentStr,
1368  physics.getNode("physicsOtherParametersLink"),
1369  "physicsParameter" /*parameterType*/,
1370  false /*onlyInsertAtTableParameters*/,
1371  false /*includeAtTableParameters*/);
1372 
1373  POPTAB;
1374  OUT << "}\n\n"; // end physics
1375  }
1376 
1377  //--------------------------------------
1378  // handle source
1379  //__COUT__ << "Filling art.source" << __E__;
1380  auto source = art.getNode("sourceLink");
1381  if(!source.isDisconnected())
1382  {
1383  OUT << "source: {\n";
1384  PUSHTAB;
1385  insertModuleType(out, tabStr, commentStr, source.getNode("sourceModuleType"));
1386  POPTAB;
1387  OUT << "}\n\n"; // end source
1388  }
1389  else
1390  {
1391  OUT << "source: {\n";
1392  PUSHTAB;
1393  OUT << "module_type: ArtdaqInput";
1394  POPTAB;
1395  OUT << "}\n\n"; // end source
1396  }
1397 
1398  //--------------------------------------
1399  // handle process_name
1400  //__COUT__ << "Writing art.process_name" << __E__;
1401  OUT << "process_name: " << art.getNode("ProcessName") << "\n";
1402 
1403  //--------------------------------------
1404  // handle art @table:: art add on parameters
1405  insertParameters(out,
1406  tabStr,
1407  commentStr,
1408  art.getNode("AddOnParametersLink"),
1409  "artParameter" /*parameterType*/,
1410  false /*onlyInsertAtTableParameters*/,
1411  true /*includeAtTableParameters*/);
1412 
1413 } // end insertArtProcessBlock()
1414 
1415 //==============================================================================
1416 void ARTDAQTableBase::outputRoutingManagerFHICL(
1417  const ConfigurationTree& routingManagerNode,
1418  size_t routingTimeoutMs /* = DEFAULT_ROUTING_TIMEOUT_MS */,
1419  size_t routingRetryCount /* = DEFAULT_ROUTING_RETRY_COUNT */)
1420 {
1421  std::string filename =
1422  getFHICLFilename(ARTDAQAppType::RoutingManager, routingManagerNode.getValue());
1423 
1425  // generate xdaq run parameter file
1426  std::fstream out;
1427 
1428  std::string tabStr = "";
1429  std::string commentStr = "";
1430 
1431  out.open(filename, std::fstream::out | std::fstream::trunc);
1432  if(out.fail())
1433  {
1434  __SS__ << "Failed to open ARTDAQ RoutingManager fcl file: " << filename << __E__;
1435  __SS_THROW__;
1436  }
1437 
1438  //--------------------------------------
1439  // header
1440  OUT << "###########################################################" << __E__;
1441  OUT << "#" << __E__;
1442  OUT << "# artdaq routingManager fcl configuration file produced by otsdaq." << __E__;
1443  OUT << "# Creation time: \t" << StringMacros::getTimestampString()
1444  << __E__;
1445  OUT << "# Original filename: \t" << filename << __E__;
1446  OUT << "# otsdaq-ARTDAQ RoutingManager UID:\t" << routingManagerNode.getValue()
1447  << __E__;
1448  OUT << "#" << __E__;
1449  OUT << "###########################################################" << __E__;
1450  OUT << "\n\n";
1451 
1452  // no primary link to table tree for reader node!
1453  try
1454  {
1455  if(routingManagerNode.isDisconnected())
1456  {
1457  // create empty fcl
1458  OUT << "{}\n\n";
1459  out.close();
1460  return;
1461  }
1462  }
1463  catch(const std::runtime_error&)
1464  {
1465  //__COUT__ << "Ignoring error, assume this a valid UID node." << __E__;
1466  // error is expected here for UIDs.. so just ignore
1467  // this check is valuable if source node is a unique-Link node, rather than UID
1468  }
1469 
1470  //--------------------------------------
1471  // handle daq
1472  OUT << "daq: {\n";
1473  PUSHTAB;
1474 
1475  OUT << "policy: {\n";
1476  PUSHTAB;
1477  auto policyName = routingManagerNode.getNode("routingPolicyPluginType").getValue();
1478  if(policyName == "DEFAULT")
1479  policyName = "NoOp";
1480  OUT << "policy: " << policyName << "\n";
1481  OUT << "receiver_ranks: []\n";
1482 
1483  // shared and unique parameters
1484  auto parametersLink = routingManagerNode.getNode("routingPolicyParametersLink");
1485  if(!parametersLink.isDisconnected())
1486  {
1487  auto parameters = parametersLink.getChildren();
1488  for(auto& parameter : parameters)
1489  {
1490  if(!parameter.second.status())
1491  PUSHCOMMENT;
1492 
1493  // __COUT__ <<
1494  // parameter.second.getNode("daqParameterKey").getValue() <<
1495  // ": " <<
1496  // parameter.second.getNode("daqParameterValue").getValue()
1497  // <<
1498  // "\n";
1499 
1500  auto comment =
1501  parameter.second.getNode(TableViewColumnInfo::COL_NAME_COMMENT);
1502  OUT << parameter.second.getNode("daqParameterKey").getValue() << ": "
1503  << parameter.second.getNode("daqParameterValue").getValue()
1504  << (comment.isDefaultValue() ? "" : ("\t # " + comment.getValue()))
1505  << "\n";
1506 
1507  if(!parameter.second.status())
1508  POPCOMMENT;
1509  }
1510  }
1511 
1512  POPTAB;
1513  OUT << "}\n";
1514 
1515  OUT << "use_routing_manager: true\n";
1516 
1517  auto routingManagerSubsystemID = 1;
1518  auto routingManagerSubsystemLink = routingManagerNode.getNode("SubsystemLink");
1519  std::string rmHost = "localhost";
1520  if(!routingManagerSubsystemLink.isDisconnected())
1521  {
1522  routingManagerSubsystemID = getSubsytemId(routingManagerSubsystemLink);
1523  rmHost = info_.subsystems[routingManagerSubsystemID].routingManagerHost;
1524  }
1525  if(rmHost == "localhost" || rmHost == "127.0.0.1")
1526  {
1527  char hostbuf[HOST_NAME_MAX + 1];
1528  gethostname(hostbuf, HOST_NAME_MAX);
1529  rmHost = std::string(hostbuf);
1530  }
1531 
1532  // Bookkept parameters
1533  OUT << "routing_manager_hostname: \"" << rmHost << "\"\n";
1534  OUT << "sender_ranks: []\n";
1535  OUT << "table_update_port: 0\n";
1536  OUT << "table_update_address: \"0.0.0.0\"\n";
1537  OUT << "table_acknowledge_port: 0\n";
1538  OUT << "token_receiver: {\n";
1539  PUSHTAB;
1540 
1541  OUT << "routing_token_port: 0\n";
1542 
1543  POPTAB;
1544  OUT << "}\n";
1545 
1546  // Optional parameters
1547  auto tableUpdateIntervalMs =
1548  routingManagerNode.getNode("tableUpdateIntervalMs").getValue();
1549  if(tableUpdateIntervalMs != "DEFAULT")
1550  {
1551  OUT << "table_update_interval_ms: " << tableUpdateIntervalMs << "\n";
1552  }
1553  auto tableAckRetryCount = routingManagerNode.getNode("tableAckRetryCount").getValue();
1554  if(tableAckRetryCount != "DEFAULT")
1555  {
1556  OUT << "table_ack_retry_count: " << tableAckRetryCount << "\n";
1557  }
1558 
1559  OUT << "routing_timeout_ms: " << routingTimeoutMs << "\n";
1560  OUT << "routing_retry_count: " << routingRetryCount << "\n";
1561 
1562  insertMetricsBlock(OUT, tabStr, commentStr, routingManagerNode);
1563 
1564  POPTAB;
1565  OUT << "}\n\n"; // end daq
1566 
1567  out.close();
1568 } // end outputReaderFHICL()
1569 
1570 //==============================================================================
1571 const ARTDAQTableBase::ARTDAQInfo& ARTDAQTableBase::extractARTDAQInfo(
1572  ConfigurationTree artdaqSupervisorNode,
1573  bool getStatusFalseNodes /* = false */,
1574  bool doWriteFHiCL /* = false */,
1575  size_t maxFragmentSizeBytes /* = DEFAULT_MAX_FRAGMENT_SIZE*/,
1576  size_t routingTimeoutMs /* = DEFAULT_ROUTING_TIMEOUT_MS */,
1577  size_t routingRetryCount /* = DEFAULT_ROUTING_RETRY_COUNT */,
1578  ProgressBar* progressBar /* = 0 */)
1579 {
1580  if(progressBar)
1581  progressBar->step();
1582 
1583  // reset info every time, because it could be called after configuration manipulations
1584  info_.subsystems.clear();
1585  info_.processes.clear();
1586 
1587  if(progressBar)
1588  progressBar->step();
1589 
1590  info_.subsystems[NULL_SUBSYSTEM_DESTINATION].id = NULL_SUBSYSTEM_DESTINATION;
1591  info_.subsystems[NULL_SUBSYSTEM_DESTINATION].label = NULL_SUBSYSTEM_DESTINATION_LABEL;
1592 
1593  // if no supervisor, then done
1594  if(artdaqSupervisorNode.isDisconnected())
1595  return info_;
1596 
1597  // We do RoutingManagers first so we can properly fill in routing tables later
1598  extractRoutingManagersInfo(artdaqSupervisorNode,
1599  getStatusFalseNodes,
1600  doWriteFHiCL,
1601  routingTimeoutMs,
1602  routingRetryCount);
1603 
1604  if(progressBar)
1605  progressBar->step();
1606 
1607  extractBoardReadersInfo(artdaqSupervisorNode,
1608  getStatusFalseNodes,
1609  doWriteFHiCL,
1610  maxFragmentSizeBytes,
1611  routingTimeoutMs,
1612  routingRetryCount);
1613 
1614  if(progressBar)
1615  progressBar->step();
1616 
1617  extractEventBuildersInfo(
1618  artdaqSupervisorNode, getStatusFalseNodes, doWriteFHiCL, maxFragmentSizeBytes);
1619 
1620  if(progressBar)
1621  progressBar->step();
1622 
1623  extractDataLoggersInfo(
1624  artdaqSupervisorNode, getStatusFalseNodes, doWriteFHiCL, maxFragmentSizeBytes);
1625 
1626  if(progressBar)
1627  progressBar->step();
1628 
1629  extractDispatchersInfo(
1630  artdaqSupervisorNode, getStatusFalseNodes, doWriteFHiCL, maxFragmentSizeBytes);
1631 
1632  if(progressBar)
1633  progressBar->step();
1634 
1635  return info_;
1636 } // end extractARTDAQInfo()
1637 
1638 //==============================================================================
1639 void ARTDAQTableBase::extractRoutingManagersInfo(ConfigurationTree artdaqSupervisorNode,
1640  bool getStatusFalseNodes,
1641  bool doWriteFHiCL,
1642  size_t routingTimeoutMs,
1643  size_t routingRetryCount)
1644 {
1645  __COUT__ << "Checking for Routing Managers..." << __E__;
1646  ConfigurationTree rmsLink =
1647  artdaqSupervisorNode.getNode(colARTDAQSupervisor_.colLinkToRoutingManagers_);
1648  if(!rmsLink.isDisconnected() && rmsLink.getChildren().size() > 0)
1649  {
1650  std::vector<std::pair<std::string, ConfigurationTree>> routingManagers =
1651  rmsLink.getChildren();
1652 
1653  __COUT__ << "There are " << routingManagers.size()
1654  << " configured Routing Managers" << __E__;
1655 
1656  for(auto& routingManager : routingManagers)
1657  {
1658  const std::string& rmUID = routingManager.first;
1659 
1660  if(getStatusFalseNodes || routingManager.second.status())
1661  {
1662  std::string rmHost =
1663  routingManager.second
1664  .getNode(ARTDAQTableBase::ARTDAQ_TYPE_TABLE_HOSTNAME)
1665  .getValueWithDefault("localhost");
1666  if(rmHost == "localhost" || rmHost == "127.0.0.1")
1667  {
1668  char hostbuf[HOST_NAME_MAX + 1];
1669  gethostname(hostbuf, HOST_NAME_MAX);
1670  rmHost = std::string(hostbuf);
1671  }
1672 
1673  std::string rmAP =
1674  routingManager.second
1675  .getNode(ARTDAQTableBase::ARTDAQ_TYPE_TABLE_ALLOWED_PROCESSORS)
1676  .getValueWithDefault("");
1677 
1678  int routingManagerSubsystemID = 1;
1679  ConfigurationTree routingManagerSubsystemLink =
1680  routingManager.second.getNode(
1681  ARTDAQTableBase::ARTDAQ_TYPE_TABLE_SUBSYSTEM_LINK);
1682  if(!routingManagerSubsystemLink.isDisconnected())
1683  {
1684  routingManagerSubsystemID =
1685  getSubsytemId(routingManagerSubsystemLink);
1686 
1687  //__COUTV__(routingManagerSubsystemID);
1688  info_.subsystems[routingManagerSubsystemID].id =
1689  routingManagerSubsystemID;
1690 
1691  const std::string& routingManagerSubsystemName =
1692  routingManagerSubsystemLink.getUIDAsString();
1693  //__COUTV__(routingManagerSubsystemName);
1694 
1695  info_.subsystems[routingManagerSubsystemID].label =
1696  routingManagerSubsystemName;
1697 
1698  if(info_.subsystems[routingManagerSubsystemID].hasRoutingManager)
1699  {
1700  __SS__ << "Error: You cannot have multiple Routing Managers in a "
1701  "subsystem!";
1702  __SS_THROW__;
1703  return;
1704  }
1705 
1706  auto routingManagerSubsystemDestinationLink =
1707  routingManagerSubsystemLink.getNode(
1708  colARTDAQSubsystem_.colLinkToDestination_);
1709  if(routingManagerSubsystemDestinationLink.isDisconnected())
1710  {
1711  // default to no destination when no link
1712  info_.subsystems[routingManagerSubsystemID].destination = 0;
1713  }
1714  else
1715  {
1716  // get destination subsystem id
1717  info_.subsystems[routingManagerSubsystemID].destination =
1718  getSubsytemId(routingManagerSubsystemDestinationLink);
1719  }
1720  //__COUTV__(info_.subsystems[routingManagerSubsystemID].destination);
1721 
1722  // add this subsystem to destination subsystem's sources, if not
1723  // there
1724  if(!info_.subsystems.count(
1725  info_.subsystems[routingManagerSubsystemID].destination) ||
1726  !info_
1727  .subsystems[info_.subsystems[routingManagerSubsystemID]
1728  .destination]
1729  .sources.count(routingManagerSubsystemID))
1730  {
1731  info_
1732  .subsystems[info_.subsystems[routingManagerSubsystemID]
1733  .destination]
1734  .sources.insert(routingManagerSubsystemID);
1735  }
1736 
1737  } // end subsystem instantiation
1738 
1739  __COUT__ << "Found Routing Manager with UID " << rmUID
1740  << ", DAQInterface Hostname " << rmHost << ", and Subsystem "
1741  << routingManagerSubsystemID << __E__;
1742  info_.processes[ARTDAQAppType::RoutingManager].emplace_back(
1743  rmUID,
1744  rmHost,
1745  rmAP,
1746  routingManagerSubsystemID,
1747  ARTDAQAppType::RoutingManager,
1748  routingManager.second.status());
1749 
1750  info_.subsystems[routingManagerSubsystemID].hasRoutingManager = true;
1751  info_.subsystems[routingManagerSubsystemID].routingManagerHost = rmHost;
1752 
1753  if(doWriteFHiCL)
1754  {
1755  outputRoutingManagerFHICL(
1756  routingManager.second, routingTimeoutMs, routingRetryCount);
1757 
1758  flattenFHICL(ARTDAQAppType::RoutingManager,
1759  routingManager.second.getValue());
1760  }
1761  }
1762  else // disabled
1763  {
1764  __COUT__ << "Routing Manager " << rmUID << " is disabled." << __E__;
1765  }
1766  } // end routing manager loop
1767  }
1768 } // end extractRoutingManagersInfo()
1769 
1770 //==============================================================================
1771 void ARTDAQTableBase::extractBoardReadersInfo(ConfigurationTree artdaqSupervisorNode,
1772  bool getStatusFalseNodes,
1773  bool doWriteFHiCL,
1774  size_t maxFragmentSizeBytes,
1775  size_t routingTimeoutMs,
1776  size_t routingRetryCount)
1777 {
1778  __COUT__ << "Checking for Board Readers..." << __E__;
1779  ConfigurationTree readersLink =
1780  artdaqSupervisorNode.getNode(colARTDAQSupervisor_.colLinkToBoardReaders_);
1781  if(!readersLink.isDisconnected() && readersLink.getChildren().size() > 0)
1782  {
1783  std::vector<std::pair<std::string, ConfigurationTree>> readers =
1784  readersLink.getChildren();
1785  __COUT__ << "There are " << readers.size() << " configured Board Readers."
1786  << __E__;
1787 
1788  for(auto& reader : readers)
1789  {
1790  const std::string& readerUID = reader.first;
1791 
1792  if(getStatusFalseNodes || reader.second.status())
1793  {
1794  std::string readerHost =
1795  reader.second.getNode(ARTDAQTableBase::ARTDAQ_TYPE_TABLE_HOSTNAME)
1796  .getValueWithDefault("localhost");
1797  std::string readerAP =
1798  reader.second
1799  .getNode(ARTDAQTableBase::ARTDAQ_TYPE_TABLE_ALLOWED_PROCESSORS)
1800  .getValueWithDefault("");
1801 
1802  int readerSubsystemID = 1;
1803  ConfigurationTree readerSubsystemLink =
1804  reader.second.getNode(ARTDAQ_TYPE_TABLE_SUBSYSTEM_LINK);
1805  if(!readerSubsystemLink.isDisconnected())
1806  {
1807  readerSubsystemID = getSubsytemId(readerSubsystemLink);
1808  //__COUTV__(readerSubsystemID);
1809  info_.subsystems[readerSubsystemID].id = readerSubsystemID;
1810 
1811  const std::string& readerSubsystemName =
1812  readerSubsystemLink.getUIDAsString();
1813  //__COUTV__(readerSubsystemName);
1814 
1815  info_.subsystems[readerSubsystemID].label = readerSubsystemName;
1816 
1817  auto readerSubsystemDestinationLink = readerSubsystemLink.getNode(
1818  colARTDAQSubsystem_.colLinkToDestination_);
1819  if(readerSubsystemDestinationLink.isDisconnected())
1820  {
1821  // default to no destination when no link
1822  info_.subsystems[readerSubsystemID].destination = 0;
1823  }
1824  else
1825  {
1826  // get destination subsystem id
1827  info_.subsystems[readerSubsystemID].destination =
1828  getSubsytemId(readerSubsystemDestinationLink);
1829  }
1830  //__COUTV__(info_.subsystems[readerSubsystemID].destination);
1831 
1832  // add this subsystem to destination subsystem's sources, if not
1833  // there
1834  if(!info_.subsystems.count(
1835  info_.subsystems[readerSubsystemID].destination) ||
1836  !info_.subsystems[info_.subsystems[readerSubsystemID].destination]
1837  .sources.count(readerSubsystemID))
1838  {
1839  info_.subsystems[info_.subsystems[readerSubsystemID].destination]
1840  .sources.insert(readerSubsystemID);
1841  }
1842 
1843  } // end subsystem instantiation
1844 
1845  __COUT__ << "Found Board Reader with UID " << readerUID
1846  << ", DAQInterface Hostname " << readerHost << ", and Subsystem "
1847  << readerSubsystemID << __E__;
1848  info_.processes[ARTDAQAppType::BoardReader].emplace_back(
1849  readerUID,
1850  readerHost,
1851  readerAP,
1852  readerSubsystemID,
1853  ARTDAQAppType::BoardReader,
1854  reader.second.status());
1855 
1856  if(doWriteFHiCL)
1857  {
1858  outputBoardReaderFHICL(reader.second,
1859  maxFragmentSizeBytes,
1860  routingTimeoutMs,
1861  routingRetryCount);
1862 
1863  flattenFHICL(ARTDAQAppType::BoardReader, reader.second.getValue());
1864  }
1865  }
1866  else // disabled
1867  {
1868  __COUT__ << "Board Reader " << readerUID << " is disabled." << __E__;
1869  }
1870  } // end reader loop
1871  }
1872  else
1873  {
1874  __COUT_WARN__ << "There should be at least one Board Reader!";
1875  //__SS_THROW__;
1876  // return;
1877  }
1878 } // end extractBoardReadersInfo()
1879 
1880 //==============================================================================
1881 void ARTDAQTableBase::extractEventBuildersInfo(ConfigurationTree artdaqSupervisorNode,
1882  bool getStatusFalseNodes,
1883  bool doWriteFHiCL,
1884  size_t maxFragmentSizeBytes)
1885 {
1886  __COUT__ << "Checking for Event Builders..." << __E__;
1887  ConfigurationTree buildersLink =
1888  artdaqSupervisorNode.getNode(colARTDAQSupervisor_.colLinkToEventBuilders_);
1889  if(!buildersLink.isDisconnected() && buildersLink.getChildren().size() > 0)
1890  {
1891  std::vector<std::pair<std::string, ConfigurationTree>> builders =
1892  buildersLink.getChildren();
1893 
1894  for(auto& builder : builders)
1895  {
1896  const std::string& builderUID = builder.first;
1897 
1898  if(getStatusFalseNodes || builder.second.status())
1899  {
1900  std::string builderHost =
1901  builder.second.getNode(ARTDAQTableBase::ARTDAQ_TYPE_TABLE_HOSTNAME)
1902  .getValueWithDefault("localhost");
1903  std::string builderAP =
1904  builder.second
1905  .getNode(ARTDAQTableBase::ARTDAQ_TYPE_TABLE_ALLOWED_PROCESSORS)
1906  .getValueWithDefault("");
1907 
1908  int builderSubsystemID = 1;
1909  ConfigurationTree builderSubsystemLink =
1910  builder.second.getNode(ARTDAQ_TYPE_TABLE_SUBSYSTEM_LINK);
1911  if(!builderSubsystemLink.isDisconnected())
1912  {
1913  builderSubsystemID = getSubsytemId(builderSubsystemLink);
1914  //__COUTV__(builderSubsystemID);
1915 
1916  info_.subsystems[builderSubsystemID].id = builderSubsystemID;
1917 
1918  const std::string& builderSubsystemName =
1919  builderSubsystemLink.getUIDAsString();
1920  //__COUTV__(builderSubsystemName);
1921 
1922  info_.subsystems[builderSubsystemID].label = builderSubsystemName;
1923 
1924  auto builderSubsystemDestinationLink = builderSubsystemLink.getNode(
1925  colARTDAQSubsystem_.colLinkToDestination_);
1926  if(builderSubsystemDestinationLink.isDisconnected())
1927  {
1928  // default to no destination when no link
1929  info_.subsystems[builderSubsystemID].destination = 0;
1930  }
1931  else
1932  {
1933  // get destination subsystem id
1934  info_.subsystems[builderSubsystemID].destination =
1935  getSubsytemId(builderSubsystemDestinationLink);
1936  }
1937  //__COUTV__(info_.subsystems[builderSubsystemID].destination);
1938 
1939  // add this subsystem to destination subsystem's sources, if not
1940  // there
1941  if(!info_.subsystems.count(
1942  info_.subsystems[builderSubsystemID].destination) ||
1943  !info_.subsystems[info_.subsystems[builderSubsystemID].destination]
1944  .sources.count(builderSubsystemID))
1945  {
1946  info_.subsystems[info_.subsystems[builderSubsystemID].destination]
1947  .sources.insert(builderSubsystemID);
1948  }
1949 
1950  } // end subsystem instantiation
1951 
1952  __COUT__ << "Found Event Builder with UID " << builderUID
1953  << ", on Hostname " << builderHost << ", in Subsystem "
1954  << builderSubsystemID << __E__;
1955  info_.processes[ARTDAQAppType::EventBuilder].emplace_back(
1956  builderUID,
1957  builderHost,
1958  builderAP,
1959  builderSubsystemID,
1960  ARTDAQAppType::EventBuilder,
1961  builder.second.status());
1962 
1963  if(doWriteFHiCL)
1964  {
1965  outputDataReceiverFHICL(builder.second,
1966  ARTDAQAppType::EventBuilder,
1967  maxFragmentSizeBytes);
1968 
1969  flattenFHICL(ARTDAQAppType::EventBuilder, builder.second.getValue());
1970  }
1971  }
1972  else // disabled
1973  {
1974  __COUT__ << "Event Builder " << builderUID << " is disabled." << __E__;
1975  }
1976  } // end builder loop
1977  }
1978  else
1979  {
1980  __COUT_WARN__ << "There should be at least one Event Builder!";
1981  //__SS_THROW__;
1982  // return;
1983  }
1984 } // end extractEventBuildersInfo()
1985 
1986 //==============================================================================
1987 void ARTDAQTableBase::extractDataLoggersInfo(ConfigurationTree artdaqSupervisorNode,
1988  bool getStatusFalseNodes,
1989  bool doWriteFHiCL,
1990  size_t maxFragmentSizeBytes)
1991 {
1992  __COUT__ << "Checking for Data Loggers..." << __E__;
1993  ConfigurationTree dataloggersLink =
1994  artdaqSupervisorNode.getNode(colARTDAQSupervisor_.colLinkToDataLoggers_);
1995  if(!dataloggersLink.isDisconnected())
1996  {
1997  std::vector<std::pair<std::string, ConfigurationTree>> dataloggers =
1998  dataloggersLink.getChildren();
1999 
2000  for(auto& datalogger : dataloggers)
2001  {
2002  const std::string& loggerUID = datalogger.first;
2003 
2004  if(getStatusFalseNodes || datalogger.second.status())
2005  {
2006  std::string loggerHost =
2007  datalogger.second.getNode(ARTDAQTableBase::ARTDAQ_TYPE_TABLE_HOSTNAME)
2008  .getValueWithDefault("localhost");
2009  std::string loggerAP =
2010  datalogger.second
2011  .getNode(ARTDAQTableBase::ARTDAQ_TYPE_TABLE_ALLOWED_PROCESSORS)
2012  .getValueWithDefault("");
2013 
2014  int loggerSubsystemID = 1;
2015  ConfigurationTree loggerSubsystemLink =
2016  datalogger.second.getNode(ARTDAQ_TYPE_TABLE_SUBSYSTEM_LINK);
2017  if(!loggerSubsystemLink.isDisconnected())
2018  {
2019  loggerSubsystemID = getSubsytemId(loggerSubsystemLink);
2020  //__COUTV__(loggerSubsystemID);
2021  info_.subsystems[loggerSubsystemID].id = loggerSubsystemID;
2022 
2023  const std::string& loggerSubsystemName =
2024  loggerSubsystemLink.getUIDAsString();
2025  //__COUTV__(loggerSubsystemName);
2026 
2027  info_.subsystems[loggerSubsystemID].label = loggerSubsystemName;
2028 
2029  auto loggerSubsystemDestinationLink = loggerSubsystemLink.getNode(
2030  colARTDAQSubsystem_.colLinkToDestination_);
2031  if(loggerSubsystemDestinationLink.isDisconnected())
2032  {
2033  // default to no destination when no link
2034  info_.subsystems[loggerSubsystemID].destination = 0;
2035  }
2036  else
2037  {
2038  // get destination subsystem id
2039  info_.subsystems[loggerSubsystemID].destination =
2040  getSubsytemId(loggerSubsystemDestinationLink);
2041  }
2042  //__COUTV__(info_.subsystems[loggerSubsystemID].destination);
2043 
2044  // add this subsystem to destination subsystem's sources, if not
2045  // there
2046  if(!info_.subsystems.count(
2047  info_.subsystems[loggerSubsystemID].destination) ||
2048  !info_.subsystems[info_.subsystems[loggerSubsystemID].destination]
2049  .sources.count(loggerSubsystemID))
2050  {
2051  info_.subsystems[info_.subsystems[loggerSubsystemID].destination]
2052  .sources.insert(loggerSubsystemID);
2053  }
2054 
2055  } // end subsystem instantiation
2056 
2057  __COUT__ << "Found Data Logger with UID " << loggerUID
2058  << ", DAQInterface Hostname " << loggerHost << ", and Subsystem "
2059  << loggerSubsystemID << __E__;
2060  info_.processes[ARTDAQAppType::DataLogger].emplace_back(
2061  loggerUID,
2062  loggerHost,
2063  loggerAP,
2064  loggerSubsystemID,
2065  ARTDAQAppType::DataLogger,
2066  datalogger.second.status());
2067 
2068  if(doWriteFHiCL)
2069  {
2070  outputDataReceiverFHICL(datalogger.second,
2071  ARTDAQAppType::DataLogger,
2072  maxFragmentSizeBytes);
2073 
2074  flattenFHICL(ARTDAQAppType::DataLogger, datalogger.second.getValue());
2075  }
2076  }
2077  else // disabled
2078  {
2079  __COUT__ << "Data Logger " << loggerUID << " is disabled." << __E__;
2080  }
2081  } // end logger loop
2082  }
2083  else
2084  {
2085  __COUT_WARN__ << "There were no Data Loggers found!";
2086  }
2087 } // end extractDataLoggersInfo()
2088 
2089 //==============================================================================
2090 void ARTDAQTableBase::extractDispatchersInfo(ConfigurationTree artdaqSupervisorNode,
2091  bool getStatusFalseNodes,
2092  bool doWriteFHiCL,
2093  size_t maxFragmentSizeBytes)
2094 {
2095  __COUT__ << "Checking for Dispatchers..." << __E__;
2096  ConfigurationTree dispatchersLink =
2097  artdaqSupervisorNode.getNode(colARTDAQSupervisor_.colLinkToDispatchers_);
2098  if(!dispatchersLink.isDisconnected())
2099  {
2100  std::vector<std::pair<std::string, ConfigurationTree>> dispatchers =
2101  dispatchersLink.getChildren();
2102 
2103  for(auto& dispatcher : dispatchers)
2104  {
2105  const std::string& dispatcherUID = dispatcher.first;
2106 
2107  if(getStatusFalseNodes || dispatcher.second.status())
2108  {
2109  std::string dispatcherHost =
2110  dispatcher.second.getNode(ARTDAQTableBase::ARTDAQ_TYPE_TABLE_HOSTNAME)
2111  .getValueWithDefault("localhost");
2112  std::string dispatcherAP =
2113  dispatcher.second
2114  .getNode(ARTDAQTableBase::ARTDAQ_TYPE_TABLE_ALLOWED_PROCESSORS)
2115  .getValueWithDefault("");
2116  int dispatcherPort =
2117  dispatcher.second.getNode("DispatcherPort").getValue<int>();
2118 
2119  auto dispatcherSubsystemID = 1;
2120  ConfigurationTree dispatcherSubsystemLink =
2121  dispatcher.second.getNode(ARTDAQ_TYPE_TABLE_SUBSYSTEM_LINK);
2122  if(!dispatcherSubsystemLink.isDisconnected())
2123  {
2124  dispatcherSubsystemID = getSubsytemId(dispatcherSubsystemLink);
2125  //__COUTV__(dispatcherSubsystemID);
2126  info_.subsystems[dispatcherSubsystemID].id = dispatcherSubsystemID;
2127 
2128  const std::string& dispatcherSubsystemName =
2129  dispatcherSubsystemLink.getUIDAsString();
2130  //__COUTV__(dispatcherSubsystemName);
2131 
2132  info_.subsystems[dispatcherSubsystemID].label =
2133  dispatcherSubsystemName;
2134 
2135  auto dispatcherSubsystemDestinationLink =
2136  dispatcherSubsystemLink.getNode(
2137  colARTDAQSubsystem_.colLinkToDestination_);
2138  if(dispatcherSubsystemDestinationLink.isDisconnected())
2139  {
2140  // default to no destination when no link
2141  info_.subsystems[dispatcherSubsystemID].destination = 0;
2142  }
2143  else
2144  {
2145  // get destination subsystem id
2146  info_.subsystems[dispatcherSubsystemID].destination =
2147  getSubsytemId(dispatcherSubsystemDestinationLink);
2148  }
2149  //__COUTV__(info_.subsystems[dispatcherSubsystemID].destination);
2150 
2151  // add this subsystem to destination subsystem's sources, if not
2152  // there
2153  if(!info_.subsystems.count(
2154  info_.subsystems[dispatcherSubsystemID].destination) ||
2155  !info_
2156  .subsystems[info_.subsystems[dispatcherSubsystemID]
2157  .destination]
2158  .sources.count(dispatcherSubsystemID))
2159  {
2160  info_
2161  .subsystems[info_.subsystems[dispatcherSubsystemID]
2162  .destination]
2163  .sources.insert(dispatcherSubsystemID);
2164  }
2165  }
2166 
2167  __COUT__ << "Found Dispatcher with UID " << dispatcherUID
2168  << ", DAQInterface Hostname " << dispatcherHost
2169  << ", and Subsystem " << dispatcherSubsystemID << __E__;
2170  info_.processes[ARTDAQAppType::Dispatcher].emplace_back(
2171  dispatcherUID,
2172  dispatcherHost,
2173  dispatcherAP,
2174  dispatcherSubsystemID,
2175  ARTDAQAppType::Dispatcher,
2176  dispatcher.second.status(),
2177  dispatcherPort);
2178 
2179  if(doWriteFHiCL)
2180  {
2181  outputDataReceiverFHICL(dispatcher.second,
2182  ARTDAQAppType::Dispatcher,
2183  maxFragmentSizeBytes);
2184 
2185  flattenFHICL(ARTDAQAppType::Dispatcher, dispatcher.second.getValue());
2186  }
2187  }
2188  else // disabled
2189  {
2190  __COUT__ << "Dispatcher " << dispatcherUID << " is disabled." << __E__;
2191  }
2192  } // end dispatcher loop
2193  }
2194  else
2195  {
2196  __COUT_WARN__ << "There were no Dispatchers found!";
2197  }
2198 } // end extractDispatchersInfo()
2199 
2200 //==============================================================================
2203 {
2204  auto contexts =
2205  cfgMgr->getNode(ConfigurationManager::XDAQ_CONTEXT_TABLE_NAME).getChildren();
2206  for(auto context : contexts)
2207  {
2208  if(!context.second.isEnabled())
2209  continue;
2210 
2211  auto apps = context.second
2212  .getNode(XDAQContextTable::colContext_.colLinkToApplicationTable_)
2213  .getChildren();
2214  for(auto app : apps)
2215  {
2216  // __COUTV__(app.second.getNode(XDAQContextTable::colApplication_.colClass_).getValue());
2217  if(app.second.getNode(XDAQContextTable::colApplication_.colClass_)
2218  .getValue() == ARTDAQ_SUPERVISOR_CLASS &&
2219  app.second.isEnabled())
2220  return true;
2221  }
2222  }
2223  return false;
2224 } // end isARTDAQEnabled()
2225 
2226 //==============================================================================
2236  ConfigurationManagerRW* cfgMgr,
2237  std::map<std::string /*type*/,
2238  std::map<std::string /*record*/, std::vector<std::string /*property*/>>>&
2239  nodeTypeToObjectMap,
2240  std::map<std::string /*subsystemName*/, std::string /*destinationSubsystemName*/>&
2241  subsystemObjectMap,
2242  std::vector<std::string /*property*/>& artdaqSupervisoInfo)
2243 {
2244  __COUT__ << "getARTDAQSystem()" << __E__;
2245 
2246  artdaqSupervisoInfo.clear(); // init
2247 
2248  const XDAQContextTable* contextTable = cfgMgr->__GET_CONFIG__(XDAQContextTable);
2249 
2250  // for each artdaq context, output all artdaq apps
2251 
2252  const XDAQContextTable::XDAQContext* artdaqContext =
2253  contextTable->getTheARTDAQSupervisorContext();
2254 
2255  // return empty info
2256  if(!artdaqContext)
2257  return ARTDAQTableBase::info_;
2258 
2259  __COUTV__(artdaqContext->contextUID_);
2260  __COUTV__(artdaqContext->applications_.size());
2261 
2262  for(auto& artdaqApp : artdaqContext->applications_)
2263  {
2264  if(artdaqApp.class_ != ARTDAQ_SUPERVISOR_CLASS)
2265  continue;
2266 
2267  __COUTV__(artdaqApp.applicationUID_);
2268  artdaqSupervisoInfo.push_back(artdaqApp.applicationUID_);
2269  artdaqSupervisoInfo.push_back(
2270  (artdaqContext->status_ && artdaqApp.status_) ? "1" : "0");
2271  artdaqSupervisoInfo.push_back(artdaqContext->address_);
2272  artdaqSupervisoInfo.push_back(std::to_string(artdaqContext->port_));
2273 
2274  const ARTDAQTableBase::ARTDAQInfo& info = ARTDAQTableBase::extractARTDAQInfo(
2275  XDAQContextTable::getSupervisorConfigNode(/*artdaqSupervisorNode*/
2276  cfgMgr,
2277  artdaqContext->contextUID_,
2278  artdaqApp.applicationUID_),
2279  true /*getStatusFalseNodes*/);
2280 
2281  __COUT__ << "========== "
2282  << "Found " << info.subsystems.size() << " subsystems." << __E__;
2283 
2284  // build subsystem desintation map
2285  for(auto& subsystem : info.subsystems)
2286  subsystemObjectMap.emplace(std::make_pair(
2287  subsystem.second.label, std::to_string(subsystem.second.destination)));
2288 
2289  __COUT__ << "========== "
2290  << "Found " << info.processes.size() << " process types." << __E__;
2291 
2292  for(auto& nameTypePair : ARTDAQTableBase::processTypes_.mapToType_)
2293  {
2294  const std::string& typeString = nameTypePair.first;
2295  __COUTV__(typeString);
2296 
2297  nodeTypeToObjectMap.emplace(
2298  std::make_pair(typeString,
2299  std::map<std::string /*record*/,
2300  std::vector<std::string /*property*/>>()));
2301 
2302  auto it = info.processes.find(nameTypePair.second);
2303  if(it == info.processes.end())
2304  {
2305  __COUT__ << "\t"
2306  << "Found 0 " << typeString << __E__;
2307  continue;
2308  }
2309  __COUT__ << "\t"
2310  << "Found " << it->second.size() << " " << typeString << "(s)"
2311  << __E__;
2312 
2313  auto tableIt = processTypes_.mapToTable_.find(typeString);
2314  if(tableIt == processTypes_.mapToTable_.end())
2315  {
2316  __SS__ << "Invalid artdaq node type '" << typeString << "' attempted!"
2317  << __E__;
2318  __SS_THROW__;
2319  }
2320  __COUTV__(tableIt->second);
2321 
2322  auto allNodes = cfgMgr->getNode(tableIt->second).getChildren();
2323 
2324  std::set<std::string /*nodeName*/>
2325  skipSet; // use to skip nodes when constructing multi-nodes
2326 
2327  const std::set<std::string /*colName*/> skipColumns(
2328  {ARTDAQ_TYPE_TABLE_HOSTNAME,
2329  ARTDAQ_TYPE_TABLE_ALLOWED_PROCESSORS,
2330  ARTDAQ_TYPE_TABLE_SUBSYSTEM_LINK,
2331  TableViewColumnInfo::COL_NAME_COMMENT,
2332  TableViewColumnInfo::COL_NAME_AUTHOR,
2333  TableViewColumnInfo::
2334  COL_NAME_CREATION}); // note: also skip UID and Status
2335 
2336  // loop through all nodes of this type
2337  for(auto& artdaqNode : it->second)
2338  {
2339  // check skip set
2340  if(skipSet.find(StringMacros::encodeURIComponent(artdaqNode.label)) !=
2341  skipSet.end())
2342  continue;
2343 
2344  __COUT__ << "\t\t"
2345  << "Found '" << artdaqNode.label << "' " << typeString << __E__;
2346 
2347  std::string nodeName = artdaqNode.label;
2348  bool status = artdaqNode.status;
2349  std::string hostname = artdaqNode.hostname;
2350  std::string subsystemId = std::to_string(artdaqNode.subsystem);
2351  std::string subsystemName =
2352  info.subsystems.at(artdaqNode.subsystem).label;
2353 
2354  ConfigurationTree thisNode =
2355  cfgMgr->getNode(tableIt->second).getNode(nodeName);
2356  auto thisNodeColumns = thisNode.getChildren();
2357 
2358  // check for multi-node
2359  // Steps:
2360  // search for other records with same values/links except hostname/name
2361 
2362  std::vector<std::string> multiNodeNames, hostnameArray;
2363  // unsigned int hostnameFixedWidth = 0;
2364 
2365  __COUTV__(allNodes.size());
2366  for(auto& otherNode : allNodes) // start multi-node search loop
2367  {
2368  if(otherNode.first == nodeName ||
2369  skipSet.find(StringMacros::encodeURIComponent(otherNode.first)) !=
2370  skipSet.end() ||
2371  otherNode.second.status() != status) // skip if status mismatch
2372  continue; // skip unless 'other' and not in skip set
2373 
2374  //__COUTV__(subsystemName);
2375  //__COUTV__(otherNode.second.getNode(ARTDAQ_TYPE_TABLE_SUBSYSTEM_LINK_UID).getValue());
2376 
2377  if(subsystemName ==
2378  otherNode.second.getNode(ARTDAQ_TYPE_TABLE_SUBSYSTEM_LINK_UID)
2379  .getValue())
2380  {
2381  // possible multi-node situation
2382  //__COUT__ << "Checking for multi-node..." << __E__;
2383 
2384  //__COUTV__(thisNode.getNodeRow());
2385  //__COUTV__(otherNode.second.getNodeRow());
2386 
2387  auto otherNodeColumns = otherNode.second.getChildren();
2388 
2389  bool isMultiNode = true;
2390  for(unsigned int i = 0;
2391  i < thisNodeColumns.size() && i < otherNodeColumns.size();
2392  ++i)
2393  {
2394  // skip columns that do not need to be checked for multi-node consideration
2395  if(skipColumns.find(thisNodeColumns[i].first) !=
2396  skipColumns.end() ||
2397  thisNodeColumns[i].second.isLinkNode())
2398  continue;
2399 
2400  // at this point must match for multinode
2401 
2402  //__COUTV__(thisNodeColumns[i].first);
2403  //__COUTV__(otherNodeColumns[i].first);
2404 
2405  //__COUTV__(thisNodeColumns[i].second.getValue());
2406  //__COUTV__(otherNodeColumns[i].second.getValue());
2407 
2408  if(thisNodeColumns[i].second.getValue() !=
2409  otherNodeColumns[i].second.getValue())
2410  {
2411  __COUT__ << "Mismatch, not multi-node member." << __E__;
2412  isMultiNode = false;
2413  break;
2414  }
2415  }
2416 
2417  if(isMultiNode)
2418  {
2419  __COUT__ << "Found '" << nodeName
2420  << "' multi-node member candidate '"
2421  << otherNode.first << "'" << __E__;
2422 
2423  //use StringMacros::encodeURIComponent because dashes will confuse printer syntax later!
2424  if(!multiNodeNames.size()) // add this node first!
2425  {
2426  multiNodeNames.push_back(
2427  StringMacros::encodeURIComponent(nodeName));
2428  hostnameArray.push_back(
2429  StringMacros::encodeURIComponent(hostname));
2430  }
2431  multiNodeNames.push_back(
2432  StringMacros::encodeURIComponent(otherNode.first));
2433  hostnameArray.push_back(StringMacros::encodeURIComponent(
2434  otherNode.second.getNode(ARTDAQ_TYPE_TABLE_HOSTNAME)
2435  .getValue()));
2436 
2437  __COUTV__(hostnameArray.back());
2438  skipSet.emplace(
2439  StringMacros::encodeURIComponent(otherNode.first));
2440  }
2441  }
2442  } // end loop to search for multi-node members
2443 
2444  unsigned int nodeFixedWildcardLength = 0, hostFixedWildcardLength = 0;
2445  std::string multiNodeString = "", hostArrayString = "";
2446 
2447  if(multiNodeNames.size() > 1)
2448  {
2449  __COUT__ << "Handling multi-node printer syntax" << __E__;
2450 
2451  __COUTV__(StringMacros::vectorToString(multiNodeNames));
2452  __COUTV__(StringMacros::vectorToString(hostnameArray));
2453  __COUTV__(StringMacros::setToString(skipSet));
2454 
2455  {
2456  // check for alpha-based similarity groupings (ignore numbers and special characters)
2457  unsigned int maxScore = 0;
2458  unsigned int score;
2459  unsigned int minScore = -1;
2460  std::vector<unsigned int> scoreVector;
2461  scoreVector.push_back(-1); // for 0 index (it's perfect)
2462  for(unsigned int i = 1; i < multiNodeNames.size(); ++i)
2463  {
2464  score = 0;
2465 
2466  //__COUT__ << multiNodeNames[0] << " vs " << multiNodeNames[i] << __E__;
2467 
2468  // start forward score loop
2469  for(unsigned int j = 0, k = 0; j < multiNodeNames[0].size() &&
2470  k < multiNodeNames[i].size();
2471  ++j, ++k)
2472  {
2473  while(j < multiNodeNames[0].size() &&
2474  !(multiNodeNames[0][j] >= 'a' &&
2475  multiNodeNames[0][j] <= 'z') &&
2476  !(multiNodeNames[0][j] >= 'A' &&
2477  multiNodeNames[0][j] <= 'Z'))
2478  ++j; // skip non-alpha characters
2479  while(k < multiNodeNames[i].size() &&
2480  !(multiNodeNames[i][k] >= 'a' &&
2481  multiNodeNames[i][k] <= 'z') &&
2482  !(multiNodeNames[i][k] >= 'A' &&
2483  multiNodeNames[i][k] <= 'Z'))
2484  ++k; // skip non-alpha characters
2485 
2486  while(k < multiNodeNames[i].size() &&
2487  multiNodeNames[0][j] != multiNodeNames[i][k])
2488  ++k; // skip non-matching alpha characters
2489 
2490  //__COUT__ << j << "-" << k << " of " <<
2491  // multiNodeNames[0].size() << "-" <<
2492  // multiNodeNames[i].size() << __E__;
2493 
2494  if(j < multiNodeNames[0].size() &&
2495  k < multiNodeNames[i].size())
2496  ++score; // found a matching letter!
2497  } // end forward score loop
2498 
2499  //__COUTV__(score);
2500 
2501  // start backward score loop
2502  for(unsigned int j = multiNodeNames[0].size() - 1,
2503  k = multiNodeNames[i].size() - 1;
2504  j < multiNodeNames[0].size() &&
2505  k < multiNodeNames[i].size();
2506  --j, --k)
2507  {
2508  while(j < multiNodeNames[0].size() &&
2509  !(multiNodeNames[0][j] >= 'a' &&
2510  multiNodeNames[0][j] <= 'z') &&
2511  !(multiNodeNames[0][j] >= 'A' &&
2512  multiNodeNames[0][j] <= 'Z'))
2513  --j; // skip non-alpha characters
2514  while(k < multiNodeNames[i].size() &&
2515  !(multiNodeNames[i][k] >= 'a' &&
2516  multiNodeNames[i][k] <= 'z') &&
2517  !(multiNodeNames[i][k] >= 'A' &&
2518  multiNodeNames[i][k] <= 'Z'))
2519  --k; // skip non-alpha characters
2520 
2521  while(k < multiNodeNames[i].size() &&
2522  multiNodeNames[0][j] != multiNodeNames[i][k])
2523  --k; // skip non-matching alpha characters
2524 
2525  //__COUT__ << "BACK" << j << "-" << k << " of " <<
2526  // multiNodeNames[0].size() << "-" <<
2527  // multiNodeNames[i].size() << __E__;
2528 
2529  if(j < multiNodeNames[0].size() &&
2530  k < multiNodeNames[i].size())
2531  ++score; // found a matching letter!
2532  } // end backward score loop
2533 
2534  //__COUTV__(score/2.0);
2535 
2536  scoreVector.push_back(score);
2537 
2538  if(score > maxScore)
2539  {
2540  maxScore = score;
2541  }
2542 
2543  if(score < minScore)
2544  {
2545  minScore = score;
2546  }
2547 
2548  } // end multi-node member scoring loop
2549 
2550  //__COUTV__(minScore);
2551  //__COUTV__(maxScore);
2552 
2553  __COUT__ << "Trimming multi-node members with low match score..."
2554  << __E__;
2555 
2556  // go backwards, to not mess up indices as deleted
2557  // do not delete index 0
2558  for(unsigned int i = multiNodeNames.size() - 1;
2559  i > 0 && i < multiNodeNames.size();
2560  --i)
2561  {
2562  //__COUTV__(scoreVector[i]);
2563  //__COUTV__(i);
2564  if(maxScore > multiNodeNames[0].size() &&
2565  scoreVector[i] >= maxScore)
2566  continue;
2567 
2568  // else trim
2569  __COUT__ << "Trimming " << multiNodeNames[i] << __E__;
2570 
2571  skipSet.erase(multiNodeNames[i]);
2572  multiNodeNames.erase(multiNodeNames.begin() + i);
2573  hostnameArray.erase(hostnameArray.begin() + i);
2574 
2575  } // end multi-node trim loop
2576 
2577  } // done with multi-node member trim
2578 
2579  __COUTV__(StringMacros::vectorToString(multiNodeNames));
2580  __COUTV__(StringMacros::vectorToString(hostnameArray));
2581  __COUTV__(StringMacros::setToString(skipSet));
2582 
2583  // from set of nodename wildcards, make printer syntax
2584  if(multiNodeNames.size() > 1)
2585  {
2586  std::vector<std::string> commonChunks;
2587  std::vector<std::string> wildcards;
2588 
2589  //can not change the order of wildcards for node names! or the names will not keep pairing with host
2590 
2591  bool wildcardsNeeded =
2592  StringMacros::extractCommonChunks(multiNodeNames,
2593  commonChunks,
2594  wildcards,
2595  nodeFixedWildcardLength);
2596 
2597  if(!wildcardsNeeded || wildcards.size() != multiNodeNames.size())
2598  {
2599  __SS__
2600  << "Impossible extractCommonChunks result! Please notify "
2601  "admins or try to simplify record naming convention."
2602  << __E__;
2603  __SS_THROW__;
2604  }
2605 
2606  __COUTV__(StringMacros::vectorToString(commonChunks));
2607 
2608  nodeName = "";
2609  bool first = true;
2610  for(auto& commonChunk : commonChunks)
2611  {
2612  nodeName += (!first ? "*" : "") + commonChunk;
2613  if(first)
2614  first = false;
2615  }
2616  if(commonChunks.size() == 1)
2617  nodeName += '*';
2618 
2619  __COUTV__(nodeName);
2620 
2621  // steps:
2622  // determine if all unsigned ints
2623  // if int, then order and attempt to hyphenate
2624  // if not ints, then comma separated
2625 
2626  bool allIntegers = true;
2627  for(auto& wildcard : wildcards)
2628  if(!allIntegers)
2629  break;
2630  else if(wildcard.size() == 0) // emtpy string is not a number
2631  {
2632  allIntegers = false;
2633  break;
2634  }
2635  else
2636  for(unsigned int i = 0; i < wildcard.size(); ++i)
2637  if(!(wildcard[i] >= '0' && wildcard[i] <= '9'))
2638  {
2639  allIntegers = false;
2640  break;
2641  }
2642 
2643  __COUTV__(allIntegers);
2644  if(allIntegers)
2645  {
2646  __COUTV__(StringMacros::vectorToString(wildcards));
2647 
2648  // need ints in vector for random access to for hyphenating
2649  std::vector<unsigned int> intWildcards;
2650  for(auto& wildcard : wildcards)
2651  intWildcards.push_back(strtol(wildcard.c_str(), 0, 10));
2652 
2653  __COUTV__(StringMacros::vectorToString(intWildcards));
2654 
2655  unsigned int hyphenLo = -1;
2656  bool isFirst = true;
2657  for(unsigned int i = 0; i < intWildcards.size(); ++i)
2658  {
2659  if(i + 1 < intWildcards.size() &&
2660  intWildcards[i] + 1 == intWildcards[i + 1])
2661  {
2662  if(i < hyphenLo)
2663  hyphenLo = i; // start hyphen
2664  //else continue hyphen
2665  }
2666  else // new comma
2667  {
2668  if(i < hyphenLo)
2669  {
2670  // single number
2671  multiNodeString +=
2672  (isFirst ? "" : ",") +
2673  std::to_string(intWildcards[i]);
2674  }
2675  else
2676  {
2677  // if only 1 number apart, then comma
2678  if(intWildcards[hyphenLo] + 1 == intWildcards[i])
2679  multiNodeString +=
2680  (isFirst ? "" : ",") +
2681  std::to_string(intWildcards[hyphenLo]) +
2682  "," + std::to_string(intWildcards[i]);
2683  else // else hyphen numbers
2684  multiNodeString +=
2685  (isFirst ? "" : ",") +
2686  std::to_string(intWildcards[hyphenLo]) +
2687  "-" + std::to_string(intWildcards[i]);
2688  hyphenLo = -1; // reset for next
2689  }
2690  isFirst = false;
2691  }
2692  }
2693  } // end all integer handling
2694  else // not all integers, so csv
2695  {
2696  multiNodeString = StringMacros::vectorToString(wildcards);
2697  } // end not-all integer handling
2698 
2699  __COUTV__(multiNodeString);
2700  __COUTV__(nodeFixedWildcardLength);
2701  } // end node name printer syntax handling
2702 
2703  if(hostnameArray.size() > 1)
2704  {
2705  std::vector<std::string> commonChunks;
2706  std::vector<std::string> wildcards;
2707 
2708  //can not change the order of wildcards for hostname! or the names will not keep pairing with host
2709 
2710  bool wildcardsNeeded =
2711  StringMacros::extractCommonChunks(hostnameArray,
2712  commonChunks,
2713  wildcards,
2714  hostFixedWildcardLength);
2715 
2716  __COUTV__(wildcardsNeeded);
2717  __COUTV__(StringMacros::vectorToString(commonChunks));
2718 
2719  hostname = "";
2720  bool first = true;
2721  for(auto& commonChunk : commonChunks)
2722  {
2723  hostname += (!first ? "*" : "") + commonChunk;
2724  if(first)
2725  first = false;
2726  }
2727  if(wildcardsNeeded && commonChunks.size() == 1)
2728  hostname += '*';
2729 
2730  __COUTV__(hostname);
2731 
2732  if(wildcardsNeeded)
2733  // else if not wildcards needed, then do not make hostname array string
2734  {
2735  // steps:
2736  // determine if all unsigned ints
2737  // if int, then order and attempt to hyphenate
2738  // if not ints, then comma separated
2739 
2740  bool allIntegers = true;
2741  for(auto& wildcard : wildcards)
2742  for(unsigned int i = 0; i < wildcard.size(); ++i)
2743  if(!(wildcard[i] >= '0' && wildcard[i] <= '9'))
2744  {
2745  allIntegers = false;
2746  break;
2747  }
2748 
2749  __COUTV__(allIntegers);
2750 
2751  if(allIntegers)
2752  {
2753  __COUTV__(StringMacros::vectorToString(wildcards));
2754 
2755  // need ints in vector for random access to for hyphenating
2756  std::vector<unsigned int> intWildcards;
2757  for(auto& wildcard : wildcards)
2758  intWildcards.push_back(
2759  strtol(wildcard.c_str(), 0, 10));
2760 
2761  __COUTV__(StringMacros::vectorToString(intWildcards));
2762 
2763  unsigned int hyphenLo = -1;
2764  bool isFirst = true;
2765  for(unsigned int i = 0; i < intWildcards.size(); ++i)
2766  {
2767  if(i + 1 < intWildcards.size() &&
2768  intWildcards[i] + 1 == intWildcards[i + 1])
2769  {
2770  if(i < hyphenLo)
2771  hyphenLo = i; // start hyphen
2772  //else continue hyphen
2773  }
2774  else // new comma
2775  {
2776  if(i < hyphenLo)
2777  {
2778  // single number
2779  hostArrayString +=
2780  (isFirst ? "" : ",") +
2781  std::to_string(intWildcards[i]);
2782  }
2783  else
2784  {
2785  // if only 1 number apart, then comma
2786  if(intWildcards[hyphenLo] + 1 ==
2787  intWildcards[i])
2788  hostArrayString +=
2789  (isFirst ? "" : ",") +
2790  std::to_string(
2791  intWildcards[hyphenLo]) +
2792  "," + std::to_string(intWildcards[i]);
2793  else // else hyphen numbers
2794  hostArrayString +=
2795  (isFirst ? "" : ",") +
2796  std::to_string(
2797  intWildcards[hyphenLo]) +
2798  "-" + std::to_string(intWildcards[i]);
2799  hyphenLo = -1; // reset for next
2800  }
2801  isFirst = false;
2802  }
2803  }
2804  } // end all integer handling
2805  else // not all integers, so csv
2806  {
2807  hostArrayString = StringMacros::vectorToString(wildcards);
2808  } // end not-all integer handling
2809  } // end wildcard need handling
2810  __COUTV__(hostArrayString);
2811  __COUTV__(hostFixedWildcardLength);
2812  } // end node name printer syntax handling
2813 
2814  } // end multi node printer syntax handling
2815 
2816  nodeTypeToObjectMap.at(typeString)
2817  .emplace(std::make_pair(nodeName,
2818  std::vector<std::string /*property*/>()));
2819 
2820  nodeTypeToObjectMap.at(typeString)
2821  .at(nodeName)
2822  .push_back(status ? "1" : "0");
2823 
2824  nodeTypeToObjectMap.at(typeString).at(nodeName).push_back(hostname);
2825 
2826  nodeTypeToObjectMap.at(typeString).at(nodeName).push_back(subsystemId);
2827  if(multiNodeNames.size() > 1)
2828  {
2829  nodeTypeToObjectMap.at(typeString)
2830  .at(nodeName)
2831  .push_back(multiNodeString);
2832 
2833  nodeTypeToObjectMap.at(typeString)
2834  .at(nodeName)
2835  .push_back(std::to_string(nodeFixedWildcardLength));
2836 
2837  if(hostnameArray.size() > 1)
2838  {
2839  nodeTypeToObjectMap.at(typeString)
2840  .at(nodeName)
2841  .push_back(hostArrayString);
2842 
2843  nodeTypeToObjectMap.at(typeString)
2844  .at(nodeName)
2845  .push_back(std::to_string(hostFixedWildcardLength));
2846  }
2847  } // done adding multinode parameters
2848  }
2849  } // end processor type handling
2850 
2851  } // end artdaq app loop
2852 
2853  __COUT__ << "Done getting artdaq nodes." << __E__;
2854 
2855  return ARTDAQTableBase::info_;
2856 } // end getARTDAQSystem()
2857 
2858 //==============================================================================
2868  ConfigurationManagerRW* cfgMgr,
2869  const std::map<std::string /*type*/,
2870  std::map<std::string /*record*/,
2871  std::vector<std::string /*property*/>>>& nodeTypeToObjectMap,
2872  const std::map<std::string /*subsystemName*/,
2873  std::string /*destinationSubsystemName*/>& subsystemObjectMap)
2874 {
2875  __COUT__ << "setAndActivateARTDAQSystem()" << __E__;
2876 
2877  const std::string& author = cfgMgr->getUsername();
2878 
2879  // Steps:
2880  // 0. Check for one and only artdaq Supervisor
2881  // 1. create/verify subsystems and destinations
2882  // 2. for each node
2883  // create/verify records
2884 
2885  //------------------------
2886  // 0. Check for one and only artdaq Supervisor
2887 
2888  GroupEditStruct configGroupEdit(ConfigurationManager::GroupType::CONFIGURATION_TYPE,
2889  cfgMgr);
2890 
2891  unsigned int artdaqSupervisorRow = TableView::INVALID;
2892 
2893  const XDAQContextTable* contextTable = cfgMgr->__GET_CONFIG__(XDAQContextTable);
2894 
2895  const XDAQContextTable::XDAQContext* artdaqContext =
2896  contextTable->getTheARTDAQSupervisorContext();
2897 
2898  bool needArtdaqSupervisorParents = true;
2899  bool needArtdaqSupervisorCreation = false;
2900 
2901  if(artdaqContext) // check for full connection to supervisor
2902  {
2903  try
2904  {
2905  ConfigurationTree artdaqSupervisorNode =
2906  cfgMgr->getNode(ConfigurationManager::XDAQ_CONTEXT_TABLE_NAME)
2907  .getNode(artdaqContext->contextUID_)
2908  .getNode(XDAQContextTable::colContext_.colLinkToApplicationTable_)
2909  .getNode(artdaqContext->applications_[0].applicationUID_)
2910  .getNode(XDAQContextTable::colApplication_.colLinkToSupervisorTable_);
2911 
2912  if(artdaqSupervisorNode.isDisconnected())
2913  needArtdaqSupervisorCreation = true;
2914  else
2915  artdaqSupervisorRow = artdaqSupervisorNode.getRow();
2916 
2917  needArtdaqSupervisorParents = false;
2918  }
2919  catch(...) // parents are a problem if error
2920  {
2921  needArtdaqSupervisorCreation = true;
2922  }
2923  }
2924 
2925  if(!artdaqContext || needArtdaqSupervisorCreation)
2926  {
2927  __COUT__ << "No artdaq Supervisor found! Creating..." << __E__;
2928  __COUTV__(needArtdaqSupervisorParents);
2929 
2930  std::string artdaqSupervisorUID;
2931  unsigned int row;
2932 
2933  // create record in ARTDAQ Supervisor table
2934  // connect to an App in a Context
2935 
2936  // now create artdaq Supervisor in configuration group
2937  {
2938  TableEditStruct& artdaqSupervisorTable = configGroupEdit.getTableEditStruct(
2939  ARTDAQ_SUPERVISOR_TABLE, true /*markModified*/);
2940 
2941  // create artdaq Supervisor context record
2942  row = artdaqSupervisorTable.tableView_->addRow(
2943  author, true /*incrementUniqueData*/, "artdaqSupervisor");
2944 
2945  // get UID
2946  artdaqSupervisorUID =
2947  artdaqSupervisorTable.tableView_
2948  ->getDataView()[row][artdaqSupervisorTable.tableView_->getColUID()];
2949  artdaqSupervisorRow = row;
2950 
2951  __COUTV__(artdaqSupervisorRow);
2952  __COUTV__(artdaqSupervisorUID);
2953 
2954  // set DAQInterfaceDebugLevel
2955  artdaqSupervisorTable.tableView_->setValueAsString(
2956  "1",
2957  row,
2958  artdaqSupervisorTable.tableView_->findCol(
2959  colARTDAQSupervisor_.colDAQInterfaceDebugLevel_));
2960  // set DAQSetupScript
2961  artdaqSupervisorTable.tableView_->setValueAsString(
2962  "${MRB_BUILDDIR}/../setup_ots.sh",
2963  row,
2964  artdaqSupervisorTable.tableView_->findCol(
2965  colARTDAQSupervisor_.colDAQSetupScript_));
2966 
2967  // create group link to board readers
2968  artdaqSupervisorTable.tableView_->setValueAsString(
2969  ARTDAQ_READER_TABLE,
2970  row,
2971  artdaqSupervisorTable.tableView_->findCol(
2972  colARTDAQSupervisor_.colLinkToBoardReaders_));
2973  artdaqSupervisorTable.tableView_->setUniqueColumnValue(
2974 
2975  row,
2976  artdaqSupervisorTable.tableView_->findCol(
2977  colARTDAQSupervisor_.colLinkToBoardReadersGroupID_),
2978  artdaqSupervisorUID +
2979  processTypes_.mapToGroupIDAppend_.at(processTypes_.READER));
2980  // create group link to event builders
2981  artdaqSupervisorTable.tableView_->setValueAsString(
2982  ARTDAQ_BUILDER_TABLE,
2983  row,
2984  artdaqSupervisorTable.tableView_->findCol(
2985  colARTDAQSupervisor_.colLinkToEventBuilders_));
2986  artdaqSupervisorTable.tableView_->setUniqueColumnValue(
2987  row,
2988  artdaqSupervisorTable.tableView_->findCol(
2989  colARTDAQSupervisor_.colLinkToEventBuildersGroupID_),
2990  artdaqSupervisorUID +
2991  processTypes_.mapToGroupIDAppend_.at(processTypes_.BUILDER));
2992  // create group link to data loggers
2993  artdaqSupervisorTable.tableView_->setValueAsString(
2994  ARTDAQ_LOGGER_TABLE,
2995  row,
2996  artdaqSupervisorTable.tableView_->findCol(
2997  colARTDAQSupervisor_.colLinkToDataLoggers_));
2998  artdaqSupervisorTable.tableView_->setUniqueColumnValue(
2999  row,
3000  artdaqSupervisorTable.tableView_->findCol(
3001  colARTDAQSupervisor_.colLinkToDataLoggersGroupID_),
3002  artdaqSupervisorUID +
3003  processTypes_.mapToGroupIDAppend_.at(processTypes_.LOGGER));
3004  // create group link to dispatchers
3005  artdaqSupervisorTable.tableView_->setValueAsString(
3006  ARTDAQ_DISPATCHER_TABLE,
3007  row,
3008  artdaqSupervisorTable.tableView_->findCol(
3009  colARTDAQSupervisor_.colLinkToDispatchers_));
3010  artdaqSupervisorTable.tableView_->setUniqueColumnValue(
3011  row,
3012  artdaqSupervisorTable.tableView_->findCol(
3013  colARTDAQSupervisor_.colLinkToDispatchersGroupID_),
3014  artdaqSupervisorUID +
3015  processTypes_.mapToGroupIDAppend_.at(processTypes_.DISPATCHER));
3016 
3017  // create group link to routing managers
3018  artdaqSupervisorTable.tableView_->setValueAsString(
3019  ARTDAQ_ROUTER_TABLE,
3020  row,
3021  artdaqSupervisorTable.tableView_->findCol(
3022  colARTDAQSupervisor_.colLinkToRoutingManagers_));
3023  artdaqSupervisorTable.tableView_->setUniqueColumnValue(
3024  row,
3025  artdaqSupervisorTable.tableView_->findCol(
3026  colARTDAQSupervisor_.colLinkToRoutingManagersGroupID_),
3027  artdaqSupervisorUID +
3028  processTypes_.mapToGroupIDAppend_.at(processTypes_.ROUTER));
3029 
3030  {
3031  std::stringstream ss;
3032  artdaqSupervisorTable.tableView_->print(ss);
3033  __COUT__ << ss.str();
3034  }
3035  } // end create artdaq Supervisor in configuration group
3036 
3037  // now create artdaq Supervisor parents in context group
3038  {
3039  GroupEditStruct contextGroupEdit(
3040  ConfigurationManager::GroupType::CONTEXT_TYPE, cfgMgr);
3041 
3042  TableEditStruct& contextTable = contextGroupEdit.getTableEditStruct(
3043  ConfigurationManager::XDAQ_CONTEXT_TABLE_NAME, true /*markModified*/);
3044  TableEditStruct& appTable = contextGroupEdit.getTableEditStruct(
3045  ConfigurationManager::XDAQ_APPLICATION_TABLE_NAME, true /*markModified*/);
3046  TableEditStruct& appPropertyTable = contextGroupEdit.getTableEditStruct(
3047  ConfigurationManager::XDAQ_APP_PROPERTY_TABLE_NAME,
3048  true /*markModified*/);
3049 
3050  // open try for decorating errors and for clean code scope
3051  try
3052  {
3053  std::string contextUID;
3054  std::string contextAppGroupID;
3055 
3056  if(needArtdaqSupervisorParents)
3057  {
3058  // create artdaq Supervisor context record
3059  row = contextTable.tableView_->addRow(
3060  author, true /*incrementUniqueData*/, "artdaqContext");
3061  // set context status true
3062  contextTable.tableView_->setValueAsString(
3063  "1", row, contextTable.tableView_->getColStatus());
3064 
3065  contextUID =
3066  contextTable.tableView_
3067  ->getDataView()[row][contextTable.tableView_->getColUID()];
3068 
3069  __COUTV__(row);
3070  __COUTV__(contextUID);
3071 
3072  // set address/port
3073  contextTable.tableView_->setValueAsString(
3074  "http://${HOSTNAME}",
3075  row,
3076  contextTable.tableView_->findCol(
3077  XDAQContextTable::colContext_.colAddress_));
3078  contextTable.tableView_->setUniqueColumnValue(
3079  row,
3080  contextTable.tableView_->findCol(
3081  XDAQContextTable::colContext_.colPort_),
3082  "${OTS_MAIN_PORT}",
3083  true /*doMathAppendStrategy*/);
3084 
3085  // create group link to artdaq Supervisor app
3086  contextTable.tableView_->setValueAsString(
3087  ConfigurationManager::XDAQ_APPLICATION_TABLE_NAME,
3088  row,
3089  contextTable.tableView_->findCol(
3090  XDAQContextTable::colContext_.colLinkToApplicationTable_));
3091  contextAppGroupID = contextTable.tableView_->setUniqueColumnValue(
3092  row,
3093  contextTable.tableView_->findCol(
3094  XDAQContextTable::colContext_.colLinkToApplicationGroupID_),
3095  "artdaqContextApps");
3096 
3097  __COUTV__(contextAppGroupID);
3098 
3099  } // end create context entry
3100 
3101  std::string appUID;
3102  std::string appPropertiesGroupID;
3103 
3104  // create artdaq Supervisor app
3105  {
3106  unsigned int row;
3107 
3108  if(needArtdaqSupervisorParents)
3109  {
3110  // first disable any existing artdaq supervisor apps
3111  {
3112  unsigned int c = appTable.tableView_->findCol(
3113  XDAQContextTable::colApplication_.colClass_);
3114  for(unsigned int r = 0;
3115  r < appTable.tableView_->getNumberOfRows();
3116  ++r)
3117  if(appTable.tableView_->getDataView()[r][c] ==
3118  ARTDAQ_SUPERVISOR_CLASS)
3119  {
3120  __COUT_WARN__
3121  << "Found partially existing artdaq Supervisor "
3122  "application '"
3123  << appTable.tableView_->getDataView()
3124  [r][appTable.tableView_->getColUID()]
3125  << "'... Disabling it." << __E__;
3126  appTable.tableView_->setValueAsString(
3127  "0", r, appTable.tableView_->getColStatus());
3128  }
3129  }
3130 
3131  // create artdaq Supervisor context record
3132  row = appTable.tableView_->addRow(
3133  author, true /*incrementUniqueData*/, "artdaqSupervisor");
3134  // set app status true
3135  appTable.tableView_->setValueAsString(
3136  "1", row, appTable.tableView_->getColStatus());
3137 
3138  appUID =
3139  appTable.tableView_
3140  ->getDataView()[row][appTable.tableView_->getColUID()];
3141 
3142  __COUTV__(row);
3143  __COUTV__(appUID);
3144 
3145  // set class
3146  appTable.tableView_->setValueAsString(
3147  ARTDAQ_SUPERVISOR_CLASS,
3148  row,
3149  appTable.tableView_->findCol(
3150  XDAQContextTable::colApplication_.colClass_));
3151  // set module
3152  appTable.tableView_->setValueAsString(
3153  "${OTSDAQ_LIB}/libARTDAQSupervisor.so",
3154  row,
3155  appTable.tableView_->findCol(
3156  XDAQContextTable::colApplication_.colModule_));
3157  // set groupid
3158  appTable.tableView_->setValueAsString(
3159  contextAppGroupID,
3160  row,
3161  appTable.tableView_->findCol(XDAQContextTable::colApplication_
3162  .colApplicationGroupID_));
3163 
3164  // create group link to artdaq Supervisor app properties
3165  appTable.tableView_->setValueAsString(
3166  ConfigurationManager::XDAQ_APP_PROPERTY_TABLE_NAME,
3167  row,
3168  appTable.tableView_->findCol(XDAQContextTable::colApplication_
3169  .colLinkToPropertyTable_));
3170  appPropertiesGroupID = appTable.tableView_->setUniqueColumnValue(
3171  row,
3172  appTable.tableView_->findCol(XDAQContextTable::colApplication_
3173  .colLinkToPropertyGroupID_),
3174  appUID + "Properties");
3175 
3176  __COUTV__(appPropertiesGroupID);
3177  }
3178  else
3179  {
3180  __COUT__ << "Getting row of existing parent supervisor." << __E__;
3181 
3182  // get row of current artdaq supervisor app
3183  row =
3184  cfgMgr->getNode(ConfigurationManager::XDAQ_CONTEXT_TABLE_NAME)
3185  .getNode(artdaqContext->contextUID_)
3186  .getNode(XDAQContextTable::colContext_
3187  .colLinkToApplicationTable_)
3188  .getNode(artdaqContext->applications_[0].applicationUID_)
3189  .getRow();
3190  __COUTV__(row);
3191  }
3192 
3193  // create group link to artdaq Supervisor app properties
3194  // create link whether or not parents were created
3195  // because, if here, then artdaq supervisor record was created.
3196  appTable.tableView_->setValueAsString(
3197  ARTDAQ_SUPERVISOR_TABLE,
3198  row,
3199  appTable.tableView_->findCol(
3200  XDAQContextTable::colApplication_.colLinkToSupervisorTable_));
3201  appTable.tableView_->setValueAsString(
3202  artdaqSupervisorUID,
3203  row,
3204  appTable.tableView_->findCol(
3205  XDAQContextTable::colApplication_.colLinkToSupervisorUID_));
3206 
3207  } // end create app entry
3208 
3209  // create artdaq Supervisor properties
3210  if(needArtdaqSupervisorParents)
3211  {
3212  unsigned int row;
3213 
3214  const std::vector<std::string> propertyUIDs = {"Partition0",
3215  "ProductsDir",
3216  "FragmentSize",
3217  "BoardReaderTimeout",
3218  "EventBuilderTimeout",
3219  "DataLoggerTimeout",
3220  "DispatcherTimeout"};
3221  const std::vector<std::string> propertyNames = {
3222  "partition", //"Partition0",
3223  "productsdir_for_bash_scripts", //"ProductsDir",
3224  "max_fragment_size_bytes", //"FragmentSize",
3225  "boardreader_timeout", //"BoardReaderTimeout",
3226  "eventbuilder_timeout", //"EventBuilderTimeout",
3227  "datalogger_timeout", //"DataLoggerTimeout",
3228  "dispatcher_timeout" //"DispatcherTimeout"
3229  };
3230  const std::vector<std::string> propertyValues = {
3231  "0", //"Partition0",
3232  "${OTS_PRODUCTS}", //"ProductsDir",
3233  "1284180560", //"FragmentSize",
3234  "600", //"BoardReaderTimeout",
3235  "600", //"EventBuilderTimeout",
3236  "600", //"DataLoggerTimeout",
3237  "600" //"DispatcherTimeout"
3238  };
3239 
3240  for(unsigned int i = 0; i < propertyNames.size(); ++i)
3241  {
3242  // create artdaq Supervisor property record
3243  row = appPropertyTable.tableView_->addRow(
3244  author,
3245  true /*incrementUniqueData*/,
3246  appUID + propertyUIDs[i]);
3247  // set app status true
3248  appPropertyTable.tableView_->setValueAsString(
3249  "1", row, appPropertyTable.tableView_->getColStatus());
3250 
3251  // set type
3252  appPropertyTable.tableView_->setValueAsString(
3253  "ots::SupervisorProperty",
3254  row,
3255  appPropertyTable.tableView_->findCol(
3256  XDAQContextTable::colAppProperty_.colPropertyType_));
3257  // set name
3258  appPropertyTable.tableView_->setValueAsString(
3259  propertyNames[i],
3260  row,
3261  appPropertyTable.tableView_->findCol(
3262  XDAQContextTable::colAppProperty_.colPropertyName_));
3263  // set value
3264  appPropertyTable.tableView_->setValueAsString(
3265  propertyValues[i],
3266  row,
3267  appPropertyTable.tableView_->findCol(
3268  XDAQContextTable::colAppProperty_.colPropertyValue_));
3269  // set groupid
3270  appPropertyTable.tableView_->setValueAsString(
3271  appPropertiesGroupID,
3272  row,
3273  appPropertyTable.tableView_->findCol(
3274  XDAQContextTable::colAppProperty_.colPropertyGroupID_));
3275  } // end property create loop
3276  } // end create app property entries
3277 
3278  {
3279  std::stringstream ss;
3280  contextTable.tableView_->print(ss);
3281  __COUT__ << ss.str();
3282  }
3283  {
3284  std::stringstream ss;
3285  appTable.tableView_->print(ss);
3286  __COUT__ << ss.str();
3287  }
3288  {
3289  std::stringstream ss;
3290  appPropertyTable.tableView_->print(ss);
3291  __COUT__ << ss.str();
3292  }
3293 
3294  contextTable.tableView_
3295  ->init(); // verify new table (throws runtime_errors)
3296  appTable.tableView_->init(); // verify new table (throws runtime_errors)
3297  appPropertyTable.tableView_
3298  ->init(); // verify new table (throws runtime_errors)
3299  }
3300  catch(...)
3301  {
3302  __COUT__
3303  << "Table errors while creating ARTDAQ Supervisor. Erasing all newly "
3304  "created table versions."
3305  << __E__;
3306  throw; // re-throw
3307  } // end catch
3308 
3309  __COUT__ << "Edits complete for new artdaq Supervisor!" << __E__;
3310 
3311  TableGroupKey newContextGroupKey;
3312  contextGroupEdit.saveChanges(contextGroupEdit.originalGroupName_,
3313  newContextGroupKey,
3314  nullptr /*foundEquivalentGroupKey*/,
3315  true /*activateNewGroup*/,
3316  true /*updateGroupAliases*/,
3317  true /*updateTableAliases*/);
3318 
3319  } // end create artdaq Supervisor in context group
3320 
3321  } // end artdaq Supervisor verification
3322  else
3323  {
3324  artdaqSupervisorRow =
3325  cfgMgr->getNode(ConfigurationManager::XDAQ_CONTEXT_TABLE_NAME)
3326  .getNode(artdaqContext->contextUID_)
3327  .getNode(XDAQContextTable::colContext_.colLinkToApplicationTable_)
3328  .getNode(artdaqContext->applications_[0].applicationUID_)
3329  .getNode(XDAQContextTable::colApplication_.colLinkToSupervisorTable_)
3330  .getRow();
3331  }
3332 
3333  __COUT__ << "------------------------- artdaq nodes to save:" << __E__;
3334  for(auto& subsystemPair : subsystemObjectMap)
3335  {
3336  __COUTV__(subsystemPair.first);
3337 
3338  } // end subsystem loop
3339 
3340  for(auto& nodeTypePair : nodeTypeToObjectMap)
3341  {
3342  __COUTV__(nodeTypePair.first);
3343 
3344  for(auto& nodePair : nodeTypePair.second)
3345  {
3346  __COUTV__(nodePair.first);
3347  }
3348 
3349  } // end node type loop
3350  __COUT__ << "------------------------- end artdaq nodes to save." << __E__;
3351 
3352  //==================================
3353  // at this point artdaqSupervisor is verified and we have row
3354  __COUTV__(artdaqSupervisorRow);
3355  if(artdaqSupervisorRow >= TableView::INVALID)
3356  {
3357  __SS__ << "Invalid artdaq Supervisor row " << artdaqSupervisorRow << " found!"
3358  << __E__;
3359  __SS_THROW__;
3360  }
3361 
3362  // Remaining steps:
3363  // Step 1. create/verify subsystems and destinations
3364  // Step 2. for each node, create/verify records
3365 
3366  // open try for decorating configuration group errors and for clean code scope
3367  try
3368  {
3369  unsigned int row;
3370 
3371  TableEditStruct& artdaqSupervisorTable = configGroupEdit.getTableEditStruct(
3372  ARTDAQ_SUPERVISOR_TABLE, true /*markModified*/);
3373 
3374  // for any NO_LINK links in artdaqSupervisor record, fix them
3375  {
3376  std::string artdaqSupervisorUID =
3377  artdaqSupervisorTable.tableView_
3378  ->getDataView()[artdaqSupervisorRow]
3379  [artdaqSupervisorTable.tableView_->getColUID()];
3380 
3381  // create group link to board readers
3382  if(artdaqSupervisorTable.tableView_
3383  ->getDataView()[artdaqSupervisorRow]
3384  [artdaqSupervisorTable.tableView_->findCol(
3385  colARTDAQSupervisor_.colLinkToBoardReaders_)] ==
3386  TableViewColumnInfo::DATATYPE_LINK_DEFAULT)
3387  {
3388  __COUT__ << "Fixing missing link to Readers" << __E__;
3389  artdaqSupervisorTable.tableView_->setValueAsString(
3390  ARTDAQ_READER_TABLE,
3391  artdaqSupervisorRow,
3392  artdaqSupervisorTable.tableView_->findCol(
3393  colARTDAQSupervisor_.colLinkToBoardReaders_));
3394  artdaqSupervisorTable.tableView_->setUniqueColumnValue(
3395  artdaqSupervisorRow,
3396  artdaqSupervisorTable.tableView_->findCol(
3397  colARTDAQSupervisor_.colLinkToBoardReadersGroupID_),
3398  artdaqSupervisorUID +
3399  processTypes_.mapToGroupIDAppend_.at(processTypes_.READER));
3400  }
3401 
3402  // create group link to event builders
3403  if(artdaqSupervisorTable.tableView_
3404  ->getDataView()[artdaqSupervisorRow]
3405  [artdaqSupervisorTable.tableView_->findCol(
3406  colARTDAQSupervisor_.colLinkToEventBuilders_)] ==
3407  TableViewColumnInfo::DATATYPE_LINK_DEFAULT)
3408  {
3409  __COUT__ << "Fixing missing link to Builders" << __E__;
3410  artdaqSupervisorTable.tableView_->setValueAsString(
3411  ARTDAQ_BUILDER_TABLE,
3412  artdaqSupervisorRow,
3413  artdaqSupervisorTable.tableView_->findCol(
3414  colARTDAQSupervisor_.colLinkToEventBuilders_));
3415  artdaqSupervisorTable.tableView_->setUniqueColumnValue(
3416  artdaqSupervisorRow,
3417  artdaqSupervisorTable.tableView_->findCol(
3418  colARTDAQSupervisor_.colLinkToEventBuildersGroupID_),
3419  artdaqSupervisorUID +
3420  processTypes_.mapToGroupIDAppend_.at(processTypes_.BUILDER));
3421  }
3422 
3423  // create group link to data loggers
3424  if(artdaqSupervisorTable.tableView_
3425  ->getDataView()[artdaqSupervisorRow]
3426  [artdaqSupervisorTable.tableView_->findCol(
3427  colARTDAQSupervisor_.colLinkToDataLoggers_)] ==
3428  TableViewColumnInfo::DATATYPE_LINK_DEFAULT)
3429  {
3430  __COUT__ << "Fixing missing link to Loggers" << __E__;
3431  artdaqSupervisorTable.tableView_->setValueAsString(
3432  ARTDAQ_LOGGER_TABLE,
3433  artdaqSupervisorRow,
3434  artdaqSupervisorTable.tableView_->findCol(
3435  colARTDAQSupervisor_.colLinkToDataLoggers_));
3436  artdaqSupervisorTable.tableView_->setUniqueColumnValue(
3437  artdaqSupervisorRow,
3438  artdaqSupervisorTable.tableView_->findCol(
3439  colARTDAQSupervisor_.colLinkToDataLoggersGroupID_),
3440  artdaqSupervisorUID +
3441  processTypes_.mapToGroupIDAppend_.at(processTypes_.LOGGER));
3442  }
3443 
3444  // create group link to dispatchers
3445  if(artdaqSupervisorTable.tableView_
3446  ->getDataView()[artdaqSupervisorRow]
3447  [artdaqSupervisorTable.tableView_->findCol(
3448  colARTDAQSupervisor_.colLinkToDispatchers_)] ==
3449  TableViewColumnInfo::DATATYPE_LINK_DEFAULT)
3450  {
3451  __COUT__ << "Fixing missing link to Dispatchers" << __E__;
3452  artdaqSupervisorTable.tableView_->setValueAsString(
3453  ARTDAQ_DISPATCHER_TABLE,
3454  artdaqSupervisorRow,
3455  artdaqSupervisorTable.tableView_->findCol(
3456  colARTDAQSupervisor_.colLinkToDispatchers_));
3457  artdaqSupervisorTable.tableView_->setUniqueColumnValue(
3458  artdaqSupervisorRow,
3459  artdaqSupervisorTable.tableView_->findCol(
3460  colARTDAQSupervisor_.colLinkToDispatchersGroupID_),
3461  artdaqSupervisorUID +
3462  processTypes_.mapToGroupIDAppend_.at(processTypes_.DISPATCHER));
3463  }
3464 
3465  // create group link to routing managers
3466  if(artdaqSupervisorTable.tableView_
3467  ->getDataView()[artdaqSupervisorRow]
3468  [artdaqSupervisorTable.tableView_->findCol(
3469  colARTDAQSupervisor_.colLinkToRoutingManagers_)] ==
3470  TableViewColumnInfo::DATATYPE_LINK_DEFAULT)
3471  {
3472  __COUT__ << "Fixing missing link to Routers" << __E__;
3473  artdaqSupervisorTable.tableView_->setValueAsString(
3474  ARTDAQ_ROUTER_TABLE,
3475  artdaqSupervisorRow,
3476  artdaqSupervisorTable.tableView_->findCol(
3477  colARTDAQSupervisor_.colLinkToRoutingManagers_));
3478  artdaqSupervisorTable.tableView_->setUniqueColumnValue(
3479  artdaqSupervisorRow,
3480  artdaqSupervisorTable.tableView_->findCol(
3481  colARTDAQSupervisor_.colLinkToRoutingManagersGroupID_),
3482  artdaqSupervisorUID +
3483  processTypes_.mapToGroupIDAppend_.at(processTypes_.ROUTER));
3484  }
3485 
3486  {
3487  std::stringstream ss;
3488  artdaqSupervisorTable.tableView_->print(ss);
3489  __COUT__ << ss.str();
3490  }
3491  } // end fixing links
3492 
3493  // Step 1. create/verify subsystems and destinations
3494  TableEditStruct& artdaqSubsystemTable = configGroupEdit.getTableEditStruct(
3495  ARTDAQ_SUBSYSTEM_TABLE, true /*markModified*/);
3496 
3497  // clear all records
3498  artdaqSubsystemTable.tableView_->deleteAllRows();
3499 
3500  for(auto& subsystemPair : subsystemObjectMap)
3501  {
3502  __COUTV__(subsystemPair.first);
3503  __COUTV__(subsystemPair.second);
3504 
3505  // create artdaq Subsystem record
3506  row = artdaqSubsystemTable.tableView_->addRow(
3507  author, true /*incrementUniqueData*/, subsystemPair.first);
3508 
3509  if(subsystemPair.second != "" &&
3510  subsystemPair.second != TableViewColumnInfo::DATATYPE_STRING_DEFAULT &&
3511  subsystemPair.second != NULL_SUBSYSTEM_DESTINATION_LABEL)
3512  {
3513  // set subsystem link
3514  artdaqSubsystemTable.tableView_->setValueAsString(
3515  ARTDAQ_SUBSYSTEM_TABLE,
3516  row,
3517  artdaqSubsystemTable.tableView_->findCol(
3518  colARTDAQSubsystem_.colLinkToDestination_));
3519  artdaqSubsystemTable.tableView_->setValueAsString(
3520  subsystemPair.second,
3521  row,
3522  artdaqSubsystemTable.tableView_->findCol(
3523  colARTDAQSubsystem_.colLinkToDestinationUID_));
3524  }
3525  // else leave disconnected link
3526 
3527  } // end subsystem loop
3528 
3529  // Step 2. for each node, create/verify records
3530  for(auto& nodeTypePair : nodeTypeToObjectMap)
3531  {
3532  __COUTV__(nodeTypePair.first);
3533 
3534  //__COUTV__(StringMacros::mapToString(processTypes_.mapToTable_));
3535 
3536  auto it = processTypes_.mapToTable_.find(nodeTypePair.first);
3537  if(it == processTypes_.mapToTable_.end())
3538  {
3539  __SS__ << "Invalid artdaq node type '" << nodeTypePair.first
3540  << "' attempted!" << __E__;
3541  __SS_THROW__;
3542  }
3543  __COUTV__(it->second);
3544 
3545  // test the table before getting for real
3546  try
3547  {
3548  /* TableEditStruct& tmpTypeTable = */ configGroupEdit.getTableEditStruct(
3549  it->second, true /*markModified*/);
3550  }
3551  catch(...)
3552  {
3553  if(nodeTypePair.second.size())
3554  throw; // do not ignore if user was trying to save records
3555 
3556  __COUT__ << "Ignoring missing table '" << it->second
3557  << "' since there were no user records attempted of type '"
3558  << nodeTypePair.first << ".'" << __E__;
3559  continue;
3560  }
3561  TableEditStruct& typeTable =
3562  configGroupEdit.getTableEditStruct(it->second, true /*markModified*/);
3563 
3564  // keep track of records to delete, initialize to all in current table
3565  std::map<unsigned int /*type record row*/, bool /*doDelete*/> deleteRecordMap;
3566  for(unsigned int r = 0; r < typeTable.tableView_->getNumberOfRows(); ++r)
3567  deleteRecordMap.emplace(std::make_pair(
3568  r, // typeTable.tableView_->getDataView()[i][typeTable.tableView_->getColUID()],
3569  true)); // init to delete
3570 
3571  // node instance loop
3572  for(auto& nodePair : nodeTypePair.second)
3573  {
3574  __COUTV__(nodePair.first);
3575 
3576  // default multi-node and array hostname info to empty
3577  std::vector<std::string> nodeIndices, hostnameIndices;
3578  unsigned int hostnameFixedWidth = 0, nodeNameFixedWidth = 0;
3579  std::string hostname;
3580 
3581  // keep a map original multinode values, to maintain node specific links
3582  // (emplace when original node is delete)
3583  std::map<std::string /*originalMultiNode name*/,
3584  std::map<unsigned int /*col*/, std::string /*value*/>>
3585  originalMultinodeValues;
3586 
3587  // if original record is found, then commandeer that record
3588  // else create a new record
3589  // Node properties: {originalName,hostname,subsystemName,(nodeArrString),(nodeNameFixedWidth),(hostnameArrString),(hostnameFixedWidth)}
3590 
3591  // node parameter loop
3592  for(unsigned int i = 0; i < nodePair.second.size(); ++i)
3593  {
3594  __COUTV__(nodePair.second[i]);
3595 
3596  if(i == 0) // original UID
3597  {
3598  std::string nodeName;
3599  // Steps:
3600  // if original was multi-node,
3601  // then delete all but one
3602  // else
3603  // take over the row, or create new
3604  if(nodePair.second[i][0] == ':')
3605  {
3606  __COUT__ << "Handling original multi-node." << __E__;
3607 
3608  // format:
3609  // :<nodeNameFixedWidth>:<nodeVectorIndexString>:<nodeNameTemplate>
3610 
3611  std::vector<std::string> originalParameterArr =
3613  &(nodePair.second[i].c_str()[1]),
3614  {':'} /*delimiter*/);
3615 
3616  if(originalParameterArr.size() != 3)
3617  {
3618  __SS__ << "Illegal original name parameter string '"
3619  << nodePair.second[i] << "!'" << __E__;
3620  __SS_THROW__;
3621  }
3622 
3623  unsigned int fixedWidth;
3624  sscanf(originalParameterArr[0].c_str(), "%u", &fixedWidth);
3625  __COUTV__(fixedWidth);
3626 
3627  std::vector<std::string> printerSyntaxArr =
3628  StringMacros::getVectorFromString(originalParameterArr[1],
3629  {','} /*delimiter*/);
3630 
3631  // unsigned int count = 0;
3632  std::vector<std::string> originalNodeIndices;
3633  for(auto& printerSyntaxValue : printerSyntaxArr)
3634  {
3635  __COUTV__(printerSyntaxValue);
3636 
3637  std::vector<std::string> printerSyntaxRange =
3639  printerSyntaxValue, {'-'} /*delimiter*/);
3640 
3641  if(printerSyntaxRange.size() == 0 ||
3642  printerSyntaxRange.size() > 2)
3643  {
3644  __SS__ << "Illegal multi-node printer syntax string '"
3645  << printerSyntaxValue << "!'" << __E__;
3646  __SS_THROW__;
3647  }
3648  else if(printerSyntaxRange.size() == 1)
3649  {
3650  __COUTV__(printerSyntaxRange[0]);
3651  originalNodeIndices.push_back(printerSyntaxRange[0]);
3652  }
3653  else // printerSyntaxRange.size() == 2
3654  {
3655  unsigned int lo, hi;
3656  sscanf(printerSyntaxRange[0].c_str(), "%u", &lo);
3657  sscanf(printerSyntaxRange[1].c_str(), "%u", &hi);
3658  if(hi < lo) // swap
3659  {
3660  lo = hi;
3661  sscanf(printerSyntaxRange[0].c_str(), "%u", &hi);
3662  }
3663  for(; lo <= hi; ++lo)
3664  {
3665  __COUTV__(lo);
3666  originalNodeIndices.push_back(std::to_string(lo));
3667  }
3668  }
3669  } // end printer syntax loop
3670 
3671  std::vector<std::string> originalNamePieces =
3672  StringMacros::getVectorFromString(originalParameterArr[2],
3673  {'*'} /*delimiter*/);
3674  __COUTV__(StringMacros::vectorToString(originalNamePieces));
3675 
3676  if(originalNamePieces.size() < 2)
3677  {
3678  __SS__ << "Illegal original multi-node name template - "
3679  "please use * to indicate where the multi-node "
3680  "index should be inserted!"
3681  << __E__;
3682  __SS_THROW__;
3683  }
3684 
3685  // bool isFirst = true;
3686  unsigned int originalRow = TableView::INVALID,
3687  lastOriginalRow = TableView::INVALID;
3688  for(unsigned int i = 0; i < originalNodeIndices.size(); ++i)
3689  {
3690  std::string originalName = originalNamePieces[0];
3691  std::string nodeNameIndex;
3692  for(unsigned int p = 1; p < originalNamePieces.size();
3693  ++p)
3694  {
3695  nodeNameIndex = originalNodeIndices[i];
3696  if(fixedWidth > 1)
3697  {
3698  if(nodeNameIndex.size() > fixedWidth)
3699  {
3700  __SS__ << "Illegal original node name index '"
3701  << nodeNameIndex
3702  << "' - length is longer than fixed "
3703  "width requirement of "
3704  << fixedWidth << "!" << __E__;
3705  __SS_THROW__;
3706  }
3707 
3708  // 0 prepend as needed
3709  while(nodeNameIndex.size() < fixedWidth)
3710  nodeNameIndex = "0" + nodeNameIndex;
3711  } // end fixed width handling
3712 
3713  originalName += nodeNameIndex + originalNamePieces[p];
3714  }
3715  __COUTV__(originalName);
3716  originalRow = typeTable.tableView_->findRow(
3717  typeTable.tableView_->getColUID(),
3718  originalName,
3719  0 /*offsetRow*/,
3720  true /*doNotThrow*/);
3721  __COUTV__(originalRow);
3722 
3723  // if have a new valid row, then delete last valid row
3724  if(originalRow != TableView::INVALID &&
3725  lastOriginalRow != TableView::INVALID)
3726  {
3727  // before deleting, record all customizing values and maintain when saving
3728  originalMultinodeValues.emplace(std::make_pair(
3729  nodeName,
3730  std::map<unsigned int /*col*/,
3731  std::string /*value*/>()));
3732 
3733  __COUT__ << "Saving multinode value " << nodeName
3734  << "[" << lastOriginalRow
3735  << "][*] with row count = "
3736  << typeTable.tableView_->getNumberOfRows()
3737  << __E__;
3738 
3739  // save all link values
3740  for(unsigned int col = 0;
3741  col < typeTable.tableView_->getNumberOfColumns();
3742  ++col)
3743  if(typeTable.tableView_->getColumnInfo(col)
3744  .getName() ==
3745  ARTDAQTableBase::
3746  ARTDAQ_TYPE_TABLE_SUBSYSTEM_LINK ||
3747  typeTable.tableView_->getColumnInfo(col)
3748  .getName() ==
3749  ARTDAQTableBase::
3750  ARTDAQ_TYPE_TABLE_SUBSYSTEM_LINK_UID)
3751  continue; // skip subsystem link
3752  else if(typeTable.tableView_->getColumnInfo(col)
3753  .isChildLink() ||
3754  typeTable.tableView_->getColumnInfo(col)
3755  .isChildLinkGroupID() ||
3756  typeTable.tableView_->getColumnInfo(col)
3757  .isChildLinkUID())
3758  originalMultinodeValues.at(nodeName).emplace(
3759  std::make_pair(
3760  col,
3761  typeTable.tableView_
3762  ->getDataView()[lastOriginalRow]
3763  [col]));
3764 
3765  typeTable.tableView_->deleteRow(lastOriginalRow);
3766  if(originalRow > lastOriginalRow)
3767  --originalRow; // modify after delete
3768  }
3769 
3770  if(originalRow != TableView::INVALID)
3771  {
3772  lastOriginalRow =
3773  originalRow; // save last valid row for future deletion
3774  nodeName = originalName;
3775  }
3776 
3777  } // end loop through multi-node instances
3778 
3779  row = lastOriginalRow; // take last valid row to proceed
3780 
3781  __COUTV__(nodeName);
3782  __COUTV__(row);
3783 
3784  } // end handling of original multinode
3785  else
3786  {
3787  // attempt to find original 'single' node name
3788  row = typeTable.tableView_->findRow(
3789  typeTable.tableView_->getColUID(),
3790  nodePair.second[i],
3791  0 /*offsetRow*/,
3792  true /*doNotThrow*/);
3793  __COUTV__(row);
3794 
3795  nodeName = nodePair.first; // take new node name
3796  }
3797 
3798  __COUTV__(nodeName);
3799  if(row == TableView::INVALID)
3800  {
3801  // create artdaq type instance record
3802  row = typeTable.tableView_->addRow(
3803  author, true /*incrementUniqueData*/, nodeName);
3804 
3805  // fill defaults properties/parameters here!
3806  if(nodeTypePair.first == processTypes_.READER)
3807  {
3808  __COUT__ << "Handling new " << nodeTypePair.first
3809  << " defaults!" << __E__;
3810  TableEditStruct& daqParameterTable =
3811  configGroupEdit.getTableEditStruct(
3812  ARTDAQTableBase::ARTDAQ_DAQ_PARAMETER_TABLE,
3813  true /*markModified*/);
3814 
3815  // create group link to daq parameter table
3816  typeTable.tableView_->setValueAsString(
3817  ARTDAQTableBase::ARTDAQ_DAQ_PARAMETER_TABLE,
3818  row,
3819  typeTable.tableView_->findCol(
3820  ARTDAQTableBase::colARTDAQReader_
3821  .colLinkToDaqParameters_));
3822  std::string daqParameterGroupID =
3823  typeTable.tableView_->setUniqueColumnValue(
3824  row,
3825  typeTable.tableView_->findCol(
3826  ARTDAQTableBase::colARTDAQReader_
3827  .colLinkToDaqParametersGroupID_),
3828  nodeName + "DaqParameters");
3829 
3830  typeTable.tableView_->print();
3831 
3832  // now create parameters at target link
3833  const std::vector<std::string> parameterUIDs = {
3834  "BoardID", "FragmentID"};
3835 
3836  const std::vector<std::string> parameterNames = {
3837  "board_id", //"BoardID",
3838  "fragment_id", //"FragmentID"
3839  };
3840  const std::vector<std::string> parameterValues = {
3841  "0", //"BoardID",
3842  "0" //"FragmentID",
3843  };
3844 
3845  unsigned int parameterRow;
3846  for(unsigned int i = 0; i < parameterNames.size(); ++i)
3847  {
3848  // create artdaq Reader property record
3849  parameterRow = daqParameterTable.tableView_->addRow(
3850  author,
3851  true /*incrementUniqueData*/,
3852  nodeName + parameterUIDs[i]);
3853 
3854  // set app status true
3855  daqParameterTable.tableView_->setValueAsString(
3856  "1",
3857  parameterRow,
3858  daqParameterTable.tableView_->getColStatus());
3859  // set key
3860  daqParameterTable.tableView_->setValueAsString(
3861  parameterNames[i],
3862  parameterRow,
3863  daqParameterTable.tableView_->findCol(
3864  ARTDAQTableBase::colARTDAQDaqParameter_
3865  .colDaqParameterKey_));
3866  // set value
3867  daqParameterTable.tableView_->setValueAsString(
3868  parameterValues[i],
3869  parameterRow,
3870  daqParameterTable.tableView_->findCol(
3871  ARTDAQTableBase::colARTDAQDaqParameter_
3872  .colDaqParameterValue_));
3873  // set groupid
3874  daqParameterTable.tableView_->setValueAsString(
3875  daqParameterGroupID,
3876  parameterRow,
3877  daqParameterTable.tableView_->findCol(
3878  ARTDAQTableBase::colARTDAQDaqParameter_
3879  .colDaqParameterGroupID_));
3880 
3881  } // end Reader default property create loop
3882 
3883  daqParameterTable.tableView_
3884  ->init(); // verify new table (throws runtime_errors)
3885 
3886  } // end Reader default property setup
3887  else if(nodeTypePair.first == processTypes_.BUILDER ||
3888  nodeTypePair.first == processTypes_.LOGGER ||
3889  nodeTypePair.first == processTypes_.DISPATCHER)
3890  {
3891  __COUT__ << "Handling new " << nodeTypePair.first
3892  << " defaults!" << __E__;
3893 
3894  // goes through DAQ table
3895  TableEditStruct& daqTable =
3896  configGroupEdit.getTableEditStruct(
3897  ARTDAQTableBase::ARTDAQ_DAQ_TABLE,
3898  true /*markModified*/);
3899  // create DAQ record
3900  unsigned int daqRecordRow = daqTable.tableView_->addRow(
3901  author,
3902  true /*incrementUniqueData*/,
3903  nodeName + "Daq");
3904  std::string daqRecordUID =
3905  daqTable.tableView_
3906  ->getDataView()[daqRecordRow]
3907  [daqTable.tableView_->getColUID()];
3908 
3909  // create unique link to daq table
3910  typeTable.tableView_->setValueAsString(
3911  ARTDAQTableBase::ARTDAQ_DAQ_TABLE,
3912  row,
3913  typeTable.tableView_->findCol(
3914  ARTDAQTableBase::colARTDAQNotReader_
3915  .colLinkToDaq_));
3916  typeTable.tableView_->setValueAsString(
3917  daqRecordUID,
3918  row,
3919  typeTable.tableView_->findCol(
3920  ARTDAQTableBase::colARTDAQNotReader_
3921  .colLinkToDaqUID_));
3922 
3923  TableEditStruct& daqParameterTable =
3924  configGroupEdit.getTableEditStruct(
3925  ARTDAQTableBase::ARTDAQ_DAQ_PARAMETER_TABLE,
3926  true /*markModified*/);
3927  // create group link to daq parameter table
3928  daqTable.tableView_->setValueAsString(
3929  ARTDAQTableBase::ARTDAQ_DAQ_PARAMETER_TABLE,
3930  daqRecordRow,
3931  daqTable.tableView_->findCol(
3932  ARTDAQTableBase::colARTDAQDaq_
3933  .colLinkToDaqParameters_));
3934  std::string daqParameterGroupID =
3935  daqTable.tableView_->setUniqueColumnValue(
3936  daqRecordRow,
3937  daqTable.tableView_->findCol(
3938  ARTDAQTableBase::colARTDAQDaq_
3939  .colLinkToDaqParametersGroupID_),
3940  nodeName + "DaqParameters");
3941 
3942  // now create parameters at target link
3943  const std::vector<std::string> parameterUIDs = {
3944  "BufferCount", "FragmentsPerEvent"};
3945 
3946  const std::vector<std::string> parameterNames = {
3947  "buffer_count", //"BufferCount",
3948  "expected_fragments_per_event" //"FragmentsPerEvent"
3949  };
3950  const std::vector<std::string> parameterValues = {
3951  "10", //"BufferCount",
3952  "0" //"FragmentsPerEvent",
3953  };
3954 
3955  unsigned int parameterRow;
3956  for(unsigned int i = 0; i < parameterNames.size(); ++i)
3957  {
3958  // create artdaq Reader property record
3959  parameterRow = daqParameterTable.tableView_->addRow(
3960  author,
3961  true /*incrementUniqueData*/,
3962  nodeName + parameterUIDs[i]);
3963 
3964  // set app status true
3965  daqParameterTable.tableView_->setValueAsString(
3966  "1",
3967  parameterRow,
3968  daqParameterTable.tableView_->getColStatus());
3969  // set key
3970  daqParameterTable.tableView_->setValueAsString(
3971  parameterNames[i],
3972  parameterRow,
3973  daqParameterTable.tableView_->findCol(
3974  ARTDAQTableBase::colARTDAQDaqParameter_
3975  .colDaqParameterKey_));
3976  // set value
3977  daqParameterTable.tableView_->setValueAsString(
3978  parameterValues[i],
3979  parameterRow,
3980  daqParameterTable.tableView_->findCol(
3981  ARTDAQTableBase::colARTDAQDaqParameter_
3982  .colDaqParameterValue_));
3983  // set groupid
3984  daqParameterTable.tableView_->setValueAsString(
3985  daqParameterGroupID,
3986  parameterRow,
3987  daqParameterTable.tableView_->findCol(
3988  ARTDAQTableBase::colARTDAQDaqParameter_
3989  .colDaqParameterGroupID_));
3990 
3991  } // end Reader default property create loop
3992 
3993  daqTable.tableView_
3994  ->init(); // verify new table (throws runtime_errors)
3995  daqParameterTable.tableView_
3996  ->init(); // verify new table (throws runtime_errors)
3997 
3998  } // end Builder, Logger, Dispatcher default property setup
3999  }
4000  else // set UID
4001  {
4002  typeTable.tableView_->setValueAsString(
4003  nodeName, row, typeTable.tableView_->getColUID());
4004  }
4005  __COUTV__(row);
4006 
4007  // remove from delete map
4008  deleteRecordMap[row] = false;
4009 
4010  __COUTV__(StringMacros::mapToString(
4011  processTypes_.mapToLinkGroupIDColumn_));
4012 
4013  // set GroupID
4014  typeTable.tableView_->setValueAsString(
4015  artdaqSupervisorTable.tableView_
4016  ->getDataView()[artdaqSupervisorRow]
4017  [artdaqSupervisorTable.tableView_->findCol(
4018  processTypes_.mapToLinkGroupIDColumn_
4019  .at(nodeTypePair.first))],
4020  row,
4021  typeTable.tableView_->findCol(
4022  processTypes_.mapToGroupIDColumn_.at(
4023  nodeTypePair.first)));
4024  }
4025  else if(i == 1) // status
4026  {
4027  // enable/disable the target row
4028  typeTable.tableView_->setValueAsString(
4029  nodePair.second[i],
4030  row,
4031  typeTable.tableView_->getColStatus());
4032  }
4033  else if(i == 2) // hostname
4034  {
4035  // set hostname
4036  hostname = nodePair.second[i];
4037  typeTable.tableView_->setValueAsString(
4038  hostname,
4039  row,
4040  typeTable.tableView_->findCol(ARTDAQ_TYPE_TABLE_HOSTNAME));
4041  }
4042  else if(i == 3) // subsystemName
4043  {
4044  // set subsystemName
4045  if(nodePair.second[i] != "" &&
4046  nodePair.second[i] !=
4047  TableViewColumnInfo::DATATYPE_STRING_DEFAULT)
4048  {
4049  // real subsystem?
4050  if(subsystemObjectMap.find(nodePair.second[i]) ==
4051  subsystemObjectMap.end())
4052  {
4053  __SS__ << "Illegal subsystem '" << nodePair.second[i]
4054  << "' mismatch!" << __E__;
4055  __SS_THROW__;
4056  }
4057 
4058  typeTable.tableView_->setValueAsString(
4059  ARTDAQ_SUBSYSTEM_TABLE,
4060  row,
4061  typeTable.tableView_->findCol(
4062  ARTDAQ_TYPE_TABLE_SUBSYSTEM_LINK));
4063  typeTable.tableView_->setValueAsString(
4064  nodePair.second[i],
4065  row,
4066  typeTable.tableView_->findCol(
4067  ARTDAQ_TYPE_TABLE_SUBSYSTEM_LINK_UID));
4068  }
4069  else // no subsystem (i.e. default subsystem)
4070  {
4071  typeTable.tableView_->setValueAsString(
4072  TableViewColumnInfo::DATATYPE_LINK_DEFAULT,
4073  row,
4074  typeTable.tableView_->findCol(
4075  ARTDAQ_TYPE_TABLE_SUBSYSTEM_LINK));
4076  }
4077  }
4078  else if(
4079  i == 4 || i == 5 || i == 6 ||
4080  i ==
4081  7) //(nodeArrString),(nodeNameFixedWidth),(hostnameArrString),(hostnameFixedWidth)
4082  {
4083  // fill multi-node and array hostname info to empty
4084  // then handle after all parameters in hand.
4085 
4086  __COUT__ << "Handling printer syntax i=" << i << __E__;
4087 
4088  std::vector<std::string> printerSyntaxArr =
4089  StringMacros::getVectorFromString(nodePair.second[i],
4090  {','} /*delimiter*/);
4091 
4092  if(printerSyntaxArr.size() == 2) // consider if fixed value
4093  {
4094  if(printerSyntaxArr[0] ==
4095  "nnfw") // then node name fixed width
4096  {
4097  sscanf(printerSyntaxArr[1].c_str(),
4098  "%u",
4099  &nodeNameFixedWidth);
4100  __COUTV__(nodeNameFixedWidth);
4101  continue;
4102  }
4103  else if(printerSyntaxArr[0] ==
4104  "hnfw") // then hostname fixed width
4105  {
4106  sscanf(printerSyntaxArr[1].c_str(),
4107  "%u",
4108  &hostnameFixedWidth);
4109  __COUTV__(hostnameFixedWidth);
4110  continue;
4111  }
4112  }
4113 
4114  // unsigned int count = 0;
4115  for(auto& printerSyntaxValue : printerSyntaxArr)
4116  {
4117  __COUTV__(printerSyntaxValue);
4118 
4119  std::vector<std::string> printerSyntaxRange =
4120  StringMacros::getVectorFromString(printerSyntaxValue,
4121  {'-'} /*delimiter*/);
4122  if(printerSyntaxRange.size() == 0 ||
4123  printerSyntaxRange.size() > 2)
4124  {
4125  __SS__ << "Illegal multi-node printer syntax string '"
4126  << printerSyntaxValue << "!'" << __E__;
4127  __SS_THROW__;
4128  }
4129  else if(printerSyntaxRange.size() == 1)
4130  {
4131  // unsigned int index;
4132  __COUTV__(printerSyntaxRange[0]);
4133  // sscanf(printerSyntaxRange[0].c_str(), "%u", &index);
4134  //__COUTV__(index);
4135 
4136  if(i == 4 /*nodeArrayString*/)
4137  nodeIndices.push_back(printerSyntaxRange[0]);
4138  else
4139  hostnameIndices.push_back(printerSyntaxRange[0]);
4140  }
4141  else // printerSyntaxRange.size() == 2
4142  {
4143  unsigned int lo, hi;
4144  sscanf(printerSyntaxRange[0].c_str(), "%u", &lo);
4145  sscanf(printerSyntaxRange[1].c_str(), "%u", &hi);
4146  if(hi < lo) // swap
4147  {
4148  lo = hi;
4149  sscanf(printerSyntaxRange[0].c_str(), "%u", &hi);
4150  }
4151  for(; lo <= hi; ++lo)
4152  {
4153  __COUTV__(lo);
4154  if(i == 4 /*nodeArrayString*/)
4155  nodeIndices.push_back(std::to_string(lo));
4156  else
4157  hostnameIndices.push_back(std::to_string(lo));
4158  }
4159  }
4160  }
4161  }
4162  else
4163  {
4164  __SS__ << "Unexpected parameter[" << i << " '"
4165  << nodePair.second[i] << "' for node " << nodePair.first
4166  << "!" << __E__;
4167  __SS_THROW__;
4168  }
4169  } // end node parameter loop
4170 
4171  __COUTV__(nodeIndices.size());
4172  __COUTV__(hostnameIndices.size());
4173 
4174  if(hostnameIndices.size()) // handle hostname array
4175  {
4176  if(hostnameIndices.size() != nodeIndices.size())
4177  {
4178  __SS__ << "Illegal associated hostname array has count "
4179  << hostnameIndices.size()
4180  << " which is not equal to the node count "
4181  << nodeIndices.size() << "!" << __E__;
4182  __SS_THROW__;
4183  }
4184  }
4185 
4186  if(nodeIndices.size()) // handle multi-node instances
4187  {
4188  unsigned int hostnameCol =
4189  typeTable.tableView_->findCol(ARTDAQ_TYPE_TABLE_HOSTNAME);
4190  // Steps:
4191  // first instance takes current row,
4192  // then copy for remaining instances
4193 
4194  std::vector<std::string> namePieces =
4195  StringMacros::getVectorFromString(nodePair.first,
4196  {'*'} /*delimiter*/);
4197  __COUTV__(StringMacros::vectorToString(namePieces));
4198 
4199  if(namePieces.size() < 2)
4200  {
4201  __SS__
4202  << "Illegal multi-node name template - please use * to "
4203  "indicate where the multi-node index should be inserted!"
4204  << __E__;
4205  __SS_THROW__;
4206  }
4207 
4208  std::vector<std::string> hostnamePieces;
4209  if(hostnameIndices.size()) // handle hostname array
4210  {
4211  hostnamePieces = StringMacros::getVectorFromString(
4212  hostname, {'*'} /*delimiter*/);
4213  __COUTV__(StringMacros::vectorToString(hostnamePieces));
4214 
4215  if(hostnamePieces.size() < 2)
4216  {
4217  __SS__
4218  << "Illegal hostname array template - please use * to "
4219  "indicate where the hostname index should be inserted!"
4220  << __E__;
4221  __SS_THROW__;
4222  }
4223  }
4224 
4225  bool isFirst = true;
4226  for(unsigned int i = 0; i < nodeIndices.size(); ++i)
4227  {
4228  std::string name = namePieces[0];
4229  std::string nodeNameIndex;
4230  for(unsigned int p = 1; p < namePieces.size(); ++p)
4231  {
4232  nodeNameIndex = nodeIndices[i];
4233  if(nodeNameFixedWidth > 1)
4234  {
4235  if(nodeNameIndex.size() > nodeNameFixedWidth)
4236  {
4237  __SS__ << "Illegal node name index '" << nodeNameIndex
4238  << "' - length is longer than fixed width "
4239  "requirement of "
4240  << nodeNameFixedWidth << "!" << __E__;
4241  __SS_THROW__;
4242  }
4243 
4244  // 0 prepend as needed
4245  while(nodeNameIndex.size() < nodeNameFixedWidth)
4246  nodeNameIndex = "0" + nodeNameIndex;
4247  } // end fixed width handling
4248 
4249  name += nodeNameIndex + namePieces[p];
4250  }
4251  __COUTV__(name);
4252 
4253  if(hostnamePieces.size())
4254  {
4255  hostname = hostnamePieces[0];
4256  std::string hostnameIndex;
4257  for(unsigned int p = 1; p < hostnamePieces.size(); ++p)
4258  {
4259  hostnameIndex = hostnameIndices[i];
4260  if(hostnameFixedWidth > 1)
4261  {
4262  if(hostnameIndex.size() > hostnameFixedWidth)
4263  {
4264  __SS__ << "Illegal hostname index '"
4265  << hostnameIndex
4266  << "' - length is longer than fixed width "
4267  "requirement of "
4268  << hostnameFixedWidth << "!" << __E__;
4269  __SS_THROW__;
4270  }
4271 
4272  // 0 prepend as needed
4273  while(hostnameIndex.size() < hostnameFixedWidth)
4274  hostnameIndex = "0" + hostnameIndex;
4275  } // end fixed width handling
4276 
4277  hostname += hostnameIndex + hostnamePieces[p];
4278  }
4279  __COUTV__(hostname);
4280  }
4281  // else use hostname from above
4282 
4283  if(isFirst) // take current row
4284  {
4285  typeTable.tableView_->setValueAsString(
4286  name, row, typeTable.tableView_->getColUID());
4287 
4288  typeTable.tableView_->setValueAsString(
4289  hostname, row, hostnameCol);
4290 
4291  // remove from delete map
4292  deleteRecordMap[row] = false;
4293  }
4294  else // copy row
4295  {
4296  unsigned int copyRow = typeTable.tableView_->copyRows(
4297  author,
4298  *(typeTable.tableView_),
4299  row,
4300  1 /*srcRowsToCopy*/,
4301  -1 /*destOffsetRow*/,
4302  true /*generateUniqueDataColumns*/);
4303  typeTable.tableView_->setValueAsString(
4304  name, copyRow, typeTable.tableView_->getColUID());
4305  typeTable.tableView_->setValueAsString(
4306  hostname, copyRow, hostnameCol);
4307 
4308  // customize row if in original value map
4309  if(originalMultinodeValues.find(name) !=
4310  originalMultinodeValues.end())
4311  {
4312  for(const auto& valuePair :
4313  originalMultinodeValues.at(name))
4314  {
4315  __COUT__ << "Customizing node: " << name << "["
4316  << copyRow << "][" << valuePair.first
4317  << "] = " << valuePair.second << __E__;
4318  typeTable.tableView_->setValueAsString(
4319  valuePair.second, copyRow, valuePair.first);
4320  }
4321  }
4322 
4323  // remove from delete map
4324  deleteRecordMap[copyRow] = false;
4325  } // end copy and customize row handling
4326 
4327  isFirst = false;
4328  } // end multi-node loop
4329  } // end multi-node handling
4330  } // end node record loop
4331 
4332  { // delete record handling
4333  __COUT__ << "Deleting '" << nodeTypePair.first
4334  << "' records not specified..." << __E__;
4335 
4336  // unsigned int row;
4337  std::set<unsigned int> orderedRowSet; // need to delete in reverse order
4338  for(auto& deletePair : deleteRecordMap)
4339  {
4340  __COUTV__(deletePair.first);
4341  if(!deletePair.second)
4342  continue; // only delete if true
4343 
4344  __COUTV__(deletePair.first);
4345  orderedRowSet.emplace(deletePair.first);
4346  }
4347 
4348  // delete elements in reverse order
4349  for(std::set<unsigned int>::reverse_iterator rit = orderedRowSet.rbegin();
4350  rit != orderedRowSet.rend();
4351  rit++)
4352  typeTable.tableView_->deleteRow(*rit);
4353 
4354  } // end delete record handling
4355 
4356  {
4357  std::stringstream ss;
4358  typeTable.tableView_->print(ss);
4359  __COUT__ << ss.str();
4360  }
4361 
4362  typeTable.tableView_->init(); // verify new table (throws runtime_errors)
4363 
4364  } // end node type loop
4365 
4366  {
4367  std::stringstream ss;
4368  artdaqSupervisorTable.tableView_->print(ss);
4369  __COUT__ << ss.str();
4370  }
4371  {
4372  std::stringstream ss;
4373  artdaqSubsystemTable.tableView_->print(ss);
4374  __COUT__ << ss.str();
4375  }
4376 
4377  artdaqSupervisorTable.tableView_
4378  ->init(); // verify new table (throws runtime_errors)
4379  artdaqSubsystemTable.tableView_
4380  ->init(); // verify new table (throws runtime_errors)
4381  }
4382  catch(...)
4383  {
4384  __COUT__ << "Table errors while creating ARTDAQ nodes. Erasing all newly "
4385  "created table versions."
4386  << __E__;
4387  throw; // re-throw
4388  } // end catch
4389 
4390  __COUT__ << "Edits complete for artdaq nodes and subsystems.. now save and activate "
4391  "groups, and update aliases!"
4392  << __E__;
4393 
4394  TableGroupKey newConfigurationGroupKey;
4395  {
4396  std::string localAccumulatedWarnings;
4397  configGroupEdit.saveChanges(configGroupEdit.originalGroupName_,
4398  newConfigurationGroupKey,
4399  nullptr /*foundEquivalentGroupKey*/,
4400  true /*activateNewGroup*/,
4401  true /*updateGroupAliases*/,
4402  true /*updateTableAliases*/,
4403  nullptr /*newBackboneKey*/,
4404  nullptr /*foundEquivalentBackboneKey*/,
4405  &localAccumulatedWarnings);
4406  }
4407 
4408 } // end setAndActivateARTDAQSystem()
4409 
4410 //==============================================================================
4411 int ARTDAQTableBase::getSubsytemId(ConfigurationTree subsystemNode)
4412 {
4413  // using row forces a unique ID from 0 to rows-1
4414  // note: default no defined subsystem link to id=1; so add 2
4415 
4416  return subsystemNode.getNodeRow() + 2;
4417 } // end getSubsytemId()
<virtual so future plugins can inherit from multiple table base classes
static std::string insertModuleType(std::ostream &out, std::string &tabStr, std::string &commentStr, ConfigurationTree moduleTypeNode)
static bool isARTDAQEnabled(const ConfigurationManager *cfgMgr)
isARTDAQEnabled
static void setAndActivateARTDAQSystem(ConfigurationManagerRW *cfgMgr, const std::map< std::string, std::map< std::string, std::vector< std::string >>> &nodeTypeToObjectMap, const std::map< std::string, std::string > &subsystemObjectMap)
static struct ots::ARTDAQTableBase::ProcessTypes processTypes_
Note!!!! processTypes_ must be instantiate after the static artdaq table names (to construct map in c...
static void outputOnlineMonitorFHICL(const ConfigurationTree &onlineMonitorNode)
static void insertParameters(std::ostream &out, std::string &tabStr, std::string &commentStr, ConfigurationTree parameterLink, const std::string &parameterPreamble, bool onlyInsertAtTableParameters=false, bool includeAtTableParameters=false)
static const ARTDAQInfo & getARTDAQSystem(ConfigurationManagerRW *cfgMgr, std::map< std::string, std::map< std::string, std::vector< std::string >>> &nodeTypeToObjectMap, std::map< std::string, std::string > &subsystemObjectMap, std::vector< std::string > &artdaqSupervisoInfo)
static void insertMetricsBlock(std::ostream &out, std::string &tabStr, std::string &commentStr, ConfigurationTree daqNode)
insertMetricsBlock
static void insertArtProcessBlock(std::ostream &out, std::string &tabStr, std::string &commentStr, ConfigurationTree art, ConfigurationTree subsystemLink=ConfigurationTree(), size_t routingTimeoutMs=DEFAULT_ROUTING_TIMEOUT_MS, size_t routingRetryCount=DEFAULT_ROUTING_RETRY_COUNT)
static void outputDataReceiverFHICL(const ConfigurationTree &receiverNode, ARTDAQAppType appType, size_t maxFragmentSizeBytes=DEFAULT_MAX_FRAGMENT_SIZE, size_t routingTimeoutMs=DEFAULT_ROUTING_TIMEOUT_MS, size_t routingRetryCount=DEFAULT_ROUTING_RETRY_COUNT)
ConfigurationTree getNode(const std::string &nodeString, bool doNotThrowOnBrokenUIDLinks=false) const
"root/parent/parent/"
const std::string & getUsername(void) const
Getters.
const unsigned int & getRow(void) const
getRow
bool isDisconnected(void) const
ConfigurationTree getNode(const std::string &nodeName, bool doNotThrowOnBrokenUIDLinks=false) const
navigating between nodes
T getValueWithDefault(const T &defaultValue) const
void getValue(T &value) const
std::vector< std::pair< std::string, ConfigurationTree > > getChildren(std::map< std::string, std::string > filterMap=std::map< std::string, std::string >(), bool byPriority=false, bool onlyStatusTrue=false) const
const std::string & getUIDAsString(void) const
const unsigned int & getNodeRow(void) const
getNodeRow
void step()
thread safe
Definition: ProgressBar.cc:75
bool isChildLinkGroupID(void) const
unsigned int findRow(unsigned int col, const T &value, unsigned int offsetRow=0, bool doNotThrow=false) const
< in included .icc source
void setValueAsString(const std::string &value, unsigned int row, unsigned int col)
Definition: TableView.cc:1078
void deleteRow(int r)
Definition: TableView.cc:3424
unsigned int getColStatus(void) const
Definition: TableView.cc:1390
unsigned int copyRows(const std::string &author, const TableView &src, unsigned int srcOffsetRow=0, unsigned int srcRowsToCopy=(unsigned int) -1, unsigned int destOffsetRow=(unsigned int) -1, unsigned char generateUniqueDataColumns=false, const std::string &baseNameAutoUID="")
Definition: TableView.cc:125
const std::string & setUniqueColumnValue(unsigned int row, unsigned int col, std::string baseValueAsString="", bool doMathAppendStrategy=false, std::string childLinkIndex="", std::string groupId="")
Definition: TableView.cc:1098
void init(void)
Definition: TableView.cc:189
unsigned int getColUID(void) const
Definition: TableView.cc:1305
unsigned int findCol(const std::string &name) const
Definition: TableView.cc:1935
unsigned int addRow(const std::string &author="", unsigned char incrementUniqueData=false, const std::string &baseNameAutoUID="", unsigned int rowToAdd=(unsigned int) -1, std::string childLinkIndex="", std::string groupId="")
Definition: TableView.cc:3339
const XDAQContext * getTheARTDAQSupervisorContext(void) const
artdaq specific get methods
ARTDAQ DAQ Parameter Column names.
ARTDAQ Builder/Logger/Dispatcher Column names.
ARTDAQ Reader Column names.
ARTDAQ Subsystem Column names.
ARTDAQ Supervisor Column names.
TableEditStruct & getTableEditStruct(const std::string &tableName, bool markModified=false)
Note: if markModified, and table not found in group, this function will try to add it to group.
static std::string getTimestampString(const std::string &linuxTimeInSeconds)
static void getVectorFromString(const std::string &inputString, std::vector< std::string > &listToReturn, const std::set< char > &delimiter={',', '|', '&'}, const std::set< char > &whitespace={' ', '\t', '\n', '\r'}, std::vector< char > *listOfDelimiters=0, bool decodeURIComponents=false)
static std::string setToString(const std::set< T > &setToReturn, const std::string &delimeter=", ")
setToString ~
static std::string vectorToString(const std::vector< T > &setToReturn, const std::string &delimeter=", ")
vectorToString ~
static bool extractCommonChunks(const std::vector< std::string > &haystack, std::vector< std::string > &commonChunksToReturn, std::vector< std::string > &wildcardStrings, unsigned int &fixedWildcardLength)
static std::string mapToString(const std::map< std::string, T > &mapToReturn, const std::string &primaryDelimeter=", ", const std::string &secondaryDelimeter=": ")