otsdaq  v2_04_01
FEVInterfacesManager.cc
1 #include "otsdaq-core/FECore/FEVInterfacesManager.h"
2 #include "otsdaq-core/ConfigurationInterface/ConfigurationManager.h"
3 #include "otsdaq-core/Macros/CoutMacros.h"
4 #include "otsdaq-core/MessageFacility/MessageFacility.h"
5 #include "otsdaq-core/PluginMakers/MakeInterface.h"
6 
7 #include "artdaq-core/Utilities/configureMessageFacility.hh"
8 #include "artdaq/BuildInfo/GetPackageBuildInfo.hh"
9 #include "fhiclcpp/make_ParameterSet.h"
10 #include "messagefacility/MessageLogger/MessageLogger.h"
11 
12 #include <iostream>
13 #include <sstream>
14 #include <thread> //for std::thread
15 
16 using namespace ots;
17 
18 //========================================================================================================================
19 FEVInterfacesManager::FEVInterfacesManager(
20  const ConfigurationTree& theXDAQContextConfigTree,
21  const std::string& supervisorConfigurationPath)
22  : Configurable(theXDAQContextConfigTree, supervisorConfigurationPath)
23 {
24  init();
25  __CFG_COUT__ << "Constructed." << __E__;
26 }
27 
28 //========================================================================================================================
29 FEVInterfacesManager::~FEVInterfacesManager(void)
30 {
31  destroy();
32  __CFG_COUT__ << "Destructed." << __E__;
33 }
34 
35 //========================================================================================================================
36 void FEVInterfacesManager::init(void) {}
37 
38 //========================================================================================================================
39 void FEVInterfacesManager::destroy(void)
40 {
41  for(auto& it : theFEInterfaces_)
42  it.second.reset();
43 
44  theFEInterfaces_.clear();
45  theFENamesByPriority_.clear();
46 }
47 
48 //========================================================================================================================
49 void FEVInterfacesManager::createInterfaces(void)
50 {
51  const std::string COL_NAME_feGroupLink = "LinkToFEInterfaceTable";
52  const std::string COL_NAME_feTypeLink = "LinkToFETypeTable";
53  const std::string COL_NAME_fePlugin = "FEInterfacePluginName";
54 
55  __CFG_COUT__ << "Path: " << theConfigurationPath_ + "/" + COL_NAME_feGroupLink
56  << __E__;
57 
58  destroy();
59 
60  { // could access application node like so, ever needed?
61  ConfigurationTree appNode =
62  theXDAQContextConfigTree_.getBackNode(theConfigurationPath_, 1);
63  __CFG_COUTV__(appNode.getValueAsString());
64 
65  auto fes = appNode.getNode("LinkToSupervisorTable")
66  .getNode("LinkToFEInterfaceTable")
67  .getChildrenNames(true /*byPriority*/, true /*onlyStatusTrue*/);
68  __CFG_COUTV__(StringMacros::vectorToString(fes));
69  }
70 
71  ConfigurationTree feGroupLinkNode =
72  Configurable::getSelfNode().getNode(COL_NAME_feGroupLink);
73 
74  std::vector<std::pair<std::string, ConfigurationTree>> feChildren =
75  feGroupLinkNode.getChildren();
76 
77  // acquire names by priority
78  theFENamesByPriority_ =
79  feGroupLinkNode.getChildrenNames(true /*byPriority*/, true /*onlyStatusTrue*/);
80  __CFG_COUTV__(StringMacros::vectorToString(theFENamesByPriority_));
81 
82  for(const auto& interface : feChildren)
83  {
84  try
85  {
86  if(!interface.second.getNode(TableViewColumnInfo::COL_NAME_STATUS)
87  .getValue<bool>())
88  continue;
89  }
90  catch(...) // if Status column not there ignore (for backwards compatibility)
91  {
92  __CFG_COUT_INFO__ << "Ignoring FE Status since Status column is missing!"
93  << __E__;
94  }
95 
96  __CFG_COUT__
97  << "Interface Plugin Name: "
98  << interface.second.getNode(COL_NAME_fePlugin).getValue<std::string>()
99  << __E__;
100  __CFG_COUT__ << "Interface Name: " << interface.first << __E__;
101  __CFG_COUT__ << "XDAQContext Node: " << theXDAQContextConfigTree_ << __E__;
102  __CFG_COUT__ << "Path to configuration: "
103  << (theConfigurationPath_ + "/" + COL_NAME_feGroupLink + "/" +
104  interface.first + "/" + COL_NAME_feTypeLink)
105  << __E__;
106 
107  try
108  {
109  theFEInterfaces_[interface.first] = makeInterface(
110  interface.second.getNode(COL_NAME_fePlugin).getValue<std::string>(),
111  interface.first,
112  theXDAQContextConfigTree_,
113  (theConfigurationPath_ + "/" + COL_NAME_feGroupLink + "/" +
114  interface.first + "/" + COL_NAME_feTypeLink));
115 
116  // setup parent supervisor and interface manager
117  // of FEVinterface (for backwards compatibility, left out of constructor)
118  theFEInterfaces_[interface.first]->VStateMachine::parentSupervisor_ =
119  VStateMachine::parentSupervisor_;
120  theFEInterfaces_[interface.first]->parentInterfaceManager_ = this;
121  }
122  catch(const cet::exception& e)
123  {
124  __CFG_SS__
125  << "Failed to instantiate plugin named '" << interface.first
126  << "' of type '"
127  << interface.second.getNode(COL_NAME_fePlugin).getValue<std::string>()
128  << "' due to the following error: \n"
129  << e.what() << __E__;
130  __MOUT_ERR__ << ss.str();
131  __CFG_SS_THROW__;
132  }
133  catch(const std::runtime_error& e)
134  {
135  __CFG_SS__
136  << "Failed to instantiate plugin named '" << interface.first
137  << "' of type '"
138  << interface.second.getNode(COL_NAME_fePlugin).getValue<std::string>()
139  << "' due to the following error: \n"
140  << e.what() << __E__;
141  __MOUT_ERR__ << ss.str();
142  __CFG_SS_THROW__;
143  }
144  catch(...)
145  {
146  __CFG_SS__
147  << "Failed to instantiate plugin named '" << interface.first
148  << "' of type '"
149  << interface.second.getNode(COL_NAME_fePlugin).getValue<std::string>()
150  << "' due to an unknown error." << __E__;
151  __MOUT_ERR__ << ss.str();
152  throw; // if we do not throw, it is hard to tell what is happening..
153  //__CFG_SS_THROW__;
154  }
155  }
156  __CFG_COUT__ << "Done creating interfaces" << __E__;
157 } // end createInterfaces()
158 
159 //========================================================================================================================
160 void FEVInterfacesManager::configure(void)
161 {
162  const std::string transitionName = "Configuring";
163 
164  __CFG_COUT__ << transitionName << " FEVInterfacesManager " << __E__;
165 
166  // create interfaces (the first iteration)
167  if(VStateMachine::getIterationIndex() == 0 &&
168  VStateMachine::getSubIterationIndex() == 0)
169  createInterfaces(); // by priority
170 
171  FEVInterface* fe;
172 
173  preStateMachineExecutionLoop();
174  for(unsigned int i = 0; i < theFENamesByPriority_.size(); ++i)
175  {
176  // if one state machine is doing a sub-iteration, then target that one
177  if(subIterationWorkStateMachineIndex_ != (unsigned int)-1 &&
178  i != subIterationWorkStateMachineIndex_)
179  continue; // skip those not in the sub-iteration
180 
181  const std::string& name = theFENamesByPriority_[i];
182 
183  // test for front-end existence
184  fe = getFEInterfaceP(name);
185 
186  if(stateMachinesIterationDone_[name])
187  continue; // skip state machines already done
188 
189  __CFG_COUT__ << transitionName << " interface " << name << __E__;
190  __CFG_COUT__ << transitionName << " interface " << name << __E__;
191  __CFG_COUT__ << transitionName << " interface " << name << __E__;
192 
193  preStateMachineExecution(i);
194  fe->configure();
195  postStateMachineExecution(i);
196 
197  // configure slow controls and start slow controls workloop
198  // slow controls workloop stays alive through start/stop.. and dies on halt
199  fe->configureSlowControls();
200  fe->startSlowControlsWorkLooop();
201 
202  __CFG_COUT__ << "Done " << transitionName << " interface " << name << __E__;
203  __CFG_COUT__ << "Done " << transitionName << " interface " << name << __E__;
204  __CFG_COUT__ << "Done " << transitionName << " interface " << name << __E__;
205  }
206  postStateMachineExecutionLoop();
207 
208  __CFG_COUT__ << "Done " << transitionName << " all interfaces." << __E__;
209 } // end configure()
210 
211 //========================================================================================================================
212 void FEVInterfacesManager::halt(void)
213 {
214  const std::string transitionName = "Halting";
215  FEVInterface* fe;
216 
217  preStateMachineExecutionLoop();
218  for(unsigned int i = 0; i < theFENamesByPriority_.size(); ++i)
219  {
220  // if one state machine is doing a sub-iteration, then target that one
221  if(subIterationWorkStateMachineIndex_ != (unsigned int)-1 &&
222  i != subIterationWorkStateMachineIndex_)
223  continue; // skip those not in the sub-iteration
224 
225  const std::string& name = theFENamesByPriority_[i];
226 
227  fe = getFEInterfaceP(name);
228 
229  if(stateMachinesIterationDone_[name])
230  continue; // skip state machines already done
231 
232  __CFG_COUT__ << transitionName << " interface " << name << __E__;
233  __CFG_COUT__ << transitionName << " interface " << name << __E__;
234  __CFG_COUT__ << transitionName << " interface " << name << __E__;
235 
236  preStateMachineExecution(i);
237 
238  // since halting also occurs on errors, ignore more errors
239  try
240  {
241  fe->stopWorkLoop();
242  }
243  catch(...)
244  {
245  __CFG_COUT_WARN__
246  << "An error occurred while halting the front-end workloop for '" << name
247  << ",' ignoring." << __E__;
248  }
249 
250  // since halting also occurs on errors, ignore more errors
251  try
252  {
253  fe->stopSlowControlsWorkLooop();
254  }
255  catch(...)
256  {
257  __CFG_COUT_WARN__ << "An error occurred while halting the Slow Controls "
258  "front-end workloop for '"
259  << name << ",' ignoring." << __E__;
260  }
261 
262  // since halting also occurs on errors, ignore more errors
263  try
264  {
265  fe->halt();
266  }
267  catch(...)
268  {
269  __CFG_COUT_WARN__ << "An error occurred while halting the front-end '" << name
270  << ",' ignoring." << __E__;
271  }
272 
273  postStateMachineExecution(i);
274 
275  __CFG_COUT__ << "Done " << transitionName << " interface " << name << __E__;
276  __CFG_COUT__ << "Done " << transitionName << " interface " << name << __E__;
277  __CFG_COUT__ << "Done " << transitionName << " interface " << name << __E__;
278  }
279  postStateMachineExecutionLoop();
280 
281  destroy(); // destroy all FE interfaces on halt, must be configured for FE interfaces
282  // to exist
283 
284  __CFG_COUT__ << "Done " << transitionName << " all interfaces." << __E__;
285 } // end halt()
286 
287 //========================================================================================================================
288 void FEVInterfacesManager::pause(void)
289 {
290  const std::string transitionName = "Pausing";
291  FEVInterface* fe;
292 
293  preStateMachineExecutionLoop();
294  for(unsigned int i = 0; i < theFENamesByPriority_.size(); ++i)
295  {
296  // if one state machine is doing a sub-iteration, then target that one
297  if(subIterationWorkStateMachineIndex_ != (unsigned int)-1 &&
298  i != subIterationWorkStateMachineIndex_)
299  continue; // skip those not in the sub-iteration
300 
301  const std::string& name = theFENamesByPriority_[i];
302 
303  fe = getFEInterfaceP(name);
304 
305  if(stateMachinesIterationDone_[name])
306  continue; // skip state machines already done
307 
308  __CFG_COUT__ << transitionName << " interface " << name << __E__;
309  __CFG_COUT__ << transitionName << " interface " << name << __E__;
310  __CFG_COUT__ << transitionName << " interface " << name << __E__;
311 
312  preStateMachineExecution(i);
313  fe->stopWorkLoop();
314  fe->pause();
315  postStateMachineExecution(i);
316 
317  __CFG_COUT__ << "Done " << transitionName << " interface " << name << __E__;
318  __CFG_COUT__ << "Done " << transitionName << " interface " << name << __E__;
319  __CFG_COUT__ << "Done " << transitionName << " interface " << name << __E__;
320  }
321  postStateMachineExecutionLoop();
322 
323  __CFG_COUT__ << "Done " << transitionName << " all interfaces." << __E__;
324 } // end pause()
325 
326 //========================================================================================================================
327 void FEVInterfacesManager::resume(void)
328 {
329  const std::string transitionName = "Resuming";
330  FEVInterface* fe;
331 
332  preStateMachineExecutionLoop();
333  for(unsigned int i = 0; i < theFENamesByPriority_.size(); ++i)
334  {
335  // if one state machine is doing a sub-iteration, then target that one
336  if(subIterationWorkStateMachineIndex_ != (unsigned int)-1 &&
337  i != subIterationWorkStateMachineIndex_)
338  continue; // skip those not in the sub-iteration
339 
340  const std::string& name = theFENamesByPriority_[i];
341 
342  FEVInterface* fe = getFEInterfaceP(name);
343 
344  if(stateMachinesIterationDone_[name])
345  continue; // skip state machines already done
346 
347  __CFG_COUT__ << transitionName << " interface " << name << __E__;
348  __CFG_COUT__ << transitionName << " interface " << name << __E__;
349  __CFG_COUT__ << transitionName << " interface " << name << __E__;
350 
351  preStateMachineExecution(i);
352  fe->resume();
353  // only start workloop once transition is done
354  if(postStateMachineExecution(i))
355  fe->startWorkLoop();
356 
357  __CFG_COUT__ << "Done " << transitionName << " interface " << name << __E__;
358  __CFG_COUT__ << "Done " << transitionName << " interface " << name << __E__;
359  __CFG_COUT__ << "Done " << transitionName << " interface " << name << __E__;
360  }
361  postStateMachineExecutionLoop();
362 
363  __CFG_COUT__ << "Done " << transitionName << " all interfaces." << __E__;
364 
365 } // end resume()
366 
367 //========================================================================================================================
368 void FEVInterfacesManager::start(std::string runNumber)
369 {
370  const std::string transitionName = "Starting";
371  FEVInterface* fe;
372 
373  preStateMachineExecutionLoop();
374  for(unsigned int i = 0; i < theFENamesByPriority_.size(); ++i)
375  {
376  // if one state machine is doing a sub-iteration, then target that one
377  if(subIterationWorkStateMachineIndex_ != (unsigned int)-1 &&
378  i != subIterationWorkStateMachineIndex_)
379  continue; // skip those not in the sub-iteration
380 
381  const std::string& name = theFENamesByPriority_[i];
382 
383  fe = getFEInterfaceP(name);
384 
385  if(stateMachinesIterationDone_[name])
386  continue; // skip state machines already done
387 
388  __CFG_COUT__ << transitionName << " interface " << name << __E__;
389  __CFG_COUT__ << transitionName << " interface " << name << __E__;
390  __CFG_COUT__ << transitionName << " interface " << name << __E__;
391 
392  preStateMachineExecution(i);
393  fe->start(runNumber);
394  // only start workloop once transition is done
395  if(postStateMachineExecution(i))
396  fe->startWorkLoop();
397 
398  __CFG_COUT__ << "Done " << transitionName << " interface " << name << __E__;
399  __CFG_COUT__ << "Done " << transitionName << " interface " << name << __E__;
400  __CFG_COUT__ << "Done " << transitionName << " interface " << name << __E__;
401  }
402  postStateMachineExecutionLoop();
403 
404  __CFG_COUT__ << "Done " << transitionName << " all interfaces." << __E__;
405 
406 } // end start()
407 
408 //========================================================================================================================
409 void FEVInterfacesManager::stop(void)
410 {
411  const std::string transitionName = "Starting";
412  FEVInterface* fe;
413 
414  preStateMachineExecutionLoop();
415  for(unsigned int i = 0; i < theFENamesByPriority_.size(); ++i)
416  {
417  // if one state machine is doing a sub-iteration, then target that one
418  if(subIterationWorkStateMachineIndex_ != (unsigned int)-1 &&
419  i != subIterationWorkStateMachineIndex_)
420  continue; // skip those not in the sub-iteration
421 
422  const std::string& name = theFENamesByPriority_[i];
423 
424  fe = getFEInterfaceP(name);
425 
426  if(stateMachinesIterationDone_[name])
427  continue; // skip state machines already done
428 
429  __CFG_COUT__ << transitionName << " interface " << name << __E__;
430  __CFG_COUT__ << transitionName << " interface " << name << __E__;
431  __CFG_COUT__ << transitionName << " interface " << name << __E__;
432 
433  preStateMachineExecution(i);
434  fe->stopWorkLoop();
435  fe->stop();
436  postStateMachineExecution(i);
437 
438  __CFG_COUT__ << "Done " << transitionName << " interface " << name << __E__;
439  __CFG_COUT__ << "Done " << transitionName << " interface " << name << __E__;
440  __CFG_COUT__ << "Done " << transitionName << " interface " << name << __E__;
441  }
442  postStateMachineExecutionLoop();
443 
444  __CFG_COUT__ << "Done " << transitionName << " all interfaces." << __E__;
445 
446 } // end stop()
447 
448 //========================================================================================================================
449 // getFEInterfaceP
450 FEVInterface* FEVInterfacesManager::getFEInterfaceP(const std::string& interfaceID)
451 {
452  try
453  {
454  return theFEInterfaces_.at(interfaceID).get();
455  }
456  catch(...)
457  {
458  __CFG_SS__ << "Interface ID '" << interfaceID
459  << "' not found in configured interfaces." << __E__;
460  __CFG_SS_THROW__;
461  }
462 } // end getFEInterfaceP()
463 
464 //========================================================================================================================
465 // getFEInterface
466 const FEVInterface& FEVInterfacesManager::getFEInterface(
467  const std::string& interfaceID) const
468 {
469  try
470  {
471  return *(theFEInterfaces_.at(interfaceID));
472  }
473  catch(...)
474  {
475  __CFG_SS__ << "Interface ID '" << interfaceID
476  << "' not found in configured interfaces." << __E__;
477  __CFG_SS_THROW__;
478  }
479 } // end getFEInterface()
480 
481 //========================================================================================================================
482 // universalRead
483 // used by MacroMaker
484 // throw std::runtime_error on error/timeout
485 void FEVInterfacesManager::universalRead(const std::string& interfaceID,
486  char* address,
487  char* returnValue)
488 {
489  getFEInterfaceP(interfaceID)->universalRead(address, returnValue);
490 } // end universalRead()
491 
492 //========================================================================================================================
493 // getInterfaceUniversalAddressSize
494 // used by MacroMaker
495 unsigned int FEVInterfacesManager::getInterfaceUniversalAddressSize(
496  const std::string& interfaceID)
497 {
498  return getFEInterfaceP(interfaceID)->getUniversalAddressSize();
499 } // end getInterfaceUniversalAddressSize()
500 
501 //========================================================================================================================
502 // getInterfaceUniversalDataSize
503 // used by MacroMaker
504 unsigned int FEVInterfacesManager::getInterfaceUniversalDataSize(
505  const std::string& interfaceID)
506 {
507  return getFEInterfaceP(interfaceID)->getUniversalDataSize();
508 } // end getInterfaceUniversalDataSize()
509 
510 //========================================================================================================================
511 // universalWrite
512 // used by MacroMaker
513 void FEVInterfacesManager::universalWrite(const std::string& interfaceID,
514  char* address,
515  char* writeValue)
516 {
517  getFEInterfaceP(interfaceID)->universalWrite(address, writeValue);
518 } // end universalWrite()
519 
520 //========================================================================================================================
521 // getFEListString
522 // returns string with each new line for each FE
523 // each line:
524 // <interface type>:<parent supervisor lid>:<interface UID>
525 std::string FEVInterfacesManager::getFEListString(const std::string& supervisorLid)
526 {
527  std::string retList = "";
528 
529  for(const auto& it : theFEInterfaces_)
530  {
531  __CFG_COUT__ << "FE name = " << it.first << __E__;
532 
533  retList += it.second->getInterfaceType() + ":" + supervisorLid + ":" +
534  it.second->getInterfaceUID() + "\n";
535  }
536  return retList;
537 } // end getFEListString()
538 
539 //========================================================================================================================
540 // startMacroMultiDimensional
541 // Launches a thread that manages the multi-dimensional loop
542 // running the Macro on the specified FE interface.
543 // Called by iterator (for now).
544 //
545 // Note: no output arguments are returned, but outputs are
546 // optionally saved to file.
547 //
548 //
549 // inputs:
550 // - inputArgs: dimensional semi-colon-separated,
551 // comma separated: dimension iterations and arguments (colon-separated
552 // name/value/stepsize sets)
553 //
554 // outputs:
555 // - throws exception on failure
556 void FEVInterfacesManager::startMacroMultiDimensional(const std::string& requester,
557  const std::string& interfaceID,
558  const std::string& macroName,
559  const std::string& macroString,
560  const bool enableSavingOutput,
561  const std::string& outputFilePath,
562  const std::string& outputFileRadix,
563  const std::string& inputArgs)
564 {
565  if(requester != "iterator")
566  {
567  __CFG_SS__ << "Invalid requester '" << requester << "'" << __E__;
568  __CFG_SS_THROW__;
569  }
570 
571  __CFG_COUT__ << "Starting multi-dimensional Macro '" << macroName
572  << "' for interface '" << interfaceID << ".'" << __E__;
573 
574  __CFG_COUTV__(macroString);
575 
576  __CFG_COUTV__(inputArgs);
577 
578  // mark active(only one Macro per interface active at any time, for now)
579  { // lock mutex scope
580  std::lock_guard<std::mutex> lock(macroMultiDimensionalDoneMutex_);
581  // mark active
582  if(macroMultiDimensionalStatusMap_.find(interfaceID) !=
583  macroMultiDimensionalStatusMap_.end())
584  {
585  __SS__ << "Failed to start multi-dimensional Macro '" << macroName
586  << "' for interface '" << interfaceID
587  << "' - this interface already has an active Macro launch!" << __E__;
588  __SS_THROW__;
589  }
590  macroMultiDimensionalStatusMap_.emplace(std::make_pair(interfaceID, "Active"));
591  }
592 
593  // start thread
594  std::thread(
595  [](FEVInterfacesManager* feMgr,
596  const std::string interfaceID,
597  const std::string macroName,
598  const std::string macroString,
599  const bool enableSavingOutput,
600  const std::string outputFilePath,
601  const std::string outputFileRadix,
602  const std::string inputArgsStr) {
603 
604  // create local message facility subject
605  std::string mfSubject_ = "threadMultiD-" + macroName;
606  __GEN_COUT__ << "Thread started." << __E__;
607 
608  std::string statusResult = "Done";
609 
610  try
611  {
612  //-------------------------------
613  // check for interfaceID
614  FEVInterface* fe = feMgr->getFEInterfaceP(interfaceID);
615 
616  //-------------------------------
617  // extract macro object
618  FEVInterface::macroStruct_t macro(macroString);
619 
620  //-------------------------------
621  // create output file pointer
622  FILE* outputFilePointer = 0;
623  if(enableSavingOutput)
624  {
625  std::string filename = outputFilePath + "/" + outputFileRadix +
626  macroName + "_" + std::to_string(time(0)) +
627  ".txt";
628  __GEN_COUT__ << "Opening file... " << filename << __E__;
629 
630  outputFilePointer = fopen(filename.c_str(), "w");
631  if(!outputFilePointer)
632  {
633  __GEN_SS__ << "Failed to open output file: " << filename << __E__;
634  __GEN_SS_THROW__;
635  }
636  } // at this point output file pointer is valid or null
637 
638  //-------------------------------
639  // setup Macro arguments
640  __GEN_COUTV__(inputArgsStr);
641 
642  // inputs:
643  // - inputArgs: dimensional semi-colon-separated,
644  // comma separated: dimension iterations and arguments
645  //(colon-separated name/value/stepsize sets)
646 
647  // need to extract input arguments
648  // by dimension (by priority)
649  //
650  // two vector by dimension <map of params>
651  // one vector for long and for double
652  //
653  // map of params :=
654  // name => {
655  // <long/double current value>
656  // <long/double init value>
657  // <long/double step size>
658  // }
659 
660  std::vector<unsigned long /*dimension iterations*/> dimensionIterations,
661  dimensionIterationCnt;
662 
663  using longParamMap_t = std::map<
664  std::string /*name*/,
665  std::pair<long /*current value*/,
666  std::pair<long /*initial value*/, long /*step value*/>>>;
667 
668  std::vector<longParamMap_t> longDimensionParameters;
669  // Note: double parameters not allowed for Macro (allowed in FE Macros)
670 
671  // instead of strict inputs and outputs, make a map
672  // and populate with all input and output names
673  std::map<std::string /*name*/, uint64_t /*value*/> variableMap;
674 
675  // std::vector<FEVInterface::frontEndMacroArg_t> argsIn;
676  // std::vector<FEVInterface::frontEndMacroArg_t> argsOut;
677 
678  for(const auto& inputArgName : macro.namesOfInputArguments_)
679  variableMap.emplace( // do not care about input arg value
680  std::pair<std::string /*name*/, uint64_t /*value*/>(inputArgName,
681  0));
682  for(const auto& outputArgName : macro.namesOfOutputArguments_)
683  variableMap.emplace( // do not care about output arg value
684  std::pair<std::string /*name*/, uint64_t /*value*/>(outputArgName,
685  0));
686 
687  if(0) // example
688  {
689  // inputArgsStr = "2,fisrD:3:2,fD2:4:1;4,myOtherArg:5:2,sD:10f:1.3";
690 
691  dimensionIterations.push_back(2);
692  dimensionIterations.push_back(4);
693 
694  longDimensionParameters.push_back(longParamMap_t());
695  longDimensionParameters.push_back(longParamMap_t());
696 
697  longDimensionParameters.back().emplace(std::make_pair(
698  "myOtherArg",
699  std::make_pair(
700  3 /*current value*/,
701  std::make_pair(3 /*initial value*/, 4 /*step value*/))));
702  } // end example
703 
704  std::vector<std::string> dimensionArgs;
705  StringMacros::getVectorFromString(
706  inputArgsStr, dimensionArgs, {';'} /*delimeter set*/);
707 
708  __GEN_COUTV__(dimensionArgs.size());
709  //__GEN_COUTV__(StringMacros::vectorToString(dimensionArgs));
710 
711  if(dimensionArgs.size() == 0)
712  {
713  // just call Macro once!
714  // create dimension with 1 iteration
715  // and no arguments
716  dimensionIterations.push_back(1);
717  longDimensionParameters.push_back(longParamMap_t());
718  }
719  else
720  for(unsigned int d = 0; d < dimensionArgs.size(); ++d)
721  {
722  // for each dimension
723  // get argument and classify as long or double
724 
725  std::vector<std::string> args;
726  StringMacros::getVectorFromString(
727  dimensionArgs[d], args, {','} /*delimeter set*/);
728 
729  //__GEN_COUTV__(args.size());
730  //__GEN_COUTV__(StringMacros::vectorToString(args));
731 
732  // require first value for number of iterations
733  if(args.size() == 0)
734  {
735  __GEN_SS__ << "Invalid dimensional arguments! "
736  << "Need number of iterations at dimension " << d
737  << __E__;
738  __GEN_SS_THROW__;
739  }
740 
741  unsigned long numOfIterations;
742  StringMacros::getNumber(args[0], numOfIterations);
743  __GEN_COUT__ << "Dimension " << d
744  << " numOfIterations=" << numOfIterations << __E__;
745 
746  // create dimension!
747  {
748  dimensionIterations.push_back(numOfIterations);
749  longDimensionParameters.push_back(longParamMap_t());
750  }
751 
752  // skip iteration value, start at index 1
753  for(unsigned int a = 1; a < args.size(); ++a)
754  {
755  std::vector<std::string> argPieces;
756  StringMacros::getVectorFromString(
757  args[a], argPieces, {':'} /*delimeter set*/);
758 
759  __GEN_COUTV__(StringMacros::vectorToString(argPieces));
760 
761  // check pieces and determine if arg is long or double
762  // 3 pieces := name, init value, step value
763  if(argPieces.size() != 3)
764  {
765  __GEN_SS__ << "Invalid argument pieces! Should be size "
766  "3, but is "
767  << argPieces.size() << __E__;
768  ss << StringMacros::vectorToString(argPieces);
769  __GEN_SS_THROW__;
770  }
771 
772  // check piece 1 and 2 for double hint
773  // a la Iterator::startCommandModifyActive()
774  if((argPieces[1].size() &&
775  (argPieces[1][argPieces[1].size() - 1] == 'f' ||
776  argPieces[1].find('.') != std::string::npos)) ||
777  (argPieces[2].size() &&
778  (argPieces[2][argPieces[2].size() - 1] == 'f' ||
779  argPieces[2].find('.') != std::string::npos)))
780  {
781  // handle as double
782 
783  double startValue = strtod(argPieces[1].c_str(), 0);
784  double stepSize = strtod(argPieces[2].c_str(), 0);
785 
786  __GEN_COUTV__(startValue);
787  __GEN_COUTV__(stepSize);
788 
789  __GEN_SS__
790  << "Error! Only integer aruments allowed for Macros. "
791  << "Double style arugment found: " << argPieces[0]
792  << "' := " << startValue << ", " << stepSize << __E__;
793  __GEN_SS_THROW__;
794  // doubleDimensionParameters.back().emplace(
795  // std::make_pair(argPieces[0],
796  // std::make_pair(
797  // startValue
799  // std::make_pair(
800  // startValue
802  // stepSize
804  }
805  else
806  {
807  // handle as long
808  //__GEN_COUT__ << "Long found" << __E__;
809 
810  long int startValue;
811  long int stepSize;
812 
813  StringMacros::getNumber(argPieces[1], startValue);
814  StringMacros::getNumber(argPieces[2], stepSize);
815 
816  __GEN_COUTV__(startValue);
817  __GEN_COUTV__(stepSize);
818 
819  __GEN_COUT__ << "Creating long argument '" << argPieces[0]
820  << "' := " << startValue << ", " << stepSize
821  << __E__;
822 
823  longDimensionParameters.back().emplace(std::make_pair(
824  argPieces[0],
825  std::make_pair(
826  startValue /*current value*/,
827  std::make_pair(startValue /*initial value*/,
828  stepSize /*step value*/))));
829  }
830 
831  } // end dimensional argument loop
832 
833  } // end dimensions loop
834 
835  if(dimensionIterations.size() != longDimensionParameters.size())
836  {
837  __GEN_SS__ << "Impossible vector size mismatch! "
838  << dimensionIterations.size() << " - "
839  << longDimensionParameters.size() << __E__;
840  __GEN_SS_THROW__;
841  }
842 
843  // output header
844  {
845  std::stringstream outSS;
846  {
847  outSS << "\n==========================\n" << __E__;
848  outSS << "Macro '" << macro.macroName_
849  << "' multi-dimensional scan..." << __E__;
850  outSS << "\t" << StringMacros::getTimestampString() << __E__;
851  outSS << "\t" << dimensionIterations.size()
852  << " dimensions defined." << __E__;
853  for(unsigned int i = 0; i < dimensionIterations.size(); ++i)
854  {
855  outSS << "\t\t"
856  << "dimension[" << i << "] has "
857  << dimensionIterations[i] << " iterations and "
858  << (longDimensionParameters[i].size()) << " arguments."
859  << __E__;
860 
861  for(auto& param : longDimensionParameters[i])
862  outSS << "\t\t\t"
863  << "'" << param.first << "' of type long with "
864  << "initial value and step value [decimal] = "
865  << "\t" << param.second.second.first << " & "
866  << param.second.second.second << __E__;
867  }
868 
869  outSS << "\nInput argument names:" << __E__;
870  for(const auto& inputArgName : macro.namesOfInputArguments_)
871  outSS << "\t" << inputArgName << __E__;
872  outSS << "\nOutput argument names:" << __E__;
873  for(const auto& outputArgName : macro.namesOfOutputArguments_)
874  outSS << "\t" << outputArgName << __E__;
875 
876  outSS << "\n==========================\n" << __E__;
877  } // end outputs stringstream results
878 
879  // if enabled to save to file, do it.
880  __GEN_COUT__ << "\n" << outSS.str();
881  if(outputFilePointer)
882  fprintf(outputFilePointer, outSS.str().c_str());
883  } // end output header
884 
885  unsigned int iterationCount = 0;
886 
887  // Use lambda recursive function to do arbitrary dimensions
888  //
889  // Note: can not do lambda recursive function if using auto to declare the
890  // function, and must capture reference to the function. Also, must
891  // capture specialFolders reference for use internally (const values
892  // already are captured).
893  std::function<void(const unsigned int /*dimension*/
894  )>
895  localRecurse = [&dimensionIterations,
896  &dimensionIterationCnt,
897  &iterationCount,
898  &longDimensionParameters,
899  &fe,
900  &macro,
901  &variableMap,
902  &outputFilePointer,
903  &localRecurse](const unsigned int dimension) {
904 
905  // create local message facility subject
906  std::string mfSubject_ = "multiD-" + std::to_string(dimension) +
907  "-" + macro.macroName_;
908  __GEN_COUTV__(dimension);
909 
910  if(dimension >= dimensionIterations.size())
911  {
912  __GEN_COUT__ << "Iteration count: " << iterationCount++
913  << __E__;
914  __GEN_COUT__ << "Launching Macro '" << macro.macroName_
915  << "' ..." << __E__;
916 
917  // set argsIn to current value
918  {
919  // scan all dimension parameter objects
920  // note: Although conflicts should not be allowed
921  // at this point, lower dimensions will have priority
922  // over higher dimension with same name argument..
923  // and longs will have priority over doubles
924 
925  for(unsigned int j = 0; j < dimensionIterations.size();
926  ++j)
927  {
928  for(auto& longParam : longDimensionParameters[j])
929  {
930  __GEN_COUT__
931  << "Assigning argIn '" << longParam.first
932  << "' to current long value '"
933  << longParam.second.first
934  << "' from dimension " << j << " parameter."
935  << __E__;
936  variableMap.at(longParam.first) =
937  longParam.second.first;
938  }
939  } // end long loop
940 
941  } // done building argsIn
942 
943  // output inputs
944  {
945  std::stringstream outSS;
946  {
947  outSS << "\n---------------\n" << __E__;
948  outSS << "Macro '" << macro.macroName_
949  << "' execution..." << __E__;
950  outSS << "\t"
951  << "iteration " << iterationCount << __E__;
952  for(unsigned int i = 0;
953  i < dimensionIterationCnt.size();
954  ++i)
955  outSS << "\t"
956  << "dimension[" << i
957  << "] index := " << dimensionIterationCnt[i]
958  << __E__;
959 
960  outSS << "\n"
961  << "\t"
962  << "Input arguments (count: "
963  << macro.namesOfInputArguments_.size()
964  << "):" << __E__;
965  for(auto& argIn : macro.namesOfInputArguments_)
966  outSS << "\t\t" << argIn << " = "
967  << variableMap.at(argIn) << __E__;
968 
969  } // end outputs stringstream results
970 
971  // if enabled to save to file, do it.
972  __GEN_COUT__ << "\n" << outSS.str();
973  if(outputFilePointer)
974  fprintf(outputFilePointer, outSS.str().c_str());
975  } // end output inputs
976 
977  // have FE and Macro structure, so run it
978  fe->runMacro(macro, variableMap);
979 
980  __GEN_COUT__ << "Macro complete!" << __E__;
981 
982  // output results
983  {
984  std::stringstream outSS;
985  {
986  outSS << "\n"
987  << "\t"
988  << "Output arguments (count: "
989  << macro.namesOfOutputArguments_.size()
990  << "):" << __E__;
991  for(auto& argOut : macro.namesOfOutputArguments_)
992  outSS << "\t\t" << argOut << " = "
993  << variableMap.at(argOut) << __E__;
994  } // end outputs stringstream results
995 
996  // if enabled to save to file, do it.
997  __GEN_COUT__ << "\n" << outSS.str();
998  if(outputFilePointer)
999  fprintf(outputFilePointer, outSS.str().c_str());
1000  } // end output results
1001 
1002  return;
1003  }
1004 
1005  // init dimension index
1006  if(dimension >= dimensionIterationCnt.size())
1007  dimensionIterationCnt.push_back(0);
1008 
1009  // if enabled to save to file, do it.
1010  __GEN_COUT__ << "\n"
1011  << "======================================" << __E__
1012  << "dimension[" << dimension
1013  << "] number of iterations := "
1014  << dimensionIterations[dimension] << __E__;
1015 
1016  // update current value to initial value for this dimension's
1017  // parameters
1018  {
1019  for(auto& longPair : longDimensionParameters[dimension])
1020  {
1021  longPair.second.first = // reset to initial value
1022  longPair.second.second.first;
1023  __GEN_COUT__
1024  << "arg '" << longPair.first
1025  << "' current value: " << longPair.second.first
1026  << __E__;
1027  } // end long loop
1028 
1029  } // end update current value to initial value for all
1030  // dimensional parameters
1031 
1032  for(dimensionIterationCnt[dimension] =
1033  0; // reset each time through dimension loop
1034  dimensionIterationCnt[dimension] <
1035  dimensionIterations[dimension];
1036  ++dimensionIterationCnt[dimension])
1037  {
1038  __GEN_COUT__ << "dimension[" << dimension << "] index := "
1039  << dimensionIterationCnt[dimension] << __E__;
1040 
1041  localRecurse(dimension + 1);
1042 
1043  // update current value to next value for this dimension's
1044  // parameters
1045  {
1046  for(auto& longPair : longDimensionParameters[dimension])
1047  {
1048  longPair.second.first += // add step value
1049  longPair.second.second.second;
1050  __GEN_COUT__
1051  << "arg '" << longPair.first
1052  << "' current value: " << longPair.second.first
1053  << __E__;
1054  } // end long loop
1055 
1056  } // end update current value to next value for all
1057  // dimensional parameters
1058  }
1059  __GEN_COUT__ << "Completed dimension[" << dimension
1060  << "] number of iterations := "
1061  << dimensionIterationCnt[dimension] << " of "
1062  << dimensionIterations[dimension] << __E__;
1063  }; //end local lambda recursive function
1064 
1065  // launch multi-dimensional recursion
1066  localRecurse(0);
1067 
1068  // close output file
1069  if(outputFilePointer)
1070  fclose(outputFilePointer);
1071  }
1072  catch(const std::runtime_error& e)
1073  {
1074  __SS__ << "Error executing multi-dimensional Macro: " << e.what()
1075  << __E__;
1076  statusResult = ss.str();
1077  }
1078  catch(...)
1079  {
1080  __SS__ << "Unknown error executing multi-dimensional Macro. " << __E__;
1081  statusResult = ss.str();
1082  }
1083 
1084  __COUTV__(statusResult);
1085 
1086  { // lock mutex scope
1087  std::lock_guard<std::mutex> lock(feMgr->macroMultiDimensionalDoneMutex_);
1088  // change status at completion
1089  feMgr->macroMultiDimensionalStatusMap_[interfaceID] = statusResult;
1090  }
1091 
1092  }, // end thread()
1093  this,
1094  interfaceID,
1095  macroName,
1096  macroString,
1097  enableSavingOutput,
1098  outputFilePath,
1099  outputFileRadix,
1100  inputArgs)
1101  .detach();
1102 
1103  __CFG_COUT__ << "Started multi-dimensional Macro '" << macroName
1104  << "' for interface '" << interfaceID << ".'" << __E__;
1105 
1106 } // end startMacroMultiDimensional()
1107 
1108 //========================================================================================================================
1109 // startFEMacroMultiDimensional
1110 // Launches a thread that manages the multi-dimensional loop
1111 // running the FE Macro in the specified FE interface.
1112 // Called by iterator (for now).
1113 //
1114 // Note: no output arguments are returned, but outputs are
1115 // optionally saved to file.
1116 //
1117 //
1118 // inputs:
1119 // - inputArgs: dimensional semi-colon-separated,
1120 // comma separated: dimension iterations and arguments (colon-separated
1121 // name/value/stepsize sets)
1122 //
1123 // outputs:
1124 // - throws exception on failure
1125 void FEVInterfacesManager::startFEMacroMultiDimensional(
1126  const std::string& requester,
1127  const std::string& interfaceID,
1128  const std::string& feMacroName,
1129  const bool enableSavingOutput,
1130  const std::string& outputFilePath,
1131  const std::string& outputFileRadix,
1132  const std::string& inputArgs)
1133 {
1134  if(requester != "iterator")
1135  {
1136  __CFG_SS__ << "Invalid requester '" << requester << "'" << __E__;
1137  __CFG_SS_THROW__;
1138  }
1139 
1140  __CFG_COUT__ << "Starting multi-dimensional FE Macro '" << feMacroName
1141  << "' for interface '" << interfaceID << ".'" << __E__;
1142  __CFG_COUTV__(inputArgs);
1143 
1144  // mark active(only one FE Macro per interface active at any time, for now)
1145  { // lock mutex scope
1146  std::lock_guard<std::mutex> lock(macroMultiDimensionalDoneMutex_);
1147  // mark active
1148  if(macroMultiDimensionalStatusMap_.find(interfaceID) !=
1149  macroMultiDimensionalStatusMap_.end())
1150  {
1151  __SS__ << "Failed to start multi-dimensional FE Macro '" << feMacroName
1152  << "' for interface '" << interfaceID
1153  << "' - this interface already has an active FE Macro launch!"
1154  << __E__;
1155  __SS_THROW__;
1156  }
1157  macroMultiDimensionalStatusMap_.emplace(std::make_pair(interfaceID, "Active"));
1158  }
1159 
1160  // start thread
1161  std::thread(
1162  [](FEVInterfacesManager* feMgr,
1163  const std::string interfaceID,
1164  const std::string feMacroName,
1165  const bool enableSavingOutput,
1166  const std::string outputFilePath,
1167  const std::string outputFileRadix,
1168  const std::string inputArgsStr) {
1169 
1170  // create local message facility subject
1171  std::string mfSubject_ = "threadMultiD-" + feMacroName;
1172  __GEN_COUT__ << "Thread started." << __E__;
1173 
1174  std::string statusResult = "Done";
1175 
1176  try
1177  {
1178  //-------------------------------
1179  // check for interfaceID and macro
1180  FEVInterface* fe = feMgr->getFEInterfaceP(interfaceID);
1181 
1182  // have pointer to virtual FEInterface, find Macro structure
1183  auto FEMacroIt = fe->getMapOfFEMacroFunctions().find(feMacroName);
1184  if(FEMacroIt == fe->getMapOfFEMacroFunctions().end())
1185  {
1186  __GEN_SS__ << "FE Macro '" << feMacroName << "' of interfaceID '"
1187  << interfaceID << "' was not found!" << __E__;
1188  __GEN_SS_THROW__;
1189  }
1190  const FEVInterface::frontEndMacroStruct_t& feMacro = FEMacroIt->second;
1191 
1192  //-------------------------------
1193  // create output file pointer
1194  FILE* outputFilePointer = 0;
1195  if(enableSavingOutput)
1196  {
1197  std::string filename = outputFilePath + "/" + outputFileRadix +
1198  feMacroName + "_" + std::to_string(time(0)) +
1199  ".txt";
1200  __GEN_COUT__ << "Opening file... " << filename << __E__;
1201 
1202  outputFilePointer = fopen(filename.c_str(), "w");
1203  if(!outputFilePointer)
1204  {
1205  __GEN_SS__ << "Failed to open output file: " << filename << __E__;
1206  __GEN_SS_THROW__;
1207  }
1208  } // at this point output file pointer is valid or null
1209 
1210  //-------------------------------
1211  // setup FE macro aruments
1212  __GEN_COUTV__(inputArgsStr);
1213 
1214  // inputs:
1215  // - inputArgs: dimensional semi-colon-separated,
1216  // comma separated: dimension iterations and arguments
1217  //(colon-separated name/value/stepsize sets)
1218 
1219  // need to extract input arguments
1220  // by dimension (by priority)
1221  //
1222  // two vector by dimension <map of params>
1223  // one vector for long and for double
1224  //
1225  // map of params :=
1226  // name => {
1227  // <long/double current value>
1228  // <long/double init value>
1229  // <long/double step size>
1230  // }
1231 
1232  std::vector<unsigned long /*dimension iterations*/> dimensionIterations,
1233  dimensionIterationCnt;
1234 
1235  using longParamMap_t = std::map<
1236  std::string /*name*/,
1237  std::pair<long /*current value*/,
1238  std::pair<long /*initial value*/, long /*step value*/>>>;
1239  using doubleParamMap_t =
1240  std::map<std::string /*name*/,
1241  std::pair<double /*current value*/,
1242  std::pair<double /*initial value*/,
1243  double /*step value*/>>>;
1244 
1245  std::vector<longParamMap_t> longDimensionParameters;
1246  std::vector<doubleParamMap_t> doubleDimensionParameters;
1247 
1248  std::vector<FEVInterface::frontEndMacroArg_t> argsIn;
1249  std::vector<FEVInterface::frontEndMacroArg_t> argsOut;
1250 
1251  for(unsigned int i = 0; i < feMacro.namesOfInputArguments_.size(); ++i)
1252  argsIn.push_back(std::make_pair( // do not care about input arg value
1253  feMacro.namesOfInputArguments_[i],
1254  ""));
1255  for(unsigned int i = 0; i < feMacro.namesOfOutputArguments_.size(); ++i)
1256  argsOut.push_back(
1257  std::make_pair( // do not care about output arg value
1258  feMacro.namesOfOutputArguments_[i],
1259  ""));
1260 
1261  if(0) // example
1262  {
1263  // inputArgsStr = "2,fisrD:3:2,fD2:4:1;4,myOtherArg:5:2,sD:10f:1.3";
1264 
1265  argsIn.push_back(std::make_pair("myOtherArg", "3"));
1266 
1267  dimensionIterations.push_back(2);
1268  dimensionIterations.push_back(4);
1269 
1270  longDimensionParameters.push_back(longParamMap_t());
1271  longDimensionParameters.push_back(longParamMap_t());
1272 
1273  doubleDimensionParameters.push_back(doubleParamMap_t());
1274  doubleDimensionParameters.push_back(doubleParamMap_t());
1275 
1276  longDimensionParameters.back().emplace(std::make_pair(
1277  "myOtherArg",
1278  std::make_pair(
1279  3 /*current value*/,
1280  std::make_pair(3 /*initial value*/, 4 /*step value*/))));
1281  } // end example
1282 
1283  std::vector<std::string> dimensionArgs;
1284  StringMacros::getVectorFromString(
1285  inputArgsStr, dimensionArgs, {';'} /*delimeter set*/);
1286 
1287  __GEN_COUTV__(dimensionArgs.size());
1288  //__GEN_COUTV__(StringMacros::vectorToString(dimensionArgs));
1289 
1290  if(dimensionArgs.size() == 0)
1291  {
1292  // just call FE Macro once!
1293  // create dimension with 1 iteration
1294  // and no arguments
1295  dimensionIterations.push_back(1);
1296  longDimensionParameters.push_back(longParamMap_t());
1297  doubleDimensionParameters.push_back(doubleParamMap_t());
1298  }
1299  else
1300  for(unsigned int d = 0; d < dimensionArgs.size(); ++d)
1301  {
1302  // for each dimension
1303  // get argument and classify as long or double
1304 
1305  std::vector<std::string> args;
1306  StringMacros::getVectorFromString(
1307  dimensionArgs[d], args, {','} /*delimeter set*/);
1308 
1309  //__GEN_COUTV__(args.size());
1310  //__GEN_COUTV__(StringMacros::vectorToString(args));
1311 
1312  // require first value for number of iterations
1313  if(args.size() == 0)
1314  {
1315  __GEN_SS__ << "Invalid dimensional arguments! "
1316  << "Need number of iterations at dimension " << d
1317  << __E__;
1318  __GEN_SS_THROW__;
1319  }
1320 
1321  unsigned long numOfIterations;
1322  StringMacros::getNumber(args[0], numOfIterations);
1323  __GEN_COUT__ << "Dimension " << d
1324  << " numOfIterations=" << numOfIterations << __E__;
1325 
1326  // create dimension!
1327  {
1328  dimensionIterations.push_back(numOfIterations);
1329  longDimensionParameters.push_back(longParamMap_t());
1330  doubleDimensionParameters.push_back(doubleParamMap_t());
1331  }
1332 
1333  // skip iteration value, start at index 1
1334  for(unsigned int a = 1; a < args.size(); ++a)
1335  {
1336  std::vector<std::string> argPieces;
1337  StringMacros::getVectorFromString(
1338  args[a], argPieces, {':'} /*delimeter set*/);
1339 
1340  __GEN_COUTV__(StringMacros::vectorToString(argPieces));
1341 
1342  // check pieces and determine if arg is long or double
1343  // 3 pieces := name, init value, step value
1344  if(argPieces.size() != 3)
1345  {
1346  __GEN_SS__ << "Invalid argument pieces! Should be size "
1347  "3, but is "
1348  << argPieces.size() << __E__;
1349  ss << StringMacros::vectorToString(argPieces);
1350  __GEN_SS_THROW__;
1351  }
1352 
1353  // check piece 1 and 2 for double hint
1354  // a la Iterator::startCommandModifyActive()
1355  if((argPieces[1].size() &&
1356  (argPieces[1][argPieces[1].size() - 1] == 'f' ||
1357  argPieces[1].find('.') != std::string::npos)) ||
1358  (argPieces[2].size() &&
1359  (argPieces[2][argPieces[2].size() - 1] == 'f' ||
1360  argPieces[2].find('.') != std::string::npos)))
1361  {
1362  // handle as double
1363  //__GEN_COUT__ << "Double found" << __E__;
1364 
1365  double startValue = strtod(argPieces[1].c_str(), 0);
1366  double stepSize = strtod(argPieces[2].c_str(), 0);
1367 
1368  __GEN_COUTV__(startValue);
1369  __GEN_COUTV__(stepSize);
1370 
1371  __GEN_COUT__ << "Creating double argument '"
1372  << argPieces[0] << "' := " << startValue
1373  << ", " << stepSize << __E__;
1374 
1375  doubleDimensionParameters.back().emplace(std::make_pair(
1376  argPieces[0],
1377  std::make_pair(
1378  startValue /*current value*/,
1379  std::make_pair(startValue /*initial value*/,
1380  stepSize /*step value*/))));
1381  }
1382  else
1383  {
1384  // handle as long
1385  //__GEN_COUT__ << "Long found" << __E__;
1386 
1387  long int startValue;
1388  long int stepSize;
1389 
1390  StringMacros::getNumber(argPieces[1], startValue);
1391  StringMacros::getNumber(argPieces[2], stepSize);
1392 
1393  __GEN_COUTV__(startValue);
1394  __GEN_COUTV__(stepSize);
1395 
1396  __GEN_COUT__ << "Creating long argument '" << argPieces[0]
1397  << "' := " << startValue << ", " << stepSize
1398  << __E__;
1399 
1400  longDimensionParameters.back().emplace(std::make_pair(
1401  argPieces[0],
1402  std::make_pair(
1403  startValue /*current value*/,
1404  std::make_pair(startValue /*initial value*/,
1405  stepSize /*step value*/))));
1406  }
1407 
1408  } // end dimensional argument loop
1409 
1410  } // end dimensions loop
1411 
1412  if(dimensionIterations.size() != longDimensionParameters.size() ||
1413  dimensionIterations.size() != doubleDimensionParameters.size())
1414  {
1415  __GEN_SS__ << "Impossible vector size mismatch! "
1416  << dimensionIterations.size() << " - "
1417  << longDimensionParameters.size() << " - "
1418  << doubleDimensionParameters.size() << __E__;
1419  __GEN_SS_THROW__;
1420  }
1421 
1422  // output header
1423  {
1424  std::stringstream outSS;
1425  {
1426  outSS << "\n==========================\n" << __E__;
1427  outSS << "FEMacro '" << feMacro.feMacroName_
1428  << "' multi-dimensional scan..." << __E__;
1429  outSS << "\t" << StringMacros::getTimestampString() << __E__;
1430  outSS << "\t" << dimensionIterations.size()
1431  << " dimensions defined." << __E__;
1432  for(unsigned int i = 0; i < dimensionIterations.size(); ++i)
1433  {
1434  outSS << "\t\t"
1435  << "dimension[" << i << "] has "
1436  << dimensionIterations[i] << " iterations and "
1437  << (longDimensionParameters[i].size() +
1438  doubleDimensionParameters[i].size())
1439  << " arguments." << __E__;
1440 
1441  for(auto& param : longDimensionParameters[i])
1442  outSS << "\t\t\t"
1443  << "'" << param.first << "' of type long with "
1444  << "initial value and step value [decimal] = "
1445  << "\t" << param.second.second.first << " & "
1446  << param.second.second.second << __E__;
1447 
1448  for(auto& param : doubleDimensionParameters[i])
1449  outSS << "\t\t\t"
1450  << "'" << param.first << "' of type double with "
1451  << "initial value and step value = "
1452  << "\t" << param.second.second.first << " & "
1453  << param.second.second.second << __E__;
1454  }
1455 
1456  outSS << "\nHere are the identified input arguments:" << __E__;
1457  for(unsigned int i = 0; i < feMacro.namesOfInputArguments_.size();
1458  ++i)
1459  outSS << "\t" << feMacro.namesOfInputArguments_[i] << __E__;
1460  outSS << "\nHere are the identified input arguments:" << __E__;
1461  for(unsigned int i = 0;
1462  i < feMacro.namesOfOutputArguments_.size();
1463  ++i)
1464  outSS << "\t" << feMacro.namesOfOutputArguments_[i] << __E__;
1465 
1466  outSS << "\n==========================\n" << __E__;
1467  } // end outputs stringstream results
1468 
1469  // if enabled to save to file, do it.
1470  __GEN_COUT__ << "\n" << outSS.str();
1471  if(outputFilePointer)
1472  fprintf(outputFilePointer, outSS.str().c_str());
1473  } // end output header
1474 
1475  unsigned int iterationCount = 0;
1476 
1477  // Use lambda recursive function to do arbitrary dimensions
1478  //
1479  // Note: can not do lambda recursive function if using auto to declare the
1480  // function, and must capture reference to the function. Also, must
1481  // capture specialFolders reference for use internally (const values
1482  // already are captured).
1483  std::function<void(const unsigned int /*dimension*/
1484  )>
1485  localRecurse = [&dimensionIterations,
1486  &dimensionIterationCnt,
1487  &iterationCount,
1488  &longDimensionParameters,
1489  &doubleDimensionParameters,
1490  &fe,
1491  &feMacro,
1492  &outputFilePointer,
1493  &argsIn,
1494  &argsOut,
1495  &localRecurse](const unsigned int dimension) {
1496 
1497  // create local message facility subject
1498  std::string mfSubject_ = "multiD-" + std::to_string(dimension) +
1499  "-" + feMacro.feMacroName_;
1500  __GEN_COUTV__(dimension);
1501 
1502  if(dimension >= dimensionIterations.size())
1503  {
1504  __GEN_COUT__ << "Iteration count: " << iterationCount++
1505  << __E__;
1506  __GEN_COUT__ << "Launching FE Macro '" << feMacro.feMacroName_
1507  << "' ..." << __E__;
1508 
1509  // set argsIn to current value
1510 
1511  // scan all dimension parameter objects
1512  // note: Although conflicts should not be allowed
1513  // at this point, lower dimensions will have priority
1514  // over higher dimension with same name argument.. and
1515  // longs will have priority over doubles
1516 
1517  bool foundAsLong;
1518  for(unsigned int i = 0; i < argsIn.size(); ++i)
1519  {
1520  foundAsLong = false;
1521  for(unsigned int j = 0; j < dimensionIterations.size();
1522  ++j)
1523  {
1524  auto longIt =
1525  longDimensionParameters[j].find(argsIn[i].first);
1526  if(longIt == longDimensionParameters[j].end())
1527  continue;
1528 
1529  // else found long!
1530  __GEN_COUT__ << "Assigning argIn '" << argsIn[i].first
1531  << "' to current long value '"
1532  << longIt->second.first
1533  << "' from dimension " << j
1534  << " parameter." << __E__;
1535  argsIn[i].second =
1536  std::to_string(longIt->second.first);
1537  foundAsLong = true;
1538  break;
1539  } // end long loop
1540  if(foundAsLong)
1541  continue; // skip double check
1542 
1543  for(unsigned int j = 0; j < dimensionIterations.size();
1544  ++j)
1545  {
1546  auto doubleIt = doubleDimensionParameters[j].find(
1547  argsIn[i].first);
1548  if(doubleIt == doubleDimensionParameters[j].end())
1549  continue;
1550 
1551  // else found long!
1552  __GEN_COUT__ << "Assigning argIn '" << argsIn[i].first
1553  << "' to current double value '"
1554  << doubleIt->second.first
1555  << "' from dimension " << j
1556  << " parameter." << __E__;
1557  argsIn[i].second =
1558  std::to_string(doubleIt->second.first);
1559  foundAsLong = true;
1560  break;
1561  } // end double loop
1562 
1563  __GEN_SS__ << "ArgIn '" << argsIn[i].first
1564  << "' was not assigned a value "
1565  << "by any dimensional loop parameter sets. "
1566  "This is illegal. FEMacro '"
1567  << feMacro.feMacroName_ << "' requires '"
1568  << argsIn[i].first
1569  << "' as an input argument. Either remove the "
1570  "input argument from this FEMacro, "
1571  << "or define a value as a dimensional loop "
1572  "parameter."
1573  << __E__;
1574  __GEN_SS_THROW__;
1575  } // done building argsIn
1576 
1577  // have pointer to Macro structure, so run it
1578  (fe->*(feMacro.macroFunction_))(feMacro, argsIn, argsOut);
1579 
1580  __GEN_COUT__ << "FE Macro complete!" << __E__;
1581 
1582  // output results
1583  {
1584  std::stringstream outSS;
1585  {
1586  outSS << "\n---------------\n" << __E__;
1587  outSS << "FEMacro '" << feMacro.feMacroName_
1588  << "' execution..." << __E__;
1589  outSS << "\t"
1590  << "iteration " << iterationCount << __E__;
1591  for(unsigned int i = 0;
1592  i < dimensionIterationCnt.size();
1593  ++i)
1594  outSS << "\t"
1595  << "dimension[" << i
1596  << "] index := " << dimensionIterationCnt[i]
1597  << __E__;
1598 
1599  outSS << "\n"
1600  << "\t"
1601  << "Input arguments (count: " << argsIn.size()
1602  << "):" << __E__;
1603  for(auto& argIn : argsIn)
1604  outSS << "\t\t" << argIn.first << " = "
1605  << argIn.second << __E__;
1606 
1607  outSS << "\n"
1608  << "\t"
1609  << "Output arguments (count: " << argsOut.size()
1610  << "):" << __E__;
1611  for(auto& argOut : argsOut)
1612  outSS << "\t\t" << argOut.first << " = "
1613  << argOut.second << __E__;
1614  } // end outputs stringstream results
1615 
1616  // if enabled to save to file, do it.
1617  __GEN_COUT__ << "\n" << outSS.str();
1618  if(outputFilePointer)
1619  fprintf(outputFilePointer, outSS.str().c_str());
1620  } // end output results
1621 
1622  return;
1623  }
1624 
1625  // init dimension index
1626  if(dimension >= dimensionIterationCnt.size())
1627  dimensionIterationCnt.push_back(0);
1628 
1629  // if enabled to save to file, do it.
1630  __GEN_COUT__ << "\n"
1631  << "======================================" << __E__
1632  << "dimension[" << dimension
1633  << "] number of iterations := "
1634  << dimensionIterations[dimension] << __E__;
1635 
1636  // update current value to initial value for this dimension's
1637  // parameters
1638  {
1639  for(auto& longPair : longDimensionParameters[dimension])
1640  {
1641  longPair.second.first = // reset to initial value
1642  longPair.second.second.first;
1643  __GEN_COUT__
1644  << "arg '" << longPair.first
1645  << "' current value: " << longPair.second.first
1646  << __E__;
1647  } // end long loop
1648 
1649  for(auto& doublePair : doubleDimensionParameters[dimension])
1650  {
1651  doublePair.second.first = // reset to initial value
1652  doublePair.second.second.first;
1653  __GEN_COUT__
1654  << "arg '" << doublePair.first
1655  << "' current value: " << doublePair.second.first
1656  << __E__;
1657  } // end double loop
1658  } // end update current value to initial value for all
1659  // dimensional parameters
1660 
1661  for(dimensionIterationCnt[dimension] =
1662  0; // reset each time through dimension loop
1663  dimensionIterationCnt[dimension] <
1664  dimensionIterations[dimension];
1665  ++dimensionIterationCnt[dimension])
1666  {
1667  __GEN_COUT__ << "dimension[" << dimension << "] index := "
1668  << dimensionIterationCnt[dimension] << __E__;
1669 
1670  localRecurse(dimension + 1);
1671 
1672  // update current value to next value for this dimension's
1673  // parameters
1674  {
1675  for(auto& longPair : longDimensionParameters[dimension])
1676  {
1677  longPair.second.first += // add step value
1678  longPair.second.second.second;
1679  __GEN_COUT__
1680  << "arg '" << longPair.first
1681  << "' current value: " << longPair.second.first
1682  << __E__;
1683  } // end long loop
1684 
1685  for(auto& doublePair :
1686  doubleDimensionParameters[dimension])
1687  {
1688  doublePair.second.first += // add step value
1689  doublePair.second.second.second;
1690 
1691  __GEN_COUT__
1692  << "arg '" << doublePair.first
1693  << "' current value: " << doublePair.second.first
1694  << __E__;
1695  } // end double loop
1696  } // end update current value to next value for all
1697  // dimensional parameters
1698  }
1699  __GEN_COUT__ << "Completed dimension[" << dimension
1700  << "] number of iterations := "
1701  << dimensionIterationCnt[dimension] << " of "
1702  << dimensionIterations[dimension] << __E__;
1703  }; //end local lambda recursive function
1704 
1705  // launch multi-dimensional recursion
1706  localRecurse(0);
1707 
1708  // close output file
1709  if(outputFilePointer)
1710  fclose(outputFilePointer);
1711  }
1712  catch(const std::runtime_error& e)
1713  {
1714  __SS__ << "Error executing multi-dimensional FE Macro: " << e.what()
1715  << __E__;
1716  statusResult = ss.str();
1717  }
1718  catch(...)
1719  {
1720  __SS__ << "Unknown error executing multi-dimensional FE Macro. " << __E__;
1721  statusResult = ss.str();
1722  }
1723 
1724  __COUTV__(statusResult);
1725 
1726  { // lock mutex scope
1727  std::lock_guard<std::mutex> lock(feMgr->macroMultiDimensionalDoneMutex_);
1728  // change status at completion
1729  feMgr->macroMultiDimensionalStatusMap_[interfaceID] = statusResult;
1730  }
1731 
1732  }, // end thread()
1733  this,
1734  interfaceID,
1735  feMacroName,
1736  enableSavingOutput,
1737  outputFilePath,
1738  outputFileRadix,
1739  inputArgs)
1740  .detach();
1741 
1742  __CFG_COUT__ << "Started multi-dimensional FE Macro '" << feMacroName
1743  << "' for interface '" << interfaceID << ".'" << __E__;
1744 
1745 } // end startFEMacroMultiDimensional()
1746 
1747 //========================================================================================================================
1748 // checkFEMacroMultiDimensional
1749 // Checks for the completion of the thread that manages the multi-dimensional loop
1750 // running the FE Macro or MacroMaker Macro in the specified FE interface.
1751 // Called by iterator (for now).
1752 //
1753 // Returns true if multi-dimensional launch is done
1754 bool FEVInterfacesManager::checkMacroMultiDimensional(const std::string& interfaceID,
1755  const std::string& macroName)
1756 {
1757  // check active(only one FE Macro per interface active at any time, for now)
1758  // lock mutex scope
1759  std::lock_guard<std::mutex> lock(macroMultiDimensionalDoneMutex_);
1760  // check status
1761  auto statusIt = macroMultiDimensionalStatusMap_.find(interfaceID);
1762  if(statusIt == macroMultiDimensionalStatusMap_.end())
1763  {
1764  __CFG_SS__ << "Status missing for multi-dimensional launch of Macro '"
1765  << macroName << "' for interface '" << interfaceID << ".'" << __E__;
1766  __CFG_SS_THROW__;
1767  }
1768  else if(statusIt->second == "Done")
1769  {
1770  __CFG_COUT__ << "Completed multi-dimensional launch of Macro '" << macroName
1771  << "' for interface '" << interfaceID << ".'" << __E__;
1772 
1773  // erase from map
1774  macroMultiDimensionalStatusMap_.erase(statusIt);
1775  return true;
1776  }
1777  else if(statusIt->second == "Active")
1778  {
1779  __CFG_COUT__ << "Still running multi-dimensional launch of Macro '" << macroName
1780  << "' for interface '" << interfaceID << ".'" << __E__;
1781  return false;
1782  }
1783  // else //assume error
1784 
1785  __CFG_SS__ << "Error occured during multi-dimensional launch of Macro '" << macroName
1786  << "' for interface '" << interfaceID << "':" << statusIt->second << __E__;
1787  __CFG_SS_THROW__;
1788 
1789 } // end checkMacroMultiDimensional()
1790 
1791 //========================================================================================================================
1792 // runFEMacroByFE
1793 // Runs the FE Macro in the specified FE interface. Called by another FE.
1794 //
1795 // inputs:
1796 // - inputArgs: colon-separated name/value pairs, and then comma-separated
1797 // - outputArgs: comma-separated (Note: resolved for FE, allowing FE to not know
1798 // output arguments)
1799 //
1800 // outputs:
1801 // - throws exception on failure
1802 // - outputArgs: colon-separate name/value pairs, and then comma-separated
1803 void FEVInterfacesManager::runFEMacroByFE(const std::string& callingInterfaceID,
1804  const std::string& interfaceID,
1805  const std::string& feMacroName,
1806  const std::string& inputArgs,
1807  std::string& outputArgs)
1808 {
1809  __CFG_COUTV__(callingInterfaceID);
1810 
1811  // check for interfaceID
1812  FEVInterface* fe = getFEInterfaceP(interfaceID);
1813 
1814  // have pointer to virtual FEInterface, find Macro structure
1815  auto FEMacroIt = fe->getMapOfFEMacroFunctions().find(feMacroName);
1816  if(FEMacroIt == fe->getMapOfFEMacroFunctions().end())
1817  {
1818  __CFG_SS__ << "FE Macro '" << feMacroName << "' of interfaceID '" << interfaceID
1819  << "' was not found!" << __E__;
1820  __CFG_COUT_ERR__ << "\n" << ss.str();
1821  __CFG_SS_THROW__;
1822  }
1823 
1824  auto& feMacro = FEMacroIt->second;
1825 
1826  std::set<std::string> allowedFEsSet;
1827  StringMacros::getSetFromString(feMacro.allowedCallingFrontEnds_, allowedFEsSet);
1828 
1829  // check if calling interface is allowed to call macro
1830  if(!StringMacros::inWildCardSet(callingInterfaceID, allowedFEsSet))
1831  {
1832  __CFG_SS__ << "FE Macro '" << feMacroName << "' of interfaceID '" << interfaceID
1833  << "' does not allow access to calling interfaceID '"
1834  << callingInterfaceID
1835  << "!' Did the interface add the calling interfaceID "
1836  << "to the access list when registering the front-end macro." << __E__;
1837  __CFG_COUT_ERR__ << "\n" << ss.str();
1838  __CFG_SS_THROW__;
1839  }
1840 
1841  // if here, then access allowed
1842  // build output args list
1843 
1844  outputArgs = "";
1845 
1846  for(unsigned int i = 0; i < feMacro.namesOfOutputArguments_.size(); ++i)
1847  outputArgs += (i ? "," : "") + feMacro.namesOfOutputArguments_[i];
1848 
1849  __CFG_COUTV__(outputArgs);
1850 
1851  runFEMacro(interfaceID, feMacro, inputArgs, outputArgs);
1852 
1853  __CFG_COUTV__(outputArgs);
1854 
1855 } // end runFEMacroByFE()
1856 
1857 //========================================================================================================================
1858 // runMacro
1859 // Runs the MacroMaker Macro in the specified FE interface.
1860 //
1861 // inputs:
1862 // - inputArgs: colon-separated name/value pairs, and then comma-separated
1863 // - outputArgs: comma-separated
1864 //
1865 // outputs:
1866 // - throws exception on failure
1867 // - outputArgs: colon-separate name/value pairs, and then comma-separated
1868 void FEVInterfacesManager::runMacro(const std::string& interfaceID,
1869  const std::string& macroObjectString,
1870  const std::string& inputArgs,
1871  std::string& outputArgs)
1872 {
1873  //-------------------------------
1874  // extract macro object
1875  FEVInterface::macroStruct_t macro(macroObjectString);
1876 
1877  // check for interfaceID
1878  FEVInterface* fe = getFEInterfaceP(interfaceID);
1879 
1880  // build input arguments
1881  // parse args, semicolon-separated pairs, and then comma-separated
1882  std::vector<FEVInterface::frontEndMacroArg_t> argsIn;
1883  {
1884  std::istringstream inputStream(inputArgs);
1885  std::string splitVal, argName, argValue;
1886  while(getline(inputStream, splitVal, ';'))
1887  {
1888  std::istringstream pairInputStream(splitVal);
1889  getline(pairInputStream, argName, ',');
1890  getline(pairInputStream, argValue, ',');
1891  argsIn.push_back(std::make_pair(argName, argValue));
1892  }
1893  }
1894 
1895  // check namesOfInputArguments_
1896  if(macro.namesOfInputArguments_.size() != argsIn.size())
1897  {
1898  __CFG_SS__ << "MacroMaker Macro '" << macro.macroName_
1899  << "' was attempted on interfaceID '" << interfaceID
1900  << "' with a mismatch in"
1901  << " number of input arguments. " << argsIn.size() << " were given. "
1902  << macro.namesOfInputArguments_.size() << " expected." << __E__;
1903  __CFG_SS_THROW__;
1904  }
1905  for(unsigned int i = 0; i < argsIn.size(); ++i)
1906  if(macro.namesOfInputArguments_.find(argsIn[i].first) ==
1907  macro.namesOfInputArguments_.end())
1908  {
1909  __CFG_SS__ << "MacroMaker Macro '" << macro.macroName_
1910  << "' was attempted on interfaceID '" << interfaceID
1911  << "' with a mismatch in"
1912  << " a name of an input argument. " << argsIn[i].first
1913  << " was given. Expected: "
1914  << StringMacros::setToString(macro.namesOfInputArguments_)
1915  << __E__;
1916 
1917  __CFG_SS_THROW__;
1918  }
1919 
1920  // build output arguments
1921  std::vector<std::string> returnStrings;
1922  std::vector<FEVInterface::frontEndMacroArg_t> argsOut;
1923 
1924  {
1925  std::istringstream inputStream(outputArgs);
1926  std::string argName;
1927  while(getline(inputStream, argName, ','))
1928  {
1929  __CFG_COUT__ << "argName " << argName << __E__;
1930 
1931  returnStrings.push_back("DEFAULT"); // std::string());
1932  argsOut.push_back(FEVInterface::frontEndMacroArg_t(
1933  argName, returnStrings[returnStrings.size() - 1]));
1934  //
1935  // __CFG_COUT__ << argsOut[argsOut.size()-1].first << __E__;
1936  //__CFG_COUT__ << (uint64_t) & (returnStrings[returnStrings.size() - 1])
1937  // << __E__;
1938  }
1939  }
1940 
1941  // check namesOfOutputArguments_
1942  if(macro.namesOfOutputArguments_.size() != argsOut.size())
1943  {
1944  __CFG_SS__ << "MacroMaker Macro '" << macro.macroName_
1945  << "' was attempted on interfaceID '" << interfaceID
1946  << "' with a mismatch in"
1947  << " number of output arguments. " << argsOut.size() << " were given. "
1948  << macro.namesOfOutputArguments_.size() << " expected." << __E__;
1949 
1950  __CFG_SS_THROW__;
1951  }
1952  for(unsigned int i = 0; i < argsOut.size(); ++i)
1953  if(macro.namesOfOutputArguments_.find(argsOut[i].first) ==
1954  macro.namesOfOutputArguments_.end())
1955  {
1956  __CFG_SS__ << "MacroMaker Macro '" << macro.macroName_
1957  << "' was attempted on interfaceID '" << interfaceID
1958  << "' with a mismatch in"
1959  << " a name of an output argument. " << argsOut[i].first
1960  << " were given. Expected: "
1961  << StringMacros::setToString(macro.namesOfOutputArguments_)
1962  << __E__;
1963 
1964  __CFG_SS_THROW__;
1965  }
1966 
1967  __CFG_COUT__ << "# of input args = " << argsIn.size() << __E__;
1968 
1969  std::map<std::string /*name*/, uint64_t /*value*/> variableMap;
1970  // fill variable map
1971  for(const auto& outputArgName : macro.namesOfOutputArguments_)
1972  variableMap.emplace( // do not care about output arg value
1973  std::pair<std::string /*name*/, uint64_t /*value*/>(outputArgName, 0));
1974  for(const auto& inputArgName : macro.namesOfInputArguments_)
1975  variableMap.emplace( // do not care about input arg value
1976  std::pair<std::string /*name*/, uint64_t /*value*/>(inputArgName, 0));
1977 
1978  for(auto& argIn : argsIn) // set map values
1979  {
1980  __CFG_COUT__ << argIn.first << ": " << argIn.second << __E__;
1981  StringMacros::getNumber(argIn.second, variableMap.at(argIn.first));
1982  }
1983 
1984  fe->runMacro(macro, variableMap);
1985 
1986  __CFG_COUT__ << "MacroMaker Macro complete!" << __E__;
1987 
1988  __CFG_COUT__ << "# of output args = " << argsOut.size() << __E__;
1989  for(auto& arg : argsOut)
1990  {
1991  std::stringstream numberSs;
1992  numberSs << std::dec << variableMap.at(arg.first) << " (0x" << std::hex
1993  << variableMap.at(arg.first) << ")" << std::dec;
1994  arg.second = numberSs.str();
1995  __CFG_COUT__ << arg.first << ": " << arg.second << __E__;
1996  }
1997 
1998  // Success! at this point so return the output string
1999  outputArgs = "";
2000  for(unsigned int i = 0; i < argsOut.size(); ++i)
2001  {
2002  if(i)
2003  outputArgs += ";";
2004  outputArgs += argsOut[i].first + "," + argsOut[i].second;
2005  }
2006 
2007  __CFG_COUT__ << "outputArgs = " << outputArgs << __E__;
2008 
2009 } // end runMacro()
2010 
2011 //========================================================================================================================
2012 // runFEMacro
2013 // Runs the FE Macro in the specified FE interface.
2014 //
2015 // inputs:
2016 // - inputArgs: colon-separated name/value pairs, and then comma-separated
2017 // - outputArgs: comma-separated
2018 //
2019 // outputs:
2020 // - throws exception on failure
2021 // - outputArgs: colon-separate name/value pairs, and then comma-separated
2022 void FEVInterfacesManager::runFEMacro(const std::string& interfaceID,
2023  const std::string& feMacroName,
2024  const std::string& inputArgs,
2025  std::string& outputArgs)
2026 {
2027  // check for interfaceID
2028  FEVInterface* fe = getFEInterfaceP(interfaceID);
2029 
2030  // have pointer to virtual FEInterface, find Macro structure
2031  auto FEMacroIt = fe->getMapOfFEMacroFunctions().find(feMacroName);
2032  if(FEMacroIt == fe->getMapOfFEMacroFunctions().end())
2033  {
2034  __CFG_SS__ << "FE Macro '" << feMacroName << "' of interfaceID '" << interfaceID
2035  << "' was not found!" << __E__;
2036  __CFG_COUT_ERR__ << "\n" << ss.str();
2037  __CFG_SS_THROW__;
2038  }
2039 
2040  runFEMacro(interfaceID, FEMacroIt->second, inputArgs, outputArgs);
2041 
2042 } // end runFEMacro()
2043 
2044 //========================================================================================================================
2045 // runFEMacro
2046 // Runs the FE Macro in the specified FE interface.
2047 //
2048 // inputs:
2049 // - inputArgs: semicolon-separated name/value pairs, and then comma-separated
2050 // - outputArgs: comma-separated
2051 //
2052 // outputs:
2053 // - throws exception on failure
2054 // - outputArgs: colon-separate name/value pairs, and then comma-separated
2055 void FEVInterfacesManager::runFEMacro(const std::string& interfaceID,
2056  const FEVInterface::frontEndMacroStruct_t& feMacro,
2057  const std::string& inputArgs,
2058  std::string& outputArgs)
2059 {
2060  // build input arguments
2061  // parse args, semicolon-separated pairs, and then comma-separated
2062  std::vector<FEVInterface::frontEndMacroArg_t> argsIn;
2063  {
2064  std::istringstream inputStream(inputArgs);
2065  std::string splitVal, argName, argValue;
2066  while(getline(inputStream, splitVal, ';'))
2067  {
2068  std::istringstream pairInputStream(splitVal);
2069  getline(pairInputStream, argName, ',');
2070  getline(pairInputStream, argValue, ',');
2071  argsIn.push_back(std::make_pair(argName, argValue));
2072  }
2073  }
2074 
2075  // check namesOfInputArguments_
2076  if(feMacro.namesOfInputArguments_.size() != argsIn.size())
2077  {
2078  __CFG_SS__ << "FE Macro '" << feMacro.feMacroName_ << "' of interfaceID '"
2079  << interfaceID << "' was attempted with a mismatch in"
2080  << " number of input arguments. " << argsIn.size() << " were given. "
2081  << feMacro.namesOfInputArguments_.size() << " expected." << __E__;
2082  __CFG_COUT_ERR__ << "\n" << ss.str();
2083  __CFG_SS_THROW__;
2084  }
2085  for(unsigned int i = 0; i < argsIn.size(); ++i)
2086  if(argsIn[i].first != feMacro.namesOfInputArguments_[i])
2087  {
2088  __CFG_SS__ << "FE Macro '" << feMacro.feMacroName_ << "' of interfaceID '"
2089  << interfaceID << "' was attempted with a mismatch in"
2090  << " a name of an input argument. " << argsIn[i].first
2091  << " was given. " << feMacro.namesOfInputArguments_[i]
2092  << " expected." << __E__;
2093  __CFG_COUT_ERR__ << "\n" << ss.str();
2094  __CFG_SS_THROW__;
2095  }
2096 
2097  // build output arguments
2098  std::vector<std::string> returnStrings;
2099  std::vector<FEVInterface::frontEndMacroArg_t> argsOut;
2100 
2101  {
2102  std::istringstream inputStream(outputArgs);
2103  std::string argName;
2104  while(getline(inputStream, argName, ','))
2105  {
2106  __CFG_COUT__ << "argName " << argName << __E__;
2107 
2108  returnStrings.push_back("DEFAULT"); // std::string());
2109  argsOut.push_back(FEVInterface::frontEndMacroArg_t(
2110  argName, returnStrings[returnStrings.size() - 1]));
2111  //
2112  // __CFG_COUT__ << argsOut[argsOut.size()-1].first << __E__;
2113  __CFG_COUT__ << (uint64_t) & (returnStrings[returnStrings.size() - 1])
2114  << __E__;
2115  }
2116  }
2117 
2118  // check namesOfOutputArguments_
2119  if(feMacro.namesOfOutputArguments_.size() != argsOut.size())
2120  {
2121  __CFG_SS__ << "FE Macro '" << feMacro.feMacroName_ << "' of interfaceID '"
2122  << interfaceID << "' was attempted with a mismatch in"
2123  << " number of output arguments. " << argsOut.size() << " were given. "
2124  << feMacro.namesOfOutputArguments_.size() << " expected." << __E__;
2125  __CFG_COUT_ERR__ << "\n" << ss.str();
2126  __CFG_SS_THROW__;
2127  }
2128  for(unsigned int i = 0; i < argsOut.size(); ++i)
2129  if(argsOut[i].first != feMacro.namesOfOutputArguments_[i])
2130  {
2131  __CFG_SS__ << "FE Macro '" << feMacro.feMacroName_ << "' of interfaceID '"
2132  << interfaceID << "' was attempted with a mismatch in"
2133  << " a name of an output argument. " << argsOut[i].first
2134  << " were given. " << feMacro.namesOfOutputArguments_[i]
2135  << " expected." << __E__;
2136  __CFG_COUT_ERR__ << "\n" << ss.str();
2137  __CFG_SS_THROW__;
2138  }
2139 
2140  __CFG_COUT__ << "# of input args = " << argsIn.size() << __E__;
2141  for(auto& argIn : argsIn)
2142  __CFG_COUT__ << argIn.first << ": " << argIn.second << __E__;
2143 
2144  // __CFG_COUT__ << "# of output args = " << argsOut.size() << __E__;
2145  // for(unsigned int i=0;i<argsOut.size();++i)
2146  // __CFG_COUT__ << i << ": " << argsOut[i].first << __E__;
2147  // for(unsigned int i=0;i<returnStrings.size();++i)
2148  // __CFG_COUT__ << i << ": " << returnStrings[i] << __E__;
2149 
2150  __MOUT__ << "Launching FE Macro '" << feMacro.feMacroName_ << "' ..." << __E__;
2151  __CFG_COUT__ << "Launching FE Macro '" << feMacro.feMacroName_ << "' ..." << __E__;
2152 
2153  // have pointer to Macro structure, so run it
2154  (getFEInterfaceP(interfaceID)->*(feMacro.macroFunction_))(feMacro, argsIn, argsOut);
2155 
2156  __CFG_COUT__ << "FE Macro complete!" << __E__;
2157 
2158  __CFG_COUT__ << "# of output args = " << argsOut.size() << __E__;
2159  for(const auto& arg : argsOut)
2160  __CFG_COUT__ << arg.first << ": " << arg.second << __E__;
2161 
2162  // check namesOfOutputArguments_ size
2163  if(feMacro.namesOfOutputArguments_.size() != argsOut.size())
2164  {
2165  __CFG_SS__ << "FE Macro '" << feMacro.feMacroName_ << "' of interfaceID '"
2166  << interfaceID
2167  << "' was attempted but the FE macro "
2168  "manipulated the output arguments vector. It is illegal "
2169  "to add or remove output vector name/value pairs."
2170  << __E__;
2171  __CFG_COUT_ERR__ << "\n" << ss.str();
2172  __CFG_SS_THROW__;
2173  }
2174 
2175  // Success! at this point so return the output string
2176  outputArgs = "";
2177  for(unsigned int i = 0; i < argsOut.size(); ++i)
2178  {
2179  if(i)
2180  outputArgs += ";";
2181 
2182  // attempt to get number, and output hex version
2183  // otherwise just output result
2184  try
2185  {
2186  uint64_t tmpNumber;
2187  if(StringMacros::getNumber(argsOut[i].second, tmpNumber))
2188  {
2189  std::stringstream outNumberSs;
2190  outNumberSs << std::dec << tmpNumber << " (0x" << std::hex << tmpNumber
2191  << ")" << std::dec;
2192  outputArgs += argsOut[i].first + "," + outNumberSs.str();
2193  continue;
2194  }
2195  }
2196  catch(...)
2197  { // ignore error, assume not a number
2198  }
2199 
2200  outputArgs += argsOut[i].first + "," + argsOut[i].second;
2201  }
2202 
2203  __CFG_COUT__ << "outputArgs = " << outputArgs << __E__;
2204 
2205 } // end runFEMacro()
2206 
2207 //========================================================================================================================
2208 // getFEMacrosString
2209 // returns string with each new line indicating the macros for a FE
2210 // each line:
2211 // <parent supervisor name>:<parent supervisor lid>:<interface type>:<interface UID>
2212 // :<macro name>:<macro permissions req>:<macro num of inputs>:...<input names :
2213 // separated>...
2214 // :<macro num of outputs>:...<output names : separated>...
2215 std::string FEVInterfacesManager::getFEMacrosString(const std::string& supervisorName,
2216  const std::string& supervisorLid)
2217 {
2218  std::string retList = "";
2219 
2220  for(const auto& it : theFEInterfaces_)
2221  {
2222  __CFG_COUT__ << "FE interface UID = " << it.first << __E__;
2223 
2224  retList += supervisorName + ":" + supervisorLid + ":" +
2225  it.second->getInterfaceType() + ":" + it.second->getInterfaceUID();
2226 
2227  for(const auto& macroPair : it.second->getMapOfFEMacroFunctions())
2228  {
2229  __CFG_COUT__ << "FE Macro name = " << macroPair.first << __E__;
2230  retList += ":" + macroPair.first + ":" +
2231  std::to_string(macroPair.second.requiredUserPermissions_) + ":" +
2232  std::to_string(macroPair.second.namesOfInputArguments_.size());
2233  for(const auto& name : macroPair.second.namesOfInputArguments_)
2234  retList += ":" + name;
2235 
2236  retList +=
2237  ":" + std::to_string(macroPair.second.namesOfOutputArguments_.size());
2238  for(const auto& name : macroPair.second.namesOfOutputArguments_)
2239  retList += ":" + name;
2240  }
2241 
2242  retList += "\n";
2243  }
2244  return retList;
2245 }
2246 
2247 //========================================================================================================================
2248 bool FEVInterfacesManager::allFEWorkloopsAreDone(void)
2249 {
2250  bool allFEWorkloopsAreDone = true;
2251  bool isActive;
2252 
2253  for(const auto& FEInterface : theFEInterfaces_)
2254  {
2255  isActive = FEInterface.second->WorkLoop::isActive();
2256 
2257  __CFG_COUT__ << FEInterface.second->getInterfaceUID() << " of type "
2258  << FEInterface.second->getInterfaceType() << ": \t"
2259  << "workLoop_->isActive() " << (isActive ? "yes" : "no") << __E__;
2260 
2261  if(isActive) // then not done
2262  {
2263  allFEWorkloopsAreDone = false;
2264  break;
2265  }
2266  }
2267 
2268  return allFEWorkloopsAreDone;
2269 } // end allFEWorkloopsAreDone()
2270 
2271 //========================================================================================================================
2272 void FEVInterfacesManager::preStateMachineExecutionLoop(void)
2273 {
2274  VStateMachine::clearIterationWork();
2275  VStateMachine::clearSubIterationWork();
2276 
2277  stateMachinesIterationWorkCount_ = 0;
2278 
2279  __CFG_COUT__ << "Number of front ends to transition: " << theFENamesByPriority_.size()
2280  << __E__;
2281 
2282  if(VStateMachine::getIterationIndex() == 0 &&
2283  VStateMachine::getSubIterationIndex() == 0)
2284  {
2285  // reset map for iterations done on first iteration
2286 
2287  subIterationWorkStateMachineIndex_ = -1; // clear sub iteration work index
2288 
2289  stateMachinesIterationDone_.clear();
2290  for(const auto& FEPair : theFEInterfaces_)
2291  stateMachinesIterationDone_[FEPair.first] = false; // init to not done
2292  }
2293  else
2294  __CFG_COUT__ << "Iteration " << VStateMachine::getIterationIndex() << "."
2295  << VStateMachine::getSubIterationIndex() << "("
2296  << subIterationWorkStateMachineIndex_ << ")" << __E__;
2297 } // end preStateMachineExecutionLoop()
2298 
2299 //========================================================================================================================
2300 void FEVInterfacesManager::preStateMachineExecution(unsigned int i)
2301 {
2302  if(i >= theFENamesByPriority_.size())
2303  {
2304  __CFG_SS__ << "FE Interface " << i << " not found!" << __E__;
2305  __CFG_SS_THROW__;
2306  }
2307 
2308  const std::string& name = theFENamesByPriority_[i];
2309 
2310  FEVInterface* fe = getFEInterfaceP(name);
2311 
2312  fe->VStateMachine::setIterationIndex(VStateMachine::getIterationIndex());
2313  fe->VStateMachine::setSubIterationIndex(VStateMachine::getSubIterationIndex());
2314 
2315  fe->VStateMachine::clearIterationWork();
2316  fe->VStateMachine::clearSubIterationWork();
2317 
2318  __CFG_COUT__ << "theStateMachineImplementation Iteration "
2319  << fe->VStateMachine::getIterationIndex() << "."
2320  << fe->VStateMachine::getSubIterationIndex() << __E__;
2321 } // end preStateMachineExecution()
2322 
2323 //========================================================================================================================
2324 // postStateMachineExecution
2325 // return false to indicate state machine is NOT done with transition
2326 bool FEVInterfacesManager::postStateMachineExecution(unsigned int i)
2327 {
2328  if(i >= theFENamesByPriority_.size())
2329  {
2330  __CFG_SS__ << "FE Interface index " << i << " not found!" << __E__;
2331  __CFG_SS_THROW__;
2332  }
2333 
2334  const std::string& name = theFENamesByPriority_[i];
2335 
2336  FEVInterface* fe = getFEInterfaceP(name);
2337 
2338  // sub-iteration has priority
2339  if(fe->VStateMachine::getSubIterationWork())
2340  {
2341  subIterationWorkStateMachineIndex_ = i;
2342  VStateMachine::indicateSubIterationWork();
2343 
2344  __CFG_COUT__ << "FE Interface '" << name
2345  << "' is flagged for another sub-iteration..." << __E__;
2346  return false; // to indicate state machine is NOT done with transition
2347  }
2348  else
2349  {
2350  subIterationWorkStateMachineIndex_ = -1; // clear sub iteration work index
2351 
2352  bool& stateMachineDone = stateMachinesIterationDone_[name];
2353  stateMachineDone = !fe->VStateMachine::getIterationWork();
2354 
2355  if(!stateMachineDone)
2356  {
2357  __CFG_COUT__ << "FE Interface '" << name
2358  << "' is flagged for another iteration..." << __E__;
2359  VStateMachine::indicateIterationWork(); // mark not done at
2360  // FEVInterfacesManager level
2361  ++stateMachinesIterationWorkCount_; // increment still working count
2362  return false; // to indicate state machine is NOT done with transition
2363  }
2364  }
2365  return true; // to indicate state machine is done with transition
2366 } // end postStateMachineExecution()
2367 
2368 //========================================================================================================================
2369 void FEVInterfacesManager::postStateMachineExecutionLoop(void)
2370 {
2371  if(VStateMachine::getSubIterationWork())
2372  __CFG_COUT__ << "FE Interface state machine implementation "
2373  << subIterationWorkStateMachineIndex_
2374  << " is flagged for another sub-iteration..." << __E__;
2375  else if(VStateMachine::getIterationWork())
2376  __CFG_COUT__ << stateMachinesIterationWorkCount_
2377  << " FE Interface state machine implementation(s) flagged for "
2378  "another iteration..."
2379  << __E__;
2380  else
2381  __CFG_COUT__ << "Done transitioning all state machine implementations..."
2382  << __E__;
2383 } // end postStateMachineExecutionLoop()
void startMacroMultiDimensional(const std::string &requester, const std::string &interfaceID, const std::string &macroName, const std::string &macroString, const bool enableSavingOutput, const std::string &outputFilePath, const std::string &outputFileRadix, const std::string &inputArgs)