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