Refactoring. Made optimization parameters command line arguments. Added optimization parameters to the settings. Exporting of optimization parameters. main.py runs a batch of optimization with different optimization parameters

This commit is contained in:
iasonmanolas 2021-12-23 15:48:41 +02:00
parent 3eaef7a37c
commit 46227380aa
5 changed files with 274 additions and 167 deletions

View File

@ -45,7 +45,7 @@ else()
add_compile_definitions(POLYSCOPE_DEFINED)
endif()
set(MYSOURCES_STATIC_LINK false)
set(USE_ENSMALLEN true)
set(USE_ENSMALLEN false)
if(${USE_ENSMALLEN})
add_compile_definitions(USE_ENSMALLEN)
endif()

88
main.py
View File

@ -15,14 +15,16 @@ import sys
from datetime import datetime
from subprocess import check_output
from shutil import copyfile
from enum import Enum
numberOfOptimizedPatterns=0
numberOfSkippedPatterns=0
numberOfFunctionCalls=0
numberOfFunctionCalls=10
start_time = datetime.now()
def listener(q):
#print("Entered listener")
with open(os.path.join(resultsDir,'results.csv'), 'a') as f:
def listener(q,resultsDir):
print("Entered")
print("result dir in listener:",resultsDir)
with open(os.path.join(resultsDir,'results.csv'), 'a',newline='\n') as f:
while 1:
m = q.get()
if m == 'kill':
@ -35,6 +37,7 @@ def listener(q):
global numberOfSkippedPatterns
numberOfSkippedPatterns=numberOfSkippedPatterns+1
continue
print(m)
f.write(m)
f.flush()
global start_time
@ -50,7 +53,7 @@ def listener(q):
# completionPercentage=numberOfOptimizedPatterns/totalNumberOfPatterns
# print("Optimized patterns:" + str(completionPercentage))
def optimize(fullPatternFilepath, reducedPatternFilepath,translationalObjectiveWeight):
def optimize(fullPatternFilepath, reducedPatternFilepath,translationalObjectiveWeight,optimizationParameters,resultsDir,intermediateResultsDir):
"""Call run(), catch exceptions."""
dirname = os.path.abspath(os.path.dirname(__file__))
# dirname="/home/iason/Coding/build/ReducedModelOptimization/Release"
@ -65,7 +68,7 @@ def optimize(fullPatternFilepath, reducedPatternFilepath,translationalObjectiveW
reducedPatternFilepath,
str(numberOfFunctionCalls),str(translationalObjectiveWeight),
#os.path.join(resultsDir,os.path.basename(os.path.dirname(fullPatternFilepath))))
putResultsTo)
putResultsTo,optimizationParameters,intermediateResultsDir)
patternStartTime=datetime.now()
#print("Optimizing " + fullPatternFilepath+" at "+str(datetime.now()))
@ -73,6 +76,7 @@ def optimize(fullPatternFilepath, reducedPatternFilepath,translationalObjectiveW
#popen.wait()
#output = popen.stdout.read()
output = check_output(args).decode("utf-8")
# print(output)
#output,error=popen.communicate()
duration_min=(datetime.now() - patternStartTime).total_seconds()/60
#print("Optimized " + fullPatternFilepath+" in "+str(duration_min)+" minutes")
@ -81,25 +85,15 @@ def optimize(fullPatternFilepath, reducedPatternFilepath,translationalObjectiveW
except Exception as e:
print("error: %s run(*%r, **%r)" % (e, fullPatternFilepath,reducedPatternFilepath))
# Press the green button in the gutter to run the script.
if __name__ == '__main__':
dirOfThisFile = os.path.abspath(os.path.dirname(__file__))
copyFrom="/home/iason/Coding/build/ReducedModelOptimization/Release/ReducedModelOptimization"
copyfile(copyFrom, os.path.join(dirOfThisFile,"ReducedModelOptimization"))
fullPatternDirectory= "/home/iason/Coding/Projects/Approximating shapes with flat patterns/ReducedModelOptimization/TestSet/FullPatterns/selectionOfPatterns"
numberOfFunctionCalls=100000
optimizationBatchName='variableComparison_AllVars_ensmallen'+'_'+str(int(numberOfFunctionCalls/1000))+'k'
resultsDir=os.path.join(dirOfThisFile,os.path.join('Results/OptimizationResults/',optimizationBatchName))
#print(resultsDir)
def optimizeBatch(fullPatternDirectory,optimizationParameters,resultsDir,intermediateResultsDir):
watcher = pool.apply_async(listener, (q,resultsDir))
# print(optimizationParameters)
if not os.path.exists(resultsDir):
os.makedirs(resultsDir)
#shutil.rmtree(resultsDir)
manager = multiprocessing.Manager()
q = manager.Queue()
reducedPatternFilepath= "TestSet/ReducedPatterns/single_reduced.ply"
reducedPatternFilepath= "/home/iason/Coding/Projects/Approximating shapes with flat patterns/ReducedModelOptimization/TestSet/ReducedPatterns/single_reduced.ply"
fullPatternFilepaths=[]
pool=multiprocessing.Pool(11)
watcher = pool.apply_async(listener, (q,))
for subdir, dirs, files in os.walk(fullPatternDirectory):
#print(subdir)
#print(dirs)
@ -114,7 +108,9 @@ if __name__ == '__main__':
#print(optimizationPairs)
jobs=[]
translationalObjectiveWeights=[1.2] #[x/10 for x in range(2,18,2)]
jobs.extend(list(itertools.product(fullPatternFilepaths,[reducedPatternFilepath],translationalObjectiveWeights)))
optimizationParameters_str=list(map(str, optimizationParameters))
print(str(optimizationParameters))
jobs.extend(list(itertools.product(fullPatternFilepaths,[reducedPatternFilepath],translationalObjectiveWeights,[str(optimizationParameters)],[resultsDir],[intermediateResultsDir])))
#print(optimizationPairs)
totalNumberOfPatterns=len(jobs)
print("Runnning:",optimizationBatchName)
@ -125,8 +121,52 @@ if __name__ == '__main__':
print("Start time:", start_time)
pool.starmap(optimize,jobs)
print("Completed")
# f.close()
q.put('kill')
# f.close()
# Press the green button in the gutter to run the script.
if __name__ == '__main__':
# resultsDir="uninitialized dir"
manager = multiprocessing.Manager()
q = manager.Queue()
pool=multiprocessing.Pool(2)
#get latest optimization binary
copyFrom="/home/iason/Coding/build/ReducedModelOptimization/Release/ReducedModelOptimization"
dirOfThisFile = os.path.abspath(os.path.dirname(__file__))
copyfile(copyFrom, os.path.join(dirOfThisFile,"ReducedModelOptimization"))
fullPatternDirectory= "/home/iason/Coding/Projects/Approximating shapes with flat patterns/ReducedModelOptimization/TestSet/FullPatterns/selectionOfPatterns"
intermediateResultsDir='/home/iason/Coding/build/ReducedModelOptimization/IntermediateResults'
E=0
A=1
I2=2
I3=3
J=4
R=5
Theta=6
# optimizationParametersScenarios=[]
optimizationParametersScenarios={
"AllVar":{E, A, I2, I3, J, R, Theta},
"GeoYM":{R, Theta, E},
"noYM":{A, I2, I3, J, R, Theta},
"YMMat_Geo":[{E, A, I2, I3, J}, {R, Theta}],
"YM_MatGeo":[{E}, {A, I2, I3, J, R, Theta}],
"MatGeo_YM":[{A, I2, I3, J, R, Theta}, {E}],
"Geo_YM_Mat":[{R, Theta}, {E}, {A, I2, I3, J}],
"YM_Geo_Mat":[{E}, {R, Theta}, {A, I2, I3, J}],
"Geo_Mat":[{R, Theta}, {A, I2, I3, J}],
"YMGeo_Mat":[{E, R, Theta}, {A, I2, I3, J}]
}
for key, optimizationParameters in optimizationParametersScenarios.items():
optimizationBatchName='variableComparison_'+key+'_'+str(int(numberOfFunctionCalls/1000))+'k'
resultsDir=os.path.join(dirOfThisFile,os.path.join('Results/OptimizationResults/',optimizationBatchName))
optimizeBatch(fullPatternDirectory,optimizationParameters,resultsDir,intermediateResultsDir)
pool.close()
pool.join()

View File

@ -10,19 +10,30 @@
#include <iterator>
#include <stdexcept>
#include <string>
#include <string_view>
#include <vcg/complex/algorithms/update/position.h>
#include <boost/algorithm/string.hpp>
#ifdef POLYSCOPE_DEFINED
#include "polyscope/curve_network.h"
#include "polyscope/point_cloud.h"
#include "polyscope/polyscope.h"
#endif
int main(int argc, char *argv[]) {
if (argc < 3) {
std::cerr << "Specify at least the two pattern filepaths to be "
"optimized.Exiting.."
int main(int argc, char *argv[])
{
if (argc <= 7) {
std::cerr << "Wrong number of input parameters. Expects at least 6 input parameters."
"Usage:\n"
"1)full pattern file path\n"
"2)reduced pattern file path\n"
"3)Number of optimizaion function calls\n"
"4)Translational error weight\n"
"5)Optimization results directory path\n"
"6)[optional]Optimization parameters\n"
"7)[optional]Intermediate results directory path\n"
"Exiting.."
<< std::endl;
std::terminate();
return 1;
}
// Populate the pattern pair to be optimized
@ -40,7 +51,6 @@ int main(int argc, char *argv[]) {
// Set the optization settings
ReducedPatternOptimization::xRange beamE{"E", 0.001, 1000};
ReducedPatternOptimization::xRange beamA{"A", 0.001, 1000};
ReducedPatternOptimization::xRange beamI{"I", 0.001, 1000};
ReducedPatternOptimization::xRange beamI2{"I2", 0.001, 1000};
ReducedPatternOptimization::xRange beamI3{"I3", 0.001, 1000};
ReducedPatternOptimization::xRange beamJ{"J", 0.001, 1000};
@ -49,10 +59,105 @@ int main(int argc, char *argv[]) {
ReducedPatternOptimization::Settings settings_optimization;
settings_optimization.parameterRanges
= {beamE, beamA, beamI2, beamI3, beamJ, innerHexagonSize, innerHexagonAngle};
const bool input_numberOfFunctionCallsDefined = argc >= 4;
settings_optimization.numberOfFunctionCalls = input_numberOfFunctionCallsDefined
? std::atoi(argv[3])
: 100;
settings_optimization.numberOfFunctionCalls = std::atoi(argv[3]);
const bool input_optimizationParametersDefined = argc >= 8;
if (input_optimizationParametersDefined) {
const std::string optimizationParametersTag = argv[7];
std::vector <std::string> split=Utilities::split(optimizationParametersTag,",");
//parse parameter tag
std::vector<std::vector<ReducedPatternOptimization::OptimizationParameterIndex>>
optimizationParameters;
std::vector<ReducedPatternOptimization::OptimizationParameterIndex> parameterGroup;
for (std::string &s : split) {
// std::cout<<s<<std::endl;
// s=Utilities::trimLeftAndRightSpaces(s);
if(boost::algorithm::contains(s,"{")){
// std::cout<<"{ detected"<<std::endl;
parameterGroup.clear();
}
if(boost::algorithm::contains(s,std::to_string(static_cast<int>(ReducedPatternOptimization::E)))){
parameterGroup.push_back(ReducedPatternOptimization::E);
}else if(boost::algorithm::contains(s,std::to_string(static_cast<int>(ReducedPatternOptimization::A)))){
parameterGroup.push_back(ReducedPatternOptimization::A);
}else if(boost::algorithm::contains(s,std::to_string(static_cast<int>(ReducedPatternOptimization::I2)))){
parameterGroup.push_back(ReducedPatternOptimization::I2);
}else if(boost::algorithm::contains(s,std::to_string(static_cast<int>(ReducedPatternOptimization::I3)))){
parameterGroup.push_back(ReducedPatternOptimization::I3);
}else if(boost::algorithm::contains(s,std::to_string(static_cast<int>(ReducedPatternOptimization::J)))){
parameterGroup.push_back(ReducedPatternOptimization::J);
}else if(boost::algorithm::contains(s,std::to_string(static_cast<int>(ReducedPatternOptimization::R)))){
parameterGroup.push_back(ReducedPatternOptimization::R);
}else if(boost::algorithm::contains(s,std::to_string(static_cast<int>(ReducedPatternOptimization::Theta)))){
parameterGroup.push_back(ReducedPatternOptimization::Theta);
}
else{
std::cerr << "Wrong optimization parameter input: " << optimizationParametersTag
<< std::endl;
}
if(boost::algorithm::contains(s,"}")){
optimizationParameters.push_back(parameterGroup);
}
}
settings_optimization.optimizationVariables=optimizationParameters;
#ifdef POLYSCOPE_DEFINED
for(const std::vector<ReducedPatternOptimization::OptimizationParameterIndex>& v:settings_optimization.optimizationVariables){
for(const ReducedPatternOptimization::OptimizationParameterIndex& i:v ){
std::cout<<static_cast<int>(i)<<" ";
}
std::cout<<std::endl;
}
#endif
} else {
enum OptimizationParameterComparisonScenarioIndex {
AllVar,
GeoYM,
noYM,
YMMat_Geo,
YM_MatGeo,
MatGeo_YM,
Geo_YM_Mat,
YM_Geo_Mat,
Geo_Mat,
YMGeo_Mat,
NumberOfScenarios
};
const std::vector<
std::vector<std::vector<ReducedPatternOptimization::OptimizationParameterIndex>>>
optimizationParameters = [&]() {
std::vector<
std::vector<std::vector<ReducedPatternOptimization::OptimizationParameterIndex>>>
optimizationParameters(NumberOfScenarios);
using namespace ReducedPatternOptimization;
optimizationParameters[AllVar] = {{E, A, I2, I3, J, R, Theta}};
optimizationParameters[GeoYM] = {{R, Theta, E}};
optimizationParameters[noYM] = {{A, I2, I3, J, R, Theta}};
optimizationParameters[YMMat_Geo] = {{E, A, I2, I3, J}, {R, Theta}};
optimizationParameters[YM_MatGeo] = {{E}, {A, I2, I3, J, R, Theta}};
optimizationParameters[MatGeo_YM] = {{A, I2, I3, J, R, Theta}, {E}};
optimizationParameters[Geo_YM_Mat] = {{R, Theta}, {E}, {A, I2, I3, J}};
optimizationParameters[YM_Geo_Mat] = {{E}, {R, Theta}, {A, I2, I3, J}};
optimizationParameters[Geo_Mat] = {{R, Theta}, {A, I2, I3, J}};
optimizationParameters[YMGeo_Mat] = {{E, R, Theta}, {A, I2, I3, J}};
return optimizationParameters;
}();
constexpr OptimizationParameterComparisonScenarioIndex scenario = YMGeo_Mat;
settings_optimization.optimizationVariables = optimizationParameters[scenario];
}
if(settings_optimization.optimizationVariables.empty()){
std::cerr<<"No optimization variables. Exiting.."<<std::endl;
std::terminate();
}
const bool input_intermediateResultsDirectoryDefined = argc >= 7;
if (input_intermediateResultsDirectoryDefined) {
settings_optimization.intermediateResultsDirectoryPath = std::filesystem::path(argv[6]);
}
settings_optimization.normalizationStrategy
= ReducedPatternOptimization::Settings::NormalizationStrategy::Epsilon;
#ifdef POLYSCOPE_DEFINED
@ -80,11 +185,7 @@ int main(int argc, char *argv[]) {
+ to_string_with_precision(
settings_optimization.objectiveWeights.translational)
+ ")" + "_" + xConcatNames;
const bool input_resultDirectoryDefined = argc >= 6;
const std::string optimizationResultsDirectory = input_resultDirectoryDefined
? argv[5]
: std::filesystem::current_path().append(
"OptimizationResults").string();
const std::string optimizationResultsDirectory = argv[5];
std::string resultsOutputDir;
bool optimizationResultFolderExists = false;
const std::filesystem::path crashedJobsDirPath(std::filesystem::path(optimizationResultsDirectory)

View File

@ -30,10 +30,10 @@ struct GlobalOptimizationVariables
std::vector<double> objectiveValueHistory;
std::vector<double> plotColors;
std::array<double,
ReducedModelOptimizer::OptimizationParameterIndex::NumberOfOptimizationParameters>
ReducedPatternOptimization::OptimizationParameterIndex::NumberOfOptimizationParameters>
parametersInitialValue;
std::array<double,
ReducedModelOptimizer::OptimizationParameterIndex::NumberOfOptimizationParameters>
ReducedPatternOptimization::OptimizationParameterIndex::NumberOfOptimizationParameters>
optimizationInitialValue;
std::vector<int> simulationScenarioIndices;
double minY{DBL_MAX};
@ -949,7 +949,7 @@ ReducedModelOptimizer::getFullPatternMaxSimulationForces(
const std::filesystem::path &intermediateResultsDirectoryPath)
{
std::array<double, NumberOfBaseSimulationScenarios> fullPatternSimulationScenarioMaxMagnitudes;
#ifdef POLYSCOPE_DEFINED
//#ifdef POLYSCOPE_DEFINED
const std::filesystem::path forceMagnitudesDirectoryPath(
std::filesystem::path(intermediateResultsDirectoryPath).append("ForceMagnitudes"));
std::filesystem::path patternMaxForceMagnitudesFilePath(
@ -965,11 +965,11 @@ ReducedModelOptimizer::getFullPatternMaxSimulationForces(
= static_cast<std::array<double, NumberOfBaseSimulationScenarios>>(json.at("maxMagn"));
return fullPatternSimulationScenarioMaxMagnitudes;
}
#endif
//#endif
fullPatternSimulationScenarioMaxMagnitudes = computeFullPatternMaxSimulationForces(
desiredBaseSimulationScenarioIndices);
#ifdef POLYSCOPE_DEFINED
//#ifdef POLYSCOPE_DEFINED
nlohmann::json json;
json["maxMagn"] = fullPatternSimulationScenarioMaxMagnitudes;
@ -977,7 +977,7 @@ ReducedModelOptimizer::getFullPatternMaxSimulationForces(
std::ofstream jsonFile(patternMaxForceMagnitudesFilePath.string());
jsonFile << json;
#endif
//#endif
assert(fullPatternSimulationScenarioMaxMagnitudes.size()
== desiredBaseSimulationScenarioIndices.size());
@ -995,60 +995,31 @@ void ReducedModelOptimizer::runOptimization(const Settings &settings,
#if POLYSCOPE_DEFINED
// global.plotColors.reserve(settings.numberOfFunctionCalls);
#endif
#ifdef USE_ENSMALLEN
#else
#endif
enum OptimizationParameterComparisonScenarioIndex {
AllVar, //ok
GeoYM, //ok
noYM, //ok
YMMat_Geo, //ok
YM_MatGeo, //executing
MatGeo_YM, //ok
Geo_YM_Mat, //ok
YM_Geo_Mat, //ok
Geo_Mat, //ok
YMGeo_Mat,
NumberOfScenarios
};
const std::vector<std::vector<std::vector<OptimizationParameterIndex>>> scenarioParameters =
[&]() {
std::vector<std::vector<std::vector<OptimizationParameterIndex>>> scenarioParameters(
NumberOfScenarios);
scenarioParameters[AllVar] = {{E, A, I2, I3, J, R, Theta}};
scenarioParameters[GeoYM] = {{R, Theta, E}};
scenarioParameters[noYM] = {{A, I2, I3, J, R, Theta}};
scenarioParameters[YMMat_Geo] = {{E, A, I2, I3, J}, {R, Theta}};
scenarioParameters[YM_MatGeo] = {{E}, {A, I2, I3, J, R, Theta}};
scenarioParameters[MatGeo_YM] = {{A, I2, I3, J, R, Theta}, {E}};
scenarioParameters[Geo_YM_Mat] = {{R, Theta}, {E}, {A, I2, I3, J}};
scenarioParameters[YM_Geo_Mat] = {{E},{R, Theta}, {A, I2, I3, J}};
scenarioParameters[Geo_Mat] = {{R, Theta}, {A, I2, I3, J}};
scenarioParameters[YMGeo_Mat] = {{E, R, Theta}, {A, I2, I3, J}};
return scenarioParameters;
assert(!settings.optimizationVariables.empty());
const std::vector<std::vector<OptimizationParameterIndex>> &optimizationParametersGroups
= settings.optimizationVariables;
}();
constexpr OptimizationParameterComparisonScenarioIndex scenario = YM_MatGeo;
const std::vector<std::vector<OptimizationParameterIndex>> scenarioParameterGroups
= scenarioParameters[scenario];
#ifndef USE_ENSMALLEN
const int totalNumberOfOptimizationParameters
= std::accumulate(scenarioParameterGroups.begin(),
scenarioParameterGroups.end(),
= std::accumulate(optimizationParametersGroups.begin(),
optimizationParametersGroups.end(),
0,
[](const int &sum,
const std::vector<OptimizationParameterIndex> &parameterGroup) {
return sum + parameterGroup.size();
});
#endif
FunctionEvaluation optimization_optimalResult;
optimization_optimalResult.x.resize(NumberOfOptimizationParameters,0);
for (int optimizationParameterIndex = E;
optimizationParameterIndex != NumberOfOptimizationParameters;
optimizationParameterIndex++) {
optimization_optimalResult.x[optimizationParameterIndex]=global.parametersInitialValue[optimizationParameterIndex];
optimization_optimalResult.x[optimizationParameterIndex]
= global.parametersInitialValue[optimizationParameterIndex];
}
for (const std::vector<OptimizationParameterIndex> &parameterGroup : scenarioParameterGroups) {
for (const std::vector<OptimizationParameterIndex> &parameterGroup :
optimizationParametersGroups) {
FunctionEvaluation parameterGroup_optimalResult;
//Set update function. TODO: Make this function immutable by defining it once and using the global variable to set parameterGroup
function_updateReducedPattern = [&](const std::vector<double> &x,
@ -1231,7 +1202,6 @@ optimization_optimalResult.y=parameterGroup_optimalResult.y;
const OptimizationParameterIndex parameterIndex = parameterGroup[xIndex];
optimization_optimalResult.x[parameterIndex] = parameterGroup_optimalResult.x[xIndex];
}
}
getResults(optimization_optimalResult, settings, results);
}
@ -1806,6 +1776,7 @@ void ReducedModelOptimizer::optimize(
ReducedPatternOptimization::Results &results,
const std::vector<BaseSimulationScenario> &desiredBaseSimulationScenarioIndices)
{
assert(!optimizationSettings.optimizationVariables.empty());
for (int baseSimulationScenarioIndex : desiredBaseSimulationScenarioIndices) {
//Increase the size of the vector holding the simulation scenario indices
global.simulationScenarioIndices.resize(
@ -1831,14 +1802,9 @@ void ReducedModelOptimizer::optimize(
global.optimizationSettings = optimizationSettings;
global.pFullPatternSimulationMesh = m_pFullPatternSimulationMesh;
#ifdef POLYSCOPE_DEFINED
const std::filesystem::path intermediateResultsDirectoryPath(
std::filesystem::current_path().parent_path().append("IntermediateResults"));
#else
const std::filesystem::path intermediateResultsDirectoryPath(
std::filesystem::current_path().append("IntermediateResults"));
optimizationSettings.intermediateResultsDirectoryPath);
#endif
std::array<double, NumberOfBaseSimulationScenarios> fullPatternSimulationScenarioMaxMagnitudes
= getFullPatternMaxSimulationForces(desiredBaseSimulationScenarioIndices,
intermediateResultsDirectoryPath);

View File

@ -52,20 +52,20 @@ public:
double y = std::numeric_limits<double>::quiet_NaN();
};
struct ParameterLabels
{
inline const static std::string E = {"E"};
inline const static std::string A = {"A"};
inline const static std::string I2 = {"I2"};
inline const static std::string I3 = {"I3"};
inline const static std::string J = {"J"};
inline const static std::string theta = {"Theta"};
inline const static std::string R = {"R"};
};
inline constexpr static ParameterLabels parameterLabels();
enum OptimizationParameterIndex { E, A, I2, I3, J, R, Theta, NumberOfOptimizationParameters };
// struct ParameterLabels
// {
// inline const static std::string E = {"E"};
// inline const static std::string A = {"A"};
// inline const static std::string I2 ={"I2"};
// inline const static std::string I3 ={"I3"};
// inline const static std::string J = {"J"};
// inline const static std::string th= {"Theta"};
// inline const static std::string R = {"R"};
// };
// inline constexpr static ParameterLabels parameterLabels();
inline static std::array<std::string, ReducedPatternOptimization::NumberOfOptimizationParameters>
parameterLabels = {"R", "A", "I2", "I3", "J", "Theta", "R"};
constexpr static std::array<int, ReducedPatternOptimization::NumberOfBaseSimulationScenarios>
simulationScenariosResolution = {11, 11, 20, 20, 20};
constexpr static std::array<int, ReducedPatternOptimization::NumberOfBaseSimulationScenarios>