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