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