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