diff --git a/reducedmodeloptimizer_structs.hpp b/reducedmodeloptimizer_structs.hpp index 683cf77..64c6f03 100644 --- a/reducedmodeloptimizer_structs.hpp +++ b/reducedmodeloptimizer_structs.hpp @@ -15,13 +15,15 @@ enum BaseSimulationScenario { Bending, Dome, Saddle, + S, NumberOfBaseSimulationScenarios }; inline static std::vector baseSimulationScenarioNames{"Axial", "Shear", "Bending", "Dome", - "Saddle"}; + "Saddle", + "S"}; struct Colors { @@ -107,24 +109,122 @@ inline int getParameterIndex(const std::string &s) struct Settings { inline static std::string defaultFilename{"OptimizationSettings.json"}; + std::array baseScenarioMaxMagnitudes{0, + 3, + 0.95, + 0.087, + 1.9, + /*3*/ 0}; //custom + // std::array baseScenarioMaxMagnitudes{2.74429, + // 5.9173, + // 0.493706, + // 0.0820769, + // 1.57789}; + + // std::array + // baseScenarioMaxMagnitudes{20.85302947095844, + // 1.8073431893126763, + // 0.2864731720436702, + // 0.14982243562639147, + // 0.18514829631059054};//median + // std::array + // baseScenarioMaxMagnitudes{1.1725844893199244, + // 0.3464275389927846, + // 0.09527915004635197, + // 0.06100757786262501, + // 0.10631914784812076}; //5_1565 0.03axial + // std::array + // baseScenarioMaxMagnitudes{/*15*/ 0 /*1.711973658196369*/, + // 1.878077115238504, + // 0.8, + // 0.15851675178327318, + // 0.8, + // /*1.711973658196369*/ 0}; //custom + // std::array + // baseScenarioMaxMagnitudes{0, + // 14.531854387244818, + // 0.38321932238436796, + // 0.21381267870193282, + // 0.28901381608791094, + // 1.711973658196369}; //9_14423 + // std::array + // baseScenarioMaxMagnitudes{1.1725844893199244, + // 0.3464275389927846, + // 0.09527915004635197, + // 0.06100757786262501, + // 0.10631914784812076}; //5_1565 0.03axial + // std::array + // baseScenarioMagnitudes{9.82679, 0.138652, 0.247242, 0.739443, 0.00675865}; //Hyperparam opt + // std::array baseScenarioMaxMagnitudes{ + // 30, 8, 0.4421382884449713, 0.22758433903942452, 0.3247935583883217}; + + // std::array + // baseScenarioMagnitudes{10 * 6.310485381644259, + // 10 * 1.7100142258819078, + // 10 * 0.18857048204421728, + // 10 * 0.10813697502645818, + // 10 * 0.11982893539207524}; //6_338 + // std::array baseScenarioMagnitudes{7.72224, + // 7.72224, + // 0.89468, + // 0.445912, + // 0.625905}; + // std::array baseScenarioMagnitudes{0.407714, + // 22.3524, + // 0.703164, + // 0.0226138, + // 0.161316}; + // std::array + // baseScenarioMagnitudes{2, 1, 0.4, 0.2, 0.2}; //8_15444 magnitudes from randomBending0 + + // std::array + // baseScenarioMagnitudes{1.0600375226325425, + // 0.6381040280710403, + // 0.17201755995098306, + // 0.0706601822149856, + // 0.13578373479448072}; //8_15444 magnitudes from displacements + // std::array + // baseScenarioMagnitudes{10 * 1.0600375226325425, + // 10 * 0.6381040280710403, + // 10 * 0.17201755995098306, + // 10 * 0.0706601822149856, + // 10 * 0.13578373479448072}; //8_15444 magnitudes from displacements + + // std::array baseScenarioMaxMagnitudes; std::vector> optimizationStrategy = { - {E, A, I2, I3, J, R, Theta}}; - // {A, I2, I3, J, R, Theta}}; + // {E,A, I2, I3, J, R, Theta}}; + {A, I2, I3, J, R, Theta}}; std::optional> optimizationVariablesGroupsWeights; //TODO:should be removed in the future if not a splitting strategy is used for the optimization enum NormalizationStrategy { NonNormalized, Epsilon }; inline static std::vector normalizationStrategyStrings{"NonNormalized", "Epsilon"}; NormalizationStrategy normalizationStrategy{Epsilon}; - std::array variablesRanges{xRange{"E", 0.001, 1000}, - xRange{"A", 0.001, 1000}, - xRange{"I2", 0.001, 1000}, - xRange{"I3", 0.001, 1000}, - xRange{"J", 0.001, 1000}, + std::array variablesRanges{xRange{"E", 1e-3, 1e3}, + xRange{"A", 1e-3, 1e3}, + xRange{"I2", 1e-3, 1e3}, + xRange{"I3", 1e-3, 1e3}, + xRange{"J", 1e-3, 1e3}, xRange{"R", 0.05, 0.95}, xRange{"Theta", -30, 30}}; - int numberOfFunctionCalls{100000}; - double solverAccuracy{1e-3}; - double translationEpsilon{3e-3}; + struct SettingsPSO + { + int numberOfParticles{200}; +#ifdef USE_PSO + inline static std::string optimizerName{"pso"}; +#else + inline static std::string optimizerName{"sa"}; +#endif + } pso; + + struct SettingsDlibGlobal + { + int numberOfFunctionCalls{100000}; + } dlib; + + double solverAccuracy{1e-2}; + double translationEpsilon{4e-3}; + // double translationEpsilon{0}; + // double angularDistanceEpsilon{vcg::math::ToRad(2.0)}; double angularDistanceEpsilon{vcg::math::ToRad(0.0)}; double targetBaseTriangleSize{0.03}; std::filesystem::path intermediateResultsDirectoryPath; @@ -132,11 +232,7 @@ struct Settings { double translational{1.2}; double rotational{0.8}; - bool operator==(const ObjectiveWeights &other) const - { - return this->translational == other.translational - && this->rotational == other.rotational; - } + bool operator==(const ObjectiveWeights &other) const; }; std::array perBaseScenarioObjectiveWeights; std::array, NumberOfBaseSimulationScenarios> @@ -163,10 +259,8 @@ struct Settings inline static std::string ObjectiveWeights{"ObjectiveWeight"}; }; - void save(const std::filesystem::path &saveToPath) + nlohmann::json toJson() const { - assert(std::filesystem::is_directory(saveToPath)); - nlohmann::json json; json[GET_VARIABLE_NAME(optimizationStrategy)] = optimizationStrategy; if (optimizationVariablesGroupsWeights.has_value()) { @@ -193,7 +287,6 @@ struct Settings // = xRange.toString(); // } - json[GET_VARIABLE_NAME(numberOfFunctionCalls)] = numberOfFunctionCalls; json[GET_VARIABLE_NAME(solverAccuracy)] = solverAccuracy; //Objective weights std::array, NumberOfBaseSimulationScenarios> objectiveWeightsPairs; @@ -206,10 +299,24 @@ struct Settings }); json[JsonKeys::ObjectiveWeights] = objectiveWeightsPairs; json[GET_VARIABLE_NAME(translationEpsilon)] = translationEpsilon; - json[GET_VARIABLE_NAME(angularDistanceEpsilon)] = vcg::math::ToDeg( - angularDistanceEpsilon); + json[GET_VARIABLE_NAME(angularDistanceEpsilon)] = vcg::math::ToDeg(angularDistanceEpsilon); json[GET_VARIABLE_NAME(targetBaseTriangleSize)] = targetBaseTriangleSize; + json[GET_VARIABLE_NAME(baseScenarioMaxMagnitudes)] = baseScenarioMaxMagnitudes; +#ifdef USE_ENSMALLEN +#ifdef USE_PSO + json[GET_VARIABLE_NAME(pso.numberOfParticles)] = pso.numberOfParticles; +#endif + json[GET_VARIABLE_NAME(pso.optimizerName)] = pso.optimizerName; +#else + json[GET_VARIABLE_NAME(dlib.numberOfFunctionCalls)] = dlib.numberOfFunctionCalls; +#endif + return json; + } + void save(const std::filesystem::path &saveToPath) + { + assert(std::filesystem::is_directory(saveToPath)); + nlohmann::json json = toJson(); std::filesystem::path jsonFilePath( std::filesystem::path(saveToPath).append(defaultFilename)); std::ofstream jsonFile(jsonFilePath.string()); @@ -260,8 +367,8 @@ struct Settings } } - if (json.contains(GET_VARIABLE_NAME(numberOfFunctionCalls))) { - numberOfFunctionCalls = json.at(GET_VARIABLE_NAME(numberOfFunctionCalls)); + if (json.contains(GET_VARIABLE_NAME(dlib.numberOfFunctionCalls))) { + dlib.numberOfFunctionCalls = json.at(GET_VARIABLE_NAME(dlib.numberOfFunctionCalls)); } if (json.contains(GET_VARIABLE_NAME(solverAccuracy))) { solverAccuracy = json.at(GET_VARIABLE_NAME(solverAccuracy)); @@ -293,33 +400,17 @@ struct Settings json[GET_VARIABLE_NAME(targetBaseTriangleSize)]); } + if (json.contains(GET_VARIABLE_NAME(pso.numberOfParticles))) { + pso.numberOfParticles = static_cast(json[GET_VARIABLE_NAME(pso.numberOfParticles)]); + } + // perBaseScenarioObjectiveWeights = json.at(JsonKeys::ObjectiveWeights); // objectiveWeights.translational = json.at(JsonKeys::ObjectiveWeights); // objectiveWeights.rotational = 2 - objectiveWeights.translational; return true; } - std::string toString() const - { - std::string settingsString; - if (!variablesRanges.empty()) { - std::string xRangesString; - for (const xRange &range : variablesRanges) { - xRangesString += range.toString() + " "; - } - settingsString += xRangesString; - } - settingsString += "FuncCalls=" + std::to_string(numberOfFunctionCalls) - + " Accuracy=" + std::to_string(solverAccuracy); - for (int baseScenario = Axial; baseScenario != NumberOfBaseSimulationScenarios; - baseScenario++) { - +" W_t=" + std::to_string(perBaseScenarioObjectiveWeights[baseScenario].translational) - + " W_r=" - + std::to_string(perBaseScenarioObjectiveWeights[baseScenario].rotational); - } - - return settingsString; - } + std::string toString() const { return toJson().dump(); } void writeHeaderTo(csvFile &os) const { @@ -346,7 +437,7 @@ struct Settings os << range.min; } } - os << numberOfFunctionCalls; + os << dlib.numberOfFunctionCalls; os << solverAccuracy; os << std::to_string(translationEpsilon); os << std::to_string(vcg::math::ToDeg(angularDistanceEpsilon)); @@ -384,11 +475,10 @@ struct Settings settings2.perBaseScenarioObjectiveWeights.begin()) .first == settings1.perBaseScenarioObjectiveWeights.end(); - return settings1.numberOfFunctionCalls == settings2.numberOfFunctionCalls + return settings1.dlib.numberOfFunctionCalls == settings2.dlib.numberOfFunctionCalls && settings1.variablesRanges == settings2.variablesRanges && settings1.solverAccuracy == settings2.solverAccuracy && haveTheSameObjectiveWeights - && settings1.translationEpsilon - == settings2.translationEpsilon; + && settings1.translationEpsilon == settings2.translationEpsilon; } inline void updateMeshWithOptimalVariables(const std::vector &x, SimulationMesh &m) @@ -477,6 +567,8 @@ struct Settings std::vector objectiveValueHistory; std::vector objectiveValueHistory_iteration; + inline static std::string DefaultFileName{"OptimizationResults.json"}; + struct CSVExportingSettings { bool exportPE{false}; @@ -488,7 +580,6 @@ struct Settings const CSVExportingSettings exportSettings; struct JsonKeys { - inline static std::string filename{"OptimizationResults.json"}; inline static std::string optimizationVariables{"OptimizationVariables"}; inline static std::string baseTriangle{"BaseTriangle"}; inline static std::string Label{"Label"}; @@ -552,7 +643,7 @@ struct Settings json_optimizationResults[JsonKeys::fullPatternYoungsModulus] = fullPatternYoungsModulus; ////Save to json file std::filesystem::path jsonFilePath( - std::filesystem::path(saveToPath).append(JsonKeys::filename)); + std::filesystem::path(saveToPath).append(DefaultFileName)); std::ofstream jsonFile_optimizationResults(jsonFilePath.string()); jsonFile_optimizationResults << json_optimizationResults; @@ -602,18 +693,18 @@ struct Settings #endif } - bool load(const std::string &loadFromPath, const bool &shouldLoadDebugFiles = false) + bool load(const std::filesystem::path &loadFromPath, const bool &shouldLoadDebugFiles = false) { assert(std::filesystem::is_directory(loadFromPath)); std::filesystem::path jsonFilepath( - std::filesystem::path(loadFromPath).append(JsonKeys::filename)); + std::filesystem::path(loadFromPath).append(DefaultFileName)); if (!std::filesystem::exists(jsonFilepath)) { std::cerr << "Input path does not exist:" << loadFromPath << std::endl; return false; } //Load optimal X nlohmann::json json_optimizationResults; - std::ifstream ifs(std::filesystem::path(loadFromPath).append(JsonKeys::filename)); + std::ifstream ifs(std::filesystem::path(loadFromPath).append(DefaultFileName)); ifs >> json_optimizationResults; label = json_optimizationResults.at(JsonKeys::Label); @@ -665,40 +756,30 @@ struct Settings const std::filesystem::path simulationJobsFolderPath( std::filesystem::path(loadFromPath).append("SimulationJobs")); - std::vector sortedByName; - for (auto &entry : std::filesystem::directory_iterator(simulationJobsFolderPath)) - sortedByName.push_back(entry.path()); + const std::vector scenariosSortedByName = [&]() { + std::vector sortedByName; + for (auto &entry : std::filesystem::directory_iterator(simulationJobsFolderPath)) + sortedByName.push_back(entry.path()); - std::sort(sortedByName.begin(), sortedByName.end(), &Utilities::compareNat); - - for (const auto &simulationScenarioPath : sortedByName) { + std::sort(sortedByName.begin(), sortedByName.end(), &Utilities::compareNat); + return sortedByName; + }(); + for (const auto &simulationScenarioPath : scenariosSortedByName) { if (!std::filesystem::is_directory(simulationScenarioPath)) { continue; } - // Load full pattern files - for (const auto &fileEntry : std::filesystem::directory_iterator( - std::filesystem::path(simulationScenarioPath).append("Full"))) { - const auto filepath = fileEntry.path(); - if (filepath.extension() == ".json") { - SimulationJob job; - job.load(filepath.string()); - job.pMesh->setBeamMaterial(0.3, fullPatternYoungsModulus); - fullPatternSimulationJobs.push_back(std::make_shared(job)); - } - } - + // Load full job const auto fullJobFilepath = Utilities::getFilepathWithExtension( std::filesystem::path(simulationScenarioPath).append("Full"), ".json"); SimulationJob fullJob; fullJob.load(fullJobFilepath.string()); fullJob.pMesh->setBeamMaterial(0.3, fullPatternYoungsModulus); fullPatternSimulationJobs.push_back(std::make_shared(fullJob)); - + // Load reduced job const auto reducedJobFilepath = Utilities::getFilepathWithExtension( std::filesystem::path(simulationScenarioPath).append("Reduced"), ".json"); SimulationJob reducedJob; reducedJob.load(reducedJobFilepath.string()); - // applyOptimizationResults_innerHexagon(*this, baseTriangle, *job.pMesh); applyOptimizationResults_elements(*this, reducedJob.pMesh); reducedPatternSimulationJobs.push_back( std::make_shared(reducedJob)); @@ -834,67 +915,77 @@ struct Settings } #if POLYSCOPE_DEFINED - void draw() const { - PolyscopeInterface::init(); - DRMSimulationModel drmSimulator; - LinearSimulationModel linearSimulator; - assert(fullPatternSimulationJobs.size() == reducedPatternSimulationJobs.size()); - fullPatternSimulationJobs[0]->pMesh->registerForDrawing(Colors::fullInitial); - reducedPatternSimulationJobs[0]->pMesh->registerForDrawing(Colors::reducedInitial, false); + void draw(const std::vector &desiredSimulationScenariosIndices = std::vector()) const + { + PolyscopeInterface::init(); + DRMSimulationModel drmSimulator; + LinearSimulationModel linearSimulator; + assert(fullPatternSimulationJobs.size() == reducedPatternSimulationJobs.size()); + fullPatternSimulationJobs[0]->pMesh->registerForDrawing(Colors::fullInitial); + reducedPatternSimulationJobs[0]->pMesh->registerForDrawing(Colors::reducedInitial, false); - const int numberOfSimulationJobs = fullPatternSimulationJobs.size(); - for (int simulationJobIndex = 0; simulationJobIndex < numberOfSimulationJobs; - simulationJobIndex++) { - // Drawing of full pattern results - const std::shared_ptr &pFullPatternSimulationJob - = fullPatternSimulationJobs[simulationJobIndex]; - pFullPatternSimulationJob->registerForDrawing( - fullPatternSimulationJobs[0]->pMesh->getLabel()); - DRMSimulationModel::Settings drmSettings; - SimulationResults fullModelResults - = drmSimulator.executeSimulation(pFullPatternSimulationJob, drmSettings); - fullModelResults.registerForDrawing(Colors::fullDeformed, true); - // SimulationResults fullModelLinearResults = - // linearSimulator.executeSimulation(pFullPatternSimulationJob); - // fullModelLinearResults.setLabelPrefix("linear"); - // fullModelLinearResults.registerForDrawing(Colors::fullDeformed,false); - // Drawing of reduced pattern results - const std::shared_ptr &pReducedPatternSimulationJob - = reducedPatternSimulationJobs[simulationJobIndex]; - // pReducedPatternSimulationJob->pMesh->registerForDrawing(); - // polyscope::show(); - // SimulationResults reducedModelResults = drmSimulator.executeSimulation( - // pReducedPatternSimulationJob); - // reducedModelResults.registerForDrawing(Colors::reducedDeformed, false); - // SimulationResults reducedModelResults - // = drmSimulator.executeSimulation(pReducedPatternSimulationJob, - // DRMSimulationModel::Settings()); - SimulationResults reducedModelResults = linearSimulator.executeSimulation( - pReducedPatternSimulationJob); - reducedModelResults.setLabelPrefix("linear"); - reducedModelResults.registerForDrawing(Colors::reducedDeformed, true); - polyscope::options::programName = fullPatternSimulationJobs[0]->pMesh->getLabel(); - // polyscope::view::resetCameraToHomeView(); - polyscope::show(); - // Save a screensh - const std::string screenshotFilename - = "/home/iason/Coding/Projects/Approximating shapes with flat " - "patterns/RodModelOptimizationForPatterns/Results/Images/" - + fullPatternSimulationJobs[0]->pMesh->getLabel() + "_" - + pFullPatternSimulationJob->getLabel(); - polyscope::screenshot(screenshotFilename, false); - pFullPatternSimulationJob->unregister(fullPatternSimulationJobs[0]->pMesh->getLabel()); - fullModelResults.unregister(); - // reducedModelResults.unregister(); - reducedModelResults.unregister(); - // fullModelLinearResults.unregister(); - // double error = computeError(reducedModelLinearResults.displacements, - // fullModelResults.displacements); - // std::cout << "Error of simulation scenario " - // << simulationScenarioStrings[simulationScenarioIndex] << " is " << error - // << std::endl; + const int numberOfSimulationJobs = fullPatternSimulationJobs.size(); + const std::vector scenariosToDraw = [&]() { + if (desiredSimulationScenariosIndices.empty()) { + std::vector v(numberOfSimulationJobs); + std::iota(v.begin(), v.end(), 0); //draw all + return v; + } else { + return desiredSimulationScenariosIndices; + } + }(); + + for (const int &simulationJobIndex : scenariosToDraw) { + // Drawing of full pattern results + const std::shared_ptr &pFullPatternSimulationJob + = fullPatternSimulationJobs[simulationJobIndex]; + pFullPatternSimulationJob->registerForDrawing( + fullPatternSimulationJobs[0]->pMesh->getLabel()); + DRMSimulationModel::Settings drmSettings; + SimulationResults fullModelResults + = drmSimulator.executeSimulation(pFullPatternSimulationJob, drmSettings); + fullModelResults.registerForDrawing(Colors::fullDeformed, true); + // SimulationResults fullModelLinearResults = + // linearSimulator.executeSimulation(pFullPatternSimulationJob); + // fullModelLinearResults.setLabelPrefix("linear"); + // fullModelLinearResults.registerForDrawing(Colors::fullDeformed,false); + // Drawing of reduced pattern results + const std::shared_ptr &pReducedPatternSimulationJob + = reducedPatternSimulationJobs[simulationJobIndex]; + // pReducedPatternSimulationJob->pMesh->registerForDrawing(); + // polyscope::show(); + // SimulationResults reducedModelResults = drmSimulator.executeSimulation( + // pReducedPatternSimulationJob); + // reducedModelResults.registerForDrawing(Colors::reducedDeformed, false); + // SimulationResults reducedModelResults + // = drmSimulator.executeSimulation(pReducedPatternSimulationJob, + // DRMSimulationModel::Settings()); + SimulationResults reducedModelResults = linearSimulator.executeSimulation( + pReducedPatternSimulationJob); + reducedModelResults.setLabelPrefix("linear"); + reducedModelResults.registerForDrawing(Colors::reducedDeformed, true); + polyscope::options::programName = fullPatternSimulationJobs[0]->pMesh->getLabel(); + // polyscope::view::resetCameraToHomeView(); + polyscope::show(); + // Save a screensh + const std::string screenshotFilename + = "/home/iason/Coding/Projects/Approximating shapes with flat " + "patterns/RodModelOptimizationForPatterns/Results/Images/" + + fullPatternSimulationJobs[0]->pMesh->getLabel() + "_" + + pFullPatternSimulationJob->getLabel(); + polyscope::screenshot(screenshotFilename, false); + pFullPatternSimulationJob->unregister(fullPatternSimulationJobs[0]->pMesh->getLabel()); + fullModelResults.unregister(); + // reducedModelResults.unregister(); + reducedModelResults.unregister(); + // fullModelLinearResults.unregister(); + // double error = computeError(reducedModelLinearResults.displacements, + // fullModelResults.displacements); + // std::cout << "Error of simulation scenario " + // << simulationScenarioStrings[simulationScenarioIndex] << " is " << error + // << std::endl; + } } - } #endif // POLYSCOPE_DEFINED void saveMeshFiles() const { const int numberOfSimulationJobs = fullPatternSimulationJobs.size(); @@ -1027,5 +1118,9 @@ struct Settings }; enum SimulationModelTag { DRM, Linear }; - } // namespace ReducedPatternOptimization + inline bool Settings::ObjectiveWeights::operator==(const ObjectiveWeights &other) const + { + return this->translational == other.translational && this->rotational == other.rotational; + } + } // namespace ReducedModelOptimization #endif // REDUCEDMODELOPTIMIZER_STRUCTS_HPP