$treeview $search $mathjax $extrastylesheet
otsdaq
v2_03_00
$projectbrief
|
$projectbrief
|
$searchbox |
00001 #include "otsdaq-core/FECore/FEVInterfacesManager.h" 00002 #include "otsdaq-core/ConfigurationInterface/ConfigurationManager.h" 00003 #include "otsdaq-core/Macros/CoutMacros.h" 00004 #include "otsdaq-core/MessageFacility/MessageFacility.h" 00005 #include "otsdaq-core/PluginMakers/MakeInterface.h" 00006 00007 #include "artdaq-core/Utilities/configureMessageFacility.hh" 00008 #include "artdaq/BuildInfo/GetPackageBuildInfo.hh" 00009 #include "fhiclcpp/make_ParameterSet.h" 00010 #include "messagefacility/MessageLogger/MessageLogger.h" 00011 00012 #include <iostream> 00013 #include <sstream> 00014 #include <thread> //for std::thread 00015 00016 using namespace ots; 00017 00018 //======================================================================================================================== 00019 FEVInterfacesManager::FEVInterfacesManager( 00020 const ConfigurationTree& theXDAQContextConfigTree, 00021 const std::string& supervisorConfigurationPath) 00022 : Configurable(theXDAQContextConfigTree, supervisorConfigurationPath) 00023 { 00024 init(); 00025 __CFG_COUT__ << "Constructed." << __E__; 00026 } 00027 00028 //======================================================================================================================== 00029 FEVInterfacesManager::~FEVInterfacesManager(void) 00030 { 00031 destroy(); 00032 __CFG_COUT__ << "Destructed." << __E__; 00033 } 00034 00035 //======================================================================================================================== 00036 void FEVInterfacesManager::init(void) {} 00037 00038 //======================================================================================================================== 00039 void FEVInterfacesManager::destroy(void) 00040 { 00041 for(auto& it : theFEInterfaces_) 00042 it.second.reset(); 00043 00044 theFEInterfaces_.clear(); 00045 theFENamesByPriority_.clear(); 00046 } 00047 00048 //======================================================================================================================== 00049 void FEVInterfacesManager::createInterfaces(void) 00050 { 00051 const std::string COL_NAME_feGroupLink = "LinkToFEInterfaceTable"; 00052 const std::string COL_NAME_feTypeLink = "LinkToFETypeTable"; 00053 const std::string COL_NAME_fePlugin = "FEInterfacePluginName"; 00054 00055 __CFG_COUT__ << "Path: " << theConfigurationPath_ + "/" + COL_NAME_feGroupLink 00056 << __E__; 00057 00058 destroy(); 00059 00060 { // could access application node like so, ever needed? 00061 ConfigurationTree appNode = 00062 theXDAQContextConfigTree_.getBackNode(theConfigurationPath_, 1); 00063 __CFG_COUTV__(appNode.getValueAsString()); 00064 } 00065 00066 ConfigurationTree feGroupLinkNode = 00067 Configurable::getSelfNode().getNode(COL_NAME_feGroupLink); 00068 00069 std::vector<std::pair<std::string, ConfigurationTree>> feChildren = 00070 feGroupLinkNode.getChildren(); 00071 00072 // acquire names by priority 00073 theFENamesByPriority_ = 00074 feGroupLinkNode.getChildrenNames(true /*byPriority*/, true /*onlyStatusTrue*/); 00075 __CFG_COUTV__(StringMacros::vectorToString(theFENamesByPriority_)); 00076 00077 for(const auto& interface : feChildren) 00078 { 00079 try 00080 { 00081 if(!interface.second.getNode(TableViewColumnInfo::COL_NAME_STATUS) 00082 .getValue<bool>()) 00083 continue; 00084 } 00085 catch(...) // if Status column not there ignore (for backwards compatibility) 00086 { 00087 __CFG_COUT_INFO__ << "Ignoring FE Status since Status column is missing!" 00088 << __E__; 00089 } 00090 00091 __CFG_COUT__ 00092 << "Interface Plugin Name: " 00093 << interface.second.getNode(COL_NAME_fePlugin).getValue<std::string>() 00094 << __E__; 00095 __CFG_COUT__ << "Interface Name: " << interface.first << __E__; 00096 __CFG_COUT__ << "XDAQContext Node: " << theXDAQContextConfigTree_ << __E__; 00097 __CFG_COUT__ << "Path to configuration: " 00098 << (theConfigurationPath_ + "/" + COL_NAME_feGroupLink + "/" + 00099 interface.first + "/" + COL_NAME_feTypeLink) 00100 << __E__; 00101 00102 try 00103 { 00104 theFEInterfaces_[interface.first] = makeInterface( 00105 interface.second.getNode(COL_NAME_fePlugin).getValue<std::string>(), 00106 interface.first, 00107 theXDAQContextConfigTree_, 00108 (theConfigurationPath_ + "/" + COL_NAME_feGroupLink + "/" + 00109 interface.first + "/" + COL_NAME_feTypeLink)); 00110 00111 // setup parent supervisor and interface manager 00112 // of FEVinterface (for backwards compatibility, left out of constructor) 00113 theFEInterfaces_[interface.first]->VStateMachine::parentSupervisor_ = 00114 VStateMachine::parentSupervisor_; 00115 theFEInterfaces_[interface.first]->parentInterfaceManager_ = this; 00116 } 00117 catch(const cet::exception& e) 00118 { 00119 __CFG_SS__ 00120 << "Failed to instantiate plugin named '" << interface.first 00121 << "' of type '" 00122 << interface.second.getNode(COL_NAME_fePlugin).getValue<std::string>() 00123 << "' due to the following error: \n" 00124 << e.what() << __E__; 00125 __MOUT_ERR__ << ss.str(); 00126 __CFG_SS_THROW__; 00127 } 00128 catch(const std::runtime_error& e) 00129 { 00130 __CFG_SS__ 00131 << "Failed to instantiate plugin named '" << interface.first 00132 << "' of type '" 00133 << interface.second.getNode(COL_NAME_fePlugin).getValue<std::string>() 00134 << "' due to the following error: \n" 00135 << e.what() << __E__; 00136 __MOUT_ERR__ << ss.str(); 00137 __CFG_SS_THROW__; 00138 } 00139 catch(...) 00140 { 00141 __CFG_SS__ 00142 << "Failed to instantiate plugin named '" << interface.first 00143 << "' of type '" 00144 << interface.second.getNode(COL_NAME_fePlugin).getValue<std::string>() 00145 << "' due to an unknown error." << __E__; 00146 __MOUT_ERR__ << ss.str(); 00147 throw; // if we do not throw, it is hard to tell what is happening.. 00148 //__CFG_SS_THROW__; 00149 } 00150 } 00151 __CFG_COUT__ << "Done creating interfaces" << __E__; 00152 } // end createInterfaces() 00153 00154 //======================================================================================================================== 00155 void FEVInterfacesManager::configure(void) 00156 { 00157 const std::string transitionName = "Configuring"; 00158 00159 __CFG_COUT__ << transitionName << " FEVInterfacesManager " << __E__; 00160 00161 // create interfaces (the first iteration) 00162 if(VStateMachine::getIterationIndex() == 0 && 00163 VStateMachine::getSubIterationIndex() == 0) 00164 createInterfaces(); // by priority 00165 00166 FEVInterface* fe; 00167 00168 preStateMachineExecutionLoop(); 00169 for(unsigned int i = 0; i < theFENamesByPriority_.size(); ++i) 00170 { 00171 // if one state machine is doing a sub-iteration, then target that one 00172 if(subIterationWorkStateMachineIndex_ != (unsigned int)-1 && 00173 i != subIterationWorkStateMachineIndex_) 00174 continue; // skip those not in the sub-iteration 00175 00176 const std::string& name = theFENamesByPriority_[i]; 00177 00178 // test for front-end existence 00179 fe = getFEInterfaceP(name); 00180 00181 if(stateMachinesIterationDone_[name]) 00182 continue; // skip state machines already done 00183 00184 __CFG_COUT__ << transitionName << " interface " << name << __E__; 00185 __CFG_COUT__ << transitionName << " interface " << name << __E__; 00186 __CFG_COUT__ << transitionName << " interface " << name << __E__; 00187 00188 preStateMachineExecution(i); 00189 fe->configure(); 00190 postStateMachineExecution(i); 00191 00192 // configure slow controls and start slow controls workloop 00193 // slow controls workloop stays alive through start/stop.. and dies on halt 00194 fe->configureSlowControls(); 00195 fe->startSlowControlsWorkLooop(); 00196 00197 __CFG_COUT__ << "Done " << transitionName << " interface " << name << __E__; 00198 __CFG_COUT__ << "Done " << transitionName << " interface " << name << __E__; 00199 __CFG_COUT__ << "Done " << transitionName << " interface " << name << __E__; 00200 } 00201 postStateMachineExecutionLoop(); 00202 00203 __CFG_COUT__ << "Done " << transitionName << " all interfaces." << __E__; 00204 } // end configure() 00205 00206 //======================================================================================================================== 00207 void FEVInterfacesManager::halt(void) 00208 { 00209 const std::string transitionName = "Halting"; 00210 FEVInterface* fe; 00211 00212 preStateMachineExecutionLoop(); 00213 for(unsigned int i = 0; i < theFENamesByPriority_.size(); ++i) 00214 { 00215 // if one state machine is doing a sub-iteration, then target that one 00216 if(subIterationWorkStateMachineIndex_ != (unsigned int)-1 && 00217 i != subIterationWorkStateMachineIndex_) 00218 continue; // skip those not in the sub-iteration 00219 00220 const std::string& name = theFENamesByPriority_[i]; 00221 00222 fe = getFEInterfaceP(name); 00223 00224 if(stateMachinesIterationDone_[name]) 00225 continue; // skip state machines already done 00226 00227 __CFG_COUT__ << transitionName << " interface " << name << __E__; 00228 __CFG_COUT__ << transitionName << " interface " << name << __E__; 00229 __CFG_COUT__ << transitionName << " interface " << name << __E__; 00230 00231 preStateMachineExecution(i); 00232 00233 // since halting also occurs on errors, ignore more errors 00234 try 00235 { 00236 fe->stopWorkLoop(); 00237 } 00238 catch(...) 00239 { 00240 __CFG_COUT_WARN__ 00241 << "An error occurred while halting the front-end workloop for '" << name 00242 << ",' ignoring." << __E__; 00243 } 00244 00245 // since halting also occurs on errors, ignore more errors 00246 try 00247 { 00248 fe->stopSlowControlsWorkLooop(); 00249 } 00250 catch(...) 00251 { 00252 __CFG_COUT_WARN__ << "An error occurred while halting the Slow Controls " 00253 "front-end workloop for '" 00254 << name << ",' ignoring." << __E__; 00255 } 00256 00257 // since halting also occurs on errors, ignore more errors 00258 try 00259 { 00260 fe->halt(); 00261 } 00262 catch(...) 00263 { 00264 __CFG_COUT_WARN__ << "An error occurred while halting the front-end '" << name 00265 << ",' ignoring." << __E__; 00266 } 00267 00268 postStateMachineExecution(i); 00269 00270 __CFG_COUT__ << "Done " << transitionName << " interface " << name << __E__; 00271 __CFG_COUT__ << "Done " << transitionName << " interface " << name << __E__; 00272 __CFG_COUT__ << "Done " << transitionName << " interface " << name << __E__; 00273 } 00274 postStateMachineExecutionLoop(); 00275 00276 destroy(); // destroy all FE interfaces on halt, must be configured for FE interfaces 00277 // to exist 00278 00279 __CFG_COUT__ << "Done " << transitionName << " all interfaces." << __E__; 00280 } // end halt() 00281 00282 //======================================================================================================================== 00283 void FEVInterfacesManager::pause(void) 00284 { 00285 const std::string transitionName = "Pausing"; 00286 FEVInterface* fe; 00287 00288 preStateMachineExecutionLoop(); 00289 for(unsigned int i = 0; i < theFENamesByPriority_.size(); ++i) 00290 { 00291 // if one state machine is doing a sub-iteration, then target that one 00292 if(subIterationWorkStateMachineIndex_ != (unsigned int)-1 && 00293 i != subIterationWorkStateMachineIndex_) 00294 continue; // skip those not in the sub-iteration 00295 00296 const std::string& name = theFENamesByPriority_[i]; 00297 00298 fe = getFEInterfaceP(name); 00299 00300 if(stateMachinesIterationDone_[name]) 00301 continue; // skip state machines already done 00302 00303 __CFG_COUT__ << transitionName << " interface " << name << __E__; 00304 __CFG_COUT__ << transitionName << " interface " << name << __E__; 00305 __CFG_COUT__ << transitionName << " interface " << name << __E__; 00306 00307 preStateMachineExecution(i); 00308 fe->stopWorkLoop(); 00309 fe->pause(); 00310 postStateMachineExecution(i); 00311 00312 __CFG_COUT__ << "Done " << transitionName << " interface " << name << __E__; 00313 __CFG_COUT__ << "Done " << transitionName << " interface " << name << __E__; 00314 __CFG_COUT__ << "Done " << transitionName << " interface " << name << __E__; 00315 } 00316 postStateMachineExecutionLoop(); 00317 00318 __CFG_COUT__ << "Done " << transitionName << " all interfaces." << __E__; 00319 } // end pause() 00320 00321 //======================================================================================================================== 00322 void FEVInterfacesManager::resume(void) 00323 { 00324 const std::string transitionName = "Resuming"; 00325 FEVInterface* fe; 00326 00327 preStateMachineExecutionLoop(); 00328 for(unsigned int i = 0; i < theFENamesByPriority_.size(); ++i) 00329 { 00330 // if one state machine is doing a sub-iteration, then target that one 00331 if(subIterationWorkStateMachineIndex_ != (unsigned int)-1 && 00332 i != subIterationWorkStateMachineIndex_) 00333 continue; // skip those not in the sub-iteration 00334 00335 const std::string& name = theFENamesByPriority_[i]; 00336 00337 FEVInterface* fe = getFEInterfaceP(name); 00338 00339 if(stateMachinesIterationDone_[name]) 00340 continue; // skip state machines already done 00341 00342 __CFG_COUT__ << transitionName << " interface " << name << __E__; 00343 __CFG_COUT__ << transitionName << " interface " << name << __E__; 00344 __CFG_COUT__ << transitionName << " interface " << name << __E__; 00345 00346 preStateMachineExecution(i); 00347 fe->resume(); 00348 // only start workloop once transition is done 00349 if(postStateMachineExecution(i)) 00350 fe->startWorkLoop(); 00351 00352 __CFG_COUT__ << "Done " << transitionName << " interface " << name << __E__; 00353 __CFG_COUT__ << "Done " << transitionName << " interface " << name << __E__; 00354 __CFG_COUT__ << "Done " << transitionName << " interface " << name << __E__; 00355 } 00356 postStateMachineExecutionLoop(); 00357 00358 __CFG_COUT__ << "Done " << transitionName << " all interfaces." << __E__; 00359 00360 } // end resume() 00361 00362 //======================================================================================================================== 00363 void FEVInterfacesManager::start(std::string runNumber) 00364 { 00365 const std::string transitionName = "Starting"; 00366 FEVInterface* fe; 00367 00368 preStateMachineExecutionLoop(); 00369 for(unsigned int i = 0; i < theFENamesByPriority_.size(); ++i) 00370 { 00371 // if one state machine is doing a sub-iteration, then target that one 00372 if(subIterationWorkStateMachineIndex_ != (unsigned int)-1 && 00373 i != subIterationWorkStateMachineIndex_) 00374 continue; // skip those not in the sub-iteration 00375 00376 const std::string& name = theFENamesByPriority_[i]; 00377 00378 fe = getFEInterfaceP(name); 00379 00380 if(stateMachinesIterationDone_[name]) 00381 continue; // skip state machines already done 00382 00383 __CFG_COUT__ << transitionName << " interface " << name << __E__; 00384 __CFG_COUT__ << transitionName << " interface " << name << __E__; 00385 __CFG_COUT__ << transitionName << " interface " << name << __E__; 00386 00387 preStateMachineExecution(i); 00388 fe->start(runNumber); 00389 // only start workloop once transition is done 00390 if(postStateMachineExecution(i)) 00391 fe->startWorkLoop(); 00392 00393 __CFG_COUT__ << "Done " << transitionName << " interface " << name << __E__; 00394 __CFG_COUT__ << "Done " << transitionName << " interface " << name << __E__; 00395 __CFG_COUT__ << "Done " << transitionName << " interface " << name << __E__; 00396 } 00397 postStateMachineExecutionLoop(); 00398 00399 __CFG_COUT__ << "Done " << transitionName << " all interfaces." << __E__; 00400 00401 } // end start() 00402 00403 //======================================================================================================================== 00404 void FEVInterfacesManager::stop(void) 00405 { 00406 const std::string transitionName = "Starting"; 00407 FEVInterface* fe; 00408 00409 preStateMachineExecutionLoop(); 00410 for(unsigned int i = 0; i < theFENamesByPriority_.size(); ++i) 00411 { 00412 // if one state machine is doing a sub-iteration, then target that one 00413 if(subIterationWorkStateMachineIndex_ != (unsigned int)-1 && 00414 i != subIterationWorkStateMachineIndex_) 00415 continue; // skip those not in the sub-iteration 00416 00417 const std::string& name = theFENamesByPriority_[i]; 00418 00419 fe = getFEInterfaceP(name); 00420 00421 if(stateMachinesIterationDone_[name]) 00422 continue; // skip state machines already done 00423 00424 __CFG_COUT__ << transitionName << " interface " << name << __E__; 00425 __CFG_COUT__ << transitionName << " interface " << name << __E__; 00426 __CFG_COUT__ << transitionName << " interface " << name << __E__; 00427 00428 preStateMachineExecution(i); 00429 fe->stopWorkLoop(); 00430 fe->stop(); 00431 postStateMachineExecution(i); 00432 00433 __CFG_COUT__ << "Done " << transitionName << " interface " << name << __E__; 00434 __CFG_COUT__ << "Done " << transitionName << " interface " << name << __E__; 00435 __CFG_COUT__ << "Done " << transitionName << " interface " << name << __E__; 00436 } 00437 postStateMachineExecutionLoop(); 00438 00439 __CFG_COUT__ << "Done " << transitionName << " all interfaces." << __E__; 00440 00441 } // end stop() 00442 00443 //======================================================================================================================== 00444 // getFEInterfaceP 00445 FEVInterface* FEVInterfacesManager::getFEInterfaceP(const std::string& interfaceID) 00446 { 00447 try 00448 { 00449 return theFEInterfaces_.at(interfaceID).get(); 00450 } 00451 catch(...) 00452 { 00453 __CFG_SS__ << "Interface ID '" << interfaceID 00454 << "' not found in configured interfaces." << __E__; 00455 __CFG_SS_THROW__; 00456 } 00457 } // end getFEInterfaceP() 00458 00459 //======================================================================================================================== 00460 // getFEInterface 00461 const FEVInterface& FEVInterfacesManager::getFEInterface( 00462 const std::string& interfaceID) const 00463 { 00464 try 00465 { 00466 return *(theFEInterfaces_.at(interfaceID)); 00467 } 00468 catch(...) 00469 { 00470 __CFG_SS__ << "Interface ID '" << interfaceID 00471 << "' not found in configured interfaces." << __E__; 00472 __CFG_SS_THROW__; 00473 } 00474 } // end getFEInterface() 00475 00476 //======================================================================================================================== 00477 // universalRead 00478 // used by MacroMaker 00479 // throw std::runtime_error on error/timeout 00480 void FEVInterfacesManager::universalRead(const std::string& interfaceID, 00481 char* address, 00482 char* returnValue) 00483 { 00484 getFEInterfaceP(interfaceID)->universalRead(address, returnValue); 00485 } // end universalRead() 00486 00487 //======================================================================================================================== 00488 // getInterfaceUniversalAddressSize 00489 // used by MacroMaker 00490 unsigned int FEVInterfacesManager::getInterfaceUniversalAddressSize( 00491 const std::string& interfaceID) 00492 { 00493 return getFEInterfaceP(interfaceID)->getUniversalAddressSize(); 00494 } // end getInterfaceUniversalAddressSize() 00495 00496 //======================================================================================================================== 00497 // getInterfaceUniversalDataSize 00498 // used by MacroMaker 00499 unsigned int FEVInterfacesManager::getInterfaceUniversalDataSize( 00500 const std::string& interfaceID) 00501 { 00502 return getFEInterfaceP(interfaceID)->getUniversalDataSize(); 00503 } // end getInterfaceUniversalDataSize() 00504 00505 //======================================================================================================================== 00506 // universalWrite 00507 // used by MacroMaker 00508 void FEVInterfacesManager::universalWrite(const std::string& interfaceID, 00509 char* address, 00510 char* writeValue) 00511 { 00512 getFEInterfaceP(interfaceID)->universalWrite(address, writeValue); 00513 } // end universalWrite() 00514 00515 //======================================================================================================================== 00516 // getFEListString 00517 // returns string with each new line for each FE 00518 // each line: 00519 // <interface type>:<parent supervisor lid>:<interface UID> 00520 std::string FEVInterfacesManager::getFEListString(const std::string& supervisorLid) 00521 { 00522 std::string retList = ""; 00523 00524 for(const auto& it : theFEInterfaces_) 00525 { 00526 __CFG_COUT__ << "FE name = " << it.first << __E__; 00527 00528 retList += it.second->getInterfaceType() + ":" + supervisorLid + ":" + 00529 it.second->getInterfaceUID() + "\n"; 00530 } 00531 return retList; 00532 } // end getFEListString() 00533 00534 //======================================================================================================================== 00535 // startMacroMultiDimensional 00536 // Launches a thread that manages the multi-dimensional loop 00537 // running the Macro on the specified FE interface. 00538 // Called by iterator (for now). 00539 // 00540 // Note: no output arguments are returned, but outputs are 00541 // optionally saved to file. 00542 // 00543 // 00544 // inputs: 00545 // - inputArgs: dimensional semi-colon-separated, 00546 // comma separated: dimension iterations and arguments (colon-separated 00547 // name/value/stepsize sets) 00548 // 00549 // outputs: 00550 // - throws exception on failure 00551 void FEVInterfacesManager::startMacroMultiDimensional(const std::string& requester, 00552 const std::string& interfaceID, 00553 const std::string& macroName, 00554 const std::string& macroString, 00555 const bool enableSavingOutput, 00556 const std::string& outputFilePath, 00557 const std::string& outputFileRadix, 00558 const std::string& inputArgs) 00559 { 00560 if(requester != "iterator") 00561 { 00562 __CFG_SS__ << "Invalid requester '" << requester << "'" << __E__; 00563 __CFG_SS_THROW__; 00564 } 00565 00566 __CFG_COUT__ << "Starting multi-dimensional Macro '" << macroName 00567 << "' for interface '" << interfaceID << ".'" << __E__; 00568 00569 __CFG_COUTV__(macroString); 00570 00571 __CFG_COUTV__(inputArgs); 00572 00573 // mark active(only one Macro per interface active at any time, for now) 00574 { // lock mutex scope 00575 std::lock_guard<std::mutex> lock(macroMultiDimensionalDoneMutex_); 00576 // mark active 00577 if(macroMultiDimensionalStatusMap_.find(interfaceID) != 00578 macroMultiDimensionalStatusMap_.end()) 00579 { 00580 __SS__ << "Failed to start multi-dimensional Macro '" << macroName 00581 << "' for interface '" << interfaceID 00582 << "' - this interface already has an active Macro launch!" << __E__; 00583 __SS_THROW__; 00584 } 00585 macroMultiDimensionalStatusMap_.emplace(std::make_pair(interfaceID, "Active")); 00586 } 00587 00588 // start thread 00589 std::thread( 00590 [](FEVInterfacesManager* feMgr, 00591 const std::string interfaceID, 00592 const std::string macroName, 00593 const std::string macroString, 00594 const bool enableSavingOutput, 00595 const std::string outputFilePath, 00596 const std::string outputFileRadix, 00597 const std::string inputArgsStr) { 00598 00599 // create local message facility subject 00600 std::string mfSubject_ = "threadMultiD-" + macroName; 00601 __GEN_COUT__ << "Thread started." << __E__; 00602 00603 std::string statusResult = "Done"; 00604 00605 try 00606 { 00607 //------------------------------- 00608 // check for interfaceID 00609 FEVInterface* fe = feMgr->getFEInterfaceP(interfaceID); 00610 00611 //------------------------------- 00612 // extract macro object 00613 FEVInterface::macroStruct_t macro(macroString); 00614 00615 //------------------------------- 00616 // create output file pointer 00617 FILE* outputFilePointer = 0; 00618 if(enableSavingOutput) 00619 { 00620 std::string filename = outputFilePath + "/" + outputFileRadix + 00621 macroName + "_" + std::to_string(time(0)) + 00622 ".txt"; 00623 __GEN_COUT__ << "Opening file... " << filename << __E__; 00624 00625 outputFilePointer = fopen(filename.c_str(), "w"); 00626 if(!outputFilePointer) 00627 { 00628 __GEN_SS__ << "Failed to open output file: " << filename << __E__; 00629 __GEN_SS_THROW__; 00630 } 00631 } // at this point output file pointer is valid or null 00632 00633 //------------------------------- 00634 // setup Macro arguments 00635 __GEN_COUTV__(inputArgsStr); 00636 00637 // inputs: 00638 // - inputArgs: dimensional semi-colon-separated, 00639 // comma separated: dimension iterations and arguments 00640 //(colon-separated name/value/stepsize sets) 00641 00642 // need to extract input arguments 00643 // by dimension (by priority) 00644 // 00645 // two vector by dimension <map of params> 00646 // one vector for long and for double 00647 // 00648 // map of params := 00649 // name => { 00650 // <long/double current value> 00651 // <long/double init value> 00652 // <long/double step size> 00653 // } 00654 00655 std::vector<unsigned long /*dimension iterations*/> dimensionIterations, 00656 dimensionIterationCnt; 00657 00658 using longParamMap_t = std::map< 00659 std::string /*name*/, 00660 std::pair<long /*current value*/, 00661 std::pair<long /*initial value*/, long /*step value*/>>>; 00662 00663 std::vector<longParamMap_t> longDimensionParameters; 00664 // Note: double parameters not allowed for Macro (allowed in FE Macros) 00665 00666 // instead of strict inputs and outputs, make a map 00667 // and populate with all input and output names 00668 std::map<std::string /*name*/, uint64_t /*value*/> variableMap; 00669 00670 // std::vector<FEVInterface::frontEndMacroArg_t> argsIn; 00671 // std::vector<FEVInterface::frontEndMacroArg_t> argsOut; 00672 00673 for(const auto& inputArgName : macro.namesOfInputArguments_) 00674 variableMap.emplace( // do not care about input arg value 00675 std::pair<std::string /*name*/, uint64_t /*value*/>(inputArgName, 00676 0)); 00677 for(const auto& outputArgName : macro.namesOfOutputArguments_) 00678 variableMap.emplace( // do not care about output arg value 00679 std::pair<std::string /*name*/, uint64_t /*value*/>(outputArgName, 00680 0)); 00681 00682 if(0) // example 00683 { 00684 // inputArgsStr = "2,fisrD:3:2,fD2:4:1;4,myOtherArg:5:2,sD:10f:1.3"; 00685 00686 dimensionIterations.push_back(2); 00687 dimensionIterations.push_back(4); 00688 00689 longDimensionParameters.push_back(longParamMap_t()); 00690 longDimensionParameters.push_back(longParamMap_t()); 00691 00692 longDimensionParameters.back().emplace(std::make_pair( 00693 "myOtherArg", 00694 std::make_pair( 00695 3 /*current value*/, 00696 std::make_pair(3 /*initial value*/, 4 /*step value*/)))); 00697 } // end example 00698 00699 std::vector<std::string> dimensionArgs; 00700 StringMacros::getVectorFromString( 00701 inputArgsStr, dimensionArgs, {';'} /*delimeter set*/); 00702 00703 __GEN_COUTV__(dimensionArgs.size()); 00704 //__GEN_COUTV__(StringMacros::vectorToString(dimensionArgs)); 00705 00706 if(dimensionArgs.size() == 0) 00707 { 00708 // just call Macro once! 00709 // create dimension with 1 iteration 00710 // and no arguments 00711 dimensionIterations.push_back(1); 00712 longDimensionParameters.push_back(longParamMap_t()); 00713 } 00714 else 00715 for(unsigned int d = 0; d < dimensionArgs.size(); ++d) 00716 { 00717 // for each dimension 00718 // get argument and classify as long or double 00719 00720 std::vector<std::string> args; 00721 StringMacros::getVectorFromString( 00722 dimensionArgs[d], args, {','} /*delimeter set*/); 00723 00724 //__GEN_COUTV__(args.size()); 00725 //__GEN_COUTV__(StringMacros::vectorToString(args)); 00726 00727 // require first value for number of iterations 00728 if(args.size() == 0) 00729 { 00730 __GEN_SS__ << "Invalid dimensional arguments! " 00731 << "Need number of iterations at dimension " << d 00732 << __E__; 00733 __GEN_SS_THROW__; 00734 } 00735 00736 unsigned long numOfIterations; 00737 StringMacros::getNumber(args[0], numOfIterations); 00738 __GEN_COUT__ << "Dimension " << d 00739 << " numOfIterations=" << numOfIterations << __E__; 00740 00741 // create dimension! 00742 { 00743 dimensionIterations.push_back(numOfIterations); 00744 longDimensionParameters.push_back(longParamMap_t()); 00745 } 00746 00747 // skip iteration value, start at index 1 00748 for(unsigned int a = 1; a < args.size(); ++a) 00749 { 00750 std::vector<std::string> argPieces; 00751 StringMacros::getVectorFromString( 00752 args[a], argPieces, {':'} /*delimeter set*/); 00753 00754 __GEN_COUTV__(StringMacros::vectorToString(argPieces)); 00755 00756 // check pieces and determine if arg is long or double 00757 // 3 pieces := name, init value, step value 00758 if(argPieces.size() != 3) 00759 { 00760 __GEN_SS__ << "Invalid argument pieces! Should be size " 00761 "3, but is " 00762 << argPieces.size() << __E__; 00763 ss << StringMacros::vectorToString(argPieces); 00764 __GEN_SS_THROW__; 00765 } 00766 00767 // check piece 1 and 2 for double hint 00768 // a la Iterator::startCommandModifyActive() 00769 if((argPieces[1].size() && 00770 (argPieces[1][argPieces[1].size() - 1] == 'f' || 00771 argPieces[1].find('.') != std::string::npos)) || 00772 (argPieces[2].size() && 00773 (argPieces[2][argPieces[2].size() - 1] == 'f' || 00774 argPieces[2].find('.') != std::string::npos))) 00775 { 00776 // handle as double 00777 00778 double startValue = strtod(argPieces[1].c_str(), 0); 00779 double stepSize = strtod(argPieces[2].c_str(), 0); 00780 00781 __GEN_COUTV__(startValue); 00782 __GEN_COUTV__(stepSize); 00783 00784 __GEN_SS__ 00785 << "Error! Only integer aruments allowed for Macros. " 00786 << "Double style arugment found: " << argPieces[0] 00787 << "' := " << startValue << ", " << stepSize << __E__; 00788 __GEN_SS_THROW__; 00789 // doubleDimensionParameters.back().emplace( 00790 // std::make_pair(argPieces[0], 00791 // std::make_pair( 00792 // startValue 00794 // std::make_pair( 00795 // startValue 00797 // stepSize 00799 } 00800 else 00801 { 00802 // handle as long 00803 //__GEN_COUT__ << "Long found" << __E__; 00804 00805 long int startValue; 00806 long int stepSize; 00807 00808 StringMacros::getNumber(argPieces[1], startValue); 00809 StringMacros::getNumber(argPieces[2], stepSize); 00810 00811 __GEN_COUTV__(startValue); 00812 __GEN_COUTV__(stepSize); 00813 00814 __GEN_COUT__ << "Creating long argument '" << argPieces[0] 00815 << "' := " << startValue << ", " << stepSize 00816 << __E__; 00817 00818 longDimensionParameters.back().emplace(std::make_pair( 00819 argPieces[0], 00820 std::make_pair( 00821 startValue /*current value*/, 00822 std::make_pair(startValue /*initial value*/, 00823 stepSize /*step value*/)))); 00824 } 00825 00826 } // end dimensional argument loop 00827 00828 } // end dimensions loop 00829 00830 if(dimensionIterations.size() != longDimensionParameters.size()) 00831 { 00832 __GEN_SS__ << "Impossible vector size mismatch! " 00833 << dimensionIterations.size() << " - " 00834 << longDimensionParameters.size() << __E__; 00835 __GEN_SS_THROW__; 00836 } 00837 00838 // output header 00839 { 00840 std::stringstream outSS; 00841 { 00842 outSS << "\n==========================\n" << __E__; 00843 outSS << "Macro '" << macro.macroName_ 00844 << "' multi-dimensional scan..." << __E__; 00845 outSS << "\t" << StringMacros::getTimestampString() << __E__; 00846 outSS << "\t" << dimensionIterations.size() 00847 << " dimensions defined." << __E__; 00848 for(unsigned int i = 0; i < dimensionIterations.size(); ++i) 00849 { 00850 outSS << "\t\t" 00851 << "dimension[" << i << "] has " 00852 << dimensionIterations[i] << " iterations and " 00853 << (longDimensionParameters[i].size()) << " arguments." 00854 << __E__; 00855 00856 for(auto& param : longDimensionParameters[i]) 00857 outSS << "\t\t\t" 00858 << "'" << param.first << "' of type long with " 00859 << "initial value and step value [decimal] = " 00860 << "\t" << param.second.second.first << " & " 00861 << param.second.second.second << __E__; 00862 } 00863 00864 outSS << "\nInput argument names:" << __E__; 00865 for(const auto& inputArgName : macro.namesOfInputArguments_) 00866 outSS << "\t" << inputArgName << __E__; 00867 outSS << "\nOutput argument names:" << __E__; 00868 for(const auto& outputArgName : macro.namesOfOutputArguments_) 00869 outSS << "\t" << outputArgName << __E__; 00870 00871 outSS << "\n==========================\n" << __E__; 00872 } // end outputs stringstream results 00873 00874 // if enabled to save to file, do it. 00875 __GEN_COUT__ << "\n" << outSS.str(); 00876 if(outputFilePointer) 00877 fprintf(outputFilePointer, outSS.str().c_str()); 00878 } // end output header 00879 00880 unsigned int iterationCount = 0; 00881 00882 // Use lambda recursive function to do arbitrary dimensions 00883 // 00884 // Note: can not do lambda recursive function if using auto to declare the 00885 // function, and must capture reference to the function. Also, must 00886 // capture specialFolders reference for use internally (const values 00887 // already are captured). 00888 std::function<void(const unsigned int /*dimension*/ 00889 )> 00890 localRecurse = [&dimensionIterations, 00891 &dimensionIterationCnt, 00892 &iterationCount, 00893 &longDimensionParameters, 00894 &fe, 00895 ¯o, 00896 &variableMap, 00897 &outputFilePointer, 00898 &localRecurse](const unsigned int dimension) { 00899 00900 // create local message facility subject 00901 std::string mfSubject_ = "multiD-" + std::to_string(dimension) + 00902 "-" + macro.macroName_; 00903 __GEN_COUTV__(dimension); 00904 00905 if(dimension >= dimensionIterations.size()) 00906 { 00907 __GEN_COUT__ << "Iteration count: " << iterationCount++ 00908 << __E__; 00909 __GEN_COUT__ << "Launching Macro '" << macro.macroName_ 00910 << "' ..." << __E__; 00911 00912 // set argsIn to current value 00913 { 00914 // scan all dimension parameter objects 00915 // note: Although conflicts should not be allowed 00916 // at this point, lower dimensions will have priority 00917 // over higher dimension with same name argument.. 00918 // and longs will have priority over doubles 00919 00920 for(unsigned int j = 0; j < dimensionIterations.size(); 00921 ++j) 00922 { 00923 for(auto& longParam : longDimensionParameters[j]) 00924 { 00925 __GEN_COUT__ 00926 << "Assigning argIn '" << longParam.first 00927 << "' to current long value '" 00928 << longParam.second.first 00929 << "' from dimension " << j << " parameter." 00930 << __E__; 00931 variableMap.at(longParam.first) = 00932 longParam.second.first; 00933 } 00934 } // end long loop 00935 00936 } // done building argsIn 00937 00938 // output inputs 00939 { 00940 std::stringstream outSS; 00941 { 00942 outSS << "\n---------------\n" << __E__; 00943 outSS << "Macro '" << macro.macroName_ 00944 << "' execution..." << __E__; 00945 outSS << "\t" 00946 << "iteration " << iterationCount << __E__; 00947 for(unsigned int i = 0; 00948 i < dimensionIterationCnt.size(); 00949 ++i) 00950 outSS << "\t" 00951 << "dimension[" << i 00952 << "] index := " << dimensionIterationCnt[i] 00953 << __E__; 00954 00955 outSS << "\n" 00956 << "\t" 00957 << "Input arguments (count: " 00958 << macro.namesOfInputArguments_.size() 00959 << "):" << __E__; 00960 for(auto& argIn : macro.namesOfInputArguments_) 00961 outSS << "\t\t" << argIn << " = " 00962 << variableMap.at(argIn) << __E__; 00963 00964 } // end outputs stringstream results 00965 00966 // if enabled to save to file, do it. 00967 __GEN_COUT__ << "\n" << outSS.str(); 00968 if(outputFilePointer) 00969 fprintf(outputFilePointer, outSS.str().c_str()); 00970 } // end output inputs 00971 00972 // have FE and Macro structure, so run it 00973 fe->runMacro(macro, variableMap); 00974 00975 __GEN_COUT__ << "Macro complete!" << __E__; 00976 00977 // output results 00978 { 00979 std::stringstream outSS; 00980 { 00981 outSS << "\n" 00982 << "\t" 00983 << "Output arguments (count: " 00984 << macro.namesOfOutputArguments_.size() 00985 << "):" << __E__; 00986 for(auto& argOut : macro.namesOfOutputArguments_) 00987 outSS << "\t\t" << argOut << " = " 00988 << variableMap.at(argOut) << __E__; 00989 } // end outputs stringstream results 00990 00991 // if enabled to save to file, do it. 00992 __GEN_COUT__ << "\n" << outSS.str(); 00993 if(outputFilePointer) 00994 fprintf(outputFilePointer, outSS.str().c_str()); 00995 } // end output results 00996 00997 return; 00998 } 00999 01000 // init dimension index 01001 if(dimension >= dimensionIterationCnt.size()) 01002 dimensionIterationCnt.push_back(0); 01003 01004 // if enabled to save to file, do it. 01005 __GEN_COUT__ << "\n" 01006 << "======================================" << __E__ 01007 << "dimension[" << dimension 01008 << "] number of iterations := " 01009 << dimensionIterations[dimension] << __E__; 01010 01011 // update current value to initial value for this dimension's 01012 // parameters 01013 { 01014 for(auto& longPair : longDimensionParameters[dimension]) 01015 { 01016 longPair.second.first = // reset to initial value 01017 longPair.second.second.first; 01018 __GEN_COUT__ 01019 << "arg '" << longPair.first 01020 << "' current value: " << longPair.second.first 01021 << __E__; 01022 } // end long loop 01023 01024 } // end update current value to initial value for all 01025 // dimensional parameters 01026 01027 for(dimensionIterationCnt[dimension] = 01028 0; // reset each time through dimension loop 01029 dimensionIterationCnt[dimension] < 01030 dimensionIterations[dimension]; 01031 ++dimensionIterationCnt[dimension]) 01032 { 01033 __GEN_COUT__ << "dimension[" << dimension << "] index := " 01034 << dimensionIterationCnt[dimension] << __E__; 01035 01036 localRecurse(dimension + 1); 01037 01038 // update current value to next value for this dimension's 01039 // parameters 01040 { 01041 for(auto& longPair : longDimensionParameters[dimension]) 01042 { 01043 longPair.second.first += // add step value 01044 longPair.second.second.second; 01045 __GEN_COUT__ 01046 << "arg '" << longPair.first 01047 << "' current value: " << longPair.second.first 01048 << __E__; 01049 } // end long loop 01050 01051 } // end update current value to next value for all 01052 // dimensional parameters 01053 } 01054 __GEN_COUT__ << "Completed dimension[" << dimension 01055 << "] number of iterations := " 01056 << dimensionIterationCnt[dimension] << " of " 01057 << dimensionIterations[dimension] << __E__; 01058 }; //end local lambda recursive function 01059 01060 // launch multi-dimensional recursion 01061 localRecurse(0); 01062 01063 // close output file 01064 if(outputFilePointer) 01065 fclose(outputFilePointer); 01066 } 01067 catch(const std::runtime_error& e) 01068 { 01069 __SS__ << "Error executing multi-dimensional Macro: " << e.what() 01070 << __E__; 01071 statusResult = ss.str(); 01072 } 01073 catch(...) 01074 { 01075 __SS__ << "Unknown error executing multi-dimensional Macro. " << __E__; 01076 statusResult = ss.str(); 01077 } 01078 01079 __COUTV__(statusResult); 01080 01081 { // lock mutex scope 01082 std::lock_guard<std::mutex> lock(feMgr->macroMultiDimensionalDoneMutex_); 01083 // change status at completion 01084 feMgr->macroMultiDimensionalStatusMap_[interfaceID] = statusResult; 01085 } 01086 01087 }, // end thread() 01088 this, 01089 interfaceID, 01090 macroName, 01091 macroString, 01092 enableSavingOutput, 01093 outputFilePath, 01094 outputFileRadix, 01095 inputArgs) 01096 .detach(); 01097 01098 __CFG_COUT__ << "Started multi-dimensional Macro '" << macroName 01099 << "' for interface '" << interfaceID << ".'" << __E__; 01100 01101 } // end startMacroMultiDimensional() 01102 01103 //======================================================================================================================== 01104 // startFEMacroMultiDimensional 01105 // Launches a thread that manages the multi-dimensional loop 01106 // running the FE Macro in the specified FE interface. 01107 // Called by iterator (for now). 01108 // 01109 // Note: no output arguments are returned, but outputs are 01110 // optionally saved to file. 01111 // 01112 // 01113 // inputs: 01114 // - inputArgs: dimensional semi-colon-separated, 01115 // comma separated: dimension iterations and arguments (colon-separated 01116 // name/value/stepsize sets) 01117 // 01118 // outputs: 01119 // - throws exception on failure 01120 void FEVInterfacesManager::startFEMacroMultiDimensional( 01121 const std::string& requester, 01122 const std::string& interfaceID, 01123 const std::string& feMacroName, 01124 const bool enableSavingOutput, 01125 const std::string& outputFilePath, 01126 const std::string& outputFileRadix, 01127 const std::string& inputArgs) 01128 { 01129 if(requester != "iterator") 01130 { 01131 __CFG_SS__ << "Invalid requester '" << requester << "'" << __E__; 01132 __CFG_SS_THROW__; 01133 } 01134 01135 __CFG_COUT__ << "Starting multi-dimensional FE Macro '" << feMacroName 01136 << "' for interface '" << interfaceID << ".'" << __E__; 01137 __CFG_COUTV__(inputArgs); 01138 01139 // mark active(only one FE Macro per interface active at any time, for now) 01140 { // lock mutex scope 01141 std::lock_guard<std::mutex> lock(macroMultiDimensionalDoneMutex_); 01142 // mark active 01143 if(macroMultiDimensionalStatusMap_.find(interfaceID) != 01144 macroMultiDimensionalStatusMap_.end()) 01145 { 01146 __SS__ << "Failed to start multi-dimensional FE Macro '" << feMacroName 01147 << "' for interface '" << interfaceID 01148 << "' - this interface already has an active FE Macro launch!" 01149 << __E__; 01150 __SS_THROW__; 01151 } 01152 macroMultiDimensionalStatusMap_.emplace(std::make_pair(interfaceID, "Active")); 01153 } 01154 01155 // start thread 01156 std::thread( 01157 [](FEVInterfacesManager* feMgr, 01158 const std::string interfaceID, 01159 const std::string feMacroName, 01160 const bool enableSavingOutput, 01161 const std::string outputFilePath, 01162 const std::string outputFileRadix, 01163 const std::string inputArgsStr) { 01164 01165 // create local message facility subject 01166 std::string mfSubject_ = "threadMultiD-" + feMacroName; 01167 __GEN_COUT__ << "Thread started." << __E__; 01168 01169 std::string statusResult = "Done"; 01170 01171 try 01172 { 01173 //------------------------------- 01174 // check for interfaceID and macro 01175 FEVInterface* fe = feMgr->getFEInterfaceP(interfaceID); 01176 01177 // have pointer to virtual FEInterface, find Macro structure 01178 auto FEMacroIt = fe->getMapOfFEMacroFunctions().find(feMacroName); 01179 if(FEMacroIt == fe->getMapOfFEMacroFunctions().end()) 01180 { 01181 __GEN_SS__ << "FE Macro '" << feMacroName << "' of interfaceID '" 01182 << interfaceID << "' was not found!" << __E__; 01183 __GEN_SS_THROW__; 01184 } 01185 const FEVInterface::frontEndMacroStruct_t& feMacro = FEMacroIt->second; 01186 01187 //------------------------------- 01188 // create output file pointer 01189 FILE* outputFilePointer = 0; 01190 if(enableSavingOutput) 01191 { 01192 std::string filename = outputFilePath + "/" + outputFileRadix + 01193 feMacroName + "_" + std::to_string(time(0)) + 01194 ".txt"; 01195 __GEN_COUT__ << "Opening file... " << filename << __E__; 01196 01197 outputFilePointer = fopen(filename.c_str(), "w"); 01198 if(!outputFilePointer) 01199 { 01200 __GEN_SS__ << "Failed to open output file: " << filename << __E__; 01201 __GEN_SS_THROW__; 01202 } 01203 } // at this point output file pointer is valid or null 01204 01205 //------------------------------- 01206 // setup FE macro aruments 01207 __GEN_COUTV__(inputArgsStr); 01208 01209 // inputs: 01210 // - inputArgs: dimensional semi-colon-separated, 01211 // comma separated: dimension iterations and arguments 01212 //(colon-separated name/value/stepsize sets) 01213 01214 // need to extract input arguments 01215 // by dimension (by priority) 01216 // 01217 // two vector by dimension <map of params> 01218 // one vector for long and for double 01219 // 01220 // map of params := 01221 // name => { 01222 // <long/double current value> 01223 // <long/double init value> 01224 // <long/double step size> 01225 // } 01226 01227 std::vector<unsigned long /*dimension iterations*/> dimensionIterations, 01228 dimensionIterationCnt; 01229 01230 using longParamMap_t = std::map< 01231 std::string /*name*/, 01232 std::pair<long /*current value*/, 01233 std::pair<long /*initial value*/, long /*step value*/>>>; 01234 using doubleParamMap_t = 01235 std::map<std::string /*name*/, 01236 std::pair<double /*current value*/, 01237 std::pair<double /*initial value*/, 01238 double /*step value*/>>>; 01239 01240 std::vector<longParamMap_t> longDimensionParameters; 01241 std::vector<doubleParamMap_t> doubleDimensionParameters; 01242 01243 std::vector<FEVInterface::frontEndMacroArg_t> argsIn; 01244 std::vector<FEVInterface::frontEndMacroArg_t> argsOut; 01245 01246 for(unsigned int i = 0; i < feMacro.namesOfInputArguments_.size(); ++i) 01247 argsIn.push_back(std::make_pair( // do not care about input arg value 01248 feMacro.namesOfInputArguments_[i], 01249 "")); 01250 for(unsigned int i = 0; i < feMacro.namesOfOutputArguments_.size(); ++i) 01251 argsOut.push_back( 01252 std::make_pair( // do not care about output arg value 01253 feMacro.namesOfOutputArguments_[i], 01254 "")); 01255 01256 if(0) // example 01257 { 01258 // inputArgsStr = "2,fisrD:3:2,fD2:4:1;4,myOtherArg:5:2,sD:10f:1.3"; 01259 01260 argsIn.push_back(std::make_pair("myOtherArg", "3")); 01261 01262 dimensionIterations.push_back(2); 01263 dimensionIterations.push_back(4); 01264 01265 longDimensionParameters.push_back(longParamMap_t()); 01266 longDimensionParameters.push_back(longParamMap_t()); 01267 01268 doubleDimensionParameters.push_back(doubleParamMap_t()); 01269 doubleDimensionParameters.push_back(doubleParamMap_t()); 01270 01271 longDimensionParameters.back().emplace(std::make_pair( 01272 "myOtherArg", 01273 std::make_pair( 01274 3 /*current value*/, 01275 std::make_pair(3 /*initial value*/, 4 /*step value*/)))); 01276 } // end example 01277 01278 std::vector<std::string> dimensionArgs; 01279 StringMacros::getVectorFromString( 01280 inputArgsStr, dimensionArgs, {';'} /*delimeter set*/); 01281 01282 __GEN_COUTV__(dimensionArgs.size()); 01283 //__GEN_COUTV__(StringMacros::vectorToString(dimensionArgs)); 01284 01285 if(dimensionArgs.size() == 0) 01286 { 01287 // just call FE Macro once! 01288 // create dimension with 1 iteration 01289 // and no arguments 01290 dimensionIterations.push_back(1); 01291 longDimensionParameters.push_back(longParamMap_t()); 01292 doubleDimensionParameters.push_back(doubleParamMap_t()); 01293 } 01294 else 01295 for(unsigned int d = 0; d < dimensionArgs.size(); ++d) 01296 { 01297 // for each dimension 01298 // get argument and classify as long or double 01299 01300 std::vector<std::string> args; 01301 StringMacros::getVectorFromString( 01302 dimensionArgs[d], args, {','} /*delimeter set*/); 01303 01304 //__GEN_COUTV__(args.size()); 01305 //__GEN_COUTV__(StringMacros::vectorToString(args)); 01306 01307 // require first value for number of iterations 01308 if(args.size() == 0) 01309 { 01310 __GEN_SS__ << "Invalid dimensional arguments! " 01311 << "Need number of iterations at dimension " << d 01312 << __E__; 01313 __GEN_SS_THROW__; 01314 } 01315 01316 unsigned long numOfIterations; 01317 StringMacros::getNumber(args[0], numOfIterations); 01318 __GEN_COUT__ << "Dimension " << d 01319 << " numOfIterations=" << numOfIterations << __E__; 01320 01321 // create dimension! 01322 { 01323 dimensionIterations.push_back(numOfIterations); 01324 longDimensionParameters.push_back(longParamMap_t()); 01325 doubleDimensionParameters.push_back(doubleParamMap_t()); 01326 } 01327 01328 // skip iteration value, start at index 1 01329 for(unsigned int a = 1; a < args.size(); ++a) 01330 { 01331 std::vector<std::string> argPieces; 01332 StringMacros::getVectorFromString( 01333 args[a], argPieces, {':'} /*delimeter set*/); 01334 01335 __GEN_COUTV__(StringMacros::vectorToString(argPieces)); 01336 01337 // check pieces and determine if arg is long or double 01338 // 3 pieces := name, init value, step value 01339 if(argPieces.size() != 3) 01340 { 01341 __GEN_SS__ << "Invalid argument pieces! Should be size " 01342 "3, but is " 01343 << argPieces.size() << __E__; 01344 ss << StringMacros::vectorToString(argPieces); 01345 __GEN_SS_THROW__; 01346 } 01347 01348 // check piece 1 and 2 for double hint 01349 // a la Iterator::startCommandModifyActive() 01350 if((argPieces[1].size() && 01351 (argPieces[1][argPieces[1].size() - 1] == 'f' || 01352 argPieces[1].find('.') != std::string::npos)) || 01353 (argPieces[2].size() && 01354 (argPieces[2][argPieces[2].size() - 1] == 'f' || 01355 argPieces[2].find('.') != std::string::npos))) 01356 { 01357 // handle as double 01358 //__GEN_COUT__ << "Double found" << __E__; 01359 01360 double startValue = strtod(argPieces[1].c_str(), 0); 01361 double stepSize = strtod(argPieces[2].c_str(), 0); 01362 01363 __GEN_COUTV__(startValue); 01364 __GEN_COUTV__(stepSize); 01365 01366 __GEN_COUT__ << "Creating double argument '" 01367 << argPieces[0] << "' := " << startValue 01368 << ", " << stepSize << __E__; 01369 01370 doubleDimensionParameters.back().emplace(std::make_pair( 01371 argPieces[0], 01372 std::make_pair( 01373 startValue /*current value*/, 01374 std::make_pair(startValue /*initial value*/, 01375 stepSize /*step value*/)))); 01376 } 01377 else 01378 { 01379 // handle as long 01380 //__GEN_COUT__ << "Long found" << __E__; 01381 01382 long int startValue; 01383 long int stepSize; 01384 01385 StringMacros::getNumber(argPieces[1], startValue); 01386 StringMacros::getNumber(argPieces[2], stepSize); 01387 01388 __GEN_COUTV__(startValue); 01389 __GEN_COUTV__(stepSize); 01390 01391 __GEN_COUT__ << "Creating long argument '" << argPieces[0] 01392 << "' := " << startValue << ", " << stepSize 01393 << __E__; 01394 01395 longDimensionParameters.back().emplace(std::make_pair( 01396 argPieces[0], 01397 std::make_pair( 01398 startValue /*current value*/, 01399 std::make_pair(startValue /*initial value*/, 01400 stepSize /*step value*/)))); 01401 } 01402 01403 } // end dimensional argument loop 01404 01405 } // end dimensions loop 01406 01407 if(dimensionIterations.size() != longDimensionParameters.size() || 01408 dimensionIterations.size() != doubleDimensionParameters.size()) 01409 { 01410 __GEN_SS__ << "Impossible vector size mismatch! " 01411 << dimensionIterations.size() << " - " 01412 << longDimensionParameters.size() << " - " 01413 << doubleDimensionParameters.size() << __E__; 01414 __GEN_SS_THROW__; 01415 } 01416 01417 // output header 01418 { 01419 std::stringstream outSS; 01420 { 01421 outSS << "\n==========================\n" << __E__; 01422 outSS << "FEMacro '" << feMacro.feMacroName_ 01423 << "' multi-dimensional scan..." << __E__; 01424 outSS << "\t" << StringMacros::getTimestampString() << __E__; 01425 outSS << "\t" << dimensionIterations.size() 01426 << " dimensions defined." << __E__; 01427 for(unsigned int i = 0; i < dimensionIterations.size(); ++i) 01428 { 01429 outSS << "\t\t" 01430 << "dimension[" << i << "] has " 01431 << dimensionIterations[i] << " iterations and " 01432 << (longDimensionParameters[i].size() + 01433 doubleDimensionParameters[i].size()) 01434 << " arguments." << __E__; 01435 01436 for(auto& param : longDimensionParameters[i]) 01437 outSS << "\t\t\t" 01438 << "'" << param.first << "' of type long with " 01439 << "initial value and step value [decimal] = " 01440 << "\t" << param.second.second.first << " & " 01441 << param.second.second.second << __E__; 01442 01443 for(auto& param : doubleDimensionParameters[i]) 01444 outSS << "\t\t\t" 01445 << "'" << param.first << "' of type double with " 01446 << "initial value and step value = " 01447 << "\t" << param.second.second.first << " & " 01448 << param.second.second.second << __E__; 01449 } 01450 01451 outSS << "\nHere are the identified input arguments:" << __E__; 01452 for(unsigned int i = 0; i < feMacro.namesOfInputArguments_.size(); 01453 ++i) 01454 outSS << "\t" << feMacro.namesOfInputArguments_[i] << __E__; 01455 outSS << "\nHere are the identified input arguments:" << __E__; 01456 for(unsigned int i = 0; 01457 i < feMacro.namesOfOutputArguments_.size(); 01458 ++i) 01459 outSS << "\t" << feMacro.namesOfOutputArguments_[i] << __E__; 01460 01461 outSS << "\n==========================\n" << __E__; 01462 } // end outputs stringstream results 01463 01464 // if enabled to save to file, do it. 01465 __GEN_COUT__ << "\n" << outSS.str(); 01466 if(outputFilePointer) 01467 fprintf(outputFilePointer, outSS.str().c_str()); 01468 } // end output header 01469 01470 unsigned int iterationCount = 0; 01471 01472 // Use lambda recursive function to do arbitrary dimensions 01473 // 01474 // Note: can not do lambda recursive function if using auto to declare the 01475 // function, and must capture reference to the function. Also, must 01476 // capture specialFolders reference for use internally (const values 01477 // already are captured). 01478 std::function<void(const unsigned int /*dimension*/ 01479 )> 01480 localRecurse = [&dimensionIterations, 01481 &dimensionIterationCnt, 01482 &iterationCount, 01483 &longDimensionParameters, 01484 &doubleDimensionParameters, 01485 &fe, 01486 &feMacro, 01487 &outputFilePointer, 01488 &argsIn, 01489 &argsOut, 01490 &localRecurse](const unsigned int dimension) { 01491 01492 // create local message facility subject 01493 std::string mfSubject_ = "multiD-" + std::to_string(dimension) + 01494 "-" + feMacro.feMacroName_; 01495 __GEN_COUTV__(dimension); 01496 01497 if(dimension >= dimensionIterations.size()) 01498 { 01499 __GEN_COUT__ << "Iteration count: " << iterationCount++ 01500 << __E__; 01501 __GEN_COUT__ << "Launching FE Macro '" << feMacro.feMacroName_ 01502 << "' ..." << __E__; 01503 01504 // set argsIn to current value 01505 01506 // scan all dimension parameter objects 01507 // note: Although conflicts should not be allowed 01508 // at this point, lower dimensions will have priority 01509 // over higher dimension with same name argument.. and 01510 // longs will have priority over doubles 01511 01512 bool foundAsLong; 01513 for(unsigned int i = 0; i < argsIn.size(); ++i) 01514 { 01515 foundAsLong = false; 01516 for(unsigned int j = 0; j < dimensionIterations.size(); 01517 ++j) 01518 { 01519 auto longIt = 01520 longDimensionParameters[j].find(argsIn[i].first); 01521 if(longIt == longDimensionParameters[j].end()) 01522 continue; 01523 01524 // else found long! 01525 __GEN_COUT__ << "Assigning argIn '" << argsIn[i].first 01526 << "' to current long value '" 01527 << longIt->second.first 01528 << "' from dimension " << j 01529 << " parameter." << __E__; 01530 argsIn[i].second = 01531 std::to_string(longIt->second.first); 01532 foundAsLong = true; 01533 break; 01534 } // end long loop 01535 if(foundAsLong) 01536 continue; // skip double check 01537 01538 for(unsigned int j = 0; j < dimensionIterations.size(); 01539 ++j) 01540 { 01541 auto doubleIt = doubleDimensionParameters[j].find( 01542 argsIn[i].first); 01543 if(doubleIt == doubleDimensionParameters[j].end()) 01544 continue; 01545 01546 // else found long! 01547 __GEN_COUT__ << "Assigning argIn '" << argsIn[i].first 01548 << "' to current double value '" 01549 << doubleIt->second.first 01550 << "' from dimension " << j 01551 << " parameter." << __E__; 01552 argsIn[i].second = 01553 std::to_string(doubleIt->second.first); 01554 foundAsLong = true; 01555 break; 01556 } // end double loop 01557 01558 __GEN_SS__ << "ArgIn '" << argsIn[i].first 01559 << "' was not assigned a value " 01560 << "by any dimensional loop parameter sets. " 01561 "This is illegal. FEMacro '" 01562 << feMacro.feMacroName_ << "' requires '" 01563 << argsIn[i].first 01564 << "' as an input argument. Either remove the " 01565 "input argument from this FEMacro, " 01566 << "or define a value as a dimensional loop " 01567 "parameter." 01568 << __E__; 01569 __GEN_SS_THROW__; 01570 } // done building argsIn 01571 01572 // have pointer to Macro structure, so run it 01573 (fe->*(feMacro.macroFunction_))(feMacro, argsIn, argsOut); 01574 01575 __GEN_COUT__ << "FE Macro complete!" << __E__; 01576 01577 // output results 01578 { 01579 std::stringstream outSS; 01580 { 01581 outSS << "\n---------------\n" << __E__; 01582 outSS << "FEMacro '" << feMacro.feMacroName_ 01583 << "' execution..." << __E__; 01584 outSS << "\t" 01585 << "iteration " << iterationCount << __E__; 01586 for(unsigned int i = 0; 01587 i < dimensionIterationCnt.size(); 01588 ++i) 01589 outSS << "\t" 01590 << "dimension[" << i 01591 << "] index := " << dimensionIterationCnt[i] 01592 << __E__; 01593 01594 outSS << "\n" 01595 << "\t" 01596 << "Input arguments (count: " << argsIn.size() 01597 << "):" << __E__; 01598 for(auto& argIn : argsIn) 01599 outSS << "\t\t" << argIn.first << " = " 01600 << argIn.second << __E__; 01601 01602 outSS << "\n" 01603 << "\t" 01604 << "Output arguments (count: " << argsOut.size() 01605 << "):" << __E__; 01606 for(auto& argOut : argsOut) 01607 outSS << "\t\t" << argOut.first << " = " 01608 << argOut.second << __E__; 01609 } // end outputs stringstream results 01610 01611 // if enabled to save to file, do it. 01612 __GEN_COUT__ << "\n" << outSS.str(); 01613 if(outputFilePointer) 01614 fprintf(outputFilePointer, outSS.str().c_str()); 01615 } // end output results 01616 01617 return; 01618 } 01619 01620 // init dimension index 01621 if(dimension >= dimensionIterationCnt.size()) 01622 dimensionIterationCnt.push_back(0); 01623 01624 // if enabled to save to file, do it. 01625 __GEN_COUT__ << "\n" 01626 << "======================================" << __E__ 01627 << "dimension[" << dimension 01628 << "] number of iterations := " 01629 << dimensionIterations[dimension] << __E__; 01630 01631 // update current value to initial value for this dimension's 01632 // parameters 01633 { 01634 for(auto& longPair : longDimensionParameters[dimension]) 01635 { 01636 longPair.second.first = // reset to initial value 01637 longPair.second.second.first; 01638 __GEN_COUT__ 01639 << "arg '" << longPair.first 01640 << "' current value: " << longPair.second.first 01641 << __E__; 01642 } // end long loop 01643 01644 for(auto& doublePair : doubleDimensionParameters[dimension]) 01645 { 01646 doublePair.second.first = // reset to initial value 01647 doublePair.second.second.first; 01648 __GEN_COUT__ 01649 << "arg '" << doublePair.first 01650 << "' current value: " << doublePair.second.first 01651 << __E__; 01652 } // end double loop 01653 } // end update current value to initial value for all 01654 // dimensional parameters 01655 01656 for(dimensionIterationCnt[dimension] = 01657 0; // reset each time through dimension loop 01658 dimensionIterationCnt[dimension] < 01659 dimensionIterations[dimension]; 01660 ++dimensionIterationCnt[dimension]) 01661 { 01662 __GEN_COUT__ << "dimension[" << dimension << "] index := " 01663 << dimensionIterationCnt[dimension] << __E__; 01664 01665 localRecurse(dimension + 1); 01666 01667 // update current value to next value for this dimension's 01668 // parameters 01669 { 01670 for(auto& longPair : longDimensionParameters[dimension]) 01671 { 01672 longPair.second.first += // add step value 01673 longPair.second.second.second; 01674 __GEN_COUT__ 01675 << "arg '" << longPair.first 01676 << "' current value: " << longPair.second.first 01677 << __E__; 01678 } // end long loop 01679 01680 for(auto& doublePair : 01681 doubleDimensionParameters[dimension]) 01682 { 01683 doublePair.second.first += // add step value 01684 doublePair.second.second.second; 01685 01686 __GEN_COUT__ 01687 << "arg '" << doublePair.first 01688 << "' current value: " << doublePair.second.first 01689 << __E__; 01690 } // end double loop 01691 } // end update current value to next value for all 01692 // dimensional parameters 01693 } 01694 __GEN_COUT__ << "Completed dimension[" << dimension 01695 << "] number of iterations := " 01696 << dimensionIterationCnt[dimension] << " of " 01697 << dimensionIterations[dimension] << __E__; 01698 }; //end local lambda recursive function 01699 01700 // launch multi-dimensional recursion 01701 localRecurse(0); 01702 01703 // close output file 01704 if(outputFilePointer) 01705 fclose(outputFilePointer); 01706 } 01707 catch(const std::runtime_error& e) 01708 { 01709 __SS__ << "Error executing multi-dimensional FE Macro: " << e.what() 01710 << __E__; 01711 statusResult = ss.str(); 01712 } 01713 catch(...) 01714 { 01715 __SS__ << "Unknown error executing multi-dimensional FE Macro. " << __E__; 01716 statusResult = ss.str(); 01717 } 01718 01719 __COUTV__(statusResult); 01720 01721 { // lock mutex scope 01722 std::lock_guard<std::mutex> lock(feMgr->macroMultiDimensionalDoneMutex_); 01723 // change status at completion 01724 feMgr->macroMultiDimensionalStatusMap_[interfaceID] = statusResult; 01725 } 01726 01727 }, // end thread() 01728 this, 01729 interfaceID, 01730 feMacroName, 01731 enableSavingOutput, 01732 outputFilePath, 01733 outputFileRadix, 01734 inputArgs) 01735 .detach(); 01736 01737 __CFG_COUT__ << "Started multi-dimensional FE Macro '" << feMacroName 01738 << "' for interface '" << interfaceID << ".'" << __E__; 01739 01740 } // end startFEMacroMultiDimensional() 01741 01742 //======================================================================================================================== 01743 // checkFEMacroMultiDimensional 01744 // Checks for the completion of the thread that manages the multi-dimensional loop 01745 // running the FE Macro or MacroMaker Macro in the specified FE interface. 01746 // Called by iterator (for now). 01747 // 01748 // Returns true if multi-dimensional launch is done 01749 bool FEVInterfacesManager::checkMacroMultiDimensional(const std::string& interfaceID, 01750 const std::string& macroName) 01751 { 01752 // check active(only one FE Macro per interface active at any time, for now) 01753 // lock mutex scope 01754 std::lock_guard<std::mutex> lock(macroMultiDimensionalDoneMutex_); 01755 // check status 01756 auto statusIt = macroMultiDimensionalStatusMap_.find(interfaceID); 01757 if(statusIt == macroMultiDimensionalStatusMap_.end()) 01758 { 01759 __CFG_SS__ << "Status missing for multi-dimensional launch of Macro '" 01760 << macroName << "' for interface '" << interfaceID << ".'" << __E__; 01761 __CFG_SS_THROW__; 01762 } 01763 else if(statusIt->second == "Done") 01764 { 01765 __CFG_COUT__ << "Completed multi-dimensional launch of Macro '" << macroName 01766 << "' for interface '" << interfaceID << ".'" << __E__; 01767 01768 // erase from map 01769 macroMultiDimensionalStatusMap_.erase(statusIt); 01770 return true; 01771 } 01772 else if(statusIt->second == "Active") 01773 { 01774 __CFG_COUT__ << "Still running multi-dimensional launch of Macro '" << macroName 01775 << "' for interface '" << interfaceID << ".'" << __E__; 01776 return false; 01777 } 01778 // else //assume error 01779 01780 __CFG_SS__ << "Error occured during multi-dimensional launch of Macro '" << macroName 01781 << "' for interface '" << interfaceID << "':" << statusIt->second << __E__; 01782 __CFG_SS_THROW__; 01783 01784 } // end checkMacroMultiDimensional() 01785 01786 //======================================================================================================================== 01787 // runFEMacroByFE 01788 // Runs the FE Macro in the specified FE interface. Called by another FE. 01789 // 01790 // inputs: 01791 // - inputArgs: colon-separated name/value pairs, and then comma-separated 01792 // - outputArgs: comma-separated (Note: resolved for FE, allowing FE to not know 01793 // output arguments) 01794 // 01795 // outputs: 01796 // - throws exception on failure 01797 // - outputArgs: colon-separate name/value pairs, and then comma-separated 01798 void FEVInterfacesManager::runFEMacroByFE(const std::string& callingInterfaceID, 01799 const std::string& interfaceID, 01800 const std::string& feMacroName, 01801 const std::string& inputArgs, 01802 std::string& outputArgs) 01803 { 01804 __CFG_COUTV__(callingInterfaceID); 01805 01806 // check for interfaceID 01807 FEVInterface* fe = getFEInterfaceP(interfaceID); 01808 01809 // have pointer to virtual FEInterface, find Macro structure 01810 auto FEMacroIt = fe->getMapOfFEMacroFunctions().find(feMacroName); 01811 if(FEMacroIt == fe->getMapOfFEMacroFunctions().end()) 01812 { 01813 __CFG_SS__ << "FE Macro '" << feMacroName << "' of interfaceID '" << interfaceID 01814 << "' was not found!" << __E__; 01815 __CFG_COUT_ERR__ << "\n" << ss.str(); 01816 __CFG_SS_THROW__; 01817 } 01818 01819 auto& feMacro = FEMacroIt->second; 01820 01821 std::set<std::string> allowedFEsSet; 01822 StringMacros::getSetFromString(feMacro.allowedCallingFrontEnds_, allowedFEsSet); 01823 01824 // check if calling interface is allowed to call macro 01825 if(!StringMacros::inWildCardSet(callingInterfaceID, allowedFEsSet)) 01826 { 01827 __CFG_SS__ << "FE Macro '" << feMacroName << "' of interfaceID '" << interfaceID 01828 << "' does not allow access to calling interfaceID '" 01829 << callingInterfaceID 01830 << "!' Did the interface add the calling interfaceID " 01831 << "to the access list when registering the front-end macro." << __E__; 01832 __CFG_COUT_ERR__ << "\n" << ss.str(); 01833 __CFG_SS_THROW__; 01834 } 01835 01836 // if here, then access allowed 01837 // build output args list 01838 01839 outputArgs = ""; 01840 01841 for(unsigned int i = 0; i < feMacro.namesOfOutputArguments_.size(); ++i) 01842 outputArgs += (i ? "," : "") + feMacro.namesOfOutputArguments_[i]; 01843 01844 __CFG_COUTV__(outputArgs); 01845 01846 runFEMacro(interfaceID, feMacro, inputArgs, outputArgs); 01847 01848 __CFG_COUTV__(outputArgs); 01849 01850 } // end runFEMacroByFE() 01851 01852 //======================================================================================================================== 01853 // runMacro 01854 // Runs the MacroMaker Macro in the specified FE interface. 01855 // 01856 // inputs: 01857 // - inputArgs: colon-separated name/value pairs, and then comma-separated 01858 // - outputArgs: comma-separated 01859 // 01860 // outputs: 01861 // - throws exception on failure 01862 // - outputArgs: colon-separate name/value pairs, and then comma-separated 01863 void FEVInterfacesManager::runMacro(const std::string& interfaceID, 01864 const std::string& macroObjectString, 01865 const std::string& inputArgs, 01866 std::string& outputArgs) 01867 { 01868 //------------------------------- 01869 // extract macro object 01870 FEVInterface::macroStruct_t macro(macroObjectString); 01871 01872 // check for interfaceID 01873 FEVInterface* fe = getFEInterfaceP(interfaceID); 01874 01875 // build input arguments 01876 // parse args, semicolon-separated pairs, and then comma-separated 01877 std::vector<FEVInterface::frontEndMacroArg_t> argsIn; 01878 { 01879 std::istringstream inputStream(inputArgs); 01880 std::string splitVal, argName, argValue; 01881 while(getline(inputStream, splitVal, ';')) 01882 { 01883 std::istringstream pairInputStream(splitVal); 01884 getline(pairInputStream, argName, ','); 01885 getline(pairInputStream, argValue, ','); 01886 argsIn.push_back(std::make_pair(argName, argValue)); 01887 } 01888 } 01889 01890 // check namesOfInputArguments_ 01891 if(macro.namesOfInputArguments_.size() != argsIn.size()) 01892 { 01893 __CFG_SS__ << "MacroMaker Macro '" << macro.macroName_ 01894 << "' was attempted on interfaceID '" << interfaceID 01895 << "' with a mismatch in" 01896 << " number of input arguments. " << argsIn.size() << " were given. " 01897 << macro.namesOfInputArguments_.size() << " expected." << __E__; 01898 __CFG_SS_THROW__; 01899 } 01900 for(unsigned int i = 0; i < argsIn.size(); ++i) 01901 if(macro.namesOfInputArguments_.find(argsIn[i].first) == 01902 macro.namesOfInputArguments_.end()) 01903 { 01904 __CFG_SS__ << "MacroMaker Macro '" << macro.macroName_ 01905 << "' was attempted on interfaceID '" << interfaceID 01906 << "' with a mismatch in" 01907 << " a name of an input argument. " << argsIn[i].first 01908 << " was given. Expected: " 01909 << StringMacros::setToString(macro.namesOfInputArguments_) 01910 << __E__; 01911 01912 __CFG_SS_THROW__; 01913 } 01914 01915 // build output arguments 01916 std::vector<std::string> returnStrings; 01917 std::vector<FEVInterface::frontEndMacroArg_t> argsOut; 01918 01919 { 01920 std::istringstream inputStream(outputArgs); 01921 std::string argName; 01922 while(getline(inputStream, argName, ',')) 01923 { 01924 __CFG_COUT__ << "argName " << argName << __E__; 01925 01926 returnStrings.push_back("DEFAULT"); // std::string()); 01927 argsOut.push_back(FEVInterface::frontEndMacroArg_t( 01928 argName, returnStrings[returnStrings.size() - 1])); 01929 // 01930 // __CFG_COUT__ << argsOut[argsOut.size()-1].first << __E__; 01931 //__CFG_COUT__ << (uint64_t) & (returnStrings[returnStrings.size() - 1]) 01932 // << __E__; 01933 } 01934 } 01935 01936 // check namesOfOutputArguments_ 01937 if(macro.namesOfOutputArguments_.size() != argsOut.size()) 01938 { 01939 __CFG_SS__ << "MacroMaker Macro '" << macro.macroName_ 01940 << "' was attempted on interfaceID '" << interfaceID 01941 << "' with a mismatch in" 01942 << " number of output arguments. " << argsOut.size() << " were given. " 01943 << macro.namesOfOutputArguments_.size() << " expected." << __E__; 01944 01945 __CFG_SS_THROW__; 01946 } 01947 for(unsigned int i = 0; i < argsOut.size(); ++i) 01948 if(macro.namesOfOutputArguments_.find(argsOut[i].first) == 01949 macro.namesOfOutputArguments_.end()) 01950 { 01951 __CFG_SS__ << "MacroMaker Macro '" << macro.macroName_ 01952 << "' was attempted on interfaceID '" << interfaceID 01953 << "' with a mismatch in" 01954 << " a name of an output argument. " << argsOut[i].first 01955 << " were given. Expected: " 01956 << StringMacros::setToString(macro.namesOfOutputArguments_) 01957 << __E__; 01958 01959 __CFG_SS_THROW__; 01960 } 01961 01962 __CFG_COUT__ << "# of input args = " << argsIn.size() << __E__; 01963 01964 std::map<std::string /*name*/, uint64_t /*value*/> variableMap; 01965 // fill variable map 01966 for(const auto& outputArgName : macro.namesOfOutputArguments_) 01967 variableMap.emplace( // do not care about output arg value 01968 std::pair<std::string /*name*/, uint64_t /*value*/>(outputArgName, 0)); 01969 for(const auto& inputArgName : macro.namesOfInputArguments_) 01970 variableMap.emplace( // do not care about input arg value 01971 std::pair<std::string /*name*/, uint64_t /*value*/>(inputArgName, 0)); 01972 01973 for(auto& argIn : argsIn) // set map values 01974 { 01975 __CFG_COUT__ << argIn.first << ": " << argIn.second << __E__; 01976 StringMacros::getNumber(argIn.second, variableMap.at(argIn.first)); 01977 } 01978 01979 fe->runMacro(macro, variableMap); 01980 01981 __CFG_COUT__ << "MacroMaker Macro complete!" << __E__; 01982 01983 __CFG_COUT__ << "# of output args = " << argsOut.size() << __E__; 01984 for(auto& arg : argsOut) 01985 { 01986 std::stringstream numberSs; 01987 numberSs << std::dec << variableMap.at(arg.first) << " (0x" << std::hex 01988 << variableMap.at(arg.first) << ")" << std::dec; 01989 arg.second = numberSs.str(); 01990 __CFG_COUT__ << arg.first << ": " << arg.second << __E__; 01991 } 01992 01993 // Success! at this point so return the output string 01994 outputArgs = ""; 01995 for(unsigned int i = 0; i < argsOut.size(); ++i) 01996 { 01997 if(i) 01998 outputArgs += ";"; 01999 outputArgs += argsOut[i].first + "," + argsOut[i].second; 02000 } 02001 02002 __CFG_COUT__ << "outputArgs = " << outputArgs << __E__; 02003 02004 } // end runMacro() 02005 02006 //======================================================================================================================== 02007 // runFEMacro 02008 // Runs the FE Macro in the specified FE interface. 02009 // 02010 // inputs: 02011 // - inputArgs: colon-separated name/value pairs, and then comma-separated 02012 // - outputArgs: comma-separated 02013 // 02014 // outputs: 02015 // - throws exception on failure 02016 // - outputArgs: colon-separate name/value pairs, and then comma-separated 02017 void FEVInterfacesManager::runFEMacro(const std::string& interfaceID, 02018 const std::string& feMacroName, 02019 const std::string& inputArgs, 02020 std::string& outputArgs) 02021 { 02022 // check for interfaceID 02023 FEVInterface* fe = getFEInterfaceP(interfaceID); 02024 02025 // have pointer to virtual FEInterface, find Macro structure 02026 auto FEMacroIt = fe->getMapOfFEMacroFunctions().find(feMacroName); 02027 if(FEMacroIt == fe->getMapOfFEMacroFunctions().end()) 02028 { 02029 __CFG_SS__ << "FE Macro '" << feMacroName << "' of interfaceID '" << interfaceID 02030 << "' was not found!" << __E__; 02031 __CFG_COUT_ERR__ << "\n" << ss.str(); 02032 __CFG_SS_THROW__; 02033 } 02034 02035 runFEMacro(interfaceID, FEMacroIt->second, inputArgs, outputArgs); 02036 02037 } // end runFEMacro() 02038 02039 //======================================================================================================================== 02040 // runFEMacro 02041 // Runs the FE Macro in the specified FE interface. 02042 // 02043 // inputs: 02044 // - inputArgs: semicolon-separated name/value pairs, and then comma-separated 02045 // - outputArgs: comma-separated 02046 // 02047 // outputs: 02048 // - throws exception on failure 02049 // - outputArgs: colon-separate name/value pairs, and then comma-separated 02050 void FEVInterfacesManager::runFEMacro(const std::string& interfaceID, 02051 const FEVInterface::frontEndMacroStruct_t& feMacro, 02052 const std::string& inputArgs, 02053 std::string& outputArgs) 02054 { 02055 // build input arguments 02056 // parse args, semicolon-separated pairs, and then comma-separated 02057 std::vector<FEVInterface::frontEndMacroArg_t> argsIn; 02058 { 02059 std::istringstream inputStream(inputArgs); 02060 std::string splitVal, argName, argValue; 02061 while(getline(inputStream, splitVal, ';')) 02062 { 02063 std::istringstream pairInputStream(splitVal); 02064 getline(pairInputStream, argName, ','); 02065 getline(pairInputStream, argValue, ','); 02066 argsIn.push_back(std::make_pair(argName, argValue)); 02067 } 02068 } 02069 02070 // check namesOfInputArguments_ 02071 if(feMacro.namesOfInputArguments_.size() != argsIn.size()) 02072 { 02073 __CFG_SS__ << "FE Macro '" << feMacro.feMacroName_ << "' of interfaceID '" 02074 << interfaceID << "' was attempted with a mismatch in" 02075 << " number of input arguments. " << argsIn.size() << " were given. " 02076 << feMacro.namesOfInputArguments_.size() << " expected." << __E__; 02077 __CFG_COUT_ERR__ << "\n" << ss.str(); 02078 __CFG_SS_THROW__; 02079 } 02080 for(unsigned int i = 0; i < argsIn.size(); ++i) 02081 if(argsIn[i].first != feMacro.namesOfInputArguments_[i]) 02082 { 02083 __CFG_SS__ << "FE Macro '" << feMacro.feMacroName_ << "' of interfaceID '" 02084 << interfaceID << "' was attempted with a mismatch in" 02085 << " a name of an input argument. " << argsIn[i].first 02086 << " was given. " << feMacro.namesOfInputArguments_[i] 02087 << " expected." << __E__; 02088 __CFG_COUT_ERR__ << "\n" << ss.str(); 02089 __CFG_SS_THROW__; 02090 } 02091 02092 // build output arguments 02093 std::vector<std::string> returnStrings; 02094 std::vector<FEVInterface::frontEndMacroArg_t> argsOut; 02095 02096 { 02097 std::istringstream inputStream(outputArgs); 02098 std::string argName; 02099 while(getline(inputStream, argName, ',')) 02100 { 02101 __CFG_COUT__ << "argName " << argName << __E__; 02102 02103 returnStrings.push_back("DEFAULT"); // std::string()); 02104 argsOut.push_back(FEVInterface::frontEndMacroArg_t( 02105 argName, returnStrings[returnStrings.size() - 1])); 02106 // 02107 // __CFG_COUT__ << argsOut[argsOut.size()-1].first << __E__; 02108 __CFG_COUT__ << (uint64_t) & (returnStrings[returnStrings.size() - 1]) 02109 << __E__; 02110 } 02111 } 02112 02113 // check namesOfOutputArguments_ 02114 if(feMacro.namesOfOutputArguments_.size() != argsOut.size()) 02115 { 02116 __CFG_SS__ << "FE Macro '" << feMacro.feMacroName_ << "' of interfaceID '" 02117 << interfaceID << "' was attempted with a mismatch in" 02118 << " number of output arguments. " << argsOut.size() << " were given. " 02119 << feMacro.namesOfOutputArguments_.size() << " expected." << __E__; 02120 __CFG_COUT_ERR__ << "\n" << ss.str(); 02121 __CFG_SS_THROW__; 02122 } 02123 for(unsigned int i = 0; i < argsOut.size(); ++i) 02124 if(argsOut[i].first != feMacro.namesOfOutputArguments_[i]) 02125 { 02126 __CFG_SS__ << "FE Macro '" << feMacro.feMacroName_ << "' of interfaceID '" 02127 << interfaceID << "' was attempted with a mismatch in" 02128 << " a name of an output argument. " << argsOut[i].first 02129 << " were given. " << feMacro.namesOfOutputArguments_[i] 02130 << " expected." << __E__; 02131 __CFG_COUT_ERR__ << "\n" << ss.str(); 02132 __CFG_SS_THROW__; 02133 } 02134 02135 __CFG_COUT__ << "# of input args = " << argsIn.size() << __E__; 02136 for(auto& argIn : argsIn) 02137 __CFG_COUT__ << argIn.first << ": " << argIn.second << __E__; 02138 02139 // __CFG_COUT__ << "# of output args = " << argsOut.size() << __E__; 02140 // for(unsigned int i=0;i<argsOut.size();++i) 02141 // __CFG_COUT__ << i << ": " << argsOut[i].first << __E__; 02142 // for(unsigned int i=0;i<returnStrings.size();++i) 02143 // __CFG_COUT__ << i << ": " << returnStrings[i] << __E__; 02144 02145 __MOUT__ << "Launching FE Macro '" << feMacro.feMacroName_ << "' ..." << __E__; 02146 __CFG_COUT__ << "Launching FE Macro '" << feMacro.feMacroName_ << "' ..." << __E__; 02147 02148 // have pointer to Macro structure, so run it 02149 (getFEInterfaceP(interfaceID)->*(feMacro.macroFunction_))(feMacro, argsIn, argsOut); 02150 02151 __CFG_COUT__ << "FE Macro complete!" << __E__; 02152 02153 __CFG_COUT__ << "# of output args = " << argsOut.size() << __E__; 02154 for(const auto& arg : argsOut) 02155 __CFG_COUT__ << arg.first << ": " << arg.second << __E__; 02156 02157 // check namesOfOutputArguments_ size 02158 if(feMacro.namesOfOutputArguments_.size() != argsOut.size()) 02159 { 02160 __CFG_SS__ << "FE Macro '" << feMacro.feMacroName_ << "' of interfaceID '" 02161 << interfaceID 02162 << "' was attempted but the FE macro " 02163 "manipulated the output arguments vector. It is illegal " 02164 "to add or remove output vector name/value pairs." 02165 << __E__; 02166 __CFG_COUT_ERR__ << "\n" << ss.str(); 02167 __CFG_SS_THROW__; 02168 } 02169 02170 // Success! at this point so return the output string 02171 outputArgs = ""; 02172 for(unsigned int i = 0; i < argsOut.size(); ++i) 02173 { 02174 if(i) 02175 outputArgs += ";"; 02176 02177 // attempt to get number, and output hex version 02178 // otherwise just output result 02179 try 02180 { 02181 uint64_t tmpNumber; 02182 if(StringMacros::getNumber(argsOut[i].second, tmpNumber)) 02183 { 02184 std::stringstream outNumberSs; 02185 outNumberSs << std::dec << tmpNumber << " (0x" << std::hex << tmpNumber 02186 << ")" << std::dec; 02187 outputArgs += argsOut[i].first + "," + outNumberSs.str(); 02188 continue; 02189 } 02190 } 02191 catch(...) 02192 { // ignore error, assume not a number 02193 } 02194 02195 outputArgs += argsOut[i].first + "," + argsOut[i].second; 02196 } 02197 02198 __CFG_COUT__ << "outputArgs = " << outputArgs << __E__; 02199 02200 } // end runFEMacro() 02201 02202 //======================================================================================================================== 02203 // getFEMacrosString 02204 // returns string with each new line indicating the macros for a FE 02205 // each line: 02206 // <parent supervisor name>:<parent supervisor lid>:<interface type>:<interface UID> 02207 // :<macro name>:<macro permissions req>:<macro num of inputs>:...<input names : 02208 // separated>... 02209 // :<macro num of outputs>:...<output names : separated>... 02210 std::string FEVInterfacesManager::getFEMacrosString(const std::string& supervisorName, 02211 const std::string& supervisorLid) 02212 { 02213 std::string retList = ""; 02214 02215 for(const auto& it : theFEInterfaces_) 02216 { 02217 __CFG_COUT__ << "FE interface UID = " << it.first << __E__; 02218 02219 retList += supervisorName + ":" + supervisorLid + ":" + 02220 it.second->getInterfaceType() + ":" + it.second->getInterfaceUID(); 02221 02222 for(const auto& macroPair : it.second->getMapOfFEMacroFunctions()) 02223 { 02224 __CFG_COUT__ << "FE Macro name = " << macroPair.first << __E__; 02225 retList += ":" + macroPair.first + ":" + 02226 std::to_string(macroPair.second.requiredUserPermissions_) + ":" + 02227 std::to_string(macroPair.second.namesOfInputArguments_.size()); 02228 for(const auto& name : macroPair.second.namesOfInputArguments_) 02229 retList += ":" + name; 02230 02231 retList += 02232 ":" + std::to_string(macroPair.second.namesOfOutputArguments_.size()); 02233 for(const auto& name : macroPair.second.namesOfOutputArguments_) 02234 retList += ":" + name; 02235 } 02236 02237 retList += "\n"; 02238 } 02239 return retList; 02240 } 02241 02242 //======================================================================================================================== 02243 bool FEVInterfacesManager::allFEWorkloopsAreDone(void) 02244 { 02245 bool allFEWorkloopsAreDone = true; 02246 bool isActive; 02247 02248 for(const auto& FEInterface : theFEInterfaces_) 02249 { 02250 isActive = FEInterface.second->WorkLoop::isActive(); 02251 02252 __CFG_COUT__ << FEInterface.second->getInterfaceUID() << " of type " 02253 << FEInterface.second->getInterfaceType() << ": \t" 02254 << "workLoop_->isActive() " << (isActive ? "yes" : "no") << __E__; 02255 02256 if(isActive) // then not done 02257 { 02258 allFEWorkloopsAreDone = false; 02259 break; 02260 } 02261 } 02262 02263 return allFEWorkloopsAreDone; 02264 } // end allFEWorkloopsAreDone() 02265 02266 //======================================================================================================================== 02267 void FEVInterfacesManager::preStateMachineExecutionLoop(void) 02268 { 02269 VStateMachine::clearIterationWork(); 02270 VStateMachine::clearSubIterationWork(); 02271 02272 stateMachinesIterationWorkCount_ = 0; 02273 02274 __CFG_COUT__ << "Number of front ends to transition: " << theFENamesByPriority_.size() 02275 << __E__; 02276 02277 if(VStateMachine::getIterationIndex() == 0 && 02278 VStateMachine::getSubIterationIndex() == 0) 02279 { 02280 // reset map for iterations done on first iteration 02281 02282 subIterationWorkStateMachineIndex_ = -1; // clear sub iteration work index 02283 02284 stateMachinesIterationDone_.clear(); 02285 for(const auto& FEPair : theFEInterfaces_) 02286 stateMachinesIterationDone_[FEPair.first] = false; // init to not done 02287 } 02288 else 02289 __CFG_COUT__ << "Iteration " << VStateMachine::getIterationIndex() << "." 02290 << VStateMachine::getSubIterationIndex() << "(" 02291 << subIterationWorkStateMachineIndex_ << ")" << __E__; 02292 } // end preStateMachineExecutionLoop() 02293 02294 //======================================================================================================================== 02295 void FEVInterfacesManager::preStateMachineExecution(unsigned int i) 02296 { 02297 if(i >= theFENamesByPriority_.size()) 02298 { 02299 __CFG_SS__ << "FE Interface " << i << " not found!" << __E__; 02300 __CFG_SS_THROW__; 02301 } 02302 02303 const std::string& name = theFENamesByPriority_[i]; 02304 02305 FEVInterface* fe = getFEInterfaceP(name); 02306 02307 fe->VStateMachine::setIterationIndex(VStateMachine::getIterationIndex()); 02308 fe->VStateMachine::setSubIterationIndex(VStateMachine::getSubIterationIndex()); 02309 02310 fe->VStateMachine::clearIterationWork(); 02311 fe->VStateMachine::clearSubIterationWork(); 02312 02313 __CFG_COUT__ << "theStateMachineImplementation Iteration " 02314 << fe->VStateMachine::getIterationIndex() << "." 02315 << fe->VStateMachine::getSubIterationIndex() << __E__; 02316 } // end preStateMachineExecution() 02317 02318 //======================================================================================================================== 02319 // postStateMachineExecution 02320 // return false to indicate state machine is NOT done with transition 02321 bool FEVInterfacesManager::postStateMachineExecution(unsigned int i) 02322 { 02323 if(i >= theFENamesByPriority_.size()) 02324 { 02325 __CFG_SS__ << "FE Interface index " << i << " not found!" << __E__; 02326 __CFG_SS_THROW__; 02327 } 02328 02329 const std::string& name = theFENamesByPriority_[i]; 02330 02331 FEVInterface* fe = getFEInterfaceP(name); 02332 02333 // sub-iteration has priority 02334 if(fe->VStateMachine::getSubIterationWork()) 02335 { 02336 subIterationWorkStateMachineIndex_ = i; 02337 VStateMachine::indicateSubIterationWork(); 02338 02339 __CFG_COUT__ << "FE Interface '" << name 02340 << "' is flagged for another sub-iteration..." << __E__; 02341 return false; // to indicate state machine is NOT done with transition 02342 } 02343 else 02344 { 02345 subIterationWorkStateMachineIndex_ = -1; // clear sub iteration work index 02346 02347 bool& stateMachineDone = stateMachinesIterationDone_[name]; 02348 stateMachineDone = !fe->VStateMachine::getIterationWork(); 02349 02350 if(!stateMachineDone) 02351 { 02352 __CFG_COUT__ << "FE Interface '" << name 02353 << "' is flagged for another iteration..." << __E__; 02354 VStateMachine::indicateIterationWork(); // mark not done at 02355 // FEVInterfacesManager level 02356 ++stateMachinesIterationWorkCount_; // increment still working count 02357 return false; // to indicate state machine is NOT done with transition 02358 } 02359 } 02360 return true; // to indicate state machine is done with transition 02361 } // end postStateMachineExecution() 02362 02363 //======================================================================================================================== 02364 void FEVInterfacesManager::postStateMachineExecutionLoop(void) 02365 { 02366 if(VStateMachine::getSubIterationWork()) 02367 __CFG_COUT__ << "FE Interface state machine implementation " 02368 << subIterationWorkStateMachineIndex_ 02369 << " is flagged for another sub-iteration..." << __E__; 02370 else if(VStateMachine::getIterationWork()) 02371 __CFG_COUT__ << stateMachinesIterationWorkCount_ 02372 << " FE Interface state machine implementation(s) flagged for " 02373 "another iteration..." 02374 << __E__; 02375 else 02376 __CFG_COUT__ << "Done transitioning all state machine implementations..." 02377 << __E__; 02378 } // end postStateMachineExecutionLoop()