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