Refactoring

This commit is contained in:
iasonmanolas 2022-01-05 14:10:49 +02:00
parent c9fc6ccd08
commit 282e1609c8
12 changed files with 566 additions and 300 deletions

View File

@ -1,7 +1,10 @@
cmake_minimum_required(VERSION 2.8) cmake_minimum_required(VERSION 2.8)
project(MySources) project(MySources)
set(CMAKE_CXX_STANDARD 20)
set(CMAKE_CXX_STANDARD_REQUIRED ON) file(GLOB MySourcesFiles ${CMAKE_CURRENT_LIST_DIR}/*.hpp ${CMAKE_CURRENT_LIST_DIR}/*.cpp)
add_library(${PROJECT_NAME} ${MySourcesFiles} )
target_compile_features(${PROJECT_NAME} PUBLIC cxx_std_20)
#Download external dependencies NOTE: If the user has one of these libs it shouldn't be downloaded again. #Download external dependencies NOTE: If the user has one of these libs it shouldn't be downloaded again.
include(${CMAKE_CURRENT_LIST_DIR}/cmake/DownloadProject.cmake) include(${CMAKE_CURRENT_LIST_DIR}/cmake/DownloadProject.cmake)
if (CMAKE_VERSION VERSION_LESS 3.2) if (CMAKE_VERSION VERSION_LESS 3.2)
@ -26,16 +29,18 @@ if(${USE_POLYSCOPE})
) )
add_subdirectory(${POLYSCOPE_SOURCE_DIR} ${POLYSCOPE_BINARY_DIR}) add_subdirectory(${POLYSCOPE_SOURCE_DIR} ${POLYSCOPE_BINARY_DIR})
add_compile_definitions(POLYSCOPE_DEFINED) add_compile_definitions(POLYSCOPE_DEFINED)
target_sources(${PROJECT_NAME} PUBLIC ${POLYSCOPE_SOURCE_DIR}/deps/imgui/imgui/misc/cpp/imgui_stdlib.cpp)
endif() endif()
##vcglib devel branch ##vcglib devel branch
download_project(PROJ vcglib_devel download_project(PROJ vcglib_devel
GIT_REPOSITORY https://github.com/IasonManolas/vcglib.git GIT_REPOSITORY https://gitea-s2i2s.isti.cnr.it/manolas/vcglib.git
GIT_TAG devel GIT_TAG devel
PREFIX ${EXTERNAL_DEPS_DIR} PREFIX ${EXTERNAL_DEPS_DIR}
${UPDATE_DISCONNECTED_IF_AVAILABLE} ${UPDATE_DISCONNECTED_IF_AVAILABLE}
) )
add_subdirectory(${vcglib_devel_SOURCE_DIR} ${vcglib_devel_BINARY_DIR}) add_subdirectory(${vcglib_devel_SOURCE_DIR} ${vcglib_devel_BINARY_DIR})
target_sources(${PROJECT_NAME} PUBLIC ${vcglib_devel_SOURCE_DIR}/wrap/ply/plylib.cpp)
##matplot++ lib ##matplot++ lib
set(MATPLOTPLUSPLUS_BINARY_DIR ${CMAKE_CURRENT_BINARY_DIR}/matplot) set(MATPLOTPLUSPLUS_BINARY_DIR ${CMAKE_CURRENT_BINARY_DIR}/matplot)
@ -77,23 +82,26 @@ if(MSVC)
add_compile_definitions(_HAS_STD_BYTE=0) add_compile_definitions(_HAS_STD_BYTE=0)
endif(MSVC) endif(MSVC)
#link_directories(${CMAKE_CURRENT_LIST_DIR}/boost_graph/libs) #link_directories(${CMAKE_CURRENT_LIST_DIR}/boost_graph/libs)
file(GLOB MySourcesFiles ${CMAKE_CURRENT_LIST_DIR}/*.hpp ${CMAKE_CURRENT_LIST_DIR}/*.cpp)
add_library(${PROJECT_NAME} ${MySourcesFiles} ${vcglib_devel_SOURCE_DIR}/wrap/ply/plylib.cpp)
target_include_directories(${PROJECT_NAME}
PUBLIC ${CMAKE_CURRENT_LIST_DIR}/boost_graph
PUBLIC ${vcglib_devel_SOURCE_DIR}
PUBLIC ${threed-beam-fea_SOURCE_DIR}
)
if(${MYSOURCES_STATIC_LINK}) if(${MYSOURCES_STATIC_LINK})
message("Linking statically") message("Linking statically")
target_link_libraries(${PROJECT_NAME} -static Eigen3::Eigen matplot ThreedBeamFEA ${TBB_BINARY_DIR}/libtbb_static.a pthread gfortran quadmath) target_link_libraries(${PROJECT_NAME} PUBLIC -static Eigen3::Eigen matplot ThreedBeamFEA ${TBB_BINARY_DIR}/libtbb_static.a #[[tbb_static]] pthread gfortran quadmath)
else() else()
target_link_libraries(${PROJECT_NAME} Eigen3::Eigen matplot ThreedBeamFEA tbb pthread) # set_target_properties(${PROJECT_NAME} PROPERTIES POSITION_INDEPENDENT_CODE TRUE)
target_link_libraries(${PROJECT_NAME} PUBLIC Eigen3::Eigen matplot ThreedBeamFEA tbb pthread)
if(${USE_POLYSCOPE}) if(${USE_POLYSCOPE})
target_link_libraries(${PROJECT_NAME} polyscope) message("Using polyscope")
target_link_libraries(${PROJECT_NAME} PUBLIC polyscope)
endif() endif()
endif() endif()
target_link_directories(MySources PUBLIC ${CMAKE_CURRENT_LIST_DIR}/boost_graph/libs) target_link_directories(MySources PUBLIC ${CMAKE_CURRENT_LIST_DIR}/boost_graph/libs)
target_include_directories(${PROJECT_NAME}
PUBLIC ${CMAKE_CURRENT_LIST_DIR}/boost_graph
PUBLIC ${vcglib_devel_SOURCE_DIR}
# PUBLIC ${threed-beam-fea_SOURCE_DIR}
PUBLIC ThreedBeamFEA
PUBLIC matplot
)
if(USE_ENSMALLEN) if(USE_ENSMALLEN)
##ENSMALLEN ##ENSMALLEN
@ -113,5 +121,5 @@ if(USE_ENSMALLEN)
else() else()
target_link_libraries(${PROJECT_NAME} PUBLIC armadillo ensmallen) target_link_libraries(${PROJECT_NAME} PUBLIC armadillo ensmallen)
endif() endif()
target_include_directories(${PROJECT_NAME} PUBLIC ${ARMADILLO_SOURCE_DIR}/include) target_include_directories(${PROJECT_NAME} PUBLIC ${ARMADILLO_SOURCE_DIR}/include ${ENSMALLEN_SOURCE_DIR})
endif() endif()

View File

@ -1889,7 +1889,7 @@ void DRMSimulationModel::printCurrentState() const
void DRMSimulationModel::printDebugInfo() const void DRMSimulationModel::printDebugInfo() const
{ {
std::cout << pMesh->elements[0].rigidity.toString() << std::endl; std::cout << pMesh->elements[0].rigidity.toString() << std::endl;
std::cout << "Number of dampings:" << numOfDampings << endl; std::cout << "Number of dampings:" << numOfDampings << std::endl;
printCurrentState(); printCurrentState();
} }

View File

@ -152,7 +152,7 @@ private:
const std::unordered_map<VertexIndex, std::unordered_set<DoFType>> &fixedVertices); const std::unordered_map<VertexIndex, std::unordered_set<DoFType>> &fixedVertices);
#ifdef POLYSCOPE_DEFINED #ifdef POLYSCOPE_DEFINED
void draw(const string &screenshotsFolder= {}); void draw(const std::string &screenshotsFolder = {});
#endif #endif
void void
updateNodalInternalForce(Vector6d &nodalInternalForce, updateNodalInternalForce(Vector6d &nodalInternalForce,

View File

@ -25,7 +25,7 @@ Eigen::MatrixX3d VCGEdgeMesh::getEigenEdgeNormals() const {
return eigenEdgeNormals; return eigenEdgeNormals;
} }
bool VCGEdgeMesh::save(const string &plyFilename) bool VCGEdgeMesh::save(const std::string &plyFilename)
{ {
std::string filename = plyFilename; std::string filename = plyFilename;
if (filename.empty()) { if (filename.empty()) {
@ -197,36 +197,36 @@ bool VCGEdgeMesh::createSpanGrid(const size_t desiredWidth,
return true; return true;
} }
bool VCGEdgeMesh::load(const string &plyFilename) { bool VCGEdgeMesh::load(const std::string &plyFilename)
{
std::string usedPath = plyFilename;
if (std::filesystem::path(plyFilename).is_relative()) {
usedPath = std::filesystem::absolute(plyFilename).string();
}
assert(std::filesystem::exists(usedPath));
Clear();
// if (!loadUsingNanoply(usedPath)) {
// std::cerr << "Error: Unable to open " + usedPath << std::endl;
// return false;
// }
if (!loadUsingDefaultLoader(usedPath)) {
std::cerr << "Error: Unable to open " + usedPath << std::endl;
return false;
}
std::string usedPath = plyFilename; getEdges(eigenEdges);
if (std::filesystem::path(plyFilename).is_relative()) { getVertices(eigenVertices);
usedPath = std::filesystem::absolute(plyFilename).string(); vcg::tri::UpdateTopology<VCGEdgeMesh>::VertexEdge(*this);
} label = std::filesystem::path(plyFilename).stem().string();
assert(std::filesystem::exists(usedPath));
Clear();
// if (!loadUsingNanoply(usedPath)) {
// std::cerr << "Error: Unable to open " + usedPath << std::endl;
// return false;
// }
if (!loadUsingDefaultLoader(usedPath)) {
std::cerr << "Error: Unable to open " + usedPath << std::endl;
return false;
}
getEdges(eigenEdges); const bool printDebugInfo = false;
getVertices(eigenVertices); if (printDebugInfo) {
vcg::tri::UpdateTopology<VCGEdgeMesh>::VertexEdge(*this); std::cout << plyFilename << " was loaded successfuly." << std::endl;
label = std::filesystem::path(plyFilename).stem().string(); std::cout << "Mesh has " << EN() << " edges." << std::endl;
}
const bool printDebugInfo = false; label = std::filesystem::path(plyFilename).stem().string();
if (printDebugInfo) { return true;
std::cout << plyFilename << " was loaded successfuly." << std::endl;
std::cout << "Mesh has " << EN() << " edges." << std::endl;
}
label=std::filesystem::path(plyFilename).stem().string();
return true;
} }
//bool VCGEdgeMesh::loadUsingNanoply(const std::string &plyFilename) { //bool VCGEdgeMesh::loadUsingNanoply(const std::string &plyFilename) {

View File

@ -108,8 +108,6 @@ SimulationResults LinearSimulationModel::getResults(
Eigen::Quaternion<double> q_nz; Eigen::Quaternion<double> q_nz;
q_nz = Eigen::AngleAxis<double>(nodalDisplacement[5], Eigen::Vector3d(0, 0, 1)); q_nz = Eigen::AngleAxis<double>(nodalDisplacement[5], Eigen::Vector3d(0, 0, 1));
results.rotationalDisplacementQuaternion[vi] = q_nx * q_ny * q_nz; results.rotationalDisplacementQuaternion[vi] = q_nx * q_ny * q_nz;
// results.rotationalDisplacementQuaternion[vi] = q_nz * q_ny * q_nx;
// results.rotationalDisplacementQuaternion[vi] = q_nz * q_nx * q_ny;
} }
results.setLabelPrefix("Linear"); results.setLabelPrefix("Linear");
@ -214,7 +212,11 @@ SimulationResults LinearSimulationModel::executeSimulation(
const std::shared_ptr<SimulationJob> &pSimulationJob) const std::shared_ptr<SimulationJob> &pSimulationJob)
{ {
assert(pSimulationJob->pMesh->VN() != 0); assert(pSimulationJob->pMesh->VN() != 0);
if (!simulator.wasInitialized()) { const bool wasInitializedWithDifferentStructure = pSimulationJob->pMesh->EN()
!= simulator.structure.elems.size()
|| pSimulationJob->pMesh->VN()
!= simulator.structure.nodes.size();
if (!simulator.wasInitialized() || wasInitializedWithDifferentStructure) {
setStructure(pSimulationJob->pMesh); setStructure(pSimulationJob->pMesh);
} }
// printInfo(job); // printInfo(job);

View File

@ -34,9 +34,9 @@ struct Colors
struct xRange struct xRange
{ {
std::string label; std::string label{};
double min; double min{0};
double max; double max{0};
inline bool operator<(const xRange &other) { return label < other.label; } inline bool operator<(const xRange &other) { return label < other.label; }
std::string toString() const std::string toString() const
@ -60,120 +60,321 @@ struct xRange
{ {
return label == xrange.label && min == xrange.min && max == xrange.max; return label == xrange.label && min == xrange.min && max == xrange.max;
} }
std::tuple<std::string, double, double> toTuple() const
{
return std::make_tuple(label, min, max);
}
void set(const std::tuple<std::string, double, double> &inputTuple)
{
if (std::get<1>(inputTuple) > std::get<2>(inputTuple)) {
std::cerr
<< "Invalid xRange tuple. Second argument(min) cant be smaller than the third(max)"
<< std::endl;
std::terminate();
// return;
}
std::tie(label, min, max) = inputTuple;
}
}; };
enum OptimizationParameterIndex { E, A, I2, I3, J, R, Theta, NumberOfOptimizationParameters }; enum OptimizationParameterIndex { E, A, I2, I3, J, R, Theta, NumberOfOptimizationVariables };
inline int getParameterIndex(const std::string &s)
{
if ("E" == s) {
return E;
} else if ("A" == s) {
return A;
} else if ("I2" == s) {
return I2;
} else if ("I3" == s) {
return I3;
} else if ("J" == s) {
return J;
} else if ("R" == s || "HexSize" == s) {
return R;
} else if ("Theta" == s || "HexAngle" == s) {
return Theta;
} else {
std::cerr << "Input is not recognized as a valid optimization variable index:" << s
<< std::endl;
return -1;
}
}
struct Settings struct Settings
{ {
std::filesystem::path intermediateResultsDirectoryPath; inline static std::string defaultFilename{"OptimizationSettings.json"};
std::vector<std::vector<OptimizationParameterIndex>> optimizationVariables; std::vector<std::vector<OptimizationParameterIndex>> optimizationStrategy;
std::optional<std::vector<double>>
optimizationVariablesGroupsWeights; //TODO:should be removed in the future if not a splitting strategy is used for the optimization
enum NormalizationStrategy { NonNormalized, Epsilon }; enum NormalizationStrategy { NonNormalized, Epsilon };
std::vector<xRange> parameterRanges; inline static std::vector<std::string> normalizationStrategyStrings{"NonNormalized", "Epsilon"};
inline static vector<std::string> normalizationStrategyStrings{"NonNormalized", "Epsilon"};
int numberOfFunctionCalls{100000};
double solverAccuracy{1e-2};
NormalizationStrategy normalizationStrategy{Epsilon}; NormalizationStrategy normalizationStrategy{Epsilon};
double translationNormalizationParameter{0.003}; std::array<xRange, NumberOfOptimizationVariables> variablesRanges;
double rotationNormalizationParameter{3}; int numberOfFunctionCalls{100000};
double solverAccuracy{1e-3};
double translationNormalizationEpsilon{1e-4};
double rotationNormalizationEpsilon{vcg::math::ToRad(3.0)};
struct ObjectiveWeights struct ObjectiveWeights
{ {
double translational{1}; double translational{1};
double rotational{1}; double rotational{1};
} objectiveWeights; bool operator==(const ObjectiveWeights &other) const
{
return this->translational == other.translational
&& this->rotational == other.rotational;
}
};
std::array<ObjectiveWeights, NumberOfBaseSimulationScenarios> perBaseScenarioObjectiveWeights;
std::array<std::pair<double, double>, NumberOfBaseSimulationScenarios>
convertObjectiveWeightsToPairs() const
{
std::array<std::pair<double, double>, NumberOfBaseSimulationScenarios> objectiveWeightsPairs;
for (int baseScenario = Axial; baseScenario != NumberOfBaseSimulationScenarios;
baseScenario++) {
objectiveWeightsPairs[baseScenario]
= std::make_pair(perBaseScenarioObjectiveWeights[baseScenario].translational,
perBaseScenarioObjectiveWeights[baseScenario].rotational);
}
return objectiveWeightsPairs;
}
struct JsonKeys struct JsonKeys
{ {
inline static std::string filename{"OptimizationSettings.json"}; inline static std::string OptimizationStrategy{"OptimizationStrategy"};
inline static std::string OptimizationStrategyGroupWeights{
"OptimizationStrategyGroupWeights"};
inline static std::string OptimizationVariables{"OptimizationVariables"}; inline static std::string OptimizationVariables{"OptimizationVariables"};
inline static std::string NumberOfFunctionCalls{"NumberOfFunctionCalls"}; inline static std::string NumberOfFunctionCalls{"NumberOfFunctionCalls"};
inline static std::string SolverAccuracy{"SolverAccuracy"}; inline static std::string SolverAccuracy{"SolverAccuracy"};
inline static std::string TranslationalObjectiveWeight{"TransObjWeight"}; inline static std::string ObjectiveWeights{"ObjectiveWeight"};
inline static std::string OptimizationParameters{"OptimizationParameters"};
}; };
void setDefault()
{
ReducedPatternOptimization::xRange beamE{"E", 0.001, 1000};
ReducedPatternOptimization::xRange beamA{"A", 0.001, 1000};
ReducedPatternOptimization::xRange beamI2{"I2", 0.001, 1000};
ReducedPatternOptimization::xRange beamI3{"I3", 0.001, 1000};
ReducedPatternOptimization::xRange beamJ{"J", 0.001, 1000};
ReducedPatternOptimization::xRange innerHexagonSize{"R", 0.05, 0.95};
ReducedPatternOptimization::xRange innerHexagonAngle{"Theta", -30.0, 30.0};
variablesRanges = {beamE, beamA, beamI2, beamI3, beamJ, innerHexagonSize, innerHexagonAngle};
numberOfFunctionCalls = 100000;
enum OptimizationParameterComparisonScenarioIndex {
AllVar,
GeoYM,
MatGeo,
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[MatGeo] = {{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 = MatGeo;
optimizationStrategy = optimizationParameters[scenario];
if (scenario == YMGeo_Mat) {
optimizationVariablesGroupsWeights = {0.15, 0.85};
}
normalizationStrategy = ReducedPatternOptimization::Settings::NormalizationStrategy::Epsilon;
//#ifdef POLYSCOPE_DEFINED
//#else
translationNormalizationEpsilon = 4e-3;
rotationNormalizationEpsilon = vcg::math::ToRad(3.0);
// translationNormalizationParameter = 0;
// rotationNormalizationParameter = 0;
// translationNormalizationParameter = 1e-3;
// rotationNormalizationParameter = vcg::math::ToRad(3.0);
// translationNormalizationParameter = 5e-2;
// rotationNormalizationParameter = vcg::math::ToRad(3.0);
//#endif
solverAccuracy = 1e-2;
//TODO refactor that
perBaseScenarioObjectiveWeights[ReducedPatternOptimization::Axial].translational = 1.5;
perBaseScenarioObjectiveWeights[ReducedPatternOptimization::Axial].rotational
= 2 - perBaseScenarioObjectiveWeights[ReducedPatternOptimization::Axial].translational;
perBaseScenarioObjectiveWeights[ReducedPatternOptimization::Shear].translational = 1.5;
perBaseScenarioObjectiveWeights[ReducedPatternOptimization::Shear].rotational
= 2 - perBaseScenarioObjectiveWeights[ReducedPatternOptimization::Shear].translational;
perBaseScenarioObjectiveWeights[ReducedPatternOptimization::Bending].translational = 1.2;
perBaseScenarioObjectiveWeights[ReducedPatternOptimization::Bending].rotational
= 2
- perBaseScenarioObjectiveWeights[ReducedPatternOptimization::Bending].translational;
perBaseScenarioObjectiveWeights[ReducedPatternOptimization::Dome].translational = 1.95;
perBaseScenarioObjectiveWeights[ReducedPatternOptimization::Dome].rotational
= 2 - perBaseScenarioObjectiveWeights[ReducedPatternOptimization::Dome].translational;
perBaseScenarioObjectiveWeights[ReducedPatternOptimization::Saddle].translational = 1.2;
perBaseScenarioObjectiveWeights[ReducedPatternOptimization::Saddle].rotational
= 2 - perBaseScenarioObjectiveWeights[ReducedPatternOptimization::Saddle].translational;
}
void save(const std::filesystem::path &saveToPath) void save(const std::filesystem::path &saveToPath)
{ {
assert(std::filesystem::is_directory(saveToPath)); assert(std::filesystem::is_directory(saveToPath));
nlohmann::json json; nlohmann::json json;
//write x ranges json[JsonKeys::OptimizationStrategy] = optimizationStrategy;
for (size_t xRangeIndex = 0; xRangeIndex < parameterRanges.size(); xRangeIndex++) { if (optimizationVariablesGroupsWeights.has_value()) {
const auto &xRange = parameterRanges[xRangeIndex]; json[JsonKeys::OptimizationStrategyGroupWeights] = optimizationVariablesGroupsWeights
json[JsonKeys::OptimizationVariables + "_" + std::to_string(xRangeIndex)] .value();
= xRange.toString();
} }
//write x ranges
const std::array<std::tuple<std::string, double, double>, NumberOfOptimizationVariables>
xRangesAsTuples = [=]() {
std::array<std::tuple<std::string, double, double>, NumberOfOptimizationVariables>
xRangesAsTuples;
for (int optimizationParameterIndex = E;
optimizationParameterIndex != NumberOfOptimizationVariables;
optimizationParameterIndex++) {
xRangesAsTuples[optimizationParameterIndex]
= variablesRanges[optimizationParameterIndex].toTuple();
}
return xRangesAsTuples;
}();
json[JsonKeys::OptimizationVariables] = xRangesAsTuples;
// for (size_t xRangeIndex = 0; xRangeIndex < variablesRanges.size(); xRangeIndex++) {
// const auto &xRange = variablesRanges[xRangeIndex];
// json[JsonKeys::OptimizationVariables + "_" + std::to_string(xRangeIndex)]
// = xRange.toString();
// }
json[JsonKeys::NumberOfFunctionCalls] = numberOfFunctionCalls; json[JsonKeys::NumberOfFunctionCalls] = numberOfFunctionCalls;
json[JsonKeys::SolverAccuracy] = solverAccuracy; json[JsonKeys::SolverAccuracy] = solverAccuracy;
json[JsonKeys::TranslationalObjectiveWeight] = objectiveWeights.translational; //Objective weights
json[JsonKeys::OptimizationParameters] = optimizationVariables; std::array<std::pair<double, double>, NumberOfBaseSimulationScenarios> objectiveWeightsPairs;
std::transform(perBaseScenarioObjectiveWeights.begin(),
perBaseScenarioObjectiveWeights.end(),
objectiveWeightsPairs.begin(),
[](const ObjectiveWeights &objectiveWeights) {
return std::make_pair(objectiveWeights.translational,
objectiveWeights.rotational);
});
json[JsonKeys::ObjectiveWeights] = objectiveWeightsPairs;
std::filesystem::path jsonFilePath( std::filesystem::path jsonFilePath(
std::filesystem::path(saveToPath).append(JsonKeys::filename)); std::filesystem::path(saveToPath).append(defaultFilename));
std::ofstream jsonFile(jsonFilePath.string()); std::ofstream jsonFile(jsonFilePath.string());
jsonFile << json; jsonFile << json;
} }
bool load(const std::filesystem::path &loadFromPath) bool load(const std::filesystem::path &jsonFilepath)
{ {
assert(std::filesystem::is_directory(loadFromPath));
//Load optimal X
nlohmann::json json; nlohmann::json json;
std::filesystem::path jsonFilepath(
std::filesystem::path(loadFromPath).append(JsonKeys::filename));
if (!std::filesystem::exists(jsonFilepath)) { if (!std::filesystem::exists(jsonFilepath)) {
std::cerr << "Optimization settings could not be loaded because input filepath does "
"not exist:"
<< jsonFilepath << std::endl;
return false; return false;
} }
std::ifstream ifs(jsonFilepath); std::ifstream ifs(jsonFilepath);
ifs >> json; ifs >> json;
if (json.contains(JsonKeys::OptimizationStrategy)) {
optimizationStrategy
= std::vector<std::vector<ReducedPatternOptimization::OptimizationParameterIndex>>(
(json.at(JsonKeys::OptimizationStrategy)));
}
if (json.contains(JsonKeys::OptimizationStrategyGroupWeights)) {
optimizationVariablesGroupsWeights = std::vector<double>(
json[JsonKeys::OptimizationStrategyGroupWeights]);
}
//read x ranges //read x ranges
size_t xRangeIndex = 0; if (json.contains(JsonKeys::OptimizationVariables)) {
while (true) { const std::array<std::tuple<std::string, double, double>, NumberOfOptimizationVariables>
const std::string jsonXRangeKey = JsonKeys::OptimizationVariables + "_" xRangesAsTuples = json.at(JsonKeys::OptimizationVariables);
+ std::to_string(xRangeIndex); for (const auto &rangeTuple : xRangesAsTuples) {
if (!json.contains(jsonXRangeKey)) { variablesRanges[getParameterIndex(std::get<0>(rangeTuple))].set(rangeTuple);
break; }
} else { //NOTE:legacy compatibility
size_t xRangeIndex = 0;
while (true) {
const std::string jsonXRangeKey = JsonKeys::OptimizationVariables + "_"
+ std::to_string(xRangeIndex++);
if (!json.contains(jsonXRangeKey)) {
break;
}
xRange x;
x.fromString(json.at(jsonXRangeKey));
variablesRanges[getParameterIndex(x.label)] = x;
} }
xRange x;
x.fromString(json.at(jsonXRangeKey));
parameterRanges.push_back(x);
xRangeIndex++;
} }
optimizationVariables
= std::vector<std::vector<ReducedPatternOptimization::OptimizationParameterIndex>>(
(json.at(JsonKeys::OptimizationParameters)));
numberOfFunctionCalls = json.at(JsonKeys::NumberOfFunctionCalls); numberOfFunctionCalls = json.at(JsonKeys::NumberOfFunctionCalls);
solverAccuracy = json.at(JsonKeys::SolverAccuracy); solverAccuracy = json.at(JsonKeys::SolverAccuracy);
objectiveWeights.translational = json.at(JsonKeys::TranslationalObjectiveWeight); //Objective weights
objectiveWeights.rotational = 2 - objectiveWeights.translational; if (json.contains(JsonKeys::ObjectiveWeights)) {
std::array<std::pair<double, double>, NumberOfBaseSimulationScenarios>
objectiveWeightsPairs = json.at(JsonKeys::ObjectiveWeights);
std::transform(objectiveWeightsPairs.begin(),
objectiveWeightsPairs.end(),
perBaseScenarioObjectiveWeights.begin(),
[](const std::pair<double, double> &objectiveWeightsPair) {
return ObjectiveWeights{objectiveWeightsPair.first,
objectiveWeightsPair.second};
});
}
// perBaseScenarioObjectiveWeights = json.at(JsonKeys::ObjectiveWeights);
// objectiveWeights.translational = json.at(JsonKeys::ObjectiveWeights);
// objectiveWeights.rotational = 2 - objectiveWeights.translational;
return true; return true;
} }
std::string toString() const std::string toString() const
{ {
std::string settingsString; std::string settingsString;
if (!parameterRanges.empty()) { if (!variablesRanges.empty()) {
std::string xRangesString; std::string xRangesString;
for (const xRange &range : parameterRanges) { for (const xRange &range : variablesRanges) {
xRangesString += range.toString() + " "; xRangesString += range.toString() + " ";
} }
settingsString += xRangesString; settingsString += xRangesString;
} }
settingsString += "FuncCalls=" + std::to_string(numberOfFunctionCalls) settingsString += "FuncCalls=" + std::to_string(numberOfFunctionCalls)
+ " Accuracy=" + std::to_string(solverAccuracy) + " Accuracy=" + std::to_string(solverAccuracy);
+ " TransWeight=" + std::to_string(objectiveWeights.translational) for (int baseScenario = Axial; baseScenario != NumberOfBaseSimulationScenarios;
+ " RotWeight=" + std::to_string(objectiveWeights.rotational); baseScenario++) {
+" W_t=" + std::to_string(perBaseScenarioObjectiveWeights[baseScenario].translational)
+ " W_r="
+ std::to_string(perBaseScenarioObjectiveWeights[baseScenario].rotational);
}
return settingsString; return settingsString;
} }
void writeHeaderTo(csvFile &os) const void writeHeaderTo(csvFile &os) const
{ {
if (!parameterRanges.empty()) { if (!variablesRanges.empty()) {
for (const xRange &range : parameterRanges) { for (const xRange &range : variablesRanges) {
os << range.label + " max"; os << range.label + " max";
os << range.label + " min"; os << range.label + " min";
} }
@ -181,16 +382,15 @@ struct Settings
os << "Function Calls"; os << "Function Calls";
os << "Solution Accuracy"; os << "Solution Accuracy";
os << "Normalization strategy"; os << "Normalization strategy";
os << "Trans weight"; os << JsonKeys::ObjectiveWeights;
os << "Rot weight";
os << "Optimization parameters"; os << "Optimization parameters";
// os << std::endl; // os << std::endl;
} }
void writeSettingsTo(csvFile &os) const void writeSettingsTo(csvFile &os) const
{ {
if (!parameterRanges.empty()) { if (!variablesRanges.empty()) {
for (const xRange &range : parameterRanges) { for (const xRange &range : variablesRanges) {
os << range.max; os << range.max;
os << range.min; os << range.min;
} }
@ -198,13 +398,22 @@ struct Settings
os << numberOfFunctionCalls; os << numberOfFunctionCalls;
os << solverAccuracy; os << solverAccuracy;
os << normalizationStrategyStrings[normalizationStrategy] + "_" os << normalizationStrategyStrings[normalizationStrategy] + "_"
+ std::to_string(translationNormalizationParameter); + std::to_string(translationNormalizationEpsilon);
os << objectiveWeights.translational; std::string objectiveWeightsString;
os << objectiveWeights.rotational; objectiveWeightsString += "{";
for (int baseScenario = Axial; baseScenario != NumberOfBaseSimulationScenarios;
baseScenario++) {
objectiveWeightsString
+= "{" + std::to_string(perBaseScenarioObjectiveWeights[baseScenario].translational)
+ "," + std::to_string(perBaseScenarioObjectiveWeights[baseScenario].rotational)
+ "}";
}
objectiveWeightsString += "}";
os << objectiveWeightsString;
//export optimization parameters //export optimization parameters
std::vector<std::vector<int>> vv; std::vector<std::vector<int>> vv;
for (const std::vector<OptimizationParameterIndex> &v : optimizationVariables) { for (const std::vector<OptimizationParameterIndex> &v : optimizationStrategy) {
std::vector<int> vi; std::vector<int> vi;
vi.reserve(v.size()); vi.reserve(v.size());
for (const OptimizationParameterIndex &parameter : v) { for (const OptimizationParameterIndex &parameter : v) {
@ -218,12 +427,17 @@ struct Settings
inline bool operator==(const Settings &settings1, const Settings &settings2) noexcept inline bool operator==(const Settings &settings1, const Settings &settings2) noexcept
{ {
const bool haveTheSameObjectiveWeights
= std::mismatch(settings1.perBaseScenarioObjectiveWeights.begin(),
settings1.perBaseScenarioObjectiveWeights.end(),
settings2.perBaseScenarioObjectiveWeights.begin())
.first
!= settings1.perBaseScenarioObjectiveWeights.end();
return settings1.numberOfFunctionCalls == settings2.numberOfFunctionCalls return settings1.numberOfFunctionCalls == settings2.numberOfFunctionCalls
&& settings1.parameterRanges == settings2.parameterRanges && settings1.variablesRanges == settings2.variablesRanges
&& settings1.solverAccuracy == settings2.solverAccuracy && settings1.solverAccuracy == settings2.solverAccuracy && haveTheSameObjectiveWeights
&& settings1.objectiveWeights.translational == settings2.objectiveWeights.translational && settings1.translationNormalizationEpsilon
&& settings1.translationNormalizationParameter == settings2.translationNormalizationEpsilon;
== settings2.translationNormalizationParameter;
} }
inline void updateMeshWithOptimalVariables(const std::vector<double> &x, SimulationMesh &m) inline void updateMeshWithOptimalVariables(const std::vector<double> &x, SimulationMesh &m)
@ -306,6 +520,7 @@ struct Settings
std::vector<double> perSimulationScenario_translational; std::vector<double> perSimulationScenario_translational;
std::vector<double> perSimulationScenario_rotational; std::vector<double> perSimulationScenario_rotational;
std::vector<double> perSimulationScenario_total; std::vector<double> perSimulationScenario_total;
std::vector<double> perSimulationScenario_total_unweighted;
} objectiveValue; } objectiveValue;
std::vector<double> perScenario_fullPatternPotentialEnergy; std::vector<double> perScenario_fullPatternPotentialEnergy;
std::vector<double> objectiveValueHistory; std::vector<double> objectiveValueHistory;
@ -332,7 +547,7 @@ struct Settings
inline static std::string fullPatternYoungsModulus{"youngsModulus"}; inline static std::string fullPatternYoungsModulus{"youngsModulus"};
}; };
void save(const string &saveToPath, const bool shouldExportDebugFiles = false) void save(const std::string &saveToPath, const bool shouldExportDebugFiles = false)
{ {
//clear directory //clear directory
if (std::filesystem::exists(saveToPath)) { if (std::filesystem::exists(saveToPath)) {
@ -405,7 +620,8 @@ struct Settings
= fullPatternSimulationJobs[simulationScenarioIndex]; = fullPatternSimulationJobs[simulationScenarioIndex];
std::filesystem::path simulationJobFolderPath( std::filesystem::path simulationJobFolderPath(
std::filesystem::path(simulationJobsPath) std::filesystem::path(simulationJobsPath)
.append(pFullPatternSimulationJob->label)); .append(std::to_string(simulationScenarioIndex) + "_"
+ pFullPatternSimulationJob->label));
std::filesystem::create_directories(simulationJobFolderPath); std::filesystem::create_directories(simulationJobFolderPath);
const auto fullPatternDirectoryPath const auto fullPatternDirectoryPath
= std::filesystem::path(simulationJobFolderPath).append("Full"); = std::filesystem::path(simulationJobFolderPath).append("Full");
@ -435,7 +651,7 @@ struct Settings
#endif #endif
} }
bool load(const string &loadFromPath, const bool &shouldLoadDebugFiles = false) bool load(const std::string &loadFromPath, const bool &shouldLoadDebugFiles = false)
{ {
assert(std::filesystem::is_directory(loadFromPath)); assert(std::filesystem::is_directory(loadFromPath));
std::filesystem::path jsonFilepath( std::filesystem::path jsonFilepath(
@ -496,40 +712,36 @@ struct Settings
if (shouldLoadDebugFiles) { if (shouldLoadDebugFiles) {
const std::filesystem::path simulationJobsFolderPath( const std::filesystem::path simulationJobsFolderPath(
std::filesystem::path(loadFromPath).append("SimulationJobs")); std::filesystem::path(loadFromPath).append("SimulationJobs"));
for (const auto &directoryEntry :
filesystem::directory_iterator(simulationJobsFolderPath)) { std::vector<std::filesystem::path> sortedByName;
const auto simulationScenarioPath = directoryEntry.path(); 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) {
if (!std::filesystem::is_directory(simulationScenarioPath)) { if (!std::filesystem::is_directory(simulationScenarioPath)) {
continue; continue;
} }
// Load full pattern files
for (const auto &fileEntry : 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<SimulationJob>(job));
}
}
// Load reduced pattern files and apply optimal parameters const auto fullJobFilepath = Utilities::getFilepathWithExtension(
for (const auto &fileEntry : filesystem::directory_iterator( std::filesystem::path(simulationScenarioPath).append("Full"), ".json");
std::filesystem::path(simulationScenarioPath).append("Reduced"))) { SimulationJob fullJob;
const auto filepath = fileEntry.path(); fullJob.load(fullJobFilepath.string());
if (filepath.extension() == ".json") { fullJob.pMesh->setBeamMaterial(0.3, fullPatternYoungsModulus);
SimulationJob job; fullPatternSimulationJobs.push_back(std::make_shared<SimulationJob>(fullJob));
job.load(filepath.string());
// applyOptimizationResults_innerHexagon(*this, baseTriangle, *job.pMesh); const auto reducedJobFilepath = Utilities::getFilepathWithExtension(
applyOptimizationResults_elements(*this, job.pMesh); std::filesystem::path(simulationScenarioPath).append("Reduced"), ".json");
reducedPatternSimulationJobs.push_back( SimulationJob reducedJob;
std::make_shared<SimulationJob>(job)); reducedJob.load(reducedJobFilepath.string());
} // applyOptimizationResults_innerHexagon(*this, baseTriangle, *job.pMesh);
} applyOptimizationResults_elements(*this, reducedJob.pMesh);
reducedPatternSimulationJobs.push_back(
std::make_shared<SimulationJob>(reducedJob));
} }
} }
settings.load(loadFromPath); settings.load(std::filesystem::path(loadFromPath).append(Settings::defaultFilename));
return true; return true;
} }
@ -543,9 +755,16 @@ struct Settings
std::unordered_map<std::string, double> std::unordered_map<std::string, double>
optimalXVariables(reducedPattern_optimizationResults.optimalXNameValuePairs.begin(), optimalXVariables(reducedPattern_optimizationResults.optimalXNameValuePairs.begin(),
reducedPattern_optimizationResults.optimalXNameValuePairs.end()); reducedPattern_optimizationResults.optimalXNameValuePairs.end());
assert(optimalXVariables.contains("HexSize") && optimalXVariables.contains("HexAngle")); assert(optimalXVariables.contains("R") && optimalXVariables.contains("Theta"));
applyOptimizationResults_innerHexagon(optimalXVariables.at("HexSize"), if (optimalXVariables.contains("HexSize")) {
optimalXVariables.at("HexAngle"), applyOptimizationResults_innerHexagon(optimalXVariables.at("HexSize"),
optimalXVariables.at("HexAngle"),
patternBaseTriangle,
reducedPattern);
return;
}
applyOptimizationResults_innerHexagon(optimalXVariables.at("R"),
optimalXVariables.at("Theta"),
patternBaseTriangle, patternBaseTriangle,
reducedPattern); reducedPattern);
} }
@ -589,7 +808,7 @@ struct Settings
static void applyOptimizationResults_elements( static void applyOptimizationResults_elements(
const ReducedPatternOptimization::Results &reducedPattern_optimizationResults, const ReducedPatternOptimization::Results &reducedPattern_optimizationResults,
const shared_ptr<SimulationMesh> &pTiledReducedPattern_simulationMesh) const std::shared_ptr<SimulationMesh> &pTiledReducedPattern_simulationMesh)
{ {
assert(CrossSectionType::name == RectangularBeamDimensions::name); assert(CrossSectionType::name == RectangularBeamDimensions::name);
// Set reduced parameters fron the optimization results // Set reduced parameters fron the optimization results

View File

@ -133,32 +133,32 @@ public:
return constrainedVertices.empty() && nodalExternalForces.empty() return constrainedVertices.empty() && nodalExternalForces.empty()
&& nodalForcedDisplacements.empty() && pMesh == nullptr; && nodalForcedDisplacements.empty() && pMesh == nullptr;
} }
void remap(const std::unordered_map<size_t, size_t> &thisToOtherViMap, void remap(const std::unordered_map<size_t, size_t> &sourceToDestinationViMap,
SimulationJob &simulationJobMapped) const SimulationJob &destination_simulationJob) const
{ {
assert(simulationJobMapped.pMesh->VN() != 0); std::unordered_map<VertexIndex, std::unordered_set<int>> destination_fixedVertices;
std::unordered_map<VertexIndex, std::unordered_set<int>> reducedModelFixedVertices; for (const auto &source_fixedVertex : this->constrainedVertices) {
for (auto fullModelFixedVertex : this->constrainedVertices) { destination_fixedVertices[sourceToDestinationViMap.at(source_fixedVertex.first)]
reducedModelFixedVertices[thisToOtherViMap.at(fullModelFixedVertex.first)] = source_fixedVertex.second;
= fullModelFixedVertex.second;
} }
std::unordered_map<VertexIndex, Vector6d> reducedModelNodalForces; std::unordered_map<VertexIndex, Vector6d> destination_nodalForces;
for (auto fullModelNodalForce : this->nodalExternalForces) { for (const auto &source_nodalForces : this->nodalExternalForces) {
reducedModelNodalForces[thisToOtherViMap.at(fullModelNodalForce.first)] destination_nodalForces[sourceToDestinationViMap.at(source_nodalForces.first)]
= fullModelNodalForce.second; = source_nodalForces.second;
} }
std::unordered_map<VertexIndex, Eigen::Vector3d> reducedNodalForcedDisplacements; std::unordered_map<VertexIndex, Eigen::Vector3d> destination_forcedDisplacements;
for (auto fullForcedDisplacement : this->nodalForcedDisplacements) { for (const auto &source_forcedDisplacements : this->nodalForcedDisplacements) {
reducedNodalForcedDisplacements[thisToOtherViMap.at(fullForcedDisplacement.first)] destination_forcedDisplacements[sourceToDestinationViMap.at(
= fullForcedDisplacement.second; source_forcedDisplacements.first)]
= source_forcedDisplacements.second;
} }
simulationJobMapped.constrainedVertices = reducedModelFixedVertices; destination_simulationJob.constrainedVertices = destination_fixedVertices;
simulationJobMapped.nodalExternalForces = reducedModelNodalForces; destination_simulationJob.nodalExternalForces = destination_nodalForces;
simulationJobMapped.label = this->getLabel(); destination_simulationJob.label = this->getLabel();
simulationJobMapped.nodalForcedDisplacements = reducedNodalForcedDisplacements; destination_simulationJob.nodalForcedDisplacements = destination_forcedDisplacements;
} }
SimulationJob getCopy() const { SimulationJob getCopy() const {
SimulationJob jobCopy; SimulationJob jobCopy;
@ -377,7 +377,7 @@ json[jsonLabels.meshFilename]= std::filesystem::relative(std::filesystem::path(m
return; return;
} }
std::vector<std::array<double, 3>> nodeColors(pMesh->VN()); std::vector<std::array<double, 3>> nodeColors(pMesh->VN());
for (auto fixedVertex : constrainedVertices) { for (const auto &fixedVertex : constrainedVertices) {
const bool hasRotationalDoFConstrained = fixedVertex.second.contains(3) const bool hasRotationalDoFConstrained = fixedVertex.second.contains(3)
|| fixedVertex.second.contains(4) || fixedVertex.second.contains(4)
|| fixedVertex.second.contains(5); || fixedVertex.second.contains(5);
@ -393,7 +393,8 @@ json[jsonLabels.meshFilename]= std::filesystem::relative(std::filesystem::path(m
} }
} }
if (!nodalForcedDisplacements.empty()) { if (!nodalForcedDisplacements.empty()) {
for (std::pair<VertexIndex, Eigen::Vector3d> viDisplPair : nodalForcedDisplacements) { for (const std::pair<VertexIndex, Eigen::Vector3d> &viDisplPair :
nodalForcedDisplacements) {
const VertexIndex vi = viDisplPair.first; const VertexIndex vi = viDisplPair.first;
nodeColors[vi][0] += 1; nodeColors[vi][0] += 1;
nodeColors[vi][0] /= 2; nodeColors[vi][0] /= 2;
@ -712,21 +713,21 @@ struct SimulationResults
// /*polyscope::getNextUniqueColor()*/ glm::vec3(0, 0, 1)); // /*polyscope::getNextUniqueColor()*/ glm::vec3(0, 0, 1));
// //} // //}
pJob->registerForDrawing(getLabel()); pJob->registerForDrawing(getLabel());
static bool wasExecuted = false; // static bool wasExecuted =false;
if (!wasExecuted) { // if (!wasExecuted) {
std::function<void()> callback = [&]() { // std::function<void()> callback = [&]() {
static bool showFrames = shouldShowFrames; // static bool showFrames = shouldShowFrames;
if (ImGui::Checkbox("Show Frames", &showFrames) && showFrames) { // if (ImGui::Checkbox("Show Frames", &showFrames) && showFrames) {
polyscopeHandle_frameX->setEnabled(showFrames); // polyscopeHandle_frameX->setEnabled(showFrames);
polyscopeHandle_frameY->setEnabled(showFrames); // polyscopeHandle_frameY->setEnabled(showFrames);
polyscopeHandle_frameZ->setEnabled(showFrames); // polyscopeHandle_frameZ->setEnabled(showFrames);
} // }
}; // };
PolyscopeInterface::addUserCallback(callback); // PolyscopeInterface::addUserCallback(callback);
wasExecuted = true; // wasExecuted = true;
} // }
return polyscopeHandle_deformedEdmeMesh; return polyscopeHandle_deformedEdmeMesh;
} }
#endif #endif
@ -738,7 +739,7 @@ private:
//load job //load job
//Use the first .eigenBin file for loading the displacements //Use the first .eigenBin file for loading the displacements
for (auto const &entry : std::filesystem::recursive_directory_iterator(loadFromPath)) { for (auto const &entry : std::filesystem::recursive_directory_iterator(loadFromPath)) {
if (filesystem::is_regular_file(entry) && entry.path().extension() == ".eigenBin") { if (std::filesystem::is_regular_file(entry) && entry.path().extension() == ".eigenBin") {
Eigen::MatrixXd displacements_eigen; Eigen::MatrixXd displacements_eigen;
Eigen::read_binary(entry.path().string(), displacements_eigen); Eigen::read_binary(entry.path().string(), displacements_eigen);
displacements = Utilities::fromEigenMatrix(displacements_eigen); displacements = Utilities::fromEigenMatrix(displacements_eigen);

View File

@ -15,27 +15,25 @@ struct SimulationResultsReporter {
void writeStatistics(const SimulationResults &results, void writeStatistics(const SimulationResults &results,
const std::string &reportFolderPath) { const std::string &reportFolderPath) {
std::ofstream file;
file.open(std::filesystem::path(reportFolderPath).append("results.txt").string());
ofstream file; const size_t numberOfSteps = results.history.numberOfSteps;
file.open( file << "Number of steps " << numberOfSteps << "\n";
std::filesystem::path(reportFolderPath).append("results.txt").string());
const size_t numberOfSteps = results.history.numberOfSteps; // file << "Force threshold used " << 1000 << "\n";
file << "Number of steps " << numberOfSteps << "\n";
// file << "Force threshold used " << 1000 << "\n"; // assert(numberOfSteps == results.history.potentialEnergy.size() &&
// numberOfSteps == results.history.residualForces.size());
// assert(numberOfSteps == results.history.potentialEnergy.size() && // Write kinetic energies
// numberOfSteps == results.history.residualForces.size()); const SimulationHistory &history = results.history;
// Write kinetic energies if (!history.kineticEnergy.empty()) {
const SimulationHistory &history = results.history; file << "Kinetic energies"
if (!history.kineticEnergy.empty()) { << "\n";
file << "Kinetic energies" for (size_t step = 0; step < numberOfSteps; step++) {
<< "\n"; file << history.kineticEnergy[step] << "\n";
for (size_t step = 0; step < numberOfSteps; step++) { }
file << history.kineticEnergy[step] << "\n"; file << "\n";
}
file << "\n";
} }
if (!history.logResidualForces.empty()) { if (!history.logResidualForces.empty()) {

View File

@ -284,85 +284,85 @@ std::vector<ElementMaterial> SimulationMesh::getBeamMaterial() {
return beamMaterial; return beamMaterial;
} }
bool SimulationMesh::load(const string &plyFilename) { bool SimulationMesh::load(const std::string &plyFilename)
this->Clear(); {
// assert(plyFileHasAllRequiredFields(plyFilename)); this->Clear();
// Load the ply file // assert(plyFileHasAllRequiredFields(plyFilename));
// VCGEdgeMesh::PerEdgeAttributeHandle<CrossSectionType> handleBeamDimensions = // Load the ply file
// vcg::tri::Allocator<SimulationMesh>::AddPerEdgeAttribute< // VCGEdgeMesh::PerEdgeAttributeHandle<CrossSectionType> handleBeamDimensions =
// CrossSectionType>(*this, plyPropertyBeamDimensionsID); // vcg::tri::Allocator<SimulationMesh>::AddPerEdgeAttribute<
// VCGEdgeMesh::PerEdgeAttributeHandle<ElementMaterial> handleBeamMaterial = // CrossSectionType>(*this, plyPropertyBeamDimensionsID);
// vcg::tri::Allocator<SimulationMesh>::AddPerEdgeAttribute<ElementMaterial>( // VCGEdgeMesh::PerEdgeAttributeHandle<ElementMaterial> handleBeamMaterial =
// *this, plyPropertyBeamMaterialID); // vcg::tri::Allocator<SimulationMesh>::AddPerEdgeAttribute<ElementMaterial>(
// nanoply::NanoPlyWrapper<SimulationMesh>::CustomAttributeDescriptor // *this, plyPropertyBeamMaterialID);
// customAttrib; // nanoply::NanoPlyWrapper<SimulationMesh>::CustomAttributeDescriptor
// customAttrib.GetMeshAttrib(plyFilename); // customAttrib;
// customAttrib.AddEdgeAttribDescriptor<CrossSectionType, double, 2>( // customAttrib.GetMeshAttrib(plyFilename);
// plyPropertyBeamDimensionsID, nanoply::NNP_LIST_INT8_FLOAT64, nullptr); // customAttrib.AddEdgeAttribDescriptor<CrossSectionType, double, 2>(
// /*FIXME: Since I allow CrossSectionType to take two types I should export the // plyPropertyBeamDimensionsID, nanoply::NNP_LIST_INT8_FLOAT64, nullptr);
// * type as well such that that when loaded the correct type of cross section // /*FIXME: Since I allow CrossSectionType to take two types I should export the
// * is used. // * type as well such that that when loaded the correct type of cross section
// */ // * is used.
// customAttrib.AddEdgeAttribDescriptor<vcg::Point2d, double, 2>( // */
// plyPropertyBeamMaterialID, nanoply::NNP_LIST_INT8_FLOAT64, nullptr); // customAttrib.AddEdgeAttribDescriptor<vcg::Point2d, double, 2>(
// plyPropertyBeamMaterialID, nanoply::NNP_LIST_INT8_FLOAT64, nullptr);
// VCGEdgeMesh::PerEdgeAttributeHandle<std::array<double, 6>> // VCGEdgeMesh::PerEdgeAttributeHandle<std::array<double, 6>>
// handleBeamProperties = // handleBeamProperties =
// vcg::tri::Allocator<SimulationMesh>::AddPerEdgeAttribute< // vcg::tri::Allocator<SimulationMesh>::AddPerEdgeAttribute<
// std::array<double, 6>>(*this, plyPropertyBeamProperties); // std::array<double, 6>>(*this, plyPropertyBeamProperties);
// customAttrib.AddEdgeAttribDescriptor<std::array<double, 6>, double, 6>( // customAttrib.AddEdgeAttribDescriptor<std::array<double, 6>, double, 6>(
// plyPropertyBeamProperties, nanoply::NNP_LIST_INT8_FLOAT64, nullptr); // plyPropertyBeamProperties, nanoply::NNP_LIST_INT8_FLOAT64, nullptr);
// VCGEdgeMesh::PerEdgeAttributeHandle<ElementMaterial> // VCGEdgeMesh::PerEdgeAttributeHandle<ElementMaterial>
// handleBeamRigidityContants; // handleBeamRigidityContants;
// customAttrib.AddEdgeAttribDescriptor<vcg::Point4f, float, 4>( // customAttrib.AddEdgeAttribDescriptor<vcg::Point4f, float, 4>(
// plyPropertyBeamRigidityConstantsID, nanoply::NNP_LIST_INT8_FLOAT32, // plyPropertyBeamRigidityConstantsID, nanoply::NNP_LIST_INT8_FLOAT32,
// nullptr); // nullptr);
// unsigned int mask = 0; // unsigned int mask = 0;
// mask |= nanoply::NanoPlyWrapper<VCGEdgeMesh>::IO_VERTCOORD; // mask |= nanoply::NanoPlyWrapper<VCGEdgeMesh>::IO_VERTCOORD;
// mask |= nanoply::NanoPlyWrapper<VCGEdgeMesh>::IO_VERTNORMAL; // mask |= nanoply::NanoPlyWrapper<VCGEdgeMesh>::IO_VERTNORMAL;
// mask |= nanoply::NanoPlyWrapper<VCGEdgeMesh>::IO_EDGEINDEX; // mask |= nanoply::NanoPlyWrapper<VCGEdgeMesh>::IO_EDGEINDEX;
// mask |= nanoply::NanoPlyWrapper<VCGEdgeMesh>::IO_EDGEATTRIB; // mask |= nanoply::NanoPlyWrapper<VCGEdgeMesh>::IO_EDGEATTRIB;
// mask |= nanoply::NanoPlyWrapper<VCGEdgeMesh>::IO_MESHATTRIB; // mask |= nanoply::NanoPlyWrapper<VCGEdgeMesh>::IO_MESHATTRIB;
if (!VCGEdgeMesh::load(plyFilename)) { if (!VCGEdgeMesh::load(plyFilename)) {
return false; return false;
}
// elements = vcg::tri::Allocator<SimulationMesh>::GetPerEdgeAttribute<Element>(
// *this, std::string("Elements"));
// nodes = vcg::tri::Allocator<SimulationMesh>::GetPerVertexAttribute<Node>(
// *this, std::string("Nodes"));
vcg::tri::UpdateTopology<SimulationMesh>::VertexEdge(*this);
initializeNodes();
initializeElements();
setBeamMaterial(0.3, 1 * 1e9);
updateEigenEdgeAndVertices();
// if (!handleBeamProperties._handle->data.empty()) {
// for (size_t ei = 0; ei < EN(); ei++) {
// elements[ei] =
// Element::Properties(handleBeamProperties[ei]);
// elements[ei].updateRigidity();
// }
// }
// for (size_t ei = 0; ei < EN(); ei++) {
// elements[ei].setDimensions(handleBeamDimensions[ei]);
// elements[ei].setMaterial(handleBeamMaterial[ei]);
// elements[ei].updateRigidity();
// }
bool normalsAreAbsent = vert[0].cN().Norm() < 0.000001;
if (normalsAreAbsent) {
CoordType normalVector(0, 0, 1);
std::cout << "Warning: Normals are missing from " << plyFilename
<< ". Added normal vector:" << toString(normalVector)
<< std::endl;
for (auto &v : vert) {
v.N() = normalVector;
} }
}
return true; // elements = vcg::tri::Allocator<SimulationMesh>::GetPerEdgeAttribute<Element>(
// *this, std::string("Elements"));
// nodes = vcg::tri::Allocator<SimulationMesh>::GetPerVertexAttribute<Node>(
// *this, std::string("Nodes"));
vcg::tri::UpdateTopology<SimulationMesh>::VertexEdge(*this);
initializeNodes();
initializeElements();
setBeamMaterial(0.3, 1 * 1e9);
updateEigenEdgeAndVertices();
// if (!handleBeamProperties._handle->data.empty()) {
// for (size_t ei = 0; ei < EN(); ei++) {
// elements[ei] =
// Element::Properties(handleBeamProperties[ei]);
// elements[ei].updateRigidity();
// }
// }
// for (size_t ei = 0; ei < EN(); ei++) {
// elements[ei].setDimensions(handleBeamDimensions[ei]);
// elements[ei].setMaterial(handleBeamMaterial[ei]);
// elements[ei].updateRigidity();
// }
bool normalsAreAbsent = vert[0].cN().Norm() < 0.000001;
if (normalsAreAbsent) {
CoordType normalVector(0, 0, 1);
std::cout << "Warning: Normals are missing from " << plyFilename
<< ". Added normal vector:" << toString(normalVector) << std::endl;
for (auto &v : vert) {
v.N() = normalVector;
}
}
return true;
} }
bool SimulationMesh::save(const std::string &plyFilename) bool SimulationMesh::save(const std::string &plyFilename)

View File

@ -34,7 +34,7 @@ public:
std::vector<VCGEdgeMesh::EdgePointer> std::vector<VCGEdgeMesh::EdgePointer>
getIncidentElements(const VCGEdgeMesh::VertexType &v); getIncidentElements(const VCGEdgeMesh::VertexType &v);
virtual bool load(const string &plyFilename); virtual bool load(const std::string &plyFilename);
std::vector<CrossSectionType> getBeamDimensions(); std::vector<CrossSectionType> getBeamDimensions();
std::vector<ElementMaterial> getBeamMaterial(); std::vector<ElementMaterial> getBeamMaterial();

View File

@ -145,7 +145,7 @@ PatternGeometry::PatternGeometry(PatternGeometry &other) {
vcg::tri::UpdateTopology<PatternGeometry>::EdgeEdge(*this); vcg::tri::UpdateTopology<PatternGeometry>::EdgeEdge(*this);
} }
bool PatternGeometry::load(const string &plyFilename) bool PatternGeometry::load(const std::string &plyFilename)
{ {
if (!VCGEdgeMesh::load(plyFilename)) { if (!VCGEdgeMesh::load(plyFilename)) {
return false; return false;

View File

@ -4,9 +4,11 @@
#include <Eigen/Dense> #include <Eigen/Dense>
#include <algorithm> #include <algorithm>
#include <array> #include <array>
#include <chrono>
#include <filesystem> #include <filesystem>
#include <fstream> #include <fstream>
#include <iterator> #include <iterator>
#include <numeric>
#include <regex> #include <regex>
#define GET_VARIABLE_NAME(Variable) (#Variable) #define GET_VARIABLE_NAME(Variable) (#Variable)
@ -140,16 +142,37 @@ struct Vector6d : public std::array<double, 6> {
}; };
namespace Utilities { namespace Utilities {
//inline std::vector<std::string> split(std::string text, char delim) inline bool compareNat(const std::string &a, const std::string &b)
//{ {
// std::string line; if (a.empty())
// std::vector<std::string> vec; return true;
// std::stringstream ss(text); if (b.empty())
// while (std::getline(ss, line, delim)) { return false;
// vec.push_back(line); if (std::isdigit(a[0]) && !std::isdigit(b[0]))
// } return true;
// return vec; if (!std::isdigit(a[0]) && std::isdigit(b[0]))
//} return false;
if (!std::isdigit(a[0]) && !std::isdigit(b[0])) {
if (std::toupper(a[0]) == std::toupper(b[0]))
return compareNat(a.substr(1), b.substr(1));
return (std::toupper(a[0]) < std::toupper(b[0]));
}
// Both strings begin with digit --> parse both numbers
std::istringstream issa(a);
std::istringstream issb(b);
int ia, ib;
issa >> ia;
issb >> ib;
if (ia != ib)
return ia < ib;
// Numbers are the same --> remove numbers and recurse
std::string anew, bnew;
std::getline(issa, anew);
std::getline(issb, bnew);
return (compareNat(anew, bnew));
}
inline std::string_view leftTrimSpaces(const std::string_view& str) inline std::string_view leftTrimSpaces(const std::string_view& str)
{ {
@ -175,6 +198,21 @@ std::string_view trimmedString=str;
return trimmedString; return trimmedString;
} }
template<typename InputIt>
inline void normalize(InputIt itBegin, InputIt itEnd)
{
const auto squaredSumOfElements = std::accumulate(itBegin,
itEnd,
0.0,
[](const auto &sum, const auto &el) {
return sum + el * el;
});
assert(squaredSumOfElements != 0);
std::transform(itBegin, itEnd, itBegin, [&](auto &element) {
return element / std::sqrt(squaredSumOfElements);
});
}
inline std::vector<std::string> split(const std::string& text, std::string delim) inline std::vector<std::string> split(const std::string& text, std::string delim)
{ {
std::vector<std::string> vec; std::vector<std::string> vec;
@ -273,6 +311,19 @@ inline std::vector<Vector6d> fromEigenMatrix(const Eigen::MatrixXd &m)
// return true; // return true;
//} //}
inline std::filesystem::path getFilepathWithExtension(const std::filesystem::path &folderPath,
const std::string &extension)
{
for (const std::filesystem::directory_entry &dirEntry :
std::filesystem::directory_iterator(folderPath)) {
if (dirEntry.is_regular_file() && std::filesystem::path(dirEntry).extension() == extension) {
return std::filesystem::path(dirEntry);
}
}
return "";
}
} // namespace Utilities } // namespace Utilities
#ifdef POLYSCOPE_DEFINED #ifdef POLYSCOPE_DEFINED
@ -293,7 +344,7 @@ inline void mainCallback()
// instead of full width. Must have // instead of full width. Must have
// matching PopItemWidth() below. // matching PopItemWidth() below.
for (std::function<void()> userCallback : globalPolyscopeData.userCallbacks) { for (std::function<void()> &userCallback : globalPolyscopeData.userCallbacks) {
userCallback(); userCallback();
} }
@ -418,17 +469,4 @@ inline size_t computeHashOrdered(const std::vector<int> &v)
return std::hash<std::string>{}(elementsString); return std::hash<std::string>{}(elementsString);
} }
//inline std::filesystem::path getFilepathWithExtension(const std::filesystem::path &folderPath,
// const std::string &extension)
//{
// for (const std::filesystem::directory_entry &dirEntry :
// std::filesystem::directory_iterator(folderPath)) {
// if (dirEntry.is_regular_file() && std::filesystem::path(dirEntry).extension() == extension) {
// return std::filesystem::path(dirEntry);
// }
// }
// return "";
//}
#endif // UTILITIES_H #endif // UTILITIES_H