tdaq-develop-2025-02-12
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
1063  // parameters
1064  {
1065  for(auto& longPair : longDimensionParameters[dimension])
1066  {
1067  longPair.second.first = // reset to initial value
1068  longPair.second.second.first;
1069  __GEN_COUT__
1070  << "arg '" << longPair.first
1071  << "' current value: " << longPair.second.first
1072  << __E__;
1073  } // end long loop
1074 
1075  } // end update current value to initial value for all
1076  // dimensional parameters
1077 
1078  for(dimensionIterationCnt[dimension] =
1079  0; // reset each time through dimension loop
1080  dimensionIterationCnt[dimension] <
1081  dimensionIterations[dimension];
1082  ++dimensionIterationCnt[dimension])
1083  {
1084  __GEN_COUT__ << "dimension[" << dimension << "] index := "
1085  << dimensionIterationCnt[dimension] << __E__;
1086 
1087  localRecurse(dimension + 1);
1088 
1089  // update current value to next value for this dimension's
1090  // parameters
1091  {
1092  for(auto& longPair : longDimensionParameters[dimension])
1093  {
1094  longPair.second.first += // add step value
1095  longPair.second.second.second;
1096  __GEN_COUT__
1097  << "arg '" << longPair.first
1098  << "' current value: " << longPair.second.first
1099  << __E__;
1100  } // end long loop
1101 
1102  } // end update current value to next value for all
1103  // dimensional parameters
1104  }
1105  __GEN_COUT__ << "Completed dimension[" << dimension
1106  << "] number of iterations := "
1107  << dimensionIterationCnt[dimension] << " of "
1108  << dimensionIterations[dimension] << __E__;
1109  }; // end local lambda recursive function
1110 
1111  // launch multi-dimensional recursion
1112  localRecurse(0);
1113 
1114  // close output file
1115  if(outputFilePointer)
1116  fclose(outputFilePointer);
1117  }
1118  catch(const std::runtime_error& e)
1119  {
1120  __SS__ << "Error executing multi-dimensional Macro: " << e.what()
1121  << __E__;
1122  statusResult = ss.str();
1123  }
1124  catch(...)
1125  {
1126  __SS__ << "Unknown error executing multi-dimensional Macro. " << __E__;
1127  try
1128  {
1129  throw;
1130  } //one more try to printout extra info
1131  catch(const std::exception& e)
1132  {
1133  ss << "Exception message: " << e.what();
1134  }
1135  catch(...)
1136  {
1137  }
1138  statusResult = ss.str();
1139  }
1140 
1141  __COUTV__(statusResult);
1142 
1143  { // lock mutex scope
1144  std::lock_guard<std::mutex> lock(feMgr->macroMultiDimensionalDoneMutex_);
1145  // change status at completion
1146  feMgr->macroMultiDimensionalStatusMap_[interfaceID] = statusResult;
1147  }
1148  }, // end thread()
1149  this,
1150  interfaceID,
1151  macroName,
1152  macroString,
1153  enableSavingOutput,
1154  outputFilePath,
1155  outputFileRadix,
1156  inputArgs)
1157  .detach();
1158 
1159  __CFG_COUT__ << "Started multi-dimensional Macro '" << macroName
1160  << "' for interface '" << interfaceID << ".'" << __E__;
1161 
1162 } // end startMacroMultiDimensional()
1163 
1164 //==============================================================================
1182  const std::string& requester,
1183  const std::string& interfaceID,
1184  const std::string& feMacroName,
1185  const bool enableSavingOutput,
1186  const std::string& outputFilePath,
1187  const std::string& outputFileRadix,
1188  const std::string& inputArgs)
1189 {
1190  if(requester != "iterator")
1191  {
1192  __CFG_SS__ << "Invalid requester '" << requester << "'" << __E__;
1193  __CFG_SS_THROW__;
1194  }
1195 
1196  __CFG_COUT__ << "Starting multi-dimensional FE Macro '" << feMacroName
1197  << "' for interface '" << interfaceID << ".'" << __E__;
1198  __CFG_COUTV__(inputArgs);
1199 
1200  // mark active(only one FE Macro per interface active at any time, for now)
1201  { // lock mutex scope
1202  std::lock_guard<std::mutex> lock(macroMultiDimensionalDoneMutex_);
1203  // mark active
1204  if(macroMultiDimensionalStatusMap_.find(interfaceID) !=
1205  macroMultiDimensionalStatusMap_.end())
1206  {
1207  __SS__ << "Failed to start multi-dimensional FE Macro '" << feMacroName
1208  << "' for interface '" << interfaceID
1209  << "' - this interface already has an active FE Macro launch!"
1210  << __E__;
1211  __SS_THROW__;
1212  }
1213  macroMultiDimensionalStatusMap_.emplace(std::make_pair(interfaceID, "Active"));
1214  }
1215 
1216  // start thread
1217  std::thread(
1218  [](FEVInterfacesManager* feMgr,
1219  const std::string interfaceID,
1220  const std::string feMacroName,
1221  const bool enableSavingOutput,
1222  const std::string outputFilePath,
1223  const std::string outputFileRadix,
1224  const std::string inputArgsStr) {
1225  // create local message facility subject
1226  std::string mfSubject_ = "threadMultiD-" + feMacroName;
1227  __GEN_COUT__ << "Thread started." << __E__;
1228 
1229  std::string statusResult = "Done";
1230 
1231  try
1232  {
1233  //-------------------------------
1234  // check for interfaceID and macro
1235  FEVInterface* fe = feMgr->getFEInterfaceP(interfaceID);
1236 
1237  // have pointer to virtual FEInterface, find Macro structure
1238  auto FEMacroIt = fe->getMapOfFEMacroFunctions().find(feMacroName);
1239  if(FEMacroIt == fe->getMapOfFEMacroFunctions().end())
1240  {
1241  __GEN_SS__ << "FE Macro '" << feMacroName << "' of interfaceID '"
1242  << interfaceID << "' was not found!" << __E__;
1243  __GEN_SS_THROW__;
1244  }
1245  const FEVInterface::frontEndMacroStruct_t& feMacro = FEMacroIt->second;
1246 
1247  //-------------------------------
1248  // create output file pointer
1249  FILE* outputFilePointer = 0;
1250  if(enableSavingOutput)
1251  {
1252  std::string filename = outputFilePath + "/" + outputFileRadix +
1253  feMacroName + "_" + std::to_string(time(0)) +
1254  ".txt";
1255  __GEN_COUT__ << "Opening file... " << filename << __E__;
1256 
1257  outputFilePointer = fopen(filename.c_str(), "w");
1258  if(!outputFilePointer)
1259  {
1260  __GEN_SS__ << "Failed to open output file: " << filename << __E__;
1261  __GEN_SS_THROW__;
1262  }
1263  } // at this point output file pointer is valid or null
1264 
1265  //-------------------------------
1266  // setup FE macro aruments
1267  __GEN_COUTV__(inputArgsStr);
1268 
1269  // inputs:
1270  // - inputArgs: dimensional semi-colon-separated,
1271  // comma separated: dimension iterations and arguments
1272  //(colon-separated name/value/stepsize sets)
1273 
1274  // need to extract input arguments
1275  // by dimension (by priority)
1276  //
1277  // two vector by dimension <map of params>
1278  // one vector for long and for double
1279  //
1280  // map of params :=
1281  // name => {
1282  // <long/double current value>
1283  // <long/double init value>
1284  // <long/double step size>
1285  // }
1286 
1287  std::vector<unsigned long /*dimension iterations*/> dimensionIterations,
1288  dimensionIterationCnt;
1289 
1290  using longParamMap_t = std::map<
1291  std::string /*name*/,
1292  std::pair<long /*current value*/,
1293  std::pair<long /*initial value*/, long /*step value*/>>>;
1294  using doubleParamMap_t =
1295  std::map<std::string /*name*/,
1296  std::pair<double /*current value*/,
1297  std::pair<double /*initial value*/,
1298  double /*step value*/>>>;
1299  using stringParamMap_t =
1300  std::map<std::string /*name*/, std::string /* value*/>;
1301 
1302  std::vector<longParamMap_t> longDimensionParameters;
1303  std::vector<doubleParamMap_t> doubleDimensionParameters;
1304  std::vector<stringParamMap_t> stringDimensionParameters;
1305 
1306  std::vector<FEVInterface::frontEndMacroArg_t> argsIn;
1307  std::vector<FEVInterface::frontEndMacroArg_t> argsOut;
1308 
1309  for(unsigned int i = 0; i < feMacro.namesOfInputArguments_.size(); ++i)
1310  argsIn.push_back(std::make_pair( // do not care about input arg value
1311  feMacro.namesOfInputArguments_[i],
1312  ""));
1313  for(unsigned int i = 0; i < feMacro.namesOfOutputArguments_.size(); ++i)
1314  argsOut.push_back(
1315  std::make_pair( // do not care about output arg value
1316  feMacro.namesOfOutputArguments_[i],
1317  ""));
1318 
1319  if(0) // example
1320  {
1321  // inputArgsStr = "2,fisrD:3:2,fD2:4:1;4,myOtherArg:5:2,sD:10f:1.3";
1322 
1323  argsIn.push_back(std::make_pair("myOtherArg", "3"));
1324 
1325  dimensionIterations.push_back(2);
1326  dimensionIterations.push_back(4);
1327 
1328  longDimensionParameters.push_back(longParamMap_t());
1329  longDimensionParameters.push_back(longParamMap_t());
1330 
1331  doubleDimensionParameters.push_back(doubleParamMap_t());
1332  doubleDimensionParameters.push_back(doubleParamMap_t());
1333 
1334  longDimensionParameters.back().emplace(std::make_pair(
1335  "myOtherArg",
1336  std::make_pair(
1337  3 /*current value*/,
1338  std::make_pair(3 /*initial value*/, 4 /*step value*/))));
1339  } // end example
1340 
1341  std::vector<std::string> dimensionArgs;
1343  inputArgsStr, dimensionArgs, {';'} /*delimeter set*/);
1344 
1345  __GEN_COUTV__(dimensionArgs.size());
1346  //__GEN_COUTV__(StringMacros::vectorToString(dimensionArgs));
1347 
1348  if(dimensionArgs.size() == 0)
1349  {
1350  // just call FE Macro once!
1351  // create dimension with 1 iteration
1352  // and no arguments
1353  dimensionIterations.push_back(1);
1354  longDimensionParameters.push_back(longParamMap_t());
1355  doubleDimensionParameters.push_back(doubleParamMap_t());
1356  stringDimensionParameters.push_back(stringParamMap_t());
1357  }
1358  else
1359  for(unsigned int d = 0; d < dimensionArgs.size(); ++d)
1360  {
1361  // for each dimension
1362  // get argument and classify as long or double
1363 
1364  std::vector<std::string> args;
1366  dimensionArgs[d], args, {','} /*delimeter set*/);
1367 
1368  //__GEN_COUTV__(args.size());
1369  //__GEN_COUTV__(StringMacros::vectorToString(args));
1370 
1371  // require first value for number of iterations
1372  if(args.size() == 0)
1373  {
1374  __GEN_SS__ << "Invalid dimensional arguments! "
1375  << "Need number of iterations at dimension " << d
1376  << __E__;
1377  __GEN_SS_THROW__;
1378  }
1379 
1380  unsigned long numOfIterations;
1381  StringMacros::getNumber(args[0], numOfIterations);
1382  __GEN_COUT__ << "Dimension " << d
1383  << " numOfIterations=" << numOfIterations << __E__;
1384 
1385  // create dimension!
1386  {
1387  dimensionIterations.push_back(numOfIterations);
1388  longDimensionParameters.push_back(longParamMap_t());
1389  doubleDimensionParameters.push_back(doubleParamMap_t());
1390  stringDimensionParameters.push_back(stringParamMap_t());
1391  }
1392 
1393  // skip iteration value, start at index 1
1394  for(unsigned int a = 1; a < args.size(); ++a)
1395  {
1396  std::vector<std::string> argPieces;
1398  args[a], argPieces, {':'} /*delimeter set*/);
1399 
1400  __GEN_COUTV__(StringMacros::vectorToString(argPieces));
1401 
1402  // check pieces and determine if arg is long or double
1403  // 3 pieces := name, init value, step value
1404  if(argPieces.size() != 3)
1405  {
1406  __GEN_SS__ << "Invalid argument pieces! Should be size "
1407  "3, but is "
1408  << argPieces.size() << __E__;
1409  ss << StringMacros::vectorToString(argPieces);
1410  __GEN_SS_THROW__;
1411  }
1412 
1413  // check piece 1 and 2 for double hint
1414  // a la Iterator::startCommandModifyActive()
1415  if(argPieces[2] ==
1416  TableViewColumnInfo::DATATYPE_STRING_DEFAULT)
1417  {
1418  // if step size is default, considering value an unchanging string
1419 
1420  __GEN_COUT__ << "Creating string argument '"
1421  << argPieces[0] << "' := " << argPieces[1]
1422  << __E__;
1423 
1424  stringDimensionParameters.back().emplace(
1425  std::make_pair(argPieces[0], argPieces[1]));
1426  }
1427  else if((argPieces[1].size() &&
1428  (argPieces[1][argPieces[1].size() - 1] == 'f' ||
1429  argPieces[1].find('.') != std::string::npos)) ||
1430  (argPieces[2].size() &&
1431  (argPieces[2][argPieces[2].size() - 1] == 'f' ||
1432  argPieces[2].find('.') != std::string::npos)))
1433  {
1434  // handle as double
1435  //__GEN_COUT__ << "Double found" << __E__;
1436 
1437  double startValue = strtod(argPieces[1].c_str(), 0);
1438  double stepSize = strtod(argPieces[2].c_str(), 0);
1439 
1440  __GEN_COUTV__(startValue);
1441  __GEN_COUTV__(stepSize);
1442 
1443  __GEN_COUT__ << "Creating double argument '"
1444  << argPieces[0] << "' := " << startValue
1445  << ", " << stepSize << __E__;
1446 
1447  doubleDimensionParameters.back().emplace(std::make_pair(
1448  argPieces[0],
1449  std::make_pair(
1450  startValue /*current value*/,
1451  std::make_pair(startValue /*initial value*/,
1452  stepSize /*step value*/))));
1453  }
1454  else
1455  {
1456  // handle as long
1457  //__GEN_COUT__ << "Long found" << __E__;
1458 
1459  long int startValue;
1460  long int stepSize;
1461 
1462  StringMacros::getNumber(argPieces[1], startValue);
1463  StringMacros::getNumber(argPieces[2], stepSize);
1464 
1465  __GEN_COUTV__(startValue);
1466  __GEN_COUTV__(stepSize);
1467 
1468  __GEN_COUT__ << "Creating long argument '" << argPieces[0]
1469  << "' := " << startValue << ", " << stepSize
1470  << __E__;
1471 
1472  longDimensionParameters.back().emplace(std::make_pair(
1473  argPieces[0],
1474  std::make_pair(
1475  startValue /*current value*/,
1476  std::make_pair(startValue /*initial value*/,
1477  stepSize /*step value*/))));
1478  }
1479 
1480  } // end dimensional argument loop
1481 
1482  } // end dimensions loop
1483 
1484  if(dimensionIterations.size() != longDimensionParameters.size() ||
1485  dimensionIterations.size() != doubleDimensionParameters.size() ||
1486  dimensionIterations.size() != stringDimensionParameters.size())
1487  {
1488  __GEN_SS__ << "Impossible vector size mismatch! "
1489  << dimensionIterations.size() << " - "
1490  << longDimensionParameters.size() << " - "
1491  << doubleDimensionParameters.size() << " - "
1492  << stringDimensionParameters.size() << __E__;
1493  __GEN_SS_THROW__;
1494  }
1495 
1496  // output header
1497  {
1498  std::stringstream outSS;
1499  {
1500  outSS << "\n==========================\n" << __E__;
1501  outSS << "FEMacro '" << feMacro.feMacroName_
1502  << "' multi-dimensional scan..." << __E__;
1503  outSS << "\t" << StringMacros::getTimestampString() << __E__;
1504  outSS << "\t" << dimensionIterations.size()
1505  << " dimensions defined." << __E__;
1506  for(unsigned int i = 0; i < dimensionIterations.size(); ++i)
1507  {
1508  outSS << "\t\t"
1509  << "dimension[" << i << "] has "
1510  << dimensionIterations[i] << " iterations and "
1511  << (longDimensionParameters[i].size() +
1512  doubleDimensionParameters[i].size() +
1513  stringDimensionParameters[i].size())
1514  << " arguments." << __E__;
1515 
1516  for(auto& param : longDimensionParameters[i])
1517  outSS << "\t\t\t"
1518  << "'" << param.first << "' of type long with "
1519  << "initial value and step value [decimal] = "
1520  << "\t" << param.second.second.first << " & "
1521  << param.second.second.second << __E__;
1522 
1523  for(auto& param : doubleDimensionParameters[i])
1524  outSS << "\t\t\t"
1525  << "'" << param.first << "' of type double with "
1526  << "initial value and step value = "
1527  << "\t" << param.second.second.first << " & "
1528  << param.second.second.second << __E__;
1529 
1530  for(auto& param : stringDimensionParameters[i])
1531  outSS << "\t\t\t"
1532  << "'" << param.first << "' of type string with "
1533  << "value = "
1534  << "\t" << param.second << __E__;
1535  }
1536 
1537  outSS << "\nHere are the identified input arguments:" << __E__;
1538  for(unsigned int i = 0; i < feMacro.namesOfInputArguments_.size();
1539  ++i)
1540  outSS << "\t" << feMacro.namesOfInputArguments_[i] << __E__;
1541  outSS << "\nHere are the identified input arguments:" << __E__;
1542  for(unsigned int i = 0;
1543  i < feMacro.namesOfOutputArguments_.size();
1544  ++i)
1545  outSS << "\t" << feMacro.namesOfOutputArguments_[i] << __E__;
1546 
1547  outSS << "\n==========================\n" << __E__;
1548  } // end outputs stringstream results
1549 
1550  // if enabled to save to file, do it.
1551  __GEN_COUT__ << "\n" << outSS.str();
1552  if(outputFilePointer)
1553  fprintf(outputFilePointer, "%s", outSS.str().c_str());
1554  } // end output header
1555 
1556  unsigned int iterationCount = 0;
1557 
1558  // Use lambda recursive function to do arbitrary dimensions
1559  //
1560  // Note: can not do lambda recursive function if using auto to declare the
1561  // function, and must capture reference to the function. Also, must
1562  // capture specialFolders reference for use internally (const values
1563  // already are captured).
1564  std::function<void(const unsigned int /*dimension*/
1565  )>
1566  localRecurse = [&dimensionIterations,
1567  &dimensionIterationCnt,
1568  &iterationCount,
1569  &longDimensionParameters,
1570  &doubleDimensionParameters,
1571  &stringDimensionParameters,
1572  &fe,
1573  &feMacro,
1574  &outputFilePointer,
1575  &argsIn,
1576  &argsOut,
1577  &localRecurse](const unsigned int dimension) {
1578  // create local message facility subject
1579  std::string mfSubject_ = "multiD-" + std::to_string(dimension) +
1580  "-" + feMacro.feMacroName_;
1581  __GEN_COUTV__(dimension);
1582 
1583  if(dimension >= dimensionIterations.size())
1584  {
1585  __GEN_COUT__ << "Iteration count: " << iterationCount++
1586  << __E__;
1587  __GEN_COUT__ << "Launching FE Macro '" << feMacro.feMacroName_
1588  << "' ..." << __E__;
1589 
1590  // set argsIn to current value
1591 
1592  // scan all dimension parameter objects
1593  // note: Although conflicts should not be allowed
1594  // at this point, lower dimensions will have priority
1595  // over higher dimension with same name argument.. and
1596  // longs will have priority over doubles
1597 
1598  bool foundAsLong;
1599  for(unsigned int i = 0; i < argsIn.size(); ++i)
1600  {
1601  foundAsLong = false;
1602  for(unsigned int j = 0; j < dimensionIterations.size();
1603  ++j)
1604  {
1605  auto longIt =
1606  longDimensionParameters[j].find(argsIn[i].first);
1607  if(longIt == longDimensionParameters[j].end())
1608  continue;
1609 
1610  // else found long!
1611  __GEN_COUT__ << "Assigning argIn '" << argsIn[i].first
1612  << "' to current long value '"
1613  << longIt->second.first
1614  << "' from dimension " << j
1615  << " parameter." << __E__;
1616  argsIn[i].second =
1617  std::to_string(longIt->second.first);
1618  foundAsLong = true;
1619  break;
1620  } // end long loop
1621 
1622  if(foundAsLong)
1623  {
1624  continue; // skip double check
1625  }
1626 
1627  for(unsigned int j = 0; j < dimensionIterations.size();
1628  ++j)
1629  {
1630  auto doubleIt = doubleDimensionParameters[j].find(
1631  argsIn[i].first);
1632  if(doubleIt == doubleDimensionParameters[j].end())
1633  continue;
1634 
1635  // else found long!
1636  __GEN_COUT__ << "Assigning argIn '" << argsIn[i].first
1637  << "' to current double value '"
1638  << doubleIt->second.first
1639  << "' from dimension " << j
1640  << " parameter." << __E__;
1641  argsIn[i].second =
1642  std::to_string(doubleIt->second.first);
1643  foundAsLong = true;
1644  break;
1645  } // end double loop
1646 
1647  if(foundAsLong)
1648  {
1649  continue; // skip double check
1650  }
1651 
1652  for(unsigned int j = 0; j < dimensionIterations.size();
1653  ++j)
1654  {
1655  auto stringIt = stringDimensionParameters[j].find(
1656  argsIn[i].first);
1657  if(stringIt == stringDimensionParameters[j].end())
1658  continue;
1659 
1660  // else found long!
1661  __GEN_COUT__ << "Assigning argIn '" << argsIn[i].first
1662  << "' to current string value '"
1663  << stringIt->second
1664  << "' from dimension " << j
1665  << " parameter." << __E__;
1666  argsIn[i].second = stringIt->second;
1667  foundAsLong = true;
1668  break;
1669  } // end double loop
1670 
1671  if(foundAsLong)
1672  {
1673  continue; // skip double check
1674  }
1675 
1676  __GEN_SS__ << "ArgIn '" << argsIn[i].first
1677  << "' was not assigned a value "
1678  << "by any dimensional loop parameter sets. "
1679  "This is illegal. FEMacro '"
1680  << feMacro.feMacroName_ << "' requires '"
1681  << argsIn[i].first
1682  << "' as an input argument. Either remove the "
1683  "input argument from this FEMacro, "
1684  << "or define a value as a dimensional loop "
1685  "parameter."
1686  << __E__;
1687  __GEN_SS_THROW__;
1688  } // done building argsIn
1689 
1690  // have pointer to Macro structure, so run it
1691  (fe->*(feMacro.macroFunction_))(feMacro, argsIn, argsOut);
1692 
1693  __GEN_COUT__ << "FE Macro complete!" << __E__;
1694 
1695  // output results
1696  {
1697  std::stringstream outSS;
1698  {
1699  outSS << "\n---------------\n" << __E__;
1700  outSS << "FEMacro '" << feMacro.feMacroName_
1701  << "' execution..." << __E__;
1702  outSS << "\t"
1703  << "iteration " << iterationCount << __E__;
1704  for(unsigned int i = 0;
1705  i < dimensionIterationCnt.size();
1706  ++i)
1707  outSS << "\t"
1708  << "dimension[" << i
1709  << "] index := " << dimensionIterationCnt[i]
1710  << __E__;
1711 
1712  outSS << "\n"
1713  << "\t"
1714  << "Input arguments (count: " << argsIn.size()
1715  << "):" << __E__;
1716  for(auto& argIn : argsIn)
1717  outSS << "\t\t" << argIn.first << " = "
1718  << argIn.second << __E__;
1719 
1720  outSS << "\n"
1721  << "\t"
1722  << "Output arguments (count: " << argsOut.size()
1723  << "):" << __E__;
1724  for(auto& argOut : argsOut)
1725  outSS << "\t\t" << argOut.first << " = "
1726  << argOut.second << __E__;
1727  } // end outputs stringstream results
1728 
1729  // if enabled to save to file, do it.
1730  __GEN_COUT__ << "\n" << outSS.str();
1731  if(outputFilePointer)
1732  fprintf(outputFilePointer, "%s", outSS.str().c_str());
1733  } // end output results
1734 
1735  return;
1736  }
1737 
1738  // init dimension index
1739  if(dimension >= dimensionIterationCnt.size())
1740  dimensionIterationCnt.push_back(0);
1741 
1742  // if enabled to save to file, do it.
1743  __GEN_COUT__ << "\n"
1744  << "======================================" << __E__
1745  << "dimension[" << dimension
1746  << "] number of iterations := "
1747  << dimensionIterations[dimension] << __E__;
1748 
1749  // update current value to initial value for this dimension's
1750  // parameters
1751  {
1752  for(auto& longPair : longDimensionParameters[dimension])
1753  {
1754  longPair.second.first = // reset to initial value
1755  longPair.second.second.first;
1756  __GEN_COUT__
1757  << "arg '" << longPair.first
1758  << "' current value: " << longPair.second.first
1759  << __E__;
1760  } // end long loop
1761 
1762  for(auto& doublePair : doubleDimensionParameters[dimension])
1763  {
1764  doublePair.second.first = // reset to initial value
1765  doublePair.second.second.first;
1766  __GEN_COUT__
1767  << "arg '" << doublePair.first
1768  << "' current value: " << doublePair.second.first
1769  << __E__;
1770  } // end double loop
1771  } // end update current value to initial value for all
1772  // dimensional parameters
1773 
1774  for(dimensionIterationCnt[dimension] =
1775  0; // reset each time through dimension loop
1776  dimensionIterationCnt[dimension] <
1777  dimensionIterations[dimension];
1778  ++dimensionIterationCnt[dimension])
1779  {
1780  __GEN_COUT__ << "dimension[" << dimension << "] index := "
1781  << dimensionIterationCnt[dimension] << __E__;
1782 
1783  localRecurse(dimension + 1);
1784 
1785  // update current value to next value for this dimension's
1786  // parameters
1787  {
1788  for(auto& longPair : longDimensionParameters[dimension])
1789  {
1790  longPair.second.first += // add step value
1791  longPair.second.second.second;
1792  __GEN_COUT__
1793  << "arg '" << longPair.first
1794  << "' current value: " << longPair.second.first
1795  << __E__;
1796  } // end long loop
1797 
1798  for(auto& doublePair :
1799  doubleDimensionParameters[dimension])
1800  {
1801  doublePair.second.first += // add step value
1802  doublePair.second.second.second;
1803 
1804  __GEN_COUT__
1805  << "arg '" << doublePair.first
1806  << "' current value: " << doublePair.second.first
1807  << __E__;
1808  } // end double loop
1809  } // end update current value to next value for all
1810  // dimensional parameters
1811  }
1812  __GEN_COUT__ << "Completed dimension[" << dimension
1813  << "] number of iterations := "
1814  << dimensionIterationCnt[dimension] << " of "
1815  << dimensionIterations[dimension] << __E__;
1816  }; // end local lambda recursive function
1817 
1818  // launch multi-dimensional recursion
1819  localRecurse(0);
1820 
1821  // close output file
1822  if(outputFilePointer)
1823  fclose(outputFilePointer);
1824  }
1825  catch(const std::runtime_error& e)
1826  {
1827  __SS__ << "Error executing multi-dimensional FE Macro: " << e.what()
1828  << __E__;
1829  statusResult = ss.str();
1830  }
1831  catch(...)
1832  {
1833  __SS__ << "Unknown error executing multi-dimensional FE Macro. " << __E__;
1834  try
1835  {
1836  throw;
1837  } //one more try to printout extra info
1838  catch(const std::exception& e)
1839  {
1840  ss << "Exception message: " << e.what();
1841  }
1842  catch(...)
1843  {
1844  }
1845  statusResult = ss.str();
1846  }
1847 
1848  __COUTV__(statusResult);
1849 
1850  { // lock mutex scope
1851  std::lock_guard<std::mutex> lock(feMgr->macroMultiDimensionalDoneMutex_);
1852  // change status at completion
1853  feMgr->macroMultiDimensionalStatusMap_[interfaceID] = statusResult;
1854  }
1855  }, // end thread()
1856  this,
1857  interfaceID,
1858  feMacroName,
1859  enableSavingOutput,
1860  outputFilePath,
1861  outputFileRadix,
1862  inputArgs)
1863  .detach();
1864 
1865  __CFG_COUT__ << "Started multi-dimensional FE Macro '" << feMacroName
1866  << "' for interface '" << interfaceID << ".'" << __E__;
1867 
1868 } // end startFEMacroMultiDimensional()
1869 
1870 //==============================================================================
1877 bool FEVInterfacesManager::checkMacroMultiDimensional(const std::string& interfaceID,
1878  const std::string& macroName)
1879 {
1880  // check active(only one FE Macro per interface active at any time, for now)
1881  // lock mutex scope
1882  std::lock_guard<std::mutex> lock(macroMultiDimensionalDoneMutex_);
1883  // check status
1884  auto statusIt = macroMultiDimensionalStatusMap_.find(interfaceID);
1885  if(statusIt == macroMultiDimensionalStatusMap_.end())
1886  {
1887  __CFG_SS__ << "Status missing for multi-dimensional launch of Macro '"
1888  << macroName << "' for interface '" << interfaceID << ".'" << __E__;
1889  __CFG_SS_THROW__;
1890  }
1891  else if(statusIt->second == "Done")
1892  {
1893  __CFG_COUT__ << "Completed multi-dimensional launch of Macro '" << macroName
1894  << "' for interface '" << interfaceID << ".'" << __E__;
1895 
1896  // erase from map
1897  macroMultiDimensionalStatusMap_.erase(statusIt);
1898  return true;
1899  }
1900  else if(statusIt->second == "Active")
1901  {
1902  __CFG_COUT__ << "Still running multi-dimensional launch of Macro '" << macroName
1903  << "' for interface '" << interfaceID << ".'" << __E__;
1904  return false;
1905  }
1906  // else //assume error
1907 
1908  __CFG_SS__ << "Error occured during multi-dimensional launch of Macro '" << macroName
1909  << "' for interface '" << interfaceID << "':" << statusIt->second << __E__;
1910  __CFG_SS_THROW__;
1911 
1912 } // end checkMacroMultiDimensional()
1913 
1914 //==============================================================================
1926 void FEVInterfacesManager::runFEMacroByFE(const std::string& callingInterfaceID,
1927  const std::string& interfaceID,
1928  const std::string& feMacroName,
1929  const std::string& inputArgs,
1930  std::string& outputArgs)
1931 {
1932  __CFG_COUTV__(callingInterfaceID);
1933 
1934  // check for interfaceID
1935  FEVInterface* fe = getFEInterfaceP(interfaceID);
1936 
1937  // have pointer to virtual FEInterface, find Macro structure
1938  auto FEMacroIt = fe->getMapOfFEMacroFunctions().find(feMacroName);
1939  if(FEMacroIt == fe->getMapOfFEMacroFunctions().end())
1940  {
1941  __CFG_SS__ << "FE Macro '" << feMacroName << "' of interfaceID '" << interfaceID
1942  << "' was not found!" << __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  for(unsigned int i = 0; i < argsIn.size(); ++i)
2210  if(argsIn[i].first != feMacro.namesOfInputArguments_[i])
2211  {
2212  __CFG_SS__ << "FE Macro '" << feMacro.feMacroName_ << "' of interfaceID '"
2213  << interfaceID << "' was attempted with a mismatch in"
2214  << " a name of an input argument. " << argsIn[i].first
2215  << " was given. " << feMacro.namesOfInputArguments_[i]
2216  << " expected." << __E__;
2217  __CFG_COUT_ERR__ << "\n" << ss.str();
2218  __CFG_SS_THROW__;
2219  }
2220 
2221  // build output arguments
2222  std::vector<std::string> returnStrings;
2223  std::vector<FEVInterface::frontEndMacroArg_t> argsOut;
2224 
2225  {
2226  std::istringstream inputStream(outputArgs);
2227  std::string argName;
2228  while(getline(inputStream, argName, ','))
2229  {
2230  __CFG_COUT__ << "argName " << argName << __E__;
2231 
2232  returnStrings.push_back("DEFAULT"); // std::string());
2233  argsOut.push_back(FEVInterface::frontEndMacroArg_t(
2235  returnStrings[returnStrings.size() - 1]));
2236  //
2237  // __CFG_COUT__ << argsOut[argsOut.size()-1].first << __E__;
2238  __CFG_COUT__ << (uint64_t) & (returnStrings[returnStrings.size() - 1])
2239  << __E__;
2240  }
2241  }
2242 
2243  // check namesOfOutputArguments_
2244  if(feMacro.namesOfOutputArguments_.size() != argsOut.size())
2245  {
2246  __CFG_SS__ << "FE Macro '" << feMacro.feMacroName_ << "' of interfaceID '"
2247  << interfaceID << "' was attempted with a mismatch in"
2248  << " number of output arguments. " << argsOut.size() << " were given. "
2249  << feMacro.namesOfOutputArguments_.size() << " expected." << __E__;
2250  __CFG_COUT_ERR__ << "\n" << ss.str();
2251  __CFG_SS_THROW__;
2252  }
2253  for(unsigned int i = 0; i < argsOut.size(); ++i)
2254  if(argsOut[i].first != feMacro.namesOfOutputArguments_[i])
2255  {
2256  __CFG_SS__ << "FE Macro '" << feMacro.feMacroName_ << "' of interfaceID '"
2257  << interfaceID << "' was attempted with a mismatch in"
2258  << " a name of an output argument. " << argsOut[i].first
2259  << " were given. " << feMacro.namesOfOutputArguments_[i]
2260  << " expected." << __E__;
2261  __CFG_COUT_ERR__ << "\n" << ss.str();
2262  __CFG_SS_THROW__;
2263  }
2264 
2265  __CFG_COUT__ << "# of input args = " << argsIn.size() << __E__;
2266  for(auto& argIn : argsIn)
2267  __CFG_COUT__ << argIn.first << ": " << argIn.second << __E__;
2268 
2269  // __CFG_COUT__ << "# of output args = " << argsOut.size() << __E__;
2270  // for(unsigned int i=0;i<argsOut.size();++i)
2271  // __CFG_COUT__ << i << ": " << argsOut[i].first << __E__;
2272  // for(unsigned int i=0;i<returnStrings.size();++i)
2273  // __CFG_COUT__ << i << ": " << returnStrings[i] << __E__;
2274 
2275  __COUT__ << "Launching FE Macro '" << feMacro.feMacroName_ << "' ..." << __E__;
2276  __CFG_COUT__ << "Launching FE Macro '" << feMacro.feMacroName_ << "' ..." << __E__;
2277 
2278  // have pointer to Macro structure, so run it
2279  (getFEInterfaceP(interfaceID)->*(feMacro.macroFunction_))(feMacro, argsIn, argsOut);
2280 
2281  __CFG_COUT__ << "FE Macro complete!" << __E__;
2282 
2283  __CFG_COUT__ << "# of output args = " << argsOut.size() << __E__;
2284  for(const auto& arg : argsOut)
2285  __CFG_COUT__ << arg.first << ": " << arg.second << __E__;
2286 
2287  // check namesOfOutputArguments_ size
2288  if(feMacro.namesOfOutputArguments_.size() != argsOut.size())
2289  {
2290  __CFG_SS__ << "FE Macro '" << feMacro.feMacroName_ << "' of interfaceID '"
2291  << interfaceID
2292  << "' was attempted but the FE macro "
2293  "manipulated the output arguments vector. It is illegal "
2294  "to add or remove output vector name/value pairs."
2295  << __E__;
2296  __CFG_COUT_ERR__ << "\n" << ss.str();
2297  __CFG_SS_THROW__;
2298  }
2299 
2300  // Success! at this point so return the output string
2301  outputArgs = "";
2302  for(unsigned int i = 0; i < argsOut.size(); ++i)
2303  {
2304  if(i)
2305  outputArgs += ";";
2306 
2307  // attempt to get number, and output hex version
2308  // otherwise just output result
2309  try
2310  {
2311  uint64_t tmpNumber;
2312  if(StringMacros::getNumber(argsOut[i].second, tmpNumber))
2313  {
2314  std::stringstream outNumberSs;
2315  outNumberSs << std::dec << tmpNumber << " (0x" << std::hex << tmpNumber
2316  << ")" << std::dec;
2317  outputArgs += argsOut[i].first + "," + outNumberSs.str();
2318  continue;
2319  }
2320  }
2321  catch(...)
2322  { // ignore error, assume not a number
2323  }
2324 
2325  outputArgs +=
2326  argsOut[i].first + "," + StringMacros::encodeURIComponent(argsOut[i].second);
2327  }
2328 
2329  __CFG_COUTT__ << "outputArgs = " << outputArgs << __E__;
2330 
2331 } // end runFEMacro()
2332 
2333 //==============================================================================
2342 std::string FEVInterfacesManager::getFEMacrosString(const std::string& supervisorName,
2343  const std::string& supervisorLid)
2344 {
2345  std::string retList = "";
2346 
2347  __CFG_COUTV__(theFEInterfaces_.size());
2348 
2349  for(const auto& it : theFEInterfaces_)
2350  {
2351  __CFG_COUTT__ << "FE interface UID = " << it.first << __E__;
2352 
2353  retList += supervisorName + ";" + supervisorLid + ";" +
2354  it.second->getInterfaceType() + ";" + it.second->getInterfaceUID();
2355 
2356  for(const auto& macroPair : it.second->getMapOfFEMacroFunctions())
2357  {
2358  __CFG_COUTT__ << "FE Macro name = " << macroPair.first << __E__;
2359  retList +=
2360  ";" + macroPair.first + ";" + macroPair.second.requiredUserPermissions_;
2361  retList +=
2362  ";" + StringMacros::encodeURIComponent(macroPair.second.feMacroTooltip_);
2363 
2364  retList +=
2365  ";" + std::to_string(macroPair.second.namesOfInputArguments_.size());
2366  for(const auto& name : macroPair.second.namesOfInputArguments_)
2367  retList += ";" + StringMacros::encodeURIComponent(name);
2368 
2369  retList +=
2370  ";" + std::to_string(macroPair.second.namesOfOutputArguments_.size());
2371  for(const auto& name : macroPair.second.namesOfOutputArguments_)
2372  retList += ";" + StringMacros::encodeURIComponent(name);
2373  }
2374 
2375  retList += "\n";
2376  }
2377  return retList;
2378 }
2379 
2380 //==============================================================================
2382 {
2383  bool allFEWorkloopsAreDone = true;
2384  bool isActive;
2385 
2386  for(const auto& FEInterface : theFEInterfaces_)
2387  {
2388  isActive = FEInterface.second->WorkLoop::isActive();
2389 
2390  __CFG_COUT__ << FEInterface.second->getInterfaceUID() << " of type "
2391  << FEInterface.second->getInterfaceType() << ": \t"
2392  << "workLoop_->isActive() " << (isActive ? "yes" : "no") << __E__;
2393 
2394  if(isActive) // then not done
2395  {
2396  allFEWorkloopsAreDone = false;
2397  break;
2398  }
2399  }
2400 
2401  return allFEWorkloopsAreDone;
2402 } // end allFEWorkloopsAreDone()
2403 
2404 //==============================================================================
2405 void FEVInterfacesManager::preStateMachineExecutionLoop(void)
2406 {
2407  VStateMachine::clearIterationWork();
2408  VStateMachine::clearSubIterationWork();
2409 
2410  stateMachinesIterationWorkCount_ = 0;
2411 
2412  __CFG_COUT__ << "Number of front ends to transition: " << theFENamesByPriority_.size()
2413  << __E__;
2414 
2415  if(VStateMachine::getIterationIndex() == 0 &&
2416  VStateMachine::getSubIterationIndex() == 0)
2417  {
2418  // reset map for iterations done on first iteration
2419 
2420  subIterationWorkStateMachineIndex_ = -1; // clear sub iteration work index
2421 
2422  stateMachinesIterationDone_.clear();
2423  for(const auto& FEPair : theFEInterfaces_)
2424  stateMachinesIterationDone_[FEPair.first] = false; // init to not done
2425  }
2426  else
2427  __CFG_COUT__ << "Iteration " << VStateMachine::getIterationIndex() << "."
2428  << VStateMachine::getSubIterationIndex() << "("
2429  << (int)subIterationWorkStateMachineIndex_ << ")" << __E__;
2430 } // end preStateMachineExecutionLoop()
2431 
2432 //==============================================================================
2433 void FEVInterfacesManager::preStateMachineExecution(unsigned int i,
2434  const std::string& transitionName)
2435 {
2436  if(i >= theFENamesByPriority_.size())
2437  {
2438  __CFG_SS__ << "FE Interface " << i << " not found!" << __E__;
2439  __CFG_SS_THROW__;
2440  }
2441 
2442  const std::string& name = theFENamesByPriority_[i];
2443 
2444  FEVInterface* fe = getFEInterfaceP(name);
2445 
2446  fe->VStateMachine::setTransitionName(transitionName);
2447  fe->VStateMachine::setIterationIndex(VStateMachine::getIterationIndex());
2448  fe->VStateMachine::setSubIterationIndex(VStateMachine::getSubIterationIndex());
2449 
2450  fe->VStateMachine::clearIterationWork();
2451  fe->VStateMachine::clearSubIterationWork();
2452 
2453  __CFG_COUT__ << "theStateMachineImplementation Iteration "
2454  << fe->VStateMachine::getIterationIndex() << "."
2455  << fe->VStateMachine::getSubIterationIndex() << __E__;
2456 } // end preStateMachineExecution()
2457 
2458 //==============================================================================
2461 bool FEVInterfacesManager::postStateMachineExecution(unsigned int i)
2462 {
2463  if(i >= theFENamesByPriority_.size())
2464  {
2465  __CFG_SS__ << "FE Interface index " << i << " not found!" << __E__;
2466  __CFG_SS_THROW__;
2467  }
2468 
2469  const std::string& name = theFENamesByPriority_[i];
2470 
2471  FEVInterface* fe = getFEInterfaceP(name);
2472 
2473  // sub-iteration has priority
2474  if(fe->VStateMachine::getSubIterationWork())
2475  {
2476  subIterationWorkStateMachineIndex_ = i;
2477  VStateMachine::indicateSubIterationWork();
2478 
2479  __CFG_COUT__ << "FE Interface '" << name
2480  << "' is flagged for another sub-iteration..." << __E__;
2481  return false; // to indicate state machine is NOT done with transition
2482  }
2483  else
2484  {
2485  subIterationWorkStateMachineIndex_ = -1; // clear sub iteration work index
2486 
2487  bool& stateMachineDone = stateMachinesIterationDone_[name];
2488  stateMachineDone = !fe->VStateMachine::getIterationWork();
2489 
2490  if(!stateMachineDone)
2491  {
2492  __CFG_COUT__ << "FE Interface '" << name
2493  << "' is flagged for another iteration..." << __E__;
2494  VStateMachine::indicateIterationWork(); // mark not done at
2495  // FEVInterfacesManager level
2496  ++stateMachinesIterationWorkCount_; // increment still working count
2497  return false; // to indicate state machine is NOT done with transition
2498  }
2499  }
2500 
2501  fe->VStateMachine::setTransitionName(""); // clear transition
2502  return true; // to indicate state machine is done with transition
2503 } // end postStateMachineExecution()
2504 
2505 //==============================================================================
2506 void FEVInterfacesManager::postStateMachineExecutionLoop(void)
2507 {
2508  if(VStateMachine::getSubIterationWork())
2509  __CFG_COUT__ << "FE Interface state machine implementation "
2510  << subIterationWorkStateMachineIndex_
2511  << " is flagged for another sub-iteration..." << __E__;
2512  else if(VStateMachine::getIterationWork())
2513  __CFG_COUT__ << stateMachinesIterationWorkCount_
2514  << " FE Interface state machine implementation(s) flagged for "
2515  "another iteration..."
2516  << __E__;
2517  else
2518  __CFG_COUT__ << "Done transitioning all state machine implementations..."
2519  << __E__;
2520 } // 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:89
std::pair< const std::string, std::string > frontEndMacroArg_t
end Slow Controls
Definition: FEVInterface.h:140
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:146
const frontEndMacroFunction_t macroFunction_
Note: must be called using this instance.
Definition: FEVInterface.h:166
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:94
static std::string decodeURIComponent(const std::string &data)
static bool getNumber(const std::string &s, T &retValue)