From 266aca08c20e780b7b508176c7284104f9ad85ec Mon Sep 17 00:00:00 2001 From: iasonmanolas Date: Wed, 14 Sep 2022 13:04:05 +0200 Subject: [PATCH] Backup commit --- CMakeLists.txt | 15 +- chronoseulersimulationmodel.cpp | 72 +- chronoseulersimulationmodel.hpp | 67 +- polymesh.hpp | 297 --- reducedmodelevaluator.cpp | 1048 ++++---- reducedmodelevaluator.hpp | 192 +- reducedmodeloptimizer.cpp | 3965 ++++++++++++++++------------- reducedmodeloptimizer.hpp | 653 ++--- reducedmodeloptimizer_structs.hpp | 2339 +++++++++-------- topologyenumerator.cpp | 1533 +++++------ trianglepatterngeometry.cpp | 1595 ++++++------ trianglepatterngeometry.hpp | 154 +- vcgtrimesh.cpp | 3 +- vcgtrimesh.hpp | 42 +- 14 files changed, 6146 insertions(+), 5829 deletions(-) delete mode 100755 polymesh.hpp diff --git a/CMakeLists.txt b/CMakeLists.txt index 86bce23..265a60d 100755 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -45,7 +45,8 @@ target_include_directories(${PROJECT_NAME} PUBLIC ${DRMSimulationModelDir}) #add_compile_definitions(DLIB_DEFINED) ## polyscope -#if(NOT TARGET polyscope AND ${USE_POLYSCOPE}) +if(#[[NOT TARGET polyscope AND]] ${USE_POLYSCOPE}) +message("Using polyscope") FetchContent_Declare(polyscope GIT_REPOSITORY https://github.com/nmwsharp/polyscope.git GIT_TAG master @@ -55,7 +56,7 @@ target_include_directories(${PROJECT_NAME} PUBLIC ${DRMSimulationModelDir}) # target_include_directories(${PROJECT_NAME} PUBLIC ${polyscope_SOURCE_DIR}/deps/imgui) target_sources(${PROJECT_NAME} PUBLIC ${polyscope_SOURCE_DIR}/deps/imgui/imgui/misc/cpp/imgui_stdlib.h ${polyscope_SOURCE_DIR}/deps/imgui/imgui/misc/cpp/imgui_stdlib.cpp) target_link_libraries(${PROJECT_NAME} PUBLIC polyscope) -#endif() +endif() #if(NOT TARGET polyscope AND ${USE_POLYSCOPE}) # set(POLYSCOPE_BINARY_DIR ${CMAKE_CURRENT_BINARY_DIR}/polyscope) # download_project(PROJ POLYSCOPE @@ -149,8 +150,9 @@ add_subdirectory(${ARMADILLO_SOURCE_DIR} ${ARMADILLO_BIN_DIR}) target_include_directories(${PROJECT_NAME} PUBLIC ${ARMADILLO_SOURCE_DIR}/include) add_compile_definitions(ARMA_DONT_USE_WRAPPER) target_link_libraries(${PROJECT_NAME} PUBLIC "/home/iason/Coding/Libraries/armadillo/build/libarmadillo.a" #[[blas lapack]]) -find_package(Armadillo REQUIRED) -target_link_libraries(${PROJECT_NAME} PUBLIC ${ARMADILLO_LIBRARIES}) +#find_package(Armadillo REQUIRED) +#target_link_libraries(${PROJECT_NAME} PUBLIC ${ARMADILLO_LIBRARIES}) + #if(NOT TARGET ThreedBeamFEA) #FetchContent_Declare(armadillo # GIT_REPOSITORY https://gitlab.com/conradsnicta/armadillo-code.git @@ -203,7 +205,7 @@ add_compile_definitions(USE_ENSMALLEN) # LINK_FLAGS "${CHRONO_LINKER_FLAGS}") #include_directories(${CHRONO_INCLUDE_DIRS}) #target_link_libraries(${PROJECT_NAME} PUBLIC ${CHRONO_LIBRARIES}) -#target_include_directories(${PROJECT_NAME} PUBLIC "/home/iason/Coding/Libraries/chrono-7.0.3/src" #[[${CHRONO_INCLUDE_DIRS}]] #[["/home/iason/Coding/Libraries/chrono-7.0.3/src"]] #[["/usr/include/irrlicht"]] ) +target_include_directories(${PROJECT_NAME} PUBLIC "/home/iason/Coding/Libraries/chrono-7.0.3/src" #[[${CHRONO_INCLUDE_DIRS}]] #[["/home/iason/Coding/Libraries/chrono-7.0.3/src"]] #[["/usr/include/irrlicht"]] ) #target_link_directories(${PROJECT_NAME} PRIVATE "/home/iason/Coding/build/external dependencies/CHRONO-src/build/RelWithDebInfo/lib") #target_link_libraries(${PROJECT_NAME} PUBLIC "/home/iason/Coding/build/external dependencies/CHRONO-src/build/RelWithDebInfo/lib/libChronoEngine.a") target_link_libraries(${PROJECT_NAME} PUBLIC "/home/iason/Coding/Libraries/chrono-7.0.3/build/Release/lib/libChronoEngine.a") @@ -252,11 +254,12 @@ if(NOT TARGET tbb_static AND NOT TARGET tbb) # option(TBB_BUILD_TESTS "Build TBB tests and enable testing infrastructure" OFF) # add_subdirectory(${TBB_SOURCE_DIR} ${TBB_BINARY_DIR}) #link_directories(${TBB_BINARY_DIR}) +message("Using tbb") FetchContent_Declare(tbb GIT_REPOSITORY https://github.com/wjakob/tbb.git GIT_TAG master ) FetchContent_MakeAvailable(tbb) # target_link_libraries(${PROJECT_NAME} PRIVATE tbb_static) - target_link_libraries(${PROJECT_NAME} PRIVATE tbb) endif() +target_link_libraries(${PROJECT_NAME} PRIVATE tbb_static) diff --git a/chronoseulersimulationmodel.cpp b/chronoseulersimulationmodel.cpp index 6eb1efb..33813cd 100644 --- a/chronoseulersimulationmodel.cpp +++ b/chronoseulersimulationmodel.cpp @@ -106,6 +106,33 @@ void ChronosEulerSimulationModel::parseForces( } } +void ChronosEulerSimulationModel::parseForcedDisplacements( + const std::shared_ptr& pJob, + const std::vector>& + edgeMeshVertsToChronoNodes, + chrono::ChSystemSMC& my_system) { + assert(!edgeMeshVertsToChronoNodes.empty()); + + ChState x; + ChStateDelta v; + double t; + for (const std::pair& forcedDisplacement : + pJob->nodalForcedDisplacements) { + assert(false); + std::cerr << "Forced displacements dont work" << std::endl; + // std::terminate(); + const int& constrainedVi = forcedDisplacement.first; + ChVector displacementVector( + pJob->nodalForcedDisplacements.at(constrainedVi)); + const std::shared_ptr& constrainedChronoNode = + edgeMeshVertsToChronoNodes[constrainedVi]; + constrainedChronoNode->NodeIntStateGather(0, x, 0, v, t); + std::cout << "state rows:" << x.rows() << std::endl; + std::cout << "state cols:" << x.cols() << std::endl; + // x = x + displacementVector; + constrainedChronoNode->NodeIntStateScatter(0, x, 0, v, t); + } +} void ChronosEulerSimulationModel::parseConstrainedVertices( const std::shared_ptr& pJob, const std::vector>& @@ -120,30 +147,17 @@ void ChronosEulerSimulationModel::parseConstrainedVertices( auto truss = chrono_types::make_shared(); truss->SetBodyFixed(true); my_system.Add(truss); - const auto& constrainedChronoNode = + const std::shared_ptr& constrainedChronoNode = edgeMeshVertsToChronoNodes[constrainedVi]; - // Create a constraint at the end of the beam - auto constr_a = chrono_types::make_shared(); - constr_a->SetConstrainedCoords( + auto constraint = chrono_types::make_shared(); + constraint->SetConstrainedCoords( constrainedDoF.contains(0), constrainedDoF.contains(1), constrainedDoF.contains(2), constrainedDoF.contains(3), constrainedDoF.contains(4), constrainedDoF.contains(5)); - constr_a->Initialize(constrainedChronoNode, truss, false, - constrainedChronoNode->Frame(), - constrainedChronoNode->Frame()); - // const auto frameNode = constrainedChronoNode->Frame(); - my_system.Add(constr_a); - - // edgeMeshVertsToChronoNodes[constrainedVi]->SetFixed(true); - // if (vertexIsFullyConstrained) { - // } else { - // std::cerr << "Currently only rigid vertices are handled." << - // std::endl; - // // SimulationResults simulationResults; - // // simulationResults.converged = false; - // // assert(false); - // // return simulationResults; - // } + constraint->Initialize(constrainedChronoNode, truss, false, + constrainedChronoNode->Frame(), + constrainedChronoNode->Frame()); + my_system.Add(constraint); } } @@ -177,6 +191,7 @@ SimulationResults ChronosEulerSimulationModel::executeSimulation( // -1)); // my_system.SetTimestepperType(chrono::ChTimestepper::Type::EULER_IMPLICIT_LINEARIZED); // parse forces + parseForcedDisplacements(pJob, edgeMeshVertsToChronoNodes, my_system); parseForces(mesh_chronos, edgeMeshVertsToChronoNodes, pJob->nodalExternalForces); // parse constrained vertices @@ -198,20 +213,29 @@ SimulationResults ChronosEulerSimulationModel::executeSimulation( auto solver = chrono_types::make_shared(); my_system.SetSolver(solver); - // solver->SetMaxIterations(1e5); - // solver->SetTolerance(1e-12); + solver->SetMaxIterations(1e5); solver->EnableWarmStart( true); // IMPORTANT for convergence when using EULER_IMPLICIT_LINEARIZED solver->EnableDiagonalPreconditioner(true); - my_system.SetSolverForceTolerance(1e-9); - solver->SetVerbose(false); + // solver->SetTolerance(1e-15); + my_system.SetSolverForceTolerance(1e-15); SimulationResults simulationResults; + //#ifdef POLYSCOPE_DEFINED + // solver->SetVerbose(true); + // // edgeMeshVertsToChronoNodes[10]->Frame().Move({0, 0, 1e-1}); + // simulationResults.converged = my_system.DoEntireKinematics(5e2); + //// edgeMeshVertsToChronoNodes[10]->SetForce({0, 0, 1e6}); + //#else + solver->SetVerbose(false); if (settings.analysisType == Settings::AnalysisType::Linear) { simulationResults.converged = my_system.DoStaticLinear(); + // simulationResults.converged = my_system.DoStaticRelaxing(); } else { simulationResults.converged = my_system.DoStaticNonlinear(); + // simulationResults.converged = my_system.DoStaticRelaxing(); } + //#endif if (!simulationResults.converged) { std::cerr << "Simulation failed" << std::endl; assert(false); diff --git a/chronoseulersimulationmodel.hpp b/chronoseulersimulationmodel.hpp index 2d49b01..3389f46 100644 --- a/chronoseulersimulationmodel.hpp +++ b/chronoseulersimulationmodel.hpp @@ -8,39 +8,48 @@ class ChSystemSMC; namespace fea { class ChMesh; class ChNodeFEAxyzrot; -} // namespace fea -} // namespace chrono +} // namespace fea +} // namespace chrono -class ChronosEulerSimulationModel : public SimulationModel -{ - std::shared_ptr mesh_chronos; - std::vector> edgeMeshVertsToChronoNodes; +class ChronosEulerSimulationModel : public SimulationModel { + std::shared_ptr mesh_chronos; + std::vector> + edgeMeshVertsToChronoNodes; - static void parseConstrainedVertices( - const std::shared_ptr &pJob, - const std::vector> &edgeMeshVertsToChronoNodes, - chrono::ChSystemSMC &my_system); - static void parseForces( - const std::shared_ptr &mesh_chronos, - const std::vector> &edgeMeshVertsToChronoNodes, - const std::unordered_map &nodalExternalForces); + static void parseConstrainedVertices( + const std::shared_ptr& pJob, + const std::vector>& + edgeMeshVertsToChronoNodes, + chrono::ChSystemSMC& my_system); + static void parseForces( + const std::shared_ptr& mesh_chronos, + const std::vector>& + edgeMeshVertsToChronoNodes, + const std::unordered_map& nodalExternalForces); -public: - ChronosEulerSimulationModel(); - SimulationResults executeSimulation(const std::shared_ptr &pJob) override; - void setStructure(const std::shared_ptr &pMesh) override; - static std::shared_ptr convertToChronosMesh_Euler( - const std::shared_ptr &pMesh, - std::vector> &edgeMeshVertsToChronosNodes); + static void parseForcedDisplacements( + const std::shared_ptr& pJob, + const std::vector>& + edgeMeshVertsToChronoNodes, + chrono::ChSystemSMC& my_system); - inline const static std::string label{"Chronos_Euler"}; + public: + ChronosEulerSimulationModel(); + SimulationResults executeSimulation( + const std::shared_ptr& pJob) override; + void setStructure(const std::shared_ptr& pMesh) override; + static std::shared_ptr convertToChronosMesh_Euler( + const std::shared_ptr& pMesh, + std::vector>& + edgeMeshVertsToChronosNodes); - struct Settings - { - enum AnalysisType { Linear = 0, NonLinear }; - AnalysisType analysisType{NonLinear}; - }; - Settings settings; + inline const static std::string label{"Chronos_Euler"}; + + struct Settings { + enum AnalysisType { Linear = 0, NonLinear }; + AnalysisType analysisType{NonLinear}; + }; + Settings settings; }; -#endif // CHRONOSEULERSIMULATIONMODEL_HPP +#endif // CHRONOSEULERSIMULATIONMODEL_HPP diff --git a/polymesh.hpp b/polymesh.hpp deleted file mode 100755 index 6d65562..0000000 --- a/polymesh.hpp +++ /dev/null @@ -1,297 +0,0 @@ -#ifndef POLYMESH_HPP -#define POLYMESH_HPP -#include "mesh.hpp" -#include "utilities.hpp" -#include "vcg/complex/complex.h" -#include -#include -#include -#include - -#ifdef POLYSCOPE_DEFINED -#include -#endif -class PFace; -class PVertex; -class PEdge; - -struct PUsedTypes : public vcg::UsedTypes::AsVertexType, - vcg::Use::AsFaceType, - vcg::Use::AsEdgeType> -{}; - -class PVertex : public vcg::Vertex -{}; -class PEdge : public vcg::Edge -{}; - -class PFace : public vcg::Face -{}; - -class VCGPolyMesh - : public vcg::tri::TriMesh, std::vector, std::vector>, - public Mesh -{ -public: - virtual bool load(const std::filesystem::__cxx11::path &meshFilePath) override - { - int mask; - vcg::tri::io::Importer::LoadMask(meshFilePath.c_str(), mask); - int error = vcg::tri::io::Importer::Open(*this, meshFilePath.c_str(), mask); - if (error != 0) { - std::cerr << "Could not load polygonal mesh:" << meshFilePath << std::endl; - return false; - } - - vcg::tri::UpdateTopology::FaceFace(*this); - vcg::tri::UpdateTopology::VertexEdge(*this); - vcg::tri::UpdateTopology::VertexFace(*this); - vcg::tri::UpdateNormal::PerVertexNormalized(*this); - vcg::tri::Clean::RemoveUnreferencedVertex(*this); - //finally remove valence 1 vertices on the border - // vcg::PolygonalAlgorithm::RemoveValence2Vertices(dual); - return true; - } - // // vcg::tri::io::ImporterOBJ::Open(); - // // unsigned int mask = 0; - // // mask |= nanoply::NanoPlyWrapper::IO_VERTCOORD; - // // mask |= nanoply::NanoPlyWrapper::IO_VERTNORMAL; - // // mask |= nanoply::NanoPlyWrapper::IO_VERTCOLOR; - // // mask |= nanoply::NanoPlyWrapper::IO_EDGEINDEX; - // // mask |= nanoply::NanoPlyWrapper::IO_FACEINDEX; - // // if (nanoply::NanoPlyWrapper::LoadModel( - // // std::filesystem::absolute(filename).c_str(), *this, mask) != - // // 0) { - // // std::cout << "Could not load tri mesh" << std::endl; - // // } - // } - Eigen::MatrixX3d getVertices() const - { - Eigen::MatrixX3d vertices(VN(), 3); - for (size_t vi = 0; vi < VN(); vi++) { - VCGPolyMesh::CoordType vertexCoordinates = vert[vi].cP(); - vertices.row(vi) = vertexCoordinates.ToEigenVector(); - } - return vertices; - } - std::vector> getFaces() const - { - std::vector> faces(FN()); - for (const VCGPolyMesh::FaceType &f : this->face) { - const int fi = vcg::tri::Index(*this, f); - for (size_t vi = 0; vi < f.VN(); vi++) { - const size_t viGlobal = vcg::tri::Index(*this, f.cV(vi)); - faces[fi].push_back(viGlobal); - } - } - - return faces; - } - - // bool load(const std::filesystem::__cxx11::path &meshFilePath) - // { - // const std::string extension = ".ply"; - // std::filesystem::path filePath = meshFilePath; - // assert(std::filesystem::path(filePath).extension().string() == extension); - // unsigned int mask = 0; - // mask |= vcg::tri::io::Mask::IOM_VERTCOORD; - // mask |= vcg::tri::io::Mask::IOM_VERTNORMAL; - // mask |= vcg::tri::io::Mask::IOM_FACEINDEX; - // mask |= vcg::tri::io::Mask::IOM_FACECOLOR; - // if (vcg::tri::io::Importer::Open(*this, filePath.c_str()) != 0) { - // return false; - // } - // label = meshFilePath.filename(); - // return true; - // } - - bool save(const std::filesystem::__cxx11::path &meshFilePath = std::filesystem::path()) override - { - if (meshFilePath.extension() == ".obj") { - return saveOBJ(meshFilePath); - } else if (meshFilePath.extension() == ".ply") { - return savePLY(meshFilePath); - } - - return false; - } - - bool saveOBJ(const std::filesystem::path &objFilePath = std::filesystem::path()) - { - const std::string extension = ".obj"; - std::filesystem::path filePath = objFilePath; - if (filePath.empty()) { - filePath = std::filesystem::current_path().append(getLabel() + extension).string(); - } else if (std::filesystem::is_directory(std::filesystem::path(objFilePath))) { - filePath = std::filesystem::path(objFilePath).append(getLabel() + extension).string(); - } - assert(std::filesystem::path(filePath).extension().string() == extension); - unsigned int mask = 0; - mask |= vcg::tri::io::Mask::IOM_VERTCOORD; - mask |= vcg::tri::io::Mask::IOM_VERTNORMAL; - mask |= vcg::tri::io::Mask::IOM_FACEINDEX; - mask |= vcg::tri::io::Mask::IOM_FACECOLOR; - if (vcg::tri::io::ExporterOBJ::Save(*this, filePath.string().c_str(), mask) != 0) { - return false; - } - return true; - } - - bool savePLY(const std::filesystem::path &objFilePath = std::filesystem::path()) - { - const std::string extension = ".ply"; - std::filesystem::path filePath = objFilePath; - if (filePath.empty()) { - filePath = std::filesystem::current_path().append(getLabel() + extension).string(); - } else if (std::filesystem::is_directory(std::filesystem::path(objFilePath))) { - filePath = std::filesystem::path(objFilePath).append(getLabel() + extension).string(); - } - assert(std::filesystem::path(filePath).extension().string() == extension); - unsigned int mask = 0; - mask |= vcg::tri::io::Mask::IOM_VERTCOORD; - mask |= vcg::tri::io::Mask::IOM_VERTNORMAL; - mask |= vcg::tri::io::Mask::IOM_FACEINDEX; - mask |= vcg::tri::io::Mask::IOM_FACECOLOR; - if (vcg::tri::io::ExporterPLY::Save(*this, filePath.string().c_str(), mask, false) != 0) { - return false; - } - return true; - } - -#ifdef POLYSCOPE_DEFINED - polyscope::SurfaceMesh *registerForDrawing( - const std::optional> &desiredColor = std::nullopt, - const bool &shouldEnable = true) - { - auto vertices = getVertices(); - auto faces = getFaces(); - PolyscopeInterface::init(); - - polyscope::SurfaceMesh *polyscopeHandle_mesh = polyscope::registerSurfaceMesh(label, - vertices, - faces); - - const double drawingRadius = 0.002; - polyscopeHandle_mesh->setEnabled(shouldEnable); - polyscopeHandle_mesh->setEdgeWidth(drawingRadius); - - if (desiredColor.has_value()) { - const glm::vec3 desiredColor_glm(desiredColor.value()[0], - desiredColor.value()[1], - desiredColor.value()[2]); - polyscopeHandle_mesh->setSurfaceColor(desiredColor_glm); - } - - return polyscopeHandle_mesh; - } -#endif - void moveToCenter() - { - CoordType centerOfMass(0, 0, 0); - - for (int vi = 0; vi < VN(); vi++) { - centerOfMass += vert[vi].cP(); - } - centerOfMass /= VN(); - vcg::tri::UpdatePosition::Translate(*this, -centerOfMass); - } - - /* - * Returns the average distance from the center of each edge to the center of its face over the whole mesh - * */ - double getAverageFaceRadius() const - { - double averageFaceRadius = 0; - for (int fi = 0; fi < FN(); fi++) { - const VCGPolyMesh::FaceType &f = face[fi]; - CoordType centerOfFace(0, 0, 0); - for (int vi = 0; vi < f.VN(); vi++) { - centerOfFace = centerOfFace + f.cP(vi); - } - centerOfFace /= f.VN(); - - double faceRadius = 0; - // for (int face_ei = 0; face_ei < f.EN(); face_ei++) { - // std::cout << "fi:" << getIndex(f) << std::endl; - // auto vps = f.FVp(0); - // auto vpe = vps; - for (int i = 0; i < f.VN(); i++) { - faceRadius += vcg::Distance(centerOfFace, (f.cP0(i) + f.cP1(i)) / 2); - } - - // } - const int faceEdges = f.VN(); //NOTE: When does this not hold? - faceRadius /= faceEdges; - averageFaceRadius += faceRadius; - } - averageFaceRadius /= FN(); - return averageFaceRadius; - } - - bool copy(VCGPolyMesh ©From) - { - vcg::tri::Append::MeshCopy(*this, copyFrom); - label = copyFrom.getLabel(); - // eigenEdges = mesh.getEigenEdges(); - // if (eigenEdges.rows() == 0) { - // getEdges(eigenEdges); - // } - // eigenVertices = mesh.getEigenVertices(); - // if (eigenVertices.rows() == 0) { - // getVertices(); - // } - vcg::tri::UpdateTopology::VertexEdge(*this); - vcg::tri::UpdateTopology::VertexFace(*this); - vcg::tri::UpdateTopology::FaceFace(*this); - vcg::tri::UpdateTopology::AllocateEdge(*this); - vcg::tri::UpdateTopology::EdgeEdge(*this); - // vcg::tri::UpdateTopology::VertexFace(*this); - - return true; - } - - VCGPolyMesh(VCGPolyMesh ©From) { copy(copyFrom); } - VCGPolyMesh() {} - template - size_t getIndex(const MeshElement &meshElement) const - { - return vcg::tri::Index(*this, meshElement); - } -}; - -using ConstVCGPolyMesh = VCGPolyMesh; - -#endif // POLYMESH_HPP diff --git a/reducedmodelevaluator.cpp b/reducedmodelevaluator.cpp index a1b31f2..d5ccb3a 100644 --- a/reducedmodelevaluator.cpp +++ b/reducedmodelevaluator.cpp @@ -1,594 +1,532 @@ #include "reducedmodelevaluator.hpp" + +#include +#include + #include "hexagonremesher.hpp" #include "reducedmodel.hpp" #include "reducedmodeloptimizer.hpp" #include "simulationmodelfactory.hpp" #include "trianglepatterngeometry.hpp" -#include -#include -using FullPatternVertexIndex = VertexIndex; -using ReducedPatternVertexIndex = VertexIndex; +using PatternVertexIndex = VertexIndex; +using ReducedModelVertexIndex = VertexIndex; -ReducedModelEvaluator::ReducedModelEvaluator() -{ - pTileIntoSurface = [&]() { - std::istringstream inputStream_tileIntoTriSurface(tileIntoSurfaceFileContent); - VCGTriMesh tileInto_triMesh; - const bool surfaceLoadSuccessfull = tileInto_triMesh.load(inputStream_tileIntoTriSurface); - tileInto_triMesh.setLabel("instantMeshes_plane_34"); - assert(surfaceLoadSuccessfull); - return PolygonalRemeshing::remeshWithPolygons(tileInto_triMesh); - }(); +ReducedModelEvaluator::ReducedModelEvaluator() { + pTileIntoSurface = [&]() { + std::istringstream inputStream_tileIntoTriSurface( + tileIntoSurfaceFileContent); + VCGTriMesh tileInto_triMesh; + const bool surfaceLoadSuccessfull = + tileInto_triMesh.load(inputStream_tileIntoTriSurface); + tileInto_triMesh.setLabel("instantMeshes_plane_34"); + assert(surfaceLoadSuccessfull); + return PolygonalRemeshing::remeshWithPolygons(tileInto_triMesh); + }(); } -//double ReducedModelEvaluator::evaluateOptimizationSettings( -// const ReducedModelOptimization::Settings &optimizationSettings, -// const std::vector> &pPatterns, -// std::vector &patternEvaluationResults) -//{ -// assert(!pPatterns.empty()); -// double optimizationError = 0; -// auto start = std::chrono::high_resolution_clock::now(); -// std::vector averageNormalizedError(pPatterns.size(), 0); -// patternEvaluationResults.clear(); -// patternEvaluationResults.resize(pPatterns.size()); -// std::for_each( -// // std::execution::par_unseq, -// pPatterns.begin(), -// pPatterns.end(), -// [&](const std::shared_ptr &pPattern) { -// // std::cout << "Optimizing " << pPattern->getLabel() << std::endl; -// ReducedModelOptimization::Results optimizationResults; -// ReducedModelOptimizer optimizer; -// optimizer.optimize(*pPattern, optimizationSettings, optimizationResults); -// const auto evaluationResults -// = ReducedModelEvaluator::evaluateReducedModel(optimizationResults, -// tileIntoSurfaceFilePath, -// scenariosDirPath, -// fullPatternTessellatedResultsDirPath); -// const double averageNormalizedErrorOfPattern -// = std::reduce(evaluationResults.distances_normalizedDrm2reduced.begin(), -// evaluationResults.distances_normalizedDrm2reduced.end()) -// / evaluationResults.distances_normalizedDrm2reduced.size(); -// const int patternIndex = &pPattern - &patterns[0]; -// averageNormalizedError[patternIndex] = averageNormalizedErrorOfPattern; -// patternsEvaluationResults[patternIndex] = evaluationResults; -// }); -// const double strategyAverageNormalizedError = std::reduce(std::execution::par_unseq, -// averageNormalizedError.begin(), -// averageNormalizedError.end()) -// / pPointers.size(); -// const auto totalDuration_min = std::chrono::duration_cast( -// std::chrono::high_resolution_clock::now() - start) -// .count() -// / 60.0; -// std::cout << "Optimized pattern(s) in:" << totalDuration_min << " minutes." << std::endl; -// std::cout << "Average time per pattern:" << totalDuration_min / patternsPointers.size() -// << " minutes." << std::endl; -// std::cout << "Objective value:" << strategyAverageNormalizedError << std::endl; -// return strategyAverageNormalizedError; -// // std::cout << "After:" << ++numberOfOptimizationRoundsExecuted << " iterations." << std::endl; -//} - ReducedModelEvaluator::Results ReducedModelEvaluator::evaluateReducedModel( - ReducedModelOptimization::Results &optimizationResult) -{ - const std::filesystem::path scenariosDirectoryPath - = "/home/iason/Coding/Projects/Approximating shapes with flat " - "patterns/ReducedModelEvaluator/Scenarios"; - const std::filesystem::path fullPatternTessellatedResultsDirectoryPath - = "/home/iason/Coding/Projects/Approximating shapes with flat " - "patterns/ReducedModelEvaluator/TessellatedResults"; + ReducedModelOptimization::Results& optimizationResult) { + const std::filesystem::path scenariosDirectoryPath = + "/home/iason/Coding/Projects/Approximating shapes with flat " + "patterns/ReducedModelEvaluator/Scenarios"; + const std::filesystem::path fullPatternTessellatedResultsDirectoryPath = + "/home/iason/Coding/Projects/Approximating shapes with flat " + "patterns/ReducedModelEvaluator/TessellatedResults"; - return evaluateReducedModel(optimizationResult, - scenariosDirectoryPath, - fullPatternTessellatedResultsDirectoryPath); -} -//void ReducedModelEvaluator::printResults(const Results &evaluationResults, -// const std::string &resultsLabel, -// const std::filesystem::path &resultsOutputPath) -//{ -// const bool outputPathIsDirectory = !resultsOutputPath.empty() -// && !resultsOutputPath.has_extension(); -// const bool outputPathIsFile = !resultsOutputPath.empty() && resultsOutputPath.has_extension(); -// assert(outputPathIsDirectory && outputPathIsFile); -// if (outputPathIsDirectory) { -// std::filesystem::create_directories(resultsOutputPath); -// } - -//#else -// std::filesystem::path csvOutputFilePath; -// bool shouldOverwrite = false; -// if (outputPathIsDirectory) { -// csvOutputFilePath = std::filesystem::path(resultsOutputPath) -// .append("distances_" + resultsLabel + ".csv") -// .string(); -// shouldOverwrite = true; -// } else if (outputPathIsFile) { -// csvOutputFilePath = resultsOutputPath; -// } - -// csvFile csvOutput(csvOutputFilePath, shouldOverwrite); -// printResults(evaluationResults, resultsLabel, csvOutput); -//} - -void ReducedModelEvaluator::printResults(const Results &evaluationResults, - const std::string &resultsLabel) -{ - csvFile csvOutputToCout({}, true); - Settings exportSettings; - exportSettings.exportingDirection = Vertical; - exportSettings.shouldWriteHeader = false; - exportSettings.resultsLabel = resultsLabel; - printResults(evaluationResults, exportSettings, csvOutputToCout); + return evaluateReducedModel(optimizationResult, scenariosDirectoryPath, + fullPatternTessellatedResultsDirectoryPath); } -void ReducedModelEvaluator::printResults(const Results &evaluationResults, - const Settings &settings, - csvFile &csvOutput) -{ - if (settings.shouldWriteHeader) { - csvOutput << csvExportingDataStrings[settings.exportingData]; - printHeader(settings, csvOutput); - // csvOutput << "Average error"; - // csvOutput<<"Cumulative error"; - csvOutput << endrow; - } - if (!settings.resultsLabel.empty()) { - csvOutput << settings.resultsLabel; - } - if (settings.exportingDirection == Vertical) { - printResultsVertically(evaluationResults, csvOutput); - } else { - printResultsHorizontally(evaluationResults, csvOutput); - } +void ReducedModelEvaluator::printResults(const Results& evaluationResults, + const std::string& resultsLabel) { + csvFile csvOutputToCout({}, true); + Settings exportSettings; + exportSettings.exportingDirection = Vertical; + exportSettings.shouldWriteHeader = false; + exportSettings.resultsLabel = resultsLabel; + printResults(evaluationResults, exportSettings, csvOutputToCout); } -void ReducedModelEvaluator::printHeader(const Settings &settings, csvFile &csvOutput) -{ - if (settings.exportingDirection == Horizontal) { - // csvOutput << "Job label"; - for (int jobIndex = 0; jobIndex < ReducedModelEvaluator::scenariosTestSetLabels.size(); - jobIndex++) { - const std::string &jobLabel = ReducedModelEvaluator::scenariosTestSetLabels[jobIndex]; - csvOutput << jobLabel; - } - } else { - std::cout << "Vertical header not defined" << std::endl; - assert(false); - std::terminate(); - } -} - -void ReducedModelEvaluator::printResultsHorizontally(const Results &evaluationResults, - csvFile &csvOutput) -{ - //print header - //print raw error - constexpr bool shouldPrintRawError = false; - if (shouldPrintRawError) { - // csvOutput << "drm2Reduced"; - double sumOfFull2Reduced = 0; - int numOfNonEvaluatedScenarios = 0; - for (int jobIndex = 0; jobIndex < ReducedModelEvaluator::scenariosTestSetLabels.size(); - jobIndex++) { - const double &distance_fullDrmToReduced = evaluationResults - .distances_drm2reduced[jobIndex]; - if (distance_fullDrmToReduced == -1) { - csvOutput << "notEvaluated"; - numOfNonEvaluatedScenarios++; - } else { - csvOutput << distance_fullDrmToReduced; - sumOfFull2Reduced += distance_fullDrmToReduced; - } - } - // const int numOfEvaluatedScenarios = ReducedModelEvaluator::scenariosTestSetLabels.size() - // - numOfNonEvaluatedScenarios; - // const double averageDistance_full2Reduced = sumOfFull2Reduced / numOfEvaluatedScenarios; - // csvOutput << averageDistance_full2Reduced; - // csvOutput << endrow; - } - //print normalized error - // csvOutput << "norm_drm2Reduced"; - double sumOfNormalizedFull2Reduced = 0; - for (int jobIndex = 0; jobIndex < ReducedModelEvaluator::scenariosTestSetLabels.size(); - jobIndex++) { - const double &distance_normalizedFullDrmToReduced - = evaluationResults.distances_normalizedDrm2reduced[jobIndex]; - if (distance_normalizedFullDrmToReduced == -1) { - csvOutput << "notEvaluated"; - } else { - csvOutput << distance_normalizedFullDrmToReduced; - sumOfNormalizedFull2Reduced += distance_normalizedFullDrmToReduced; - } - } - // const double averageDistance_normalizedFull2Reduced = sumOfNormalizedFull2Reduced - // / numOfEvaluatedScenarios; - // csvOutput << averageDistance_normalizedFull2Reduced; - // csvOutput << endrow; -} - -void ReducedModelEvaluator::printResultsVertically(const Results &evaluationResults, - csvFile &csvOutput) -{ -#ifdef POLYSCOPE_DEFINED - csvOutput << "pattern2Reduced" - << "norm_pattern2Reduced"; -#else - csvOutput << "Job Label" - << "drm2Reduced" - << "norm_drm2Reduced"; - -#endif +void ReducedModelEvaluator::printResults(const Results& evaluationResults, + const Settings& settings, + csvFile& csvOutput) { + if (settings.shouldWriteHeader) { + csvOutput << csvExportingDataStrings[settings.exportingData]; + printHeader(settings, csvOutput); csvOutput << endrow; + } + if (!settings.resultsLabel.empty()) { + csvOutput << settings.resultsLabel; + } + if (settings.exportingDirection == Vertical) { + printResultsVertically(evaluationResults, csvOutput); + } else { + printResultsHorizontally(evaluationResults, csvOutput); + } +} + +void ReducedModelEvaluator::printHeader(const Settings& settings, + csvFile& csvOutput) { + if (settings.exportingDirection == Horizontal) { + // csvOutput << "Job label"; + for (int jobIndex = 0; + jobIndex < ReducedModelEvaluator::scenariosTestSetLabels.size(); + jobIndex++) { + const std::string& jobLabel = + ReducedModelEvaluator::scenariosTestSetLabels[jobIndex]; + csvOutput << jobLabel; + } + } else { + std::cout << "Vertical header not defined" << std::endl; + assert(false); + std::terminate(); + } +} + +void ReducedModelEvaluator::printResultsHorizontally( + const Results& evaluationResults, + csvFile& csvOutput) { + // print header + // print raw error + constexpr bool shouldPrintRawError = false; + if (shouldPrintRawError) { double sumOfFull2Reduced = 0; - double sumOfNormalizedFull2Reduced = 0; int numOfNonEvaluatedScenarios = 0; - for (int jobIndex = 0; jobIndex < ReducedModelEvaluator::scenariosTestSetLabels.size(); + for (int jobIndex = 0; + jobIndex < ReducedModelEvaluator::scenariosTestSetLabels.size(); jobIndex++) { - const double &distance_fullDrmToReduced = evaluationResults.distances_drm2reduced[jobIndex]; - const double &distance_normalizedFullDrmToReduced - = evaluationResults.distances_normalizedDrm2reduced[jobIndex]; -#ifndef POLYSCOPE_DEFINED - const std::string &jobLabel = ReducedModelEvaluator::scenariosTestSetLabels[jobIndex]; - csvOutput << jobLabel; -#endif - if (distance_fullDrmToReduced == -1) { - csvOutput << "notEvaluated" - << "notEvaluated"; - numOfNonEvaluatedScenarios++; - } else { - csvOutput << distance_fullDrmToReduced << distance_normalizedFullDrmToReduced; - sumOfFull2Reduced += distance_fullDrmToReduced; - sumOfNormalizedFull2Reduced += distance_normalizedFullDrmToReduced; - } - csvOutput << endrow; - // sumOfNormalizedFull2Reduced += distance_normalizedFullDrmToReduced; + const double& distance_fullDrmToReduced = + evaluationResults.distances_drm2reduced[jobIndex]; + if (distance_fullDrmToReduced == -1) { + csvOutput << "notEvaluated"; + numOfNonEvaluatedScenarios++; + } else { + csvOutput << distance_fullDrmToReduced; + sumOfFull2Reduced += distance_fullDrmToReduced; + } } - const int numOfEvaluatedScenarios = ReducedModelEvaluator::scenariosTestSetLabels.size() - - numOfNonEvaluatedScenarios; - const double averageDistance_full2Reduced = sumOfFull2Reduced / numOfEvaluatedScenarios; - const double averageDistance_normalizedFull2Reduced = sumOfNormalizedFull2Reduced - / numOfEvaluatedScenarios; -#ifndef POLYSCOPE_DEFINED - csvOutput << "Average error"; -#endif - csvOutput << averageDistance_full2Reduced << averageDistance_normalizedFull2Reduced; - csvOutput << endrow; -#ifndef POLYSCOPE_DEFINED - csvOutput << "Cumulative error"; -#endif - csvOutput << sumOfFull2Reduced << sumOfNormalizedFull2Reduced; - csvOutput << endrow; - csvOutput << endrow; + } + // print normalized error + double sumOfNormalizedFull2Reduced = 0; + for (int jobIndex = 0; + jobIndex < ReducedModelEvaluator::scenariosTestSetLabels.size(); + jobIndex++) { + const double& distance_normalizedFullDrmToReduced = + evaluationResults.distances_normalizedDrm2reduced[jobIndex]; + if (distance_normalizedFullDrmToReduced == -1) { + csvOutput << "notEvaluated"; + } else { + csvOutput << distance_normalizedFullDrmToReduced; + sumOfNormalizedFull2Reduced += distance_normalizedFullDrmToReduced; + } + } } -//void ReducedModelEvaluator::createFullAndReducedPatternTessellations(){ +void ReducedModelEvaluator::printResultsVertically( + const Results& evaluationResults, + csvFile& csvOutput) { +#ifdef POLYSCOPE_DEFINED + csvOutput << "pattern2Reduced" + << "norm_pattern2Reduced"; +#else + csvOutput << "Job Label" + << "drm2Reduced" + << "norm_drm2Reduced"; -//} - -//ReducedModelEvaluator::Results ReducedModelEvaluator::evaluateReducedModel( -// std::vector &optimizationResults, -// const std::filesystem::path &tileInto_triMesh_filePath, -// const std::filesystem::path &scenariosDirectoryPath, -// // const std::filesystem::path &reducedPatternFilePath, -// const std::filesystem::path &fullPatternTessellatedResultsDirectoryPath) -//{ -// //Load surface -// std::shared_ptr pTileIntoSurface = [&]() { -// VCGTriMesh tileInto_triMesh; -// const bool surfaceLoadSuccessfull = tileInto_triMesh.load(tileInto_triMesh_filePath); -// assert(surfaceLoadSuccessfull); -// return PolygonalRemeshing::remeshWithPolygons(tileInto_triMesh); -// }(); -// const double optimizedBaseTriangleHeight = vcg::Distance(optimizationResult.baseTriangle.cP(0), -// (optimizationResult.baseTriangle.cP(1) -// + optimizationResult.baseTriangle.cP( -// 2)) -// / 2); -// pTileIntoSurface->moveToCenter(); -// const double scaleFactor = optimizedBaseTriangleHeight -// / pTileIntoSurface->getAverageFaceRadius(); -// vcg::tri::UpdatePosition::Scale(*pTileIntoSurface, scaleFactor); -// //Tile full pattern into surface - -//} +#endif + csvOutput << endrow; + double sumOfFull2Reduced = 0; + double sumOfNormalizedFull2Reduced = 0; + int numOfNonEvaluatedScenarios = 0; + for (int jobIndex = 0; + jobIndex < ReducedModelEvaluator::scenariosTestSetLabels.size(); + jobIndex++) { + const double& distance_fullDrmToReduced = + evaluationResults.distances_drm2reduced[jobIndex]; + const double& distance_normalizedFullDrmToReduced = + evaluationResults.distances_normalizedDrm2reduced[jobIndex]; +#ifndef POLYSCOPE_DEFINED + const std::string& jobLabel = + ReducedModelEvaluator::scenariosTestSetLabels[jobIndex]; + csvOutput << jobLabel; +#endif + if (distance_fullDrmToReduced == -1) { + csvOutput << "notEvaluated" + << "notEvaluated"; + numOfNonEvaluatedScenarios++; + } else { + csvOutput << distance_fullDrmToReduced + << distance_normalizedFullDrmToReduced; + sumOfFull2Reduced += distance_fullDrmToReduced; + sumOfNormalizedFull2Reduced += distance_normalizedFullDrmToReduced; + } + csvOutput << endrow; + } + const int numOfEvaluatedScenarios = + ReducedModelEvaluator::scenariosTestSetLabels.size() - + numOfNonEvaluatedScenarios; + const double averageDistance_full2Reduced = + sumOfFull2Reduced / numOfEvaluatedScenarios; + const double averageDistance_normalizedFull2Reduced = + sumOfNormalizedFull2Reduced / numOfEvaluatedScenarios; +#ifndef POLYSCOPE_DEFINED + csvOutput << "Average error"; +#endif + csvOutput << averageDistance_full2Reduced + << averageDistance_normalizedFull2Reduced; + csvOutput << endrow; +#ifndef POLYSCOPE_DEFINED + csvOutput << "Cumulative error"; +#endif + csvOutput << sumOfFull2Reduced << sumOfNormalizedFull2Reduced; + csvOutput << endrow; + csvOutput << endrow; +} ReducedModelEvaluator::Results ReducedModelEvaluator::evaluateReducedModel( - ReducedModelOptimization::Results &optimizationResult, - const std::filesystem::path &scenariosDirectoryPath, - const std::filesystem::path &fullPatternTessellatedResultsDirectoryPath) -{ - // const double optimizedBaseTriangleHeight = vcg::Distance(optimizationResult.baseTriangle.cP(0), - // (optimizationResult.baseTriangle.cP(1) - // + optimizationResult.baseTriangle.cP( - // 2)) - // / 2); - pTileIntoSurface->moveToCenter(); - const double scaleFactor = optimizationResult.settings.targetBaseTriangleSize - / pTileIntoSurface->getAverageFaceRadius(); - vcg::tri::UpdatePosition::Scale(*pTileIntoSurface, scaleFactor); - // tileIntoSurface.registerForDrawing(); - // polyscope::show(); + ReducedModelOptimization::Results& optimizationResult, + const std::filesystem::path& scenariosDirectoryPath, + const std::filesystem::path& patternTessellatedResultsDirectoryPath) { + // Apply optimization results to the reduced model + ReducedModel reducedModel; + reducedModel.deleteDanglingVertices(); + std::unordered_map optimalXVariables_set( + optimizationResult.optimalXNameValuePairs.begin(), + optimizationResult.optimalXNameValuePairs.end()); + reducedModel.updateBaseTriangleGeometry_R(optimalXVariables_set.at("R")); + reducedModel.updateBaseTriangleGeometry_theta( + optimalXVariables_set.at("Theta")); - //Tile full pattern into surface - std::vector fullPatterns(1); - fullPatterns[0].copy(optimizationResult.baseTriangleFullPattern); - //// Base triangle pattern might contain dangling vertices.Remove those - fullPatterns[0].interfaceNodeIndex = 3; - fullPatterns[0].deleteDanglingVertices(); - std::vector perSurfaceFacePatternIndices(pTileIntoSurface->FN(), 0); - std::vector> perPatternIndexTiledFullPatternEdgeIndices; - std::vector tileIntoEdgeToTiledFullVi; - std::shared_ptr pTiledFullPattern - = PatternGeometry::tilePattern(fullPatterns, - {}, - *pTileIntoSurface, - perSurfaceFacePatternIndices, - tileIntoEdgeToTiledFullVi, - perPatternIndexTiledFullPatternEdgeIndices); - pTiledFullPattern->setLabel("Tiled_full_patterns"); - // pTiledFullPattern->registerForDrawing(); - //Tile reduced pattern into surface - ReducedModel reducedModel; - reducedModel.deleteDanglingVertices(); - std::unordered_map - optimalXVariables_set(optimizationResult.optimalXNameValuePairs.begin(), - optimizationResult.optimalXNameValuePairs.end()); - reducedModel.updateBaseTriangleGeometry_R(optimalXVariables_set.at("R")); - reducedModel.updateBaseTriangleGeometry_theta(optimalXVariables_set.at("Theta")); - // const auto reducedPatternBaseTriangle = reducedModel.computeBaseTriangle(); - // ReducedModelOptimization::Results::applyOptimizationResults_reducedModel_nonFanned( - // optimizationResult, reducedPatternBaseTriangle, reducedModel); + // reducedModel.registerForDrawing(); - std::vector reducedPatterns(1); - reducedPatterns[0].copy(reducedModel); - std::vector> perPatternIndexTiledReducedPatternEdgeIndices; - std::vector tileIntoEdgeToTiledReducedVi; - std::shared_ptr pTiledReducedPattern - = PatternGeometry::tilePattern(reducedPatterns, - {0}, - *pTileIntoSurface, - perSurfaceFacePatternIndices, - tileIntoEdgeToTiledReducedVi, - perPatternIndexTiledReducedPatternEdgeIndices); - pTiledReducedPattern->setLabel("Tiled_reduced_patterns"); + // Scale tile-into surface + pTileIntoSurface->moveToCenter(); + const double scaleFactor = + optimizationResult.settings.targetBaseTriangleSize / + pTileIntoSurface->getAverageFaceRadius(); + vcg::tri::UpdatePosition::Scale(*pTileIntoSurface, scaleFactor); #ifdef POLYSCOPE_DEFINED - pTiledReducedPattern->registerForDrawing(); + pTileIntoSurface->registerForDrawing(color_tileIntoSurface); #endif - std::unordered_map - fullToReducedViMap; //of only the common vertices - std::unordered_map - reducedToFullViMap; //of only the common vertices - for (int ei = 0; ei < pTileIntoSurface->EN(); ei++) { - fullToReducedViMap[tileIntoEdgeToTiledFullVi[ei]] = tileIntoEdgeToTiledReducedVi[ei]; - } - constructInverseMap(fullToReducedViMap, reducedToFullViMap); + // Tile full pattern into surface + std::vector patterns(1); + patterns[0].copy(optimizationResult.baseTrianglePattern); + patterns[0].interfaceNodeIndex = 3; + patterns[0].deleteDanglingVertices(); + std::vector perSurfaceFacePatternIndices(pTileIntoSurface->FN(), 0); + std::vector> perPatternIndexTiledFullPatternEdgeIndices; + std::vector tileIntoEdgeToTiledFullVi; + std::shared_ptr pTilled_pattern = + PatternGeometry::tilePattern(patterns, {}, *pTileIntoSurface, + perSurfaceFacePatternIndices, + tileIntoEdgeToTiledFullVi, + perPatternIndexTiledFullPatternEdgeIndices); + pTilled_pattern->setLabel("Tilled_pattern"); - std::vector tilledFullPatternInterfaceVi; - tilledFullPatternInterfaceVi.clear(); - tilledFullPatternInterfaceVi.resize(fullToReducedViMap.size()); - size_t viIndex = 0; - for (std::pair fullToReducedPair : fullToReducedViMap) { - tilledFullPatternInterfaceVi[viIndex++] = fullToReducedPair.first; - } + // Tile reduced pattern into surface + std::vector reducedModels(1); + reducedModels[0].copy(reducedModel); + std::vector> + perPatternIndexTiledReducedPatternEdgeIndices; + std::vector tileIntoEdgeToTiledReducedVi; + std::shared_ptr pTilled_reducedModel = + PatternGeometry::tilePattern( + reducedModels, {0}, *pTileIntoSurface, perSurfaceFacePatternIndices, + tileIntoEdgeToTiledReducedVi, + perPatternIndexTiledReducedPatternEdgeIndices); + pTilled_reducedModel->setLabel("Tilled_reduced_model"); - //Create simulation meshes - ////Tessellated full pattern simulation mesh - std::shared_ptr pTiledFullPattern_simulationMesh; - pTiledFullPattern_simulationMesh = std::make_shared(*pTiledFullPattern); - //NOTE: Those should be derived from the optimization results instead of hardcoding them - // const double beamWidth = optimizationResult.settings.patternBeamDimensions.getWidth(); - // const double beamHeight = optimizationResult.settings.patternBeamDimensions.getHeight(); - pTiledFullPattern_simulationMesh->setBeamCrossSection( - optimizationResult.settings.patternBeamDimensions); - if (optimizationResult.fullPatternYoungsModulus == 0) { - std::cerr << "Full pattern's young modulus not found." << std::endl; - std::terminate(); - } - pTiledFullPattern_simulationMesh->setBeamMaterial(0.3, - optimizationResult.fullPatternYoungsModulus); - pTiledFullPattern_simulationMesh->reset(); + std::unordered_map + fullToReducedViMap; // of only the common vertices + std::unordered_map + reducedToFullViMap; // of only the common vertices + for (int ei = 0; ei < pTileIntoSurface->EN(); ei++) { + fullToReducedViMap[tileIntoEdgeToTiledFullVi[ei]] = + tileIntoEdgeToTiledReducedVi[ei]; + } + constructInverseMap(fullToReducedViMap, reducedToFullViMap); - ////Tessellated reduced pattern simulation mesh - std::shared_ptr pTiledReducedPattern_simulationMesh; - pTiledReducedPattern_simulationMesh = std::make_shared(*pTiledReducedPattern); - const std::vector &tiledPatternElementIndicesForReducedPattern - = perPatternIndexTiledReducedPatternEdgeIndices[0]; - ReducedModelOptimization::Results::applyOptimizationResults_elements( - optimizationResult, pTiledReducedPattern_simulationMesh); - // pTiledReducedPattern_simulationMesh->reset(); - Results evaluationResults; - evaluationResults.distances_drm2reduced.fill(-1); - evaluationResults.distances_normalizedDrm2reduced.fill(-1); - DRMSimulationModel::Settings drmSimulationSettings; - drmSimulationSettings.totalExternalForcesNormPercentageTermination = 1e-3; - // drmSimulationSettings.load(drmSettingsFilePath); - drmSimulationSettings.beVerbose = true; - drmSimulationSettings.maxDRMIterations = 5e6; - drmSimulationSettings.debugModeStep = 100000; - drmSimulationSettings.translationalKineticEnergyThreshold = 1e-15; - drmSimulationSettings.linearGuessForceScaleFactor = 0.8; - drmSimulationSettings.viscousDampingFactor = 7e-3; - drmSimulationSettings.xi = 0.9999; - // drmSimulationSettings.Dtini = 5.86; - drmSimulationSettings.gamma = 0.25; + std::vector tilledFullPatternInterfaceVi; + tilledFullPatternInterfaceVi.clear(); + tilledFullPatternInterfaceVi.resize(fullToReducedViMap.size()); + size_t viIndex = 0; + for (std::pair fullToReducedPair : fullToReducedViMap) { + tilledFullPatternInterfaceVi[viIndex++] = fullToReducedPair.first; + } + + // Create simulation meshes + ////Tessellated full pattern simulation mesh + std::shared_ptr pSimulationEdgeMesh_tilledPattern = + std::make_shared(*pTilled_pattern); + pSimulationEdgeMesh_tilledPattern->setBeamCrossSection( + optimizationResult.settings.beamDimensions_pattern); + if (optimizationResult.settings.youngsModulus_pattern == 0) { + std::cerr << "Full pattern's young modulus not found." << std::endl; + std::terminate(); + } + pSimulationEdgeMesh_tilledPattern->setBeamMaterial( + 0.3, optimizationResult.settings.youngsModulus_pattern); + pSimulationEdgeMesh_tilledPattern->reset(); + // optimizationResult.draw(); #ifdef POLYSCOPE_DEFINED - // drmSimulationSettings.shouldDraw = true; - drmSimulationSettings.shouldCreatePlots = true; -#endif - constexpr bool shouldRerunFullPatternSimulation = false; - const std::string &simulationModelLabel = optimizationResult.settings.simulationModelLabel; - // for (int jobIndex = 0; jobIndex < scenariosTestSetLabels.size(); jobIndex++) { - std::for_each( - //#ifndef POLYSCOPE_DEFINED - std::execution::par_unseq, - //#endif - scenariosTestSetLabels.begin(), - scenariosTestSetLabels.end(), - [&](const std::string &jobLabel) { - //check if reduced model scenario exists - // const std::string &jobLabel = scenariosTestSetLabels[jobIndex]; - const std::filesystem::path tiledReducedPatternJobFilePath - = std::filesystem::path(scenariosDirectoryPath) - .append(pTileIntoSurface->getLabel()) - .append(jobLabel) - .append("ReducedJob") - .append(SimulationJob::jsonDefaultFileName); - if (!std::filesystem::exists(tiledReducedPatternJobFilePath)) { - std::cerr << "Scenario " << jobLabel - << " not found in:" << tiledReducedPatternJobFilePath << std::endl; - // continue; //if not move on to the next scenario - return; - } - //Map the reduced job to the job on the pattern tessellation - //set jobs - std::shared_ptr pJob_tiledReducedPattern; - pJob_tiledReducedPattern = std::make_shared(SimulationJob()); - pJob_tiledReducedPattern->load(tiledReducedPatternJobFilePath, false); - pJob_tiledReducedPattern->pMesh = pTiledReducedPattern_simulationMesh; - std::shared_ptr pJob_tiledFullPattern; - pJob_tiledFullPattern = std::make_shared(SimulationJob()); - pJob_tiledFullPattern->pMesh = pTiledFullPattern_simulationMesh; - pJob_tiledReducedPattern->remap(reducedToFullViMap, *pJob_tiledFullPattern); - // pJob_tiledReducedPattern->registerForDrawing(pTiledReducedPattern->getLabel()); - // pJob_tiledFullPattern->registerForDrawing(pTiledFullPattern->getLabel()); - // polyscope::show(); - const std::filesystem::path surfaceFolderPath - = std::filesystem::path(fullPatternTessellatedResultsDirectoryPath) - .append(simulationModelLabel + "_" + pTileIntoSurface->getLabel()); - const std::string scenarioLabel = pJob_tiledFullPattern->getLabel(); - const std::filesystem::path scenarioDirectoryPath - = std::filesystem::path(surfaceFolderPath).append(scenarioLabel); - //Save reduced job - constexpr bool exportReducedJob = false; - if (exportReducedJob) { - const std::filesystem::path reducedJobDirectoryPath - = std::filesystem::path(scenarioDirectoryPath).append("ReducedJob"); - std::filesystem::create_directories(reducedJobDirectoryPath); - pJob_tiledReducedPattern->save(reducedJobDirectoryPath); - } - //Check if the drm simulation of the full pattern has already been computed - ////Full - const std::string &patternLabel = [&]() { - const std::string patternLabel = optimizationResult.baseTriangleFullPattern - .getLabel(); - if (patternLabel.find("_") == std::string::npos) { - return std::to_string(optimizationResult.baseTriangleFullPattern.EN()) + "_" - + patternLabel; - } else { - return patternLabel; - } - }(); - const auto tilledPatternResultsFolderPath = std::filesystem::path(scenarioDirectoryPath) - .append(patternLabel) - .append("Results"); - if (shouldRerunFullPatternSimulation - && std::filesystem::exists(tilledPatternResultsFolderPath)) { - std::filesystem::remove_all(tilledPatternResultsFolderPath); - } - - const std::filesystem::path fullPatternJobFolderPath = std::filesystem::path( - scenarioDirectoryPath) - .append(patternLabel) - .append("SimulationJob"); - SimulationResults simulationResults_tilledPattern; - if (std::filesystem::exists(tilledPatternResultsFolderPath)) { - //Load full pattern results - assert(std::filesystem::exists(fullPatternJobFolderPath)); - simulationResults_tilledPattern.load(tilledPatternResultsFolderPath, - fullPatternJobFolderPath); - //#ifdef POLYSCOPE_DEFINED - // std::array resultsColor({28.0, 99.0, 227.0}); - // simulationResults_tiledFullPattern_drm.registerForDrawing(resultsColor); - // std::ifstream ifs("CameraSettings.json"); - // nlohmann::json json; - // ifs >> json; - // polyscope::view::setCameraFromJson(json.dump(), false); - // // polyscope::show(); - // const std::string cameraJson = polyscope::view::getCameraJson(); - // std::filesystem::path jsonFilePath("CameraSettings.json"); - // std::ofstream jsonFile_cameraSettings(jsonFilePath.string()); - // jsonFile_cameraSettings << cameraJson; - // jsonFile_cameraSettings.close(); - // std::filesystem::create_directories("screenshots"); - // const std::string screenshotOutputFilePath - // = (std::filesystem::current_path() - // .append("screenshots") - // .append(optimizationResult.label + "_" + pJob_tiledFullPattern->getLabel())) - // .string() - // + ".png"; - // // std::cout << "Saving image to:" << screenshotOutputFilePath << std::endl; - // polyscope::screenshot(screenshotOutputFilePath, false); - // simulationResults_tiledFullPattern_drm.unregister(); - //#endif - - simulationResults_tilledPattern.converged = true; - } else { - std::cout << "Tilled pattern simulation results not found in:" - << tilledPatternResultsFolderPath << std::endl; - //Full - std::cout << "Executing:" << jobLabel << std::endl; - SimulationModelFactory factory; - std::unique_ptr pTilledPatternSimulationModel = factory.create( - simulationModelLabel); - //TODO: since the drm simulation model does not have a common interface with the rest of simulation models I need to cast it in order to pass simulation settings. Fix it by removing the SimulationSettings argument - if (simulationModelLabel == DRMSimulationModel::label) { - simulationResults_tilledPattern = static_cast( - pTilledPatternSimulationModel.get()) - ->executeSimulation(pJob_tiledFullPattern, - drmSimulationSettings); - } else if (simulationModelLabel == ChronosEulerSimulationModel::label) { - simulationResults_tilledPattern - = pTilledPatternSimulationModel->executeSimulation(pJob_tiledFullPattern); - } else { - std::cerr << "Simulation model used for computing the optimization results was " - "not recognized" - << std::endl; - std::terminate(); - } - } - if (!simulationResults_tilledPattern.converged) { - std::cerr << "Full pattern simulation failed." << std::endl; - std::cerr << "Not saving results" << std::endl; - // continue; - return; - } - std::filesystem::create_directories(tilledPatternResultsFolderPath); - const std::filesystem::path drmResultsOutputPath - = std::filesystem::path(scenarioDirectoryPath).append(patternLabel); - simulationResults_tilledPattern.save(drmResultsOutputPath); - - LinearSimulationModel linearSimulationModel; - SimulationResults simulationResults_tiledReducedModel - = linearSimulationModel.executeSimulation(pJob_tiledReducedPattern); - -#ifdef POLYSCOPE_DEFINED - simulationResults_tiledReducedModel.registerForDrawing(); - simulationResults_tilledPattern.registerForDrawing(); - polyscope::show(); + pSimulationEdgeMesh_tilledPattern->registerForDrawing( + color_tesselatedPatterns); #endif - //compute the full2reduced distance - const double distance_patternToReduced - = simulationResults_tilledPattern - .computeDistance(simulationResults_tiledReducedModel, fullToReducedViMap); - double distance_patternSumOfAllVerts = 0; - for (std::pair fullToReducedPair : fullToReducedViMap) { - distance_patternSumOfAllVerts += simulationResults_tilledPattern - .displacements[fullToReducedPair.first] - .getTranslation() - .norm(); - } - const double distance_normalizedPatternToReduced = distance_patternToReduced - / distance_patternSumOfAllVerts; - const int jobIndex = &jobLabel - &scenariosTestSetLabels[0]; - evaluationResults.distances_drm2reduced[jobIndex] = distance_patternToReduced; - evaluationResults.distances_normalizedDrm2reduced[jobIndex] - = distance_normalizedPatternToReduced; - }); + ////Tessellated reduced pattern simulation mesh + std::shared_ptr pSimulationEdgeMesh_tilledReducedModel; + pSimulationEdgeMesh_tilledReducedModel = + std::make_shared(*pTilled_reducedModel); + ReducedModelOptimization::Results::applyOptimizationResults_elements( + optimizationResult, pSimulationEdgeMesh_tilledReducedModel); + pSimulationEdgeMesh_tilledReducedModel->reset(); +#ifdef POLYSCOPE_DEFINED + pSimulationEdgeMesh_tilledReducedModel->registerForDrawing( + color_tesselatedReducedModels); + polyscope::show(); +#endif - return evaluationResults; + Results evaluationResults; + evaluationResults.distances_drm2reduced.fill(-1); + evaluationResults.distances_normalizedDrm2reduced.fill(-1); + DRMSimulationModel::Settings drmSimulationSettings; + // drmSimulationSettings.threshold_residualToExternalForcesNorm = 1e-3; + // drmSimulationSettings.load(drmSettingsFilePath); + drmSimulationSettings.beVerbose = true; + drmSimulationSettings.maxDRMIterations = 5e6; + drmSimulationSettings.debugModeStep = 100000; + drmSimulationSettings.threshold_totalTranslationalKineticEnergy = 1e-14; + // drmSimulationSettings.threshold_currentToFirstPeakTranslationalKineticEnergy + // = + // 1e-10; + drmSimulationSettings.threshold_averageResidualToExternalForcesNorm = 1e-5; +// drmSimulationSettings.linearGuessForceScaleFactor = 0.8; +// drmSimulationSettings.viscousDampingFactor = 7e-3; +// drmSimulationSettings.xi = 0.9999; +// drmSimulationSettings.gamma = 0.25; +#ifdef POLYSCOPE_DEFINED + // drmSimulationSettings.shouldDraw = true; + drmSimulationSettings.shouldCreatePlots = false; + constexpr bool shouldDrawScenarioResults = true; + if (shouldDrawScenarioResults) { + pSimulationEdgeMesh_tilledPattern->registerForDrawing( + ReducedModelOptimization::Colors::patternInitial); + } +#endif + const std::string& simulationModelLabel_pattern = + optimizationResult.settings.simulationModelLabel_groundTruth; + const std::string& simulationModelLabel_reducedModel = + optimizationResult.settings.simulationModelLabel_reducedModel; + const bool shouldRerunFullPatternSimulation = [&]() { + // if (simulationModelLabel_pattern == DRMSimulationModel::label) { + return false; + // } + // return true; + }(); + std::for_each( +#ifndef POLYSCOPE_DEFINED + std::execution::par_unseq, +#endif + scenariosTestSetLabels.begin(), scenariosTestSetLabels.end(), + [&](const std::string& jobLabel) { + // check if reduced model scenario exists + // const std::string &jobLabel = + // scenariosTestSetLabels[jobIndex]; + const std::filesystem::path tiledReducedPatternJobFilePath = + std::filesystem::path(scenariosDirectoryPath) + .append(pTileIntoSurface->getLabel()) + .append(jobLabel) + .append("ReducedJob") + .append(SimulationJob::jsonDefaultFileName); + if (!std::filesystem::exists(tiledReducedPatternJobFilePath)) { + std::cerr << "Scenario " << jobLabel + << " not found in:" << tiledReducedPatternJobFilePath + << std::endl; + // continue; //if not move on to the next scenario + return; + } + // Map the reduced job to the job on the pattern tessellation + // set jobs + std::shared_ptr pJob_tiledReducedModel; + pJob_tiledReducedModel = + std::make_shared(SimulationJob()); + pJob_tiledReducedModel->load(tiledReducedPatternJobFilePath, false); + pJob_tiledReducedModel->pMesh = pSimulationEdgeMesh_tilledReducedModel; + std::shared_ptr pJob_tilledPattern; + pJob_tilledPattern = std::make_shared(SimulationJob()); + pJob_tilledPattern->pMesh = pSimulationEdgeMesh_tilledPattern; + pJob_tiledReducedModel->remap(reducedToFullViMap, *pJob_tilledPattern); + // pJob_tiledReducedPattern->registerForDrawing(pTiledReducedPattern->getLabel()); + // pJob_tiledFullPattern->registerForDrawing(pTiledFullPattern->getLabel()); + // polyscope::show(); + const std::filesystem::path surfaceFolderPath = + std::filesystem::path(patternTessellatedResultsDirectoryPath) + .append(simulationModelLabel_pattern + "_" + + pTileIntoSurface->getLabel()); + const std::string scenarioLabel = pJob_tilledPattern->getLabel(); + const std::filesystem::path scenarioDirectoryPath = + std::filesystem::path(surfaceFolderPath).append(scenarioLabel); + // Save reduced job + constexpr bool exportReducedJob = false; + if (exportReducedJob) { + const std::filesystem::path reducedJobDirectoryPath = + std::filesystem::path(scenarioDirectoryPath).append("ReducedJob"); + std::filesystem::create_directories(reducedJobDirectoryPath); + pJob_tiledReducedModel->save(reducedJobDirectoryPath); + } + // Check if the drm simulation of the full pattern has already been + // computed + ////Full + const std::string& patternLabel = [&]() { + const std::string patternLabel = + optimizationResult.baseTrianglePattern.getLabel(); + if (patternLabel.find("_") == std::string::npos) { + return std::to_string(optimizationResult.baseTrianglePattern.EN()) + + "_" + patternLabel; + } else { + return patternLabel; + } + }(); + const auto tilledPatternResultsFolderPath = + std::filesystem::path(scenarioDirectoryPath) + .append(patternLabel) + .append("Results"); + if (shouldRerunFullPatternSimulation && + std::filesystem::exists(tilledPatternResultsFolderPath)) { + std::filesystem::remove_all(tilledPatternResultsFolderPath); + } + + const std::filesystem::path fullPatternJobFolderPath = + std::filesystem::path(scenarioDirectoryPath) + .append(patternLabel) + .append("SimulationJob"); + SimulationResults simulationResults_tilledPattern; + if (std::filesystem::exists(tilledPatternResultsFolderPath)) { + // Load full pattern results + assert(std::filesystem::exists(fullPatternJobFolderPath)); + simulationResults_tilledPattern.load(tilledPatternResultsFolderPath, + fullPatternJobFolderPath); +#ifdef POLYSCOPE_DEFINED + simulationResults_tilledPattern.registerForDrawing( + color_tesselatedPatterns); + // std::ifstream ifs("CameraSettings.json"); + // nlohmann::json json; + // ifs >> json; + // polyscope::view::setCameraFromJson(json.dump(), false); + polyscope::show(); + const std::string cameraJson = polyscope::view::getCameraJson(); + std::filesystem::path jsonFilePath("CameraSettings.json"); + std::ofstream jsonFile_cameraSettings(jsonFilePath.string()); + jsonFile_cameraSettings << cameraJson; + jsonFile_cameraSettings.close(); + std::filesystem::create_directories("screenshots"); + const std::string screenshotOutputFilePath = + (std::filesystem::current_path() + .append("screenshots") + .append(optimizationResult.label + "_" + + pJob_tilledPattern->getLabel())) + .string() + + ".png"; + std::cout << "Saving image to:" << screenshotOutputFilePath + << std::endl; + polyscope::screenshot(screenshotOutputFilePath, false); + simulationResults_tilledPattern.unregister(); +#endif + + simulationResults_tilledPattern.converged = true; + } else { + std::cout << "Tilled pattern simulation results not found in:" + << tilledPatternResultsFolderPath << std::endl; + // Full + std::cout << "Executing:" << jobLabel << std::endl; + SimulationModelFactory factory; + std::unique_ptr pTilledPatternSimulationModel = + factory.create(simulationModelLabel_pattern); + // TODO: since the drm simulation model does not have a common + // interface with the rest of simulation models I need to cast it in + // order to pass simulation settings. Fix it by removing the + // SimulationSettings argument + if (simulationModelLabel_pattern == DRMSimulationModel::label) { + simulationResults_tilledPattern = + static_cast( + pTilledPatternSimulationModel.get()) + ->executeSimulation(pJob_tilledPattern, + drmSimulationSettings); + } else { + simulationResults_tilledPattern = + pTilledPatternSimulationModel->executeSimulation( + pJob_tilledPattern); + } + } + if (!simulationResults_tilledPattern.converged) { + std::cerr << "Full pattern simulation failed." << std::endl; + std::cerr << "Not saving results" << std::endl; + // continue; + return; + } + std::filesystem::create_directories(tilledPatternResultsFolderPath); + const std::filesystem::path drmResultsOutputPath = + std::filesystem::path(scenarioDirectoryPath).append(patternLabel); + simulationResults_tilledPattern.save(drmResultsOutputPath); + + // LinearSimulationModel linearSimulationModel; + SimulationModelFactory factory; + std::unique_ptr pSimulationModel_tilledReducedModel = + factory.create(simulationModelLabel_reducedModel); + SimulationResults simulationResults_tiledReducedModel = + pSimulationModel_tilledReducedModel->executeSimulation( + pJob_tiledReducedModel); + + // ChronosEulerNonLinearSimulationModel + // debug_chronosNonLinearSimulationModel; + // const auto debug_chronosResults = + // debug_chronosNonLinearSimulationModel.executeSimulation( + // pJob_tilledPattern); + // LinearSimulationModel debug_linearSimulationModel; + // const auto debug_linearSimResults = + // debug_linearSimulationModel.executeSimulation(pJob_tilledPattern); + +#ifdef POLYSCOPE_DEFINED + if (shouldDrawScenarioResults) { + simulationResults_tiledReducedModel.registerForDrawing( + ReducedModelOptimization::Colors::reducedDeformed, true, + simulationResults_tilledPattern.pJob->pMesh + ->getBeamDimensions()[0] + .getDrawingRadius()); + simulationResults_tilledPattern.registerForDrawing( + ReducedModelOptimization::Colors::patternDeformed); + // debug_chronosResults.registerForDrawing(); + // debug_linearSimResults.registerForDrawing(); + polyscope::show(); + // debug_linearSimResults.unregister(); + simulationResults_tiledReducedModel.unregister(); + simulationResults_tilledPattern.unregister(); + // debug_chronosResults.unregister(); + } +#endif + + // compute the full2reduced distance + const double distance_patternToReduced = + simulationResults_tilledPattern.computeDistance( + simulationResults_tiledReducedModel, fullToReducedViMap); + double distance_patternSumOfAllVerts = 0; + for (std::pair fullToReducedPair : fullToReducedViMap) { + distance_patternSumOfAllVerts += + simulationResults_tilledPattern + .displacements[fullToReducedPair.first] + .getTranslation() + .norm(); + } + const double distance_normalizedPatternToReduced = + distance_patternToReduced / distance_patternSumOfAllVerts; + const int jobIndex = &jobLabel - &scenariosTestSetLabels[0]; + evaluationResults.distances_drm2reduced[jobIndex] = + distance_patternToReduced; + evaluationResults.distances_normalizedDrm2reduced[jobIndex] = + distance_normalizedPatternToReduced; + }); + + return evaluationResults; } diff --git a/reducedmodelevaluator.hpp b/reducedmodelevaluator.hpp index 4b928f3..06cacdc 100644 --- a/reducedmodelevaluator.hpp +++ b/reducedmodelevaluator.hpp @@ -2,102 +2,106 @@ #define REDUCEDMODELEVALUATOR_HPP #include "reducedmodeloptimizer_structs.hpp" +#include "utilities.hpp" -class ReducedModelEvaluator -{ -public: - enum CSVExportingDirection { Vertical = 0, Horizontal }; - enum CSVExportingData { - raw_drm2Reduced = 0, - norm_drm2Reduced, - raw_and_norm_drm2Reduced, - NumberOfDataTypes - }; - inline static std::array - csvExportingDataStrings{"raw_drm2Reduced", "norm_drm2Reduced", "raw_and_norm_drm2Reduced"}; - struct Settings - { - CSVExportingDirection exportingDirection{Horizontal}; - CSVExportingData exportingData{norm_drm2Reduced}; - bool shouldWriteHeader{true}; - std::string resultsLabel; - }; +class ReducedModelEvaluator { + public: + enum CSVExportingDirection { Vertical = 0, Horizontal }; + enum CSVExportingData { + raw_drm2Reduced = 0, + norm_drm2Reduced, + raw_and_norm_drm2Reduced, + NumberOfDataTypes + }; + inline static std::array + csvExportingDataStrings{"raw_drm2Reduced", "norm_drm2Reduced", + "raw_and_norm_drm2Reduced"}; + struct Settings { + CSVExportingDirection exportingDirection{Horizontal}; + CSVExportingData exportingData{norm_drm2Reduced}; + bool shouldWriteHeader{true}; + std::string resultsLabel; + }; - inline static constexpr int NumberOfEvaluationScenarios{22}; - struct Results - { - std::array distances_drm2reduced; - std::array distances_normalizedDrm2reduced; - std::array evaluationScenarioLabels; - }; - ReducedModelEvaluator(); - Results evaluateReducedModel( - ReducedModelOptimization::Results &optimizationResult, - const std::filesystem::path &scenariosDirectoryPath, - // const std::filesystem::path &reducedPatternFilePath, - const std::filesystem::path &fullPatternTessellatedResultsDirectoryPath); - Results evaluateReducedModel(ReducedModelOptimization::Results &optimizationResult); - static void printResultsVertically(const ReducedModelEvaluator::Results &evaluationResults, - csvFile &csvOutput); - static void printResults(const ReducedModelEvaluator::Results &evaluationResults, - const std::string &resultsLabel); + inline static constexpr int NumberOfEvaluationScenarios{22}; + struct Results { + std::array distances_drm2reduced; + std::array + distances_normalizedDrm2reduced; + std::array + evaluationScenarioLabels; + }; + ReducedModelEvaluator(); + Results evaluateReducedModel( + ReducedModelOptimization::Results& optimizationResult, + const std::filesystem::path& scenariosDirectoryPath, + // const std::filesystem::path &reducedPatternFilePath, + const std::filesystem::path& fullPatternTessellatedResultsDirectoryPath); + Results evaluateReducedModel( + ReducedModelOptimization::Results& optimizationResult); + static void printResultsVertically( + const ReducedModelEvaluator::Results& evaluationResults, + csvFile& csvOutput); + static void printResults( + const ReducedModelEvaluator::Results& evaluationResults, + const std::string& resultsLabel); - inline static std::array scenariosTestSetLabels{ - "22Hex_randomBending0", - "22Hex_randomBending1", - "22Hex_randomBending2", - // "22Hex_randomBending3", - "22Hex_randomBending4", - "22Hex_randomBending5", - // "22Hex_randomBending6", - // "22Hex_randomBending7", - "22Hex_randomBending8", - "22Hex_randomBending9", - "22Hex_randomBending10", - "22Hex_randomBending11", - "22Hex_randomBending12", - // "22Hex_randomBending13", - // "22Hex_randomBending14", - // "22Hex_randomBending15", - "22Hex_randomBending16", - "22Hex_randomBending17", - "22Hex_randomBending18", - "22Hex_randomBending19", - // "22Hex_randomBending20", - "22Hex_bending_0.005N", - "22Hex_bending_0.01N", - "22Hex_bending_0.03N", - // "22Hex_bending_0.05N", - "22Hex_pullOppositeVerts_0.05N", - "22Hex_pullOppositeVerts_0.1N", - // "22Hex_pullOppositeVerts_0.3N", - //#ifdef POLYSCOPE_DEFINED - // "22Hex_shear_2N", - // "22Hex_shear_5N", - // "22Hex_axial_10N", - // "22Hex_axial_20N", - //#else - // "notUsed_22Hex_shear_2N", - // "notUsed_22Hex_shear_5N", - // "notUsed_22Hex_axial_10N", - // "notUsed_22Hex_axial_20N", - //#endif - "22Hex_cylinder_0.05N", - "22Hex_cylinder_0.1N", - "22Hex_s_0.05N", - // "22Hex_s_0.1N" - }; - static void printResultsHorizontally(const Results &evaluationResults, csvFile &csvOutput); - static void printResults(const Results &evaluationResults, - const Settings &settings, - csvFile &csvOutput); - static void printHeader(const Settings &settings, csvFile &csvOutput); - // static double evaluateOptimizationSettings( - // const ReducedModelOptimization::Settings &optimizationSettings, - // const std::vector> &pPatterns, - // std::vector &patternEvaluationResults); - std::shared_ptr pTileIntoSurface; - inline static constexpr char *tileIntoSurfaceFileContent = R"~(OFF + inline static std::array + scenariosTestSetLabels{ + "22Hex_randomBending0", "22Hex_randomBending1", + "22Hex_randomBending2", + // "22Hex_randomBending3", + "22Hex_randomBending4", "22Hex_randomBending5", + // "22Hex_randomBending6", + // "22Hex_randomBending7", + "22Hex_randomBending8", "22Hex_randomBending9", + "22Hex_randomBending10", "22Hex_randomBending11", + "22Hex_randomBending12", + // "22Hex_randomBending13", + // "22Hex_randomBending14", + // "22Hex_randomBending15", + "22Hex_randomBending16", "22Hex_randomBending17", + "22Hex_randomBending18", "22Hex_randomBending19", + // "22Hex_randomBending20", + "22Hex_bending_0.005N", "22Hex_bending_0.01N", "22Hex_bending_0.03N", + // "22Hex_bending_0.05N", + "22Hex_pullOppositeVerts_0.05N", "22Hex_pullOppositeVerts_0.1N", + // "22Hex_pullOppositeVerts_0.3N", + //#ifdef POLYSCOPE_DEFINED + // "22Hex_shear_2N", + // "22Hex_shear_5N", + // "22Hex_axial_10N", + // "22Hex_axial_20N", + //#else + // "notUsed_22Hex_shear_2N", + // "notUsed_22Hex_shear_5N", + // "notUsed_22Hex_axial_10N", + // "notUsed_22Hex_axial_20N", + //#endif + "22Hex_cylinder_0.05N", "22Hex_cylinder_0.1N", "22Hex_s_0.05N", + // "22Hex_s_0.1N" + }; + static void printResultsHorizontally(const Results& evaluationResults, + csvFile& csvOutput); + static void printResults(const Results& evaluationResults, + const Settings& settings, + csvFile& csvOutput); + static void printHeader(const Settings& settings, csvFile& csvOutput); + // static double evaluateOptimizationSettings( + // const ReducedModelOptimization::Settings &optimizationSettings, + // const std::vector> &pPatterns, + // std::vector + // &patternEvaluationResults); + std::shared_ptr pTileIntoSurface; + ReducedModelOptimization::Colors::RGBColor color_tesselatedPatterns{ + 24.0 / 255, 23.0 / 255, 23.0 / 255}; + ReducedModelOptimization::Colors::RGBColor color_tesselatedReducedModels{ + 67.0 / 255, 160.00 / 255, 232.0 / 255}; + ReducedModelOptimization::Colors::RGBColor color_tileIntoSurface{ + 222 / 255.0, 235 / 255.0, 255 / 255.0}; + ReducedModelOptimization::Colors::RGBColor interfaceNodes_color{ + 63.0 / 255, 85.0 / 255, 42.0 / 255}; + inline static constexpr char* tileIntoSurfaceFileContent = R"~(OFF 46 66 0 -0.0745923 0.03573945 0 -0.07464622 0.02191801 0 @@ -214,4 +218,4 @@ public: )~"; }; -#endif // REDUCEDMODELEVALUATOR_HPP +#endif // REDUCEDMODELEVALUATOR_HPP diff --git a/reducedmodeloptimizer.cpp b/reducedmodeloptimizer.cpp index 3774873..a90df3c 100644 --- a/reducedmodeloptimizer.cpp +++ b/reducedmodeloptimizer.cpp @@ -1,1535 +1,1746 @@ #include "reducedmodeloptimizer.hpp" +#include "chronoseulersimulationmodel.hpp" +#include "chronosigasimulationmodel.hpp" #include "hexagonremesher.hpp" #include "linearsimulationmodel.hpp" #include "simulationhistoryplotter.hpp" +#include "simulationmodelfactory.hpp" #include "trianglepatterngeometry.hpp" #include "trianglepattterntopology.hpp" -//#ifdef USE_ENSMALLEN -//#include "ensmallen.hpp" -//#endif + +#ifdef USE_ENSMALLEN +#include "ensmallen.hpp" +#endif #include #include #include #include #include //#define USE_SCENARIO_WEIGHTS -#include "chronosigasimulationmodel.hpp" -#include "simulationmodelfactory.hpp" #include using namespace ReducedModelOptimization; -struct BaseScenarioMaxDisplacementHelperData -{ - std::function> &, - SimulationJob &)> - constructScenarioFunction; - double desiredMaxDisplacementValue; - double desiredMaxRotationAngle; - FullPatternVertexIndex interfaceViForComputingScenarioError; - std::string currentScenarioName; - std::shared_ptr pFullPatternSimulationMesh; +struct BaseScenarioMaxDisplacementHelperData { + std::function>&, + SimulationJob&)> + constructScenarioFunction; + double desiredMaxDisplacementValue; + double desiredMaxRotationAngle; + PatternVertexIndex interfaceViForComputingScenarioError; + std::string currentScenarioName; + std::shared_ptr pFullPatternSimulationEdgeMesh; - std::vector> - fullPatternOppositeInterfaceViPairs; + std::vector> + fullPatternOppositeInterfaceViPairs; } g_baseScenarioMaxDisplacementHelperData; ReducedModelOptimizer::OptimizationState - g_optimizationState; //TODO: instead of having this global I could encapsulate it into a struct as I did for ensmallen + g_optimizationState; // TODO: instead of having this global I could + // encapsulate it into a struct as I did for ensmallen double ReducedModelOptimizer::computeDisplacementError( - const std::vector &fullPatternDisplacements, - const std::vector &reducedPatternDisplacements, - const std::unordered_map - &reducedToFullInterfaceViMap, - const double &normalizationFactor) -{ - const double rawError = computeRawTranslationalError(fullPatternDisplacements, - reducedPatternDisplacements, - reducedToFullInterfaceViMap); - // std::cout << "raw trans error:" << rawError << std::endl; - // std::cout << "raw trans error:" << normalizationFactor << std::endl; - return rawError / normalizationFactor; + const std::vector& fullPatternDisplacements, + const std::vector& reducedPatternDisplacements, + const std::unordered_map& + reducedToFullInterfaceViMap, + const double& normalizationFactor) { + const double rawError = computeRawTranslationalError( + fullPatternDisplacements, reducedPatternDisplacements, + reducedToFullInterfaceViMap); + // std::cout << "raw trans error:" << rawError << std::endl; + // std::cout << "raw trans error:" << normalizationFactor << std::endl; + return rawError / normalizationFactor; } double ReducedModelOptimizer::computeRawTranslationalError( - const std::vector &fullPatternDisplacements, - const std::vector &reducedPatternDisplacements, - const std::unordered_map - &reducedToFullInterfaceViMap) -{ - double error = 0; - for (const auto reducedFullViPair : reducedToFullInterfaceViMap) { - const VertexIndex reducedModelVi = reducedFullViPair.first; - const VertexIndex fullModelVi = reducedFullViPair.second; - const Eigen::Vector3d fullPatternVertexDiplacement = fullPatternDisplacements[fullModelVi] - .getTranslation(); - const Eigen::Vector3d reducedPatternVertexDiplacement - = reducedPatternDisplacements[reducedModelVi].getTranslation(); - const double vertexError = (fullPatternVertexDiplacement - reducedPatternVertexDiplacement) - .norm(); - error += vertexError; - } + const std::vector& fullPatternDisplacements, + const std::vector& reducedPatternDisplacements, + const std::unordered_map& + reducedToFullInterfaceViMap) { + double error = 0; + for (const auto reducedFullViPair : reducedToFullInterfaceViMap) { + const VertexIndex reducedModelVi = reducedFullViPair.first; + const VertexIndex fullModelVi = reducedFullViPair.second; + const Eigen::Vector3d fullPatternVertexDiplacement = + fullPatternDisplacements[fullModelVi].getTranslation(); + const Eigen::Vector3d reducedPatternVertexDiplacement = + reducedPatternDisplacements[reducedModelVi].getTranslation(); + const double vertexError = + (fullPatternVertexDiplacement - reducedPatternVertexDiplacement).norm(); + error += vertexError; + } - return error; + return error; } double ReducedModelOptimizer::computeRawRotationalError( - const std::vector> &rotatedQuaternion_fullPattern, - const std::vector> &rotatedQuaternion_reducedPattern, - const std::unordered_map - &reducedToFullInterfaceViMap) -{ - double rawRotationalError = 0; - for (const auto &reducedToFullInterfaceViPair : reducedToFullInterfaceViMap) { - const double vertexRotationalError = std::abs( - rotatedQuaternion_fullPattern[reducedToFullInterfaceViPair.second].angularDistance( - rotatedQuaternion_reducedPattern[reducedToFullInterfaceViPair.first])); - rawRotationalError += vertexRotationalError; - } + const std::vector>& rotatedQuaternion_fullPattern, + const std::vector>& + rotatedQuaternion_reducedPattern, + const std::unordered_map& + reducedToFullInterfaceViMap) { + double rawRotationalError = 0; + for (const auto& reducedToFullInterfaceViPair : reducedToFullInterfaceViMap) { + const double vertexRotationalError = std::abs( + rotatedQuaternion_fullPattern[reducedToFullInterfaceViPair.second] + .angularDistance( + rotatedQuaternion_reducedPattern[reducedToFullInterfaceViPair + .first])); + rawRotationalError += vertexRotationalError; + } - return rawRotationalError; + return rawRotationalError; } double ReducedModelOptimizer::computeRotationalError( - const std::vector> &rotatedQuaternion_fullPattern, - const std::vector> &rotatedQuaternion_reducedPattern, - const std::unordered_map - &reducedToFullInterfaceViMap, - const double &normalizationFactor) -{ - const double rawRotationalError = computeRawRotationalError(rotatedQuaternion_fullPattern, - rotatedQuaternion_reducedPattern, - reducedToFullInterfaceViMap); - return rawRotationalError / normalizationFactor; + const std::vector>& rotatedQuaternion_fullPattern, + const std::vector>& + rotatedQuaternion_reducedPattern, + const std::unordered_map& + reducedToFullInterfaceViMap, + const double& normalizationFactor) { + const double rawRotationalError = computeRawRotationalError( + rotatedQuaternion_fullPattern, rotatedQuaternion_reducedPattern, + reducedToFullInterfaceViMap); + return rawRotationalError / normalizationFactor; } double ReducedModelOptimizer::computeError( - const SimulationResults &simulationResults_fullPattern, - const SimulationResults &simulationResults_reducedPattern, - const std::unordered_map - &reducedToFullInterfaceViMap, - const double &normalizationFactor_translationalDisplacement, - const double &normalizationFactor_rotationalDisplacement, - const double &scenarioWeight, - const Settings::ObjectiveWeights &objectiveWeights) -{ - const double translationalError - = computeDisplacementError(simulationResults_fullPattern.displacements, - simulationResults_reducedPattern.displacements, - reducedToFullInterfaceViMap, - normalizationFactor_translationalDisplacement); - // const double translationalError - // = computeRawTranslationalError(simulationResults_fullPattern.displacements, - // simulationResults_reducedPattern.displacements, - // reducedToFullInterfaceViMap); + const SimulationResults& simulationResults_fullPattern, + const SimulationResults& simulationResults_reducedPattern, + const std::unordered_map& + reducedToFullInterfaceViMap, + const double& normalizationFactor_translationalDisplacement, + const double& normalizationFactor_rotationalDisplacement, + const double& scenarioWeight, + const Settings::ObjectiveWeights& objectiveWeights) { + const double translationalError = + computeDisplacementError(simulationResults_fullPattern.displacements, + simulationResults_reducedPattern.displacements, + reducedToFullInterfaceViMap, + normalizationFactor_translationalDisplacement); + // const double translationalError + // = + // computeRawTranslationalError(simulationResults_fullPattern.displacements, + // simulationResults_reducedPattern.displacements, + // reducedToFullInterfaceViMap); - // std::cout << "normalization factor:" << normalizationFactor_rotationalDisplacement << std::endl; - // std::cout << "trans error:" << translationalError << std::endl; - const double rotationalError - = computeRotationalError(simulationResults_fullPattern.rotationalDisplacementQuaternion, - simulationResults_reducedPattern.rotationalDisplacementQuaternion, - reducedToFullInterfaceViMap, - normalizationFactor_rotationalDisplacement); - // const double rotationalError - // = computeRawRotationalError(simulationResults_fullPattern.rotationalDisplacementQuaternion, - // simulationResults_reducedPattern.rotationalDisplacementQuaternion, - // reducedToFullInterfaceViMap); - // std::cout << "rot error:" << rotationalError<< std::endl; - const double simulationError = objectiveWeights.translational * translationalError - + objectiveWeights.rotational * rotationalError; - assert(!std::isnan(simulationError)); - return simulationError * simulationError * scenarioWeight * scenarioWeight; + // std::cout << "normalization factor:" << + // normalizationFactor_rotationalDisplacement << std::endl; + // std::cout << "trans error:" << translationalError << std::endl; + const double rotationalError = computeRotationalError( + simulationResults_fullPattern.rotationalDisplacementQuaternion, + simulationResults_reducedPattern.rotationalDisplacementQuaternion, + reducedToFullInterfaceViMap, normalizationFactor_rotationalDisplacement); + // const double rotationalError + // = + // computeRawRotationalError(simulationResults_fullPattern.rotationalDisplacementQuaternion, + // simulationResults_reducedPattern.rotationalDisplacementQuaternion, + // reducedToFullInterfaceViMap); + // std::cout << "rot error:" << rotationalError<< std::endl; + const double simulationError = + objectiveWeights.translational * translationalError + + objectiveWeights.rotational * rotationalError; + assert(!std::isnan(simulationError)); + return simulationError * simulationError * scenarioWeight * scenarioWeight; } -//double ReducedModelOptimizer::objective(double E,double A,double J,double I2,double I3, +// double ReducedModelOptimizer::objective(double E,double A,double J,double +// I2,double I3, // double innerHexagonSize, // double innerHexagonRotationAngle) { -// std::vector x{E,A,J,I2,I3, innerHexagonSize, innerHexagonRotationAngle}; -// return ReducedModelOptimizer::objective(x.size(), x.data()); +// std::vector x{E,A,J,I2,I3, innerHexagonSize, +// innerHexagonRotationAngle}; return +// ReducedModelOptimizer::objective(x.size(), x.data()); //} #ifdef USE_ENSMALLEN -struct EnsmallenReducedModelOptimizationObjective -{ - EnsmallenReducedModelOptimizationObjective( - ReducedModelOptimizer::OptimizationState &optimizationState) - : optimizationState(optimizationState) - {} - ReducedModelOptimizer::OptimizationState &optimizationState; - double Evaluate(const arma::mat &x_arma) - { - for (int xi = 0; xi < x_arma.size(); xi++) { - if (x_arma[xi] > optimizationState.xMax[xi]) { - //#ifdef POLYSCOPE_DEFINED - // std::cout << "Out of range" << std::endl; - //#endif - return std::numeric_limits::max(); - // return 1e10; - // x[xi] = optimizationState.xMax[xi]; - } else if (x_arma[xi] < optimizationState.xMin[xi]) { - //#ifdef POLYSCOPE_DEFINED - // std::cout << "Out of range" << std::endl; - //#endif - return std::numeric_limits::max(); - // return 1e10; - // x[xi] = optimizationState.xMin[xi]; - } - } - std::vector x(x_arma.begin(), x_arma.end()); - return ReducedModelOptimizer::objective(x, optimizationState); +struct EnsmallenReducedModelOptimizationObjective { + EnsmallenReducedModelOptimizationObjective( + ReducedModelOptimizer::OptimizationState& optimizationState) + : optimizationState(optimizationState) {} + ReducedModelOptimizer::OptimizationState& optimizationState; + double Evaluate(const arma::mat& x_arma) { + for (int xi = 0; xi < x_arma.size(); xi++) { + if (x_arma[xi] > optimizationState.xMax[xi]) { + //#ifdef POLYSCOPE_DEFINED + // std::cout << "Out of range" << std::endl; + //#endif + return std::numeric_limits::max(); + // return 1e10; + // x[xi] = optimizationState.xMax[xi]; + } else if (x_arma[xi] < optimizationState.xMin[xi]) { + //#ifdef POLYSCOPE_DEFINED + // std::cout << "Out of range" << std::endl; + //#endif + return std::numeric_limits::max(); + // return 1e10; + // x[xi] = optimizationState.xMin[xi]; + } } + std::vector x(x_arma.begin(), x_arma.end()); + return ReducedModelOptimizer::objective(x, optimizationState); + } }; -#endif - -#ifdef DLIB_DEFINED -double ReducedModelOptimizer::objective(const dlib::matrix &x) -{ - return objective(std::vector(x.begin(), x.end()), g_optimizationState); +#elif DLIB_DEFINED +double ReducedModelOptimizer::objective(const dlib::matrix& x) { + return objective(std::vector(x.begin(), x.end()), + g_optimizationState); } #endif -//double ReducedModelOptimizer::objective(const double &xValue) +// double ReducedModelOptimizer::objective(const double &xValue) //{ // return objective(std::vector({xValue})); //} -double ReducedModelOptimizer::objective(const std::vector &x, - ReducedModelOptimizer::OptimizationState &optimizationState) -{ - // std::cout.precision(17); - // for (int i = 0; i < x.size(); i++) { - // std::cout << x[i] << " "; - // } - // std::cout << std::endl; +double ReducedModelOptimizer::objective( + const std::vector& x, + ReducedModelOptimizer::OptimizationState& optimizationState) { + // std::cout.precision(17); + // for (int i = 0; i < x.size(); i++) { + // std::cout << x[i] << " "; + // } + // std::cout << std::endl; - // std::cout << x(x.size() - 2) << " " << x(x.size() - 1) << std::endl; - // const Element &e = - // optimizationState.reducedPatternSimulationJobs[0]->pMesh->elements[0]; std::cout << - // e.axialConstFactor << " " << e.torsionConstFactor << " " - // << e.firstBendingConstFactor << " " << - // e.secondBendingConstFactor - // << std::endl; - // const int n = x.size(); - std::shared_ptr &pReducedPatternSimulationMesh - = optimizationState - .reducedPatternSimulationJobs[optimizationState.simulationScenarioIndices[0]] - ->pMesh; - function_updateReducedPattern(x, pReducedPatternSimulationMesh); - // optimizationState.reducedPatternSimulationJobs[0]->pMesh->registerForDrawing(); - // optimizationState.fullPatternSimulationJobs[0]->pMesh->registerForDrawing(); - // polyscope::show(); - // optimizationState.reducedPatternSimulationJobs[0]->pMesh->unregister(); + // std::cout << x(x.size() - 2) << " " << x(x.size() - 1) << std::endl; + // const Element &e = + // optimizationState.reducedPatternSimulationJobs[0]->pMesh->elements[0]; + // std::cout << e.axialConstFactor << " " << e.torsionConstFactor << " " + // << e.firstBendingConstFactor << " " << + // e.secondBendingConstFactor + // << std::endl; + // const int n = x.size(); + std::shared_ptr& pReducedPatternSimulationEdgeMesh = + optimizationState + .simulationJobs_reducedModel[optimizationState + .simulationScenarioIndices[0]] + ->pMesh; + function_updateReducedPattern(x, pReducedPatternSimulationEdgeMesh); + // optimizationState.reducedPatternSimulationJobs[0]->pMesh->registerForDrawing(); + // optimizationState.fullPatternSimulationJobs[0]->pMesh->registerForDrawing(); + // polyscope::show(); + // optimizationState.reducedPatternSimulationJobs[0]->pMesh->unregister(); - // run simulations - std::vector simulationErrorsPerScenario(totalNumberOfSimulationScenarios, 0); - // ChronosEulerSimulationModel simulator; - LinearSimulationModel simulator; - simulator.setStructure(pReducedPatternSimulationMesh); - // simulator.initialize(); - // FormFinder simulator; + // run simulations + std::vector simulationErrorsPerScenario( + totalNumberOfSimulationScenarios, 0); + // LinearSimulationModel simulator; + // simulator.setStructure(pReducedPatternSimulationEdgeMesh); + // simulator.initialize(); + // FormFinder simulator; + std::unique_ptr pReducedModelSimulator = nullptr; + if (optimizationState.simulationModelLabel_reducedModel == + LinearSimulationModel::label) { + pReducedModelSimulator = SimulationModelFactory::create( + optimizationState.simulationModelLabel_reducedModel); + pReducedModelSimulator->setStructure(pReducedPatternSimulationEdgeMesh); + } - std::for_each( - std::execution::par_unseq, - optimizationState.simulationScenarioIndices.begin(), - optimizationState.simulationScenarioIndices.end(), - [&](const int &simulationScenarioIndex) { - // for (const int simulationScenarioIndex : optimizationState.simulationScenarioIndices) { - const std::shared_ptr &reducedJob - = optimizationState.reducedPatternSimulationJobs[simulationScenarioIndex]; + std::for_each( + std::execution::par_unseq, + optimizationState.simulationScenarioIndices.begin(), + optimizationState.simulationScenarioIndices.end(), + [&](const int& simulationScenarioIndex) { + // for (const int simulationScenarioIndex : + // optimizationState.simulationScenarioIndices) { + const std::shared_ptr& pSimulationJob_reducedModel = + optimizationState + .simulationJobs_reducedModel[simulationScenarioIndex]; + assert(pSimulationJob_reducedModel != nullptr); + assert(pSimulationJob_reducedModel->pMesh != nullptr); + assert(pSimulationJob_reducedModel->pMesh->VN() != 0); + SimulationResults reducedModelResults; + if (pReducedModelSimulator == nullptr) { + std::unique_ptr pReducedModelSimulator = + SimulationModelFactory::create( + optimizationState.simulationModelLabel_reducedModel); + pReducedModelSimulator->setStructure( + pSimulationJob_reducedModel->pMesh); - //#ifdef POLYSCOPE_DEFINED - // std::cout << reducedJob->getLabel() << ":" << std::endl; - //#endif - SimulationResults reducedModelResults = simulator.executeSimulation(reducedJob); - // std::string filename; - if (!reducedModelResults.converged) { - simulationErrorsPerScenario[simulationScenarioIndex] - = std::numeric_limits::max(); - optimizationState.numOfSimulationCrashes++; + reducedModelResults = pReducedModelSimulator->executeSimulation( + pSimulationJob_reducedModel); + } else { + reducedModelResults = pReducedModelSimulator->executeSimulation( + pSimulationJob_reducedModel); + } + + // std::string filename; + if (!reducedModelResults.converged) { + simulationErrorsPerScenario[simulationScenarioIndex] = + std::numeric_limits::max(); + optimizationState.numOfSimulationCrashes++; #ifdef POLYSCOPE_DEFINED - std::cout << "Failed simulation with x:" << std::endl; - std::cout.precision(17); - for (int i = 0; i < x.size(); i++) { - std::cout << x[i] << " "; - } - std::cout << std::endl; - // pReducedPatternSimulationMesh->registerForDrawing(); - // polyscope::show(); - // pReducedPatternSimulationMesh->unregister(); - // std::filesystem::create_directories("failedJob"); - // reducedJob->save("failedJob"); - // Results debugRes; + std::cout << "Failed simulation with x:" << std::endl; + std::cout.precision(17); + for (int i = 0; i < x.size(); i++) { + std::cout << x[i] << " "; + } + std::cout << std::endl; + // pReducedPatternSimulationEdgeMesh->registerForDrawing(); + // polyscope::show(); + // pReducedPatternSimulationEdgeMesh->unregister(); + // std::filesystem::create_directories("failedJob"); + // reducedJob->save("failedJob"); + // Results debugRes; #endif - } else { + } else { // const double simulationScenarioError_PE = std::abs( // (reducedModelResults.internalPotentialEnergy -// - optimizationState.fullPatternResults[simulationScenarioIndex].internalPotentialEnergy) -// / optimizationState.fullPatternResults[simulationScenarioIndex].internalPotentialEnergy); +// - +// optimizationState.fullPatternResults[simulationScenarioIndex].internalPotentialEnergy) +// / +// optimizationState.fullPatternResults[simulationScenarioIndex].internalPotentialEnergy); // else { #ifdef POLYSCOPE_DEFINED #ifdef USE_SCENARIO_WEIGHTS - const double scenarioWeight = optimizationState - .scenarioWeights[simulationScenarioIndex]; + const double scenarioWeight = + optimizationState.scenarioWeights[simulationScenarioIndex]; #else - const double scenarioWeight = 1; + const double scenarioWeight = 1; #endif #else - const double scenarioWeight = 1; + const double scenarioWeight = 1; #endif - const double simulationScenarioError_displacements = computeError( - optimizationState.fullPatternResults[simulationScenarioIndex], - reducedModelResults, - optimizationState.reducedToFullInterfaceViMap, - optimizationState - .translationalDisplacementNormalizationValues[simulationScenarioIndex], - optimizationState - .rotationalDisplacementNormalizationValues[simulationScenarioIndex], - scenarioWeight, - optimizationState.objectiveWeights[simulationScenarioIndex]); + const double simulationScenarioError_displacements = computeError( + optimizationState.fullPatternResults[simulationScenarioIndex], + reducedModelResults, + optimizationState.reducedToFullInterfaceViMap, + optimizationState.translationalDisplacementNormalizationValues + [simulationScenarioIndex], + optimizationState.rotationalDisplacementNormalizationValues + [simulationScenarioIndex], + scenarioWeight, + optimizationState.objectiveWeights[simulationScenarioIndex]); - simulationErrorsPerScenario[simulationScenarioIndex] - = simulationScenarioError_displacements /*+ simulationScenarioError_PE*/; - // } - // #ifdef POLYSCOPE_DEFINED - // reducedJob->pMesh->registerForDrawing(Colors::reducedInitial); - // reducedModelResults.registerForDrawing(Colors::reducedDeformed); - // optimizationState.pFullPatternSimulationMesh->registerForDrawing(Colors::fullDeformed); - // optimizationState.fullPatternResults[simulationScenarioIndex].registerForDrawing( - // Colors::fullDeformed); - // polyscope::show(); - // reducedModelResults.unregister(); - // optimizationState.pFullPatternSimulationMesh->unregister(); - // optimizationState.fullPatternResults[simulationScenarioIndex].unregister(); - // #endif - } - }); - const double totalError = std::reduce(std::execution::par_unseq, - simulationErrorsPerScenario.begin(), - simulationErrorsPerScenario.end()); - // std::cout << totalError << std::endl; - // optimizationState.objectiveValueHistory.push_back(totalError); - // optimizationState.plotColors.push_back(10); - ++optimizationState.numberOfFunctionCalls; - if (totalError < optimizationState.minY) { - optimizationState.minY = totalError; - // optimizationState.objectiveValueHistory.push_back(totalError); - // optimizationState.objectiveValueHistory_iteration.push_back(optimizationState.numberOfFunctionCalls); -#ifdef POLYSCOPE_DEFINED - std::cout << "New best:" << totalError << std::endl; - // // optimizationState.minX.assign(x.begin(), x.begin() + n); - std::cout.precision(17); - for (int i = 0; i < x.size(); i++) { - std::cout << x[i] << " "; + simulationErrorsPerScenario[simulationScenarioIndex] = + simulationScenarioError_displacements /*+ + simulationScenarioError_PE*/ + ; + // } + // #ifdef POLYSCOPE_DEFINED + // reducedJob->pMesh->registerForDrawing(Colors::reducedInitial); + // reducedModelResults.registerForDrawing(Colors::reducedDeformed); + // optimizationState.pFullPatternSimulationEdgeMesh->registerForDrawing(Colors::fullDeformed); + // optimizationState.fullPatternResults[simulationScenarioIndex].registerForDrawing( + // Colors::fullDeformed); + // polyscope::show(); + // reducedModelResults.unregister(); + // optimizationState.pFullPatternSimulationEdgeMesh->unregister(); + // optimizationState.fullPatternResults[simulationScenarioIndex].unregister(); + // #endif } - std::cout << std::endl; -#endif - // optimizationState.objectiveValueHistoryY.push_back(std::log(totalError)); - // optimizationState.objectiveValueHistoryX.push_back(optimizationState.numberOfFunctionCalls); - // optimizationState.plotColors.push_back(0.1); - // auto xPlot = matplot::linspace(0, - // optimizationState.objectiveValueHistoryY.size(), - // optimizationState.objectiveValueHistoryY.size()); - // optimizationState.gPlotHandle = matplot::scatter(optimizationState.objectiveValueHistoryX, - // optimizationState.objectiveValueHistoryY, - // 4, - // optimizationState.plotColors); - // matplot::show(); - // SimulationResultsReporter::createPlot("Number of Steps", - // "Objective value", - // optimizationState.objectiveValueHistoryY); + }); + const double totalError = std::reduce(std::execution::par_unseq, + simulationErrorsPerScenario.begin(), + simulationErrorsPerScenario.end()); + // std::cout << totalError << std::endl; + // optimizationState.objectiveValueHistory.push_back(totalError); + // optimizationState.plotColors.push_back(10); + ++optimizationState.numberOfFunctionCalls; + if (totalError < optimizationState.minY) { + optimizationState.minY = totalError; + // optimizationState.objectiveValueHistory.push_back(totalError); + // optimizationState.objectiveValueHistory_iteration.push_back(optimizationState.numberOfFunctionCalls); + optimizationState.minX.assign(x.begin(), x.end()); +#ifdef POLYSCOPE_DEFINED + std::cout << "New best:" << totalError << std::endl; + std::cout.precision(17); + for (int i = 0; i < x.size(); i++) { + std::cout << x[i] << " "; } + std::cout << std::endl; +#endif + // optimizationState.objectiveValueHistoryY.push_back(std::log(totalError)); + // optimizationState.objectiveValueHistoryX.push_back(optimizationState.numberOfFunctionCalls); + // optimizationState.plotColors.push_back(0.1); + // auto xPlot = matplot::linspace(0, + // optimizationState.objectiveValueHistoryY.size(), + // optimizationState.objectiveValueHistoryY.size()); + // optimizationState.gPlotHandle = + // matplot::scatter(optimizationState.objectiveValueHistoryX, + // optimizationState.objectiveValueHistoryY, + // 4, + // optimizationState.plotColors); + // matplot::show(); + // SimulationResultsReporter::createPlot("Number of Steps", + // "Objective value", + // optimizationState.objectiveValueHistoryY); + } #ifdef POLYSCOPE_DEFINED #ifdef USE_ENSMALLEN - if (optimizationState.numberOfFunctionCalls % 1000 == 0) { - std::cout << "Number of function calls:" << optimizationState.numberOfFunctionCalls - << std::endl; - } + if (optimizationState.numberOfFunctionCalls % 1000 == 0) { + std::cout << "Number of function calls:" + << optimizationState.numberOfFunctionCalls << std::endl; + } #else - if (optimizationState.optimizationSettings.dlib.numberOfFunctionCalls >= 100 - && optimizationState.numberOfFunctionCalls - % (optimizationState.optimizationSettings.dlib.numberOfFunctionCalls / 100) - == 0) { - std::cout << "Number of function calls:" << optimizationState.numberOfFunctionCalls - << std::endl; - } + if (optimizationState.optimizationSettings.dlib.numberOfFunctionCalls >= + 100 && + optimizationState.numberOfFunctionCalls % + (optimizationState.optimizationSettings.dlib + .numberOfFunctionCalls / + 100) == + 0) { + std::cout << "Number of function calls:" + << optimizationState.numberOfFunctionCalls << std::endl; + } #endif #endif - // compute error and return it - return totalError; + // compute error and return it + return totalError; } -void ReducedModelOptimizer::createSimulationMeshes( - PatternGeometry &pattern, - PatternGeometry &reducedModel, - const RectangularBeamDimensions &beamDimensions, - std::shared_ptr &pFullPatternSimulationMesh, - std::shared_ptr &pReducedPatternSimulationMesh) -{ - if (typeid(CrossSectionType) != typeid(RectangularBeamDimensions)) { - std::cerr << "Error: A rectangular cross section is expected." << std::endl; - std::terminate(); - } +void ReducedModelOptimizer::createSimulationEdgeMeshes( + PatternGeometry& pattern, + PatternGeometry& reducedModel, + const Settings& optimizationSettings, + std::shared_ptr& pFullPatternSimulationEdgeMesh, + std::shared_ptr& pReducedPatternSimulationEdgeMesh) { + if (typeid(CrossSectionType) != typeid(RectangularBeamDimensions)) { + std::cerr << "Error: A rectangular cross section is expected." << std::endl; + std::terminate(); + } - // Full pattern - pFullPatternSimulationMesh = std::make_shared(pattern); - pFullPatternSimulationMesh->setBeamCrossSection(beamDimensions); - pFullPatternSimulationMesh->setBeamMaterial(0.3, youngsModulus); - pFullPatternSimulationMesh->reset(); + // Full pattern + pFullPatternSimulationEdgeMesh = + std::make_shared(pattern); + pFullPatternSimulationEdgeMesh->setBeamCrossSection( + optimizationSettings.beamDimensions_pattern); + pFullPatternSimulationEdgeMesh->setBeamMaterial( + 0.3, optimizationSettings.youngsModulus_pattern); + pFullPatternSimulationEdgeMesh->reset(); - // Reduced pattern - pReducedPatternSimulationMesh = std::make_shared(reducedModel); - pReducedPatternSimulationMesh->setBeamCrossSection(beamDimensions); - pReducedPatternSimulationMesh->setBeamMaterial(0.3, youngsModulus); - pReducedPatternSimulationMesh->reset(); + // Reduced pattern + pReducedPatternSimulationEdgeMesh = + std::make_shared(reducedModel); + pReducedPatternSimulationEdgeMesh->setBeamCrossSection( + optimizationSettings.beamDimensions_pattern); + pReducedPatternSimulationEdgeMesh->setBeamMaterial( + 0.3, optimizationSettings.youngsModulus_pattern); + pReducedPatternSimulationEdgeMesh->reset(); } -void ReducedModelOptimizer::createSimulationMeshes(PatternGeometry &fullModel, - PatternGeometry &reducedModel, - const RectangularBeamDimensions &beamDimensions) -{ - ReducedModelOptimizer::createSimulationMeshes(fullModel, - reducedModel, - beamDimensions, - m_pFullPatternSimulationMesh, - m_pReducedModelSimulationMesh); +void ReducedModelOptimizer::createSimulationEdgeMeshes( + PatternGeometry& fullModel, + PatternGeometry& reducedModel, + const Settings& optimizationSettings) { + ReducedModelOptimizer::createSimulationEdgeMeshes( + fullModel, reducedModel, optimizationSettings, + m_pSimulationEdgeMesh_pattern, m_pReducedModelSimulationEdgeMesh); } void ReducedModelOptimizer::computeMaps( - const std::unordered_map> &slotToNode, - PatternGeometry &fullPattern, - ReducedModel &reducedPattern, - std::unordered_map - &reducedToFullInterfaceViMap, - std::unordered_map - &fullToReducedInterfaceViMap, - std::vector> - &fullPatternOppositeInterfaceViPairs) -{ - // Compute the offset between the interface nodes - const size_t interfaceSlotIndex = 4; // bottom edge - assert(slotToNode.find(interfaceSlotIndex) != slotToNode.end() - && slotToNode.find(interfaceSlotIndex)->second.size() == 1); - // Assuming that in the bottom edge there is only one vertex which is also the - // interface - const size_t baseTriangleInterfaceVi = *(slotToNode.find(interfaceSlotIndex)->second.begin()); + const std::unordered_map>& slotToNode, + PatternGeometry& fullPattern, + ReducedModel& reducedModel, + std::unordered_map& + reducedToFullInterfaceViMap, + std::unordered_map& + fullToReducedInterfaceViMap, + std::vector>& + fullPatternOppositeInterfaceViPairs) { + // Compute the offset between the interface nodes + const size_t interfaceSlotIndex = 4; // bottom edge + assert(slotToNode.find(interfaceSlotIndex) != slotToNode.end() && + slotToNode.find(interfaceSlotIndex)->second.size() == 1); + // Assuming that in the bottom edge there is only one vertex which is also the + // interface + const size_t baseTriangleInterfaceVi = + *(slotToNode.find(interfaceSlotIndex)->second.begin()); - vcg::tri::Allocator::PointerUpdater pu_fullModel; - fullPattern.deleteDanglingVertices(pu_fullModel); - const size_t fullModelBaseTriangleInterfaceVi = pu_fullModel.remap.empty() - ? baseTriangleInterfaceVi - : pu_fullModel.remap[baseTriangleInterfaceVi]; - const size_t fullModelBaseTriangleVN = fullPattern.VN(); - fullPattern.createFan(); - const size_t duplicateVerticesPerFanPair = fullModelBaseTriangleVN - fullPattern.VN() / 6; - const size_t fullPatternInterfaceVertexOffset = fullModelBaseTriangleVN - - duplicateVerticesPerFanPair; - // std::cout << "Dups in fan pair:" << duplicateVerticesPerFanPair << - // std::endl; + vcg::tri::Allocator::PointerUpdater< + PatternGeometry::VertexPointer> + pu_fullModel; + fullPattern.deleteDanglingVertices(pu_fullModel); + const size_t fullModelBaseTriangleInterfaceVi = + pu_fullModel.remap.empty() ? baseTriangleInterfaceVi + : pu_fullModel.remap[baseTriangleInterfaceVi]; + const size_t fullModelBaseTriangleVN = fullPattern.VN(); + fullPattern.createFan(); + const size_t duplicateVerticesPerFanPair = + fullModelBaseTriangleVN - fullPattern.VN() / 6; + const size_t fullPatternInterfaceVertexOffset = + fullModelBaseTriangleVN - duplicateVerticesPerFanPair; + // std::cout << "Dups in fan pair:" << duplicateVerticesPerFanPair << + // std::endl; - // Save excluded edges TODO:this changes the optimizationState object. Should this be a - // function parameter? - // optimizationState.reducedPatternExludedEdges.clear(); - // const size_t reducedBaseTriangleNumberOfEdges = reducedPattern.EN(); - // for (size_t fanIndex = 0; fanIndex < fanSize; fanIndex++) { - // for (const size_t ei : reducedModelExcludedEdges) { - // optimizationState.reducedPatternExludedEdges.insert( - // fanIndex * reducedBaseTriangleNumberOfEdges + ei); - // } - // } + // Save excluded edges TODO:this changes the optimizationState object. Should + // this be a function parameter? + // optimizationState.reducedPatternExludedEdges.clear(); + // const size_t reducedBaseTriangleNumberOfEdges = reducedPattern.EN(); + // for (size_t fanIndex = 0; fanIndex < fanSize; fanIndex++) { + // for (const size_t ei : reducedModelExcludedEdges) { + // optimizationState.reducedPatternExludedEdges.insert( + // fanIndex * reducedBaseTriangleNumberOfEdges + ei); + // } + // } - // Construct reduced->full and full->reduced interface vi map - reducedToFullInterfaceViMap.clear(); - vcg::tri::Allocator::PointerUpdater pu_reducedModel; - reducedPattern.deleteDanglingVertices(pu_reducedModel); - const size_t reducedModelBaseTriangleInterfaceVi = pu_reducedModel.remap[baseTriangleInterfaceVi]; - const size_t reducedModelInterfaceVertexOffset - = reducedPattern.VN() /*- 1*/ /*- reducedModelBaseTriangleInterfaceVi*/; - Results::applyOptimizationResults_reducedModel_nonFanned(initialHexagonSize, - 0, - baseTriangle, - reducedPattern); - reducedPattern.createFan(); //TODO: should be an input parameter from main - for (size_t fanIndex = 0; fanIndex < fanSize; fanIndex++) { - reducedToFullInterfaceViMap[reducedModelInterfaceVertexOffset * fanIndex - + reducedModelBaseTriangleInterfaceVi] - = fullModelBaseTriangleInterfaceVi + fanIndex * fullPatternInterfaceVertexOffset; - } - fullToReducedInterfaceViMap.clear(); - constructInverseMap(reducedToFullInterfaceViMap, fullToReducedInterfaceViMap); + // Construct reduced->full and full->reduced interface vi map + reducedToFullInterfaceViMap.clear(); + vcg::tri::Allocator::PointerUpdater< + PatternGeometry::VertexPointer> + pu_reducedModel; + reducedModel.deleteDanglingVertices(pu_reducedModel); + const size_t reducedModelBaseTriangleInterfaceVi = + pu_reducedModel.remap[baseTriangleInterfaceVi]; + const size_t reducedModelInterfaceVertexOffset = + reducedModel.VN() /*- 1*/ /*- reducedModelBaseTriangleInterfaceVi*/; + Results::applyOptimizationResults_reducedModel_nonFanned( + initialValue_R, initialValue_theta, baseTriangle, reducedModel); + reducedModel.createFan(); // TODO: should be an input parameter from main + for (size_t fanIndex = 0; fanIndex < fanCardinality; fanIndex++) { + reducedToFullInterfaceViMap[reducedModelInterfaceVertexOffset * fanIndex + + reducedModelBaseTriangleInterfaceVi] = + fullModelBaseTriangleInterfaceVi + + fanIndex * fullPatternInterfaceVertexOffset; + } + fullToReducedInterfaceViMap.clear(); + constructInverseMap(reducedToFullInterfaceViMap, fullToReducedInterfaceViMap); - // Create opposite vertex map - fullPatternOppositeInterfaceViPairs.clear(); - fullPatternOppositeInterfaceViPairs.reserve(fanSize / 2); - // for (int fanIndex = fanSize / 2 - 1; fanIndex >= 0; fanIndex--) { - for (int fanIndex = 0; fanIndex < fanSize / 2; fanIndex++) { - const size_t vi0 = fullModelBaseTriangleInterfaceVi - + fanIndex * fullPatternInterfaceVertexOffset; - const size_t vi1 = vi0 + (fanSize / 2) * fullPatternInterfaceVertexOffset; - assert(vi0 < fullPattern.VN() && vi1 < fullPattern.VN()); - fullPatternOppositeInterfaceViPairs.emplace_back(std::make_pair(vi0, vi1)); - } + // Create opposite vertex map + fullPatternOppositeInterfaceViPairs.clear(); + fullPatternOppositeInterfaceViPairs.reserve(fanCardinality / 2); + // for (int fanIndex = fanSize / 2 - 1; fanIndex >= 0; fanIndex--) { + for (int fanIndex = 0; fanIndex < fanCardinality / 2; fanIndex++) { + const size_t vi0 = fullModelBaseTriangleInterfaceVi + + fanIndex * fullPatternInterfaceVertexOffset; + const size_t vi1 = + vi0 + (fanCardinality / 2) * fullPatternInterfaceVertexOffset; + assert(vi0 < fullPattern.VN() && vi1 < fullPattern.VN()); + fullPatternOppositeInterfaceViPairs.emplace_back(std::make_pair(vi0, vi1)); + } #if POLYSCOPE_DEFINED - const bool debugMapping = false; - if (debugMapping) { - reducedPattern.registerForDrawing(); + const bool debugMapping = false; + if (debugMapping) { + reducedModel.registerForDrawing(); - // std::vector colors_reducedPatternExcludedEdges( - // reducedPattern.EN(), glm::vec3(0, 0, 0)); - // for (const size_t ei : optimizationState.reducedPatternExludedEdges) { - // colors_reducedPatternExcludedEdges[ei] = glm::vec3(1, 0, 0); - // } - // const std::string label = reducedPattern.getLabel(); - // polyscope::getCurveNetwork(label) - // ->addEdgeColorQuantity("Excluded edges", - // colors_reducedPatternExcludedEdges) - // ->setEnabled(true); - // polyscope::show(); + // std::vector colors_reducedPatternExcludedEdges( + // reducedPattern.EN(), glm::vec3(0, 0, 0)); + // for (const size_t ei : optimizationState.reducedPatternExludedEdges) { + // colors_reducedPatternExcludedEdges[ei] = glm::vec3(1, 0, 0); + // } + // const std::string label = reducedPattern.getLabel(); + // polyscope::getCurveNetwork(label) + // ->addEdgeColorQuantity("Excluded edges", + // colors_reducedPatternExcludedEdges) + // ->setEnabled(true); + // polyscope::show(); - std::vector nodeColorsOpposite(fullPattern.VN(), glm::vec3(0, 0, 0)); - for (const std::pair oppositeVerts : fullPatternOppositeInterfaceViPairs) { - auto color = polyscope::getNextUniqueColor(); - nodeColorsOpposite[oppositeVerts.first] = color; - nodeColorsOpposite[oppositeVerts.second] = color; - } - fullPattern.registerForDrawing(); - polyscope::getCurveNetwork(fullPattern.getLabel()) - ->addNodeColorQuantity("oppositeMap", nodeColorsOpposite) - ->setEnabled(true); - polyscope::show(); - - std::vector nodeColorsReducedToFull_reduced(reducedPattern.VN(), - glm::vec3(0, 0, 0)); - std::vector nodeColorsReducedToFull_full(fullPattern.VN(), glm::vec3(0, 0, 0)); - for (size_t vi = 0; vi < reducedPattern.VN(); vi++) { - if (optimizationState.reducedToFullInterfaceViMap.contains(vi)) { - auto color = polyscope::getNextUniqueColor(); - nodeColorsReducedToFull_reduced[vi] = color; - nodeColorsReducedToFull_full[optimizationState.reducedToFullInterfaceViMap[vi]] - = color; - } - } - polyscope::getCurveNetwork(reducedPattern.getLabel()) - ->addNodeColorQuantity("reducedToFull_reduced", nodeColorsReducedToFull_reduced) - ->setEnabled(true); - polyscope::getCurveNetwork(fullPattern.getLabel()) - ->addNodeColorQuantity("reducedToFull_full", nodeColorsReducedToFull_full) - ->setEnabled(true); - polyscope::show(); + std::vector nodeColorsOpposite(fullPattern.VN(), + glm::vec3(0, 0, 0)); + for (const std::pair oppositeVerts : + fullPatternOppositeInterfaceViPairs) { + auto color = polyscope::getNextUniqueColor(); + nodeColorsOpposite[oppositeVerts.first] = color; + nodeColorsOpposite[oppositeVerts.second] = color; } + fullPattern.registerForDrawing(); + polyscope::getCurveNetwork(fullPattern.getLabel()) + ->addNodeColorQuantity("oppositeMap", nodeColorsOpposite) + ->setEnabled(true); + polyscope::show(); + + std::vector nodeColorsReducedToFull_reduced(reducedModel.VN(), + glm::vec3(0, 0, 0)); + std::vector nodeColorsReducedToFull_full(fullPattern.VN(), + glm::vec3(0, 0, 0)); + for (size_t vi = 0; vi < reducedModel.VN(); vi++) { + if (optimizationState.reducedToFullInterfaceViMap.contains(vi)) { + auto color = polyscope::getNextUniqueColor(); + nodeColorsReducedToFull_reduced[vi] = color; + nodeColorsReducedToFull_full[optimizationState + .reducedToFullInterfaceViMap[vi]] = + color; + } + } + polyscope::getCurveNetwork(reducedModel.getLabel()) + ->addNodeColorQuantity("reducedToFull_reduced", + nodeColorsReducedToFull_reduced) + ->setEnabled(true); + polyscope::getCurveNetwork(fullPattern.getLabel()) + ->addNodeColorQuantity("reducedToFull_full", + nodeColorsReducedToFull_full) + ->setEnabled(true); + polyscope::show(); + } #endif } -void ReducedModelOptimizer::computeMaps(PatternGeometry &fullPattern, ReducedModel &reducedModel) -{ - ReducedModelOptimizer::computeMaps(slotToNode, - fullPattern, - reducedModel, - optimizationState.reducedToFullInterfaceViMap, - m_fullToReducedInterfaceViMap, - m_fullPatternOppositeInterfaceViPairs); +void ReducedModelOptimizer::computeMaps(PatternGeometry& fullPattern, + ReducedModel& reducedModel) { + ReducedModelOptimizer::computeMaps( + slotToNode, fullPattern, reducedModel, + optimizationState.reducedToFullInterfaceViMap, + m_fullToReducedInterfaceViMap, m_fullPatternOppositeInterfaceViPairs); } -ReducedModelOptimizer::ReducedModelOptimizer() -{ - const std::vector numberOfNodesPerSlot{1, 0, 0, 2, 1, 2, 1}; - FlatPatternTopology::constructNodeToSlotMap(numberOfNodesPerSlot, nodeToSlot); - FlatPatternTopology::constructSlotToNodeMap(nodeToSlot, slotToNode); - interfaceNodeIndex = numberOfNodesPerSlot[0] + numberOfNodesPerSlot[3]; - // constructBaseScenarioFunctions.resize(BaseSimulationScenario::NumberOfBaseSimulationScenarios); - scenarioIsSymmetrical.resize(BaseSimulationScenario::NumberOfBaseSimulationScenarios); - constructBaseScenarioFunctions[BaseSimulationScenario::Axial] = &constructAxialSimulationScenario; - // constructBaseScenarioFunctions[BaseSimulationScenario::Axial] = &constructSSimulationScenario; - scenarioIsSymmetrical[BaseSimulationScenario::Axial] = false; - constructBaseScenarioFunctions[BaseSimulationScenario::Shear] = &constructShearSimulationScenario; - scenarioIsSymmetrical[BaseSimulationScenario::Shear] = false; - constructBaseScenarioFunctions[BaseSimulationScenario::Bending] - = &constructBendingSimulationScenario; - scenarioIsSymmetrical[BaseSimulationScenario::Bending] = true; - constructBaseScenarioFunctions[BaseSimulationScenario::Dome] = &constructDomeSimulationScenario; - scenarioIsSymmetrical[BaseSimulationScenario::Dome] = true; - constructBaseScenarioFunctions[BaseSimulationScenario::Saddle] - = &constructSaddleSimulationScenario; - scenarioIsSymmetrical[BaseSimulationScenario::Saddle] = true; - constructBaseScenarioFunctions[BaseSimulationScenario::S] = &constructSSimulationScenario; - scenarioIsSymmetrical[BaseSimulationScenario::S] = true; +ReducedModelOptimizer::ReducedModelOptimizer() { + const std::vector numberOfNodesPerSlot{1, 0, 0, 2, 1, 2, 1}; + FlatPatternTopology::constructNodeToSlotMap(numberOfNodesPerSlot, nodeToSlot); + FlatPatternTopology::constructSlotToNodeMap(nodeToSlot, slotToNode); + interfaceNodeIndex = numberOfNodesPerSlot[0] + numberOfNodesPerSlot[3]; + // constructBaseScenarioFunctions.resize(BaseSimulationScenario::NumberOfBaseSimulationScenarios); + scenarioIsSymmetrical.resize( + BaseSimulationScenario::NumberOfBaseSimulationScenarios); + constructBaseScenarioFunctions[BaseSimulationScenario::Axial] = + &constructAxialSimulationScenario; + // constructBaseScenarioFunctions[BaseSimulationScenario::Axial] = + // &constructSSimulationScenario; + scenarioIsSymmetrical[BaseSimulationScenario::Axial] = false; + constructBaseScenarioFunctions[BaseSimulationScenario::Shear] = + &constructShearSimulationScenario; + scenarioIsSymmetrical[BaseSimulationScenario::Shear] = false; + constructBaseScenarioFunctions[BaseSimulationScenario::Bending] = + &constructBendingSimulationScenario; + scenarioIsSymmetrical[BaseSimulationScenario::Bending] = true; + constructBaseScenarioFunctions[BaseSimulationScenario::Dome] = + &constructDomeSimulationScenario; + scenarioIsSymmetrical[BaseSimulationScenario::Dome] = true; + constructBaseScenarioFunctions[BaseSimulationScenario::Saddle] = + &constructSaddleSimulationScenario; + scenarioIsSymmetrical[BaseSimulationScenario::Saddle] = true; + constructBaseScenarioFunctions[BaseSimulationScenario::S] = + &constructSSimulationScenario; + scenarioIsSymmetrical[BaseSimulationScenario::S] = true; } void ReducedModelOptimizer::initializePatterns( - PatternGeometry &fullPattern, - ReducedModel &reducedModel, - const ReducedModelOptimization::Settings &optimizationSettings) -{ - assert(fullPattern.VN() == reducedModel.VN() && fullPattern.EN() >= reducedModel.EN()); - const std::array &optimizationParameters - = optimizationSettings.variablesRanges; + PatternGeometry& fullPattern, + ReducedModel& reducedModel, + const ReducedModelOptimization::Settings& optimizationSettings) { + assert(fullPattern.VN() == reducedModel.VN() && + fullPattern.EN() >= reducedModel.EN()); + const std::array& + optimizationParameters = optimizationSettings.variablesRanges; #ifdef POLYSCOPE_DEFINED - polyscope::removeAllStructures(); + polyscope::removeAllStructures(); #endif - // Create copies of the input models - PatternGeometry copyFullPattern; - ReducedModel copyReducedModel; - copyFullPattern.copy(fullPattern); - copyReducedModel.copy(reducedModel); + // Create copies of the input models + PatternGeometry copyFullPattern; + ReducedModel copyReducedModel; + copyFullPattern.copy(fullPattern); + copyReducedModel.copy(reducedModel); #ifdef POLYSCOPE_DEFINED - copyFullPattern.updateEigenEdgeAndVertices(); + copyFullPattern.updateEigenEdgeAndVertices(); #endif - copyReducedModel.updateEigenEdgeAndVertices(); - baseTriangle = copyReducedModel.getBaseTriangle(); + copyReducedModel.updateEigenEdgeAndVertices(); + baseTriangle = copyReducedModel.getBaseTriangle(); - computeMaps(copyFullPattern, copyReducedModel); - optimizationState.fullPatternOppositeInterfaceViPairs = m_fullPatternOppositeInterfaceViPairs; - g_baseScenarioMaxDisplacementHelperData.fullPatternOppositeInterfaceViPairs - = m_fullPatternOppositeInterfaceViPairs; - createSimulationMeshes(copyFullPattern, - copyReducedModel, - optimizationSettings.patternBeamDimensions); - initializeUpdateReducedPatternFunctions(); - initializeOptimizationParameters(m_pFullPatternSimulationMesh, optimizationParameters); + computeMaps(copyFullPattern, copyReducedModel); + optimizationState.fullPatternOppositeInterfaceViPairs = + m_fullPatternOppositeInterfaceViPairs; + g_baseScenarioMaxDisplacementHelperData.fullPatternOppositeInterfaceViPairs = + m_fullPatternOppositeInterfaceViPairs; + createSimulationEdgeMeshes(copyFullPattern, copyReducedModel, + optimizationSettings); + initializeUpdateReducedPatternFunctions(); + initializeOptimizationParameters(m_pSimulationEdgeMesh_pattern, + optimizationParameters); } -void ReducedModelOptimizer::optimize(ConstPatternGeometry &fullPattern, - ReducedModelOptimization::Settings &optimizationSettings, - ReducedModelOptimization::Results &optimizationResults) -{ - //scale pattern and reduced model - fullPattern.scale(optimizationSettings.targetBaseTriangleSize); - ReducedModel reducedModel; - reducedModel.scale(optimizationSettings.targetBaseTriangleSize); - auto start = std::chrono::system_clock::now(); - optimizationResults.label = fullPattern.getLabel(); - optimizationResults.baseTriangleFullPattern.copy(fullPattern); - initializePatterns(fullPattern, reducedModel, optimizationSettings); - optimize(optimizationSettings, optimizationResults); - optimizationResults.settings - = optimizationSettings; //NOTE: currently I set the max force base magn in optimize thus this must be called after the optimize function - auto end = std::chrono::system_clock::now(); - auto elapsed = std::chrono::duration_cast(end - start); - optimizationResults.time = elapsed.count() / 1000.0; +void ReducedModelOptimizer::optimize( + ConstPatternGeometry& fullPattern, + ReducedModelOptimization::Settings& optimizationSettings, + ReducedModelOptimization::Results& optimizationResults) { + // scale pattern and reduced model + fullPattern.scale(optimizationSettings.targetBaseTriangleSize); + ReducedModel reducedModel; + reducedModel.scale(optimizationSettings.targetBaseTriangleSize); + auto start = std::chrono::system_clock::now(); + optimizationResults.label = fullPattern.getLabel(); + optimizationResults.baseTrianglePattern.copy(fullPattern); + initializePatterns(fullPattern, reducedModel, optimizationSettings); + optimize(optimizationSettings, optimizationResults); + optimizationResults.settings = + optimizationSettings; // NOTE: currently I set the max force base magn in + // optimize thus this must be called after the + // optimize function + auto end = std::chrono::system_clock::now(); + auto elapsed = + std::chrono::duration_cast(end - start); + optimizationResults.time = elapsed.count() / 1000.0; } -void ReducedModelOptimizer::initializeUpdateReducedPatternFunctions() -{ - const vcg::Triangle3 &baseTriangle = this->baseTriangle; - optimizationState.functions_updateReducedPatternParameter[R] = - [=](const double &newR, std::shared_ptr &pReducedModelSimulationMesh) { - // std::shared_ptr pReducedModel_edgeMesh = std::dynamic_pointer_cast( - // pReducedModelSimulationMesh); - // ReducedModel::updateFannedGeometry_R(newR, pReducedModel_edgeMesh); - const CoordType barycentricCoordinates_hexagonBaseTriangleVertex(1 - newR, - newR / 2, - newR / 2); - // const vcg::Triangle3 &baseTriangle = getBaseTriangle(); - const CoordType hexagonBaseTriangleVertexPosition - = baseTriangle.cP(0) * barycentricCoordinates_hexagonBaseTriangleVertex[0] - + baseTriangle.cP(1) * barycentricCoordinates_hexagonBaseTriangleVertex[1] - + baseTriangle.cP(2) * barycentricCoordinates_hexagonBaseTriangleVertex[2]; +void ReducedModelOptimizer::initializeUpdateReducedPatternFunctions() { + const vcg::Triangle3& baseTriangle = this->baseTriangle; + optimizationState.functions_updateReducedPatternParameter[R] = + [=](const double& newR, std::shared_ptr& + pReducedModelSimulationEdgeMesh) { + // std::shared_ptr pReducedModel_edgeMesh = + // std::dynamic_pointer_cast( + // pReducedModelSimulationEdgeMesh); + // ReducedModel::updateFannedGeometry_R(newR, + // pReducedModel_edgeMesh); + const CoordType barycentricCoordinates_hexagonBaseTriangleVertex( + 1 - newR, newR / 2, newR / 2); + // const vcg::Triangle3 &baseTriangle = + // getBaseTriangle(); + const CoordType hexagonBaseTriangleVertexPosition = + baseTriangle.cP(0) * + barycentricCoordinates_hexagonBaseTriangleVertex[0] + + baseTriangle.cP(1) * + barycentricCoordinates_hexagonBaseTriangleVertex[1] + + baseTriangle.cP(2) * + barycentricCoordinates_hexagonBaseTriangleVertex[2]; - // constexpr int fanSize = 6; - for (int rotationCounter = 0; rotationCounter < ReducedModelOptimizer::fanSize; - rotationCounter++) { - pReducedModelSimulationMesh->vert[2 * rotationCounter].P() - = vcg::RotationMatrix(PatternGeometry::DefaultNormal, - vcg::math::ToRad(60.0 * rotationCounter)) - * hexagonBaseTriangleVertexPosition; - } - }; + // constexpr int fanSize = 6; + for (int rotationCounter = 0; + rotationCounter < ReducedModelOptimizer::fanCardinality; + rotationCounter++) { + pReducedModelSimulationEdgeMesh->vert[2 * rotationCounter].P() = + vcg::RotationMatrix(PatternGeometry::DefaultNormal, + vcg::math::ToRad(60.0 * rotationCounter)) * + hexagonBaseTriangleVertexPosition; + } + }; - optimizationState.functions_updateReducedPatternParameter[Theta] = - [](const double &newTheta_degrees, - std::shared_ptr &pReducedModelSimulationMesh) { - // std::shared_ptr pReducedModel_edgeMesh - // = std::dynamic_pointer_cast(pReducedModelSimulationMesh); - // ReducedModel::updateFannedGeometry_theta(newTheta_degrees, pReducedModel_edgeMesh); + optimizationState.functions_updateReducedPatternParameter[Theta] = + [](const double& newTheta_degrees, + std::shared_ptr& pReducedModelSimulationEdgeMesh) { + // std::shared_ptr pReducedModel_edgeMesh + // = + // std::dynamic_pointer_cast(pReducedModelSimulationEdgeMesh); + // ReducedModel::updateFannedGeometry_theta(newTheta_degrees, + // pReducedModel_edgeMesh); - const CoordType baseTriangleHexagonVertexPosition = pReducedModelSimulationMesh->vert[0] - .cP(); - const CoordType thetaRotatedHexagonBaseTriangleVertexPosition - = vcg::RotationMatrix(PatternGeometry::DefaultNormal, - vcg::math::ToRad(newTheta_degrees)) - * baseTriangleHexagonVertexPosition; - for (int rotationCounter = 0; rotationCounter < ReducedModelOptimizer::fanSize; - rotationCounter++) { - pReducedModelSimulationMesh->vert[2 * rotationCounter].P() - = vcg::RotationMatrix(PatternGeometry::DefaultNormal, - vcg::math::ToRad(60.0 * rotationCounter)) - * thetaRotatedHexagonBaseTriangleVertexPosition; - } - }; + const CoordType baseTriangleHexagonVertexPosition = + pReducedModelSimulationEdgeMesh->vert[0].cP(); + const CoordType thetaRotatedHexagonBaseTriangleVertexPosition = + vcg::RotationMatrix(PatternGeometry::DefaultNormal, + vcg::math::ToRad(newTheta_degrees)) * + baseTriangleHexagonVertexPosition; + for (int rotationCounter = 0; + rotationCounter < ReducedModelOptimizer::fanCardinality; + rotationCounter++) { + pReducedModelSimulationEdgeMesh->vert[2 * rotationCounter].P() = + vcg::RotationMatrix(PatternGeometry::DefaultNormal, + vcg::math::ToRad(60.0 * rotationCounter)) * + thetaRotatedHexagonBaseTriangleVertexPosition; + } + }; - optimizationState.functions_updateReducedPatternParameter[E] = - [](const double &newE, std::shared_ptr &pReducedPatternSimulationMesh) { - for (EdgeIndex ei = 0; ei < pReducedPatternSimulationMesh->EN(); ei++) { - Element &e = pReducedPatternSimulationMesh->elements[ei]; - e.setMaterial(ElementMaterial(e.material.poissonsRatio, newE)); - } - }; - optimizationState.functions_updateReducedPatternParameter[A] = - [](const double &newA, std::shared_ptr &pReducedPatternSimulationMesh) { - assert(pReducedPatternSimulationMesh != nullptr); - const double beamWidth = std::sqrt(newA); - const double beamHeight = beamWidth; - for (EdgeIndex ei = 0; ei < pReducedPatternSimulationMesh->EN(); ei++) { - Element &e = pReducedPatternSimulationMesh->elements[ei]; - e.setDimensions(CrossSectionType(beamWidth, beamHeight)); - } - }; + optimizationState.functions_updateReducedPatternParameter[E] = + [](const double& newE, std::shared_ptr& + pReducedPatternSimulationEdgeMesh) { + for (EdgeIndex ei = 0; ei < pReducedPatternSimulationEdgeMesh->EN(); + ei++) { + Element& e = pReducedPatternSimulationEdgeMesh->elements[ei]; + e.setMaterial(ElementMaterial(e.material.poissonsRatio, newE)); + } + }; + optimizationState.functions_updateReducedPatternParameter[A] = + [](const double& newA, std::shared_ptr& + pReducedPatternSimulationEdgeMesh) { + assert(pReducedPatternSimulationEdgeMesh != nullptr); + const double beamWidth = std::sqrt(newA); + const double beamHeight = beamWidth; + for (EdgeIndex ei = 0; ei < pReducedPatternSimulationEdgeMesh->EN(); + ei++) { + Element& e = pReducedPatternSimulationEdgeMesh->elements[ei]; + e.setDimensions(CrossSectionType(beamWidth, beamHeight)); + } + }; - optimizationState.functions_updateReducedPatternParameter[I2] = - [](const double &newI2, std::shared_ptr &pReducedPatternSimulationMesh) { - for (EdgeIndex ei = 0; ei < pReducedPatternSimulationMesh->EN(); ei++) { - Element &e = pReducedPatternSimulationMesh->elements[ei]; - e.dimensions.inertia.I2 = newI2; - e.updateRigidity(); - } - }; - optimizationState.functions_updateReducedPatternParameter[I3] = - [](const double &newI3, std::shared_ptr &pReducedPatternSimulationMesh) { - for (EdgeIndex ei = 0; ei < pReducedPatternSimulationMesh->EN(); ei++) { - Element &e = pReducedPatternSimulationMesh->elements[ei]; - e.dimensions.inertia.I3 = newI3; - e.updateRigidity(); - } - }; - optimizationState.functions_updateReducedPatternParameter[J] = - [](const double &newJ, std::shared_ptr &pReducedPatternSimulationMesh) { - for (EdgeIndex ei = 0; ei < pReducedPatternSimulationMesh->EN(); ei++) { - Element &e = pReducedPatternSimulationMesh->elements[ei]; - e.dimensions.inertia.J = newJ; - e.updateRigidity(); - } - }; + optimizationState.functions_updateReducedPatternParameter[I2] = + [](const double& newI2, std::shared_ptr& + pReducedPatternSimulationEdgeMesh) { + for (EdgeIndex ei = 0; ei < pReducedPatternSimulationEdgeMesh->EN(); + ei++) { + Element& e = pReducedPatternSimulationEdgeMesh->elements[ei]; + e.dimensions.inertia.I2 = newI2; + e.updateRigidity(); + } + }; + optimizationState.functions_updateReducedPatternParameter[I3] = + [](const double& newI3, std::shared_ptr& + pReducedPatternSimulationEdgeMesh) { + for (EdgeIndex ei = 0; ei < pReducedPatternSimulationEdgeMesh->EN(); + ei++) { + Element& e = pReducedPatternSimulationEdgeMesh->elements[ei]; + e.dimensions.inertia.I3 = newI3; + e.updateRigidity(); + } + }; + optimizationState.functions_updateReducedPatternParameter[J] = + [](const double& newJ, std::shared_ptr& + pReducedPatternSimulationEdgeMesh) { + for (EdgeIndex ei = 0; ei < pReducedPatternSimulationEdgeMesh->EN(); + ei++) { + Element& e = pReducedPatternSimulationEdgeMesh->elements[ei]; + e.dimensions.inertia.J = newJ; + e.updateRigidity(); + } + }; } void ReducedModelOptimizer::initializeOptimizationParameters( - const std::shared_ptr &mesh, + const std::shared_ptr& mesh, const std::array &optimizationParameters) -{ - for (int optimizationParameterIndex = 0; - optimizationParameterIndex < optimizationParameters.size(); - optimizationParameterIndex++) { - for (int optimizationParameterIndex = E; - optimizationParameterIndex != NumberOfOptimizationVariables; - optimizationParameterIndex++) { - // const xRange &xOptimizationParameter = optimizationParameters[optimizationParameterIndex]; - switch (optimizationParameterIndex) { - case E: - optimizationState.parametersInitialValue[optimizationParameterIndex] - = mesh->elements[0].material.youngsModulus; - optimizationState.optimizationInitialValue[optimizationParameterIndex] = 1; - break; - case A: - optimizationState.parametersInitialValue[optimizationParameterIndex] - = mesh->elements[0].dimensions.A; - optimizationState.optimizationInitialValue[optimizationParameterIndex] = 1; - break; - case I2: - optimizationState.parametersInitialValue[optimizationParameterIndex] - = mesh->elements[0].dimensions.inertia.I2; - optimizationState.optimizationInitialValue[optimizationParameterIndex] = 1; - break; - case I3: - optimizationState.parametersInitialValue[optimizationParameterIndex] - = mesh->elements[0].dimensions.inertia.I3; - optimizationState.optimizationInitialValue[optimizationParameterIndex] = 1; - break; - case J: - optimizationState.parametersInitialValue[optimizationParameterIndex] - = mesh->elements[0].dimensions.inertia.J; - optimizationState.optimizationInitialValue[optimizationParameterIndex] = 1; - break; - case R: - optimizationState.parametersInitialValue[optimizationParameterIndex] = 0; - optimizationState.optimizationInitialValue[optimizationParameterIndex] = 0.5; - break; - case Theta: - optimizationState.parametersInitialValue[optimizationParameterIndex] = 0; - optimizationState.optimizationInitialValue[optimizationParameterIndex] = 0; - break; - } - } - } -} - -void ReducedModelOptimizer::computeReducedModelSimulationJob( - const SimulationJob &simulationJobOfFullModel, - const std::unordered_map &fullToReducedMap, - SimulationJob &simulationJobOfReducedModel) -{ - assert(simulationJobOfReducedModel.pMesh->VN() != 0); - std::unordered_map> reducedModelFixedVertices; - for (auto fullModelFixedVertex : simulationJobOfFullModel.constrainedVertices) { - reducedModelFixedVertices[fullToReducedMap.at(fullModelFixedVertex.first)] - = fullModelFixedVertex.second; - } - - std::unordered_map reducedModelNodalForces; - for (auto fullModelNodalForce : simulationJobOfFullModel.nodalExternalForces) { - reducedModelNodalForces[fullToReducedMap.at(fullModelNodalForce.first)] - = fullModelNodalForce.second; - } - - std::unordered_map reducedNodalForcedDisplacements; - for (auto fullForcedDisplacement : simulationJobOfFullModel.nodalForcedDisplacements) { - reducedNodalForcedDisplacements[fullToReducedMap.at(fullForcedDisplacement.first)] - = fullForcedDisplacement.second; - } - - simulationJobOfReducedModel.constrainedVertices = reducedModelFixedVertices; - simulationJobOfReducedModel.nodalExternalForces = reducedModelNodalForces; - simulationJobOfReducedModel.label = simulationJobOfFullModel.getLabel(); - simulationJobOfReducedModel.nodalForcedDisplacements = reducedNodalForcedDisplacements; -} - -void ReducedModelOptimizer::computeDesiredReducedModelDisplacements( - const SimulationResults &fullModelResults, - const std::unordered_map &displacementsReducedToFullMap, - Eigen::MatrixX3d &optimalDisplacementsOfReducedModel) -{ - assert(optimalDisplacementsOfReducedModel.rows() != 0 - && optimalDisplacementsOfReducedModel.cols() == 3); - optimalDisplacementsOfReducedModel.setZero(optimalDisplacementsOfReducedModel.rows(), - optimalDisplacementsOfReducedModel.cols()); - - for (auto reducedFullViPair : displacementsReducedToFullMap) { - const VertexIndex fullModelVi = reducedFullViPair.second; - const Vector6d fullModelViDisplacements = fullModelResults.displacements[fullModelVi]; - optimalDisplacementsOfReducedModel.row(reducedFullViPair.first) - = Eigen::Vector3d(fullModelViDisplacements[0], - fullModelViDisplacements[1], - fullModelViDisplacements[2]); - } -} - -void ReducedModelOptimizer::getResults(const FunctionEvaluation &optimalObjective, - const Settings &settings, - ReducedModelOptimization::Results &results) -{ - // std::shared_ptr &pReducedPatternSimulationMesh - // = g_optimizationState.reducedPatternSimulationJobs[global.simulationScenarioIndices[0]] - // ->pMesh; - //Number of crashes - // results.numberOfSimulationCrashes = optimizationState.numOfSimulationCrashes; - //Value of optimal objective Y - results.objectiveValue.total = optimalObjective.y; - // results.objectiveValue.total = 0; - if (std::abs(optimalObjective.y - optimizationState.minY) > 1e-1) { - std::cout << "Different optimal y:" << optimalObjective.y << " " << optimizationState.minY - << std::endl; - } - //Optimal X values - results.optimalXNameValuePairs.resize(NumberOfOptimizationVariables); + ReducedModelOptimization::NumberOfOptimizationVariables>& + optimizationParameters) { + for (int optimizationParameterIndex = 0; + optimizationParameterIndex < optimizationParameters.size(); + optimizationParameterIndex++) { for (int optimizationParameterIndex = E; optimizationParameterIndex != NumberOfOptimizationVariables; optimizationParameterIndex++) { - if (optimizationParameterIndex != OptimizationParameterIndex::R - && optimizationParameterIndex != OptimizationParameterIndex::Theta) { - results.optimalXNameValuePairs[optimizationParameterIndex] = std::make_pair( - settings.variablesRanges[optimizationParameterIndex].label, - optimalObjective.x[optimizationParameterIndex] - * optimizationState.parametersInitialValue[optimizationParameterIndex]); - } else { - //Hex size and angle are pure values (not multipliers of the initial values) - results.optimalXNameValuePairs[optimizationParameterIndex] - = std::make_pair(settings.variablesRanges[optimizationParameterIndex].label, - optimalObjective.x[optimizationParameterIndex]); - } - - optimizationState.functions_updateReducedPatternParameter[optimizationParameterIndex]( - results.optimalXNameValuePairs[optimizationParameterIndex].second, - m_pReducedModelSimulationMesh); //NOTE:due to this call this function is not const -#ifdef POLYSCOPE_DEFINED - std::cout << results.optimalXNameValuePairs[optimizationParameterIndex].first << ":" - << results.optimalXNameValuePairs[optimizationParameterIndex].second << " "; -#endif + // const xRange &xOptimizationParameter = + // optimizationParameters[optimizationParameterIndex]; + switch (optimizationParameterIndex) { + case E: + optimizationState.parametersInitialValue[optimizationParameterIndex] = + mesh->elements[0].material.youngsModulus; + optimizationState + .optimizationInitialValue[optimizationParameterIndex] = 1; + break; + case A: + optimizationState.parametersInitialValue[optimizationParameterIndex] = + mesh->elements[0].dimensions.A; + optimizationState + .optimizationInitialValue[optimizationParameterIndex] = 1; + break; + case I2: + optimizationState.parametersInitialValue[optimizationParameterIndex] = + mesh->elements[0].dimensions.inertia.I2; + optimizationState + .optimizationInitialValue[optimizationParameterIndex] = 1; + break; + case I3: + optimizationState.parametersInitialValue[optimizationParameterIndex] = + mesh->elements[0].dimensions.inertia.I3; + optimizationState + .optimizationInitialValue[optimizationParameterIndex] = 1; + break; + case J: + optimizationState.parametersInitialValue[optimizationParameterIndex] = + mesh->elements[0].dimensions.inertia.J; + optimizationState + .optimizationInitialValue[optimizationParameterIndex] = 1; + break; + case R: + optimizationState.parametersInitialValue[optimizationParameterIndex] = + 0; + optimizationState + .optimizationInitialValue[optimizationParameterIndex] = 0.5; + break; + case Theta: + optimizationState.parametersInitialValue[optimizationParameterIndex] = + 0; + optimizationState + .optimizationInitialValue[optimizationParameterIndex] = 0; + break; + } } -#ifdef POLYSCOPE_DEFINED - std::cout << std::endl; - m_pReducedModelSimulationMesh->updateEigenEdgeAndVertices(); -#endif - m_pReducedModelSimulationMesh->reset(); - results.fullPatternYoungsModulus = youngsModulus; - // Compute obj value per simulation scenario and the raw objective value - // updateMeshFunction(optimalX); - // results.objectiveValue.totalPerSimulationScenario.resize(totalNumberOfSimulationScenarios); - //TODO:use push_back it will make the code more readable - results.objectiveValue.totalRaw = 0; - results.objectiveValue.perSimulationScenario_translational.resize( - optimizationState.simulationScenarioIndices.size()); - results.objectiveValue.perSimulationScenario_rawTranslational.resize( - optimizationState.simulationScenarioIndices.size()); - results.objectiveValue.perSimulationScenario_rotational.resize( - optimizationState.simulationScenarioIndices.size()); - results.objectiveValue.perSimulationScenario_rawRotational.resize( - optimizationState.simulationScenarioIndices.size()); - results.objectiveValue.perSimulationScenario_total.resize( - optimizationState.simulationScenarioIndices.size()); - results.objectiveValue.perSimulationScenario_total_unweighted.resize( - optimizationState.simulationScenarioIndices.size()); - //#ifdef POLYSCOPE_DEFINED - // optimizationState.pFullPatternSimulationMesh->registerForDrawing(Colors::fullDeformed); - //#endif + } +} - results.perScenario_fullPatternPotentialEnergy.resize( - optimizationState.simulationScenarioIndices.size()); - reducedModelSimulator.setStructure(m_pReducedModelSimulationMesh); - for (int i = 0; i < optimizationState.simulationScenarioIndices.size(); i++) { - const int simulationScenarioIndex = optimizationState.simulationScenarioIndices[i]; - std::shared_ptr &pReducedJob - = optimizationState.reducedPatternSimulationJobs[simulationScenarioIndex]; - SimulationResults reducedModelResults = reducedModelSimulator.executeSimulation(pReducedJob); +void ReducedModelOptimizer::computeReducedModelSimulationJob( + const SimulationJob& simulationJobOfFullModel, + const std::unordered_map& fullToReducedMap, + SimulationJob& simulationJobOfReducedModel) { + assert(simulationJobOfReducedModel.pMesh->VN() != 0); + std::unordered_map> + reducedModelFixedVertices; + for (auto fullModelFixedVertex : + simulationJobOfFullModel.constrainedVertices) { + reducedModelFixedVertices[fullToReducedMap.at(fullModelFixedVertex.first)] = + fullModelFixedVertex.second; + } + + std::unordered_map reducedModelNodalForces; + for (auto fullModelNodalForce : + simulationJobOfFullModel.nodalExternalForces) { + reducedModelNodalForces[fullToReducedMap.at(fullModelNodalForce.first)] = + fullModelNodalForce.second; + } + + std::unordered_map + reducedNodalForcedDisplacements; + for (auto fullForcedDisplacement : + simulationJobOfFullModel.nodalForcedDisplacements) { + reducedNodalForcedDisplacements[fullToReducedMap.at( + fullForcedDisplacement.first)] = fullForcedDisplacement.second; + } + + simulationJobOfReducedModel.constrainedVertices = reducedModelFixedVertices; + simulationJobOfReducedModel.nodalExternalForces = reducedModelNodalForces; + simulationJobOfReducedModel.label = simulationJobOfFullModel.getLabel(); + simulationJobOfReducedModel.nodalForcedDisplacements = + reducedNodalForcedDisplacements; +} + +void ReducedModelOptimizer::computeDesiredReducedModelDisplacements( + const SimulationResults& fullModelResults, + const std::unordered_map& displacementsReducedToFullMap, + Eigen::MatrixX3d& optimalDisplacementsOfReducedModel) { + assert(optimalDisplacementsOfReducedModel.rows() != 0 && + optimalDisplacementsOfReducedModel.cols() == 3); + optimalDisplacementsOfReducedModel.setZero( + optimalDisplacementsOfReducedModel.rows(), + optimalDisplacementsOfReducedModel.cols()); + + for (auto reducedFullViPair : displacementsReducedToFullMap) { + const VertexIndex fullModelVi = reducedFullViPair.second; + const Vector6d fullModelViDisplacements = + fullModelResults.displacements[fullModelVi]; + optimalDisplacementsOfReducedModel.row(reducedFullViPair.first) = + Eigen::Vector3d(fullModelViDisplacements[0], + fullModelViDisplacements[1], + fullModelViDisplacements[2]); + } +} + +void ReducedModelOptimizer::getResults( + const FunctionEvaluation& optimalObjective, + const Settings& settings, + ReducedModelOptimization::Results& results) { + // std::shared_ptr &pReducedPatternSimulationEdgeMesh + // = + // g_optimizationState.reducedPatternSimulationJobs[global.simulationScenarioIndices[0]] + // ->pMesh; + // Number of crashes + // results.numberOfSimulationCrashes = + // optimizationState.numOfSimulationCrashes; + // Value of optimal objective Y + results.objectiveValue.total = optimalObjective.y; + // results.objectiveValue.total = 0; + if (std::abs(optimalObjective.y - optimizationState.minY) > 1e-1) { + std::cout << "Different optimal y:" << optimalObjective.y << " " + << optimizationState.minY << std::endl; + } + // Optimal X values + results.optimalXNameValuePairs.resize(NumberOfOptimizationVariables); + for (int optimizationParameterIndex = E; + optimizationParameterIndex != NumberOfOptimizationVariables; + optimizationParameterIndex++) { + results.optimalXNameValuePairs[optimizationParameterIndex] = std::make_pair( + settings.variablesRanges[optimizationParameterIndex].label, + optimalObjective.x[optimizationParameterIndex]); + } + + std::unordered_set optimizationParametersUsed; + for (const std::vector& parameterGroup : + settings.optimizationStrategy) { + optimizationParametersUsed.insert(parameterGroup.begin(), + parameterGroup.end()); + } + + for (int optimizationParameterIndex = E; + optimizationParameterIndex != NumberOfOptimizationVariables; + optimizationParameterIndex++) { + if (optimizationParameterIndex != OptimizationParameterIndex::R && + optimizationParameterIndex != OptimizationParameterIndex::Theta) { + results.optimalXNameValuePairs[optimizationParameterIndex] = + std::make_pair( + settings.variablesRanges[optimizationParameterIndex].label, + optimalObjective.x[optimizationParameterIndex] * + optimizationState + .parametersInitialValue[optimizationParameterIndex]); + } else { + // Hex size and angle are pure values (not multipliers of the initial + // values) + results.optimalXNameValuePairs[optimizationParameterIndex] = + std::make_pair( + settings.variablesRanges[optimizationParameterIndex].label, + optimalObjective.x[optimizationParameterIndex]); + } + + optimizationState + .functions_updateReducedPatternParameter[optimizationParameterIndex]( + results.optimalXNameValuePairs[optimizationParameterIndex].second, + m_pReducedModelSimulationEdgeMesh); // NOTE:due to this call this + // function is not const +#ifdef POLYSCOPE_DEFINED + std::cout + << results.optimalXNameValuePairs[optimizationParameterIndex].first + << ":" + << results.optimalXNameValuePairs[optimizationParameterIndex].second + << " "; +#endif + } +#ifdef POLYSCOPE_DEFINED + std::cout << std::endl; + m_pReducedModelSimulationEdgeMesh->updateEigenEdgeAndVertices(); +#endif + m_pReducedModelSimulationEdgeMesh->reset(); + // Compute obj value per simulation scenario and the raw objective value + // updateMeshFunction(optimalX); + // results.objectiveValue.totalPerSimulationScenario.resize(totalNumberOfSimulationScenarios); + // TODO:use push_back it will make the code more readable + results.objectiveValue.totalRaw = 0; + results.objectiveValue.perSimulationScenario_translational.resize( + optimizationState.simulationScenarioIndices.size()); + results.objectiveValue.perSimulationScenario_rawTranslational.resize( + optimizationState.simulationScenarioIndices.size()); + results.objectiveValue.perSimulationScenario_rotational.resize( + optimizationState.simulationScenarioIndices.size()); + results.objectiveValue.perSimulationScenario_rawRotational.resize( + optimizationState.simulationScenarioIndices.size()); + results.objectiveValue.perSimulationScenario_total.resize( + optimizationState.simulationScenarioIndices.size()); + results.objectiveValue.perSimulationScenario_total_unweighted.resize( + optimizationState.simulationScenarioIndices.size()); + //#ifdef POLYSCOPE_DEFINED + // optimizationState.pFullPatternSimulationEdgeMesh->registerForDrawing(Colors::fullDeformed); + //#endif + + results.perScenario_fullPatternPotentialEnergy.resize( + optimizationState.simulationScenarioIndices.size()); + // reducedModelSimulator.setStructure(m_pReducedModelSimulationEdgeMesh); + for (int i = 0; i < optimizationState.simulationScenarioIndices.size(); i++) { + const int simulationScenarioIndex = + optimizationState.simulationScenarioIndices[i]; + std::shared_ptr& pSimulationJob_reducedModel = + optimizationState.simulationJobs_reducedModel[simulationScenarioIndex]; + // ChronosEulerSimulationModel reducedModelSimulator; + // reducedModelSimulator.settings.analysisType = + // ChronosEulerSimulationModel::Settings::AnalysisType::Linear; + // SimulationResults reducedModelResults = + // reducedModelSimulator.executeSimulation(pReducedJob); + std::unique_ptr pReducedModelSimulator = + SimulationModelFactory::create( + optimizationState.simulationModelLabel_reducedModel); + pReducedModelSimulator->setStructure(pSimulationJob_reducedModel->pMesh); + SimulationResults reducedModelResults = + pReducedModelSimulator->executeSimulation(pSimulationJob_reducedModel); #ifdef POLYSCOPE_DEFINED #ifdef USE_SCENARIO_WEIGHTS - const double scenarioWeight = optimizationState.scenarioWeights[simulationScenarioIndex]; + const double scenarioWeight = + optimizationState.scenarioWeights[simulationScenarioIndex]; #else - const double scenarioWeight = 1; + const double scenarioWeight = 1; #endif #else - const double scenarioWeight = 1; + const double scenarioWeight = 1; #endif - results.objectiveValue.perSimulationScenario_total[i] = computeError( - optimizationState.fullPatternResults[simulationScenarioIndex], - reducedModelResults, - optimizationState.reducedToFullInterfaceViMap, - optimizationState.translationalDisplacementNormalizationValues[simulationScenarioIndex], - optimizationState.rotationalDisplacementNormalizationValues[simulationScenarioIndex], - scenarioWeight, - optimizationState.objectiveWeights[simulationScenarioIndex]); + results.objectiveValue.perSimulationScenario_total[i] = computeError( + optimizationState.fullPatternResults[simulationScenarioIndex], + reducedModelResults, optimizationState.reducedToFullInterfaceViMap, + optimizationState.translationalDisplacementNormalizationValues + [simulationScenarioIndex], + optimizationState + .rotationalDisplacementNormalizationValues[simulationScenarioIndex], + scenarioWeight, + optimizationState.objectiveWeights[simulationScenarioIndex]); - results.objectiveValue.perSimulationScenario_total_unweighted[i] = computeError( - optimizationState.fullPatternResults[simulationScenarioIndex], - reducedModelResults, - optimizationState.reducedToFullInterfaceViMap, - optimizationState.translationalDisplacementNormalizationValues[simulationScenarioIndex], - optimizationState.rotationalDisplacementNormalizationValues[simulationScenarioIndex], - 1, - optimizationState.objectiveWeights[simulationScenarioIndex]); + results.objectiveValue + .perSimulationScenario_total_unweighted[i] = computeError( + optimizationState.fullPatternResults[simulationScenarioIndex], + reducedModelResults, optimizationState.reducedToFullInterfaceViMap, + optimizationState.translationalDisplacementNormalizationValues + [simulationScenarioIndex], + optimizationState + .rotationalDisplacementNormalizationValues[simulationScenarioIndex], + 1, optimizationState.objectiveWeights[simulationScenarioIndex]); - // results.objectiveValue.total += results.objectiveValue.perSimulationScenario_total[i]; - //Raw translational - const double rawTranslationalError = computeRawTranslationalError( - optimizationState.fullPatternResults[simulationScenarioIndex].displacements, - reducedModelResults.displacements, - optimizationState.reducedToFullInterfaceViMap); - results.objectiveValue.perSimulationScenario_rawTranslational[i] = rawTranslationalError; - //Raw rotational - const double rawRotationalError - = computeRawRotationalError(optimizationState - .fullPatternResults[simulationScenarioIndex] - .rotationalDisplacementQuaternion, - reducedModelResults.rotationalDisplacementQuaternion, - optimizationState.reducedToFullInterfaceViMap); - results.objectiveValue.perSimulationScenario_rawRotational[i] = rawRotationalError; + // results.objectiveValue.total += + // results.objectiveValue.perSimulationScenario_total[i]; + // Raw translational + const double rawTranslationalError = computeRawTranslationalError( + optimizationState.fullPatternResults[simulationScenarioIndex] + .displacements, + reducedModelResults.displacements, + optimizationState.reducedToFullInterfaceViMap); + results.objectiveValue.perSimulationScenario_rawTranslational[i] = + rawTranslationalError; + // Raw rotational + const double rawRotationalError = computeRawRotationalError( + optimizationState.fullPatternResults[simulationScenarioIndex] + .rotationalDisplacementQuaternion, + reducedModelResults.rotationalDisplacementQuaternion, + optimizationState.reducedToFullInterfaceViMap); + results.objectiveValue.perSimulationScenario_rawRotational[i] = + rawRotationalError; - //Normalized translational - const double normalizedTranslationalError = computeDisplacementError( - optimizationState.fullPatternResults[simulationScenarioIndex].displacements, - reducedModelResults.displacements, - optimizationState.reducedToFullInterfaceViMap, - optimizationState.translationalDisplacementNormalizationValues[simulationScenarioIndex]); - results.objectiveValue.perSimulationScenario_translational[i] = normalizedTranslationalError; - // const double test_normalizedTranslationError = computeDisplacementError( - // optimizationState.fullPatternResults[simulationScenarioIndex].displacements, - // reducedModelResults.displacements, - // optimizationState.reducedToFullInterfaceViMap, - // optimizationState.translationalDisplacementNormalizationValues[simulationScenarioIndex]); - //Normalized rotational - const double normalizedRotationalError = computeRotationalError( - optimizationState.fullPatternResults[simulationScenarioIndex] - .rotationalDisplacementQuaternion, - reducedModelResults.rotationalDisplacementQuaternion, - optimizationState.reducedToFullInterfaceViMap, - optimizationState.rotationalDisplacementNormalizationValues[simulationScenarioIndex]); - results.objectiveValue.perSimulationScenario_rotational[i] = normalizedRotationalError; - // const double test_normalizedRotationalError = computeRotationalError( - // optimizationState.fullPatternResults[simulationScenarioIndex].rotationalDisplacementQuaternion, - // reducedModelResults.rotationalDisplacementQuaternion, - // optimizationState.reducedToFullInterfaceViMap, - // optimizationState.rotationalDisplacementNormalizationValues[simulationScenarioIndex]); - // assert(test_normalizedTranslationError == normalizedTranslationalError); - // assert(test_normalizedRotationalError == normalizedRotationalError); - results.objectiveValue.totalRaw += rawTranslationalError + rawRotationalError; - results.perScenario_fullPatternPotentialEnergy[i] - = optimizationState.fullPatternResults[simulationScenarioIndex].internalPotentialEnergy; -#ifdef POLYSCOPE_DEFINED - std::cout << "Simulation scenario:" - << optimizationState.reducedPatternSimulationJobs[simulationScenarioIndex] - ->getLabel() - << std::endl; - std::cout << "raw translational error:" << rawTranslationalError << std::endl; - std::cout << "translation normalization value:" - << optimizationState - .translationalDisplacementNormalizationValues[simulationScenarioIndex] - << std::endl; - std::cout << "raw Rotational error:" << rawRotationalError << std::endl; - std::cout << "rotational normalization value:" - << optimizationState - .rotationalDisplacementNormalizationValues[simulationScenarioIndex] - << std::endl; - std::cout << "Translational error:" << normalizedTranslationalError << std::endl; - std::cout << "Rotational error:" << normalizedRotationalError << std::endl; - // results.objectiveValuePerSimulationScenario[simulationScenarioIndex] - // = normalizedTranslationalError + normalizedRotationalError; - std::cout << "Total Error value:" << results.objectiveValue.perSimulationScenario_total[i] - << std::endl; - std::cout << std::endl; + // Normalized translational + const double normalizedTranslationalError = computeDisplacementError( + optimizationState.fullPatternResults[simulationScenarioIndex] + .displacements, + reducedModelResults.displacements, + optimizationState.reducedToFullInterfaceViMap, + optimizationState.translationalDisplacementNormalizationValues + [simulationScenarioIndex]); + results.objectiveValue.perSimulationScenario_translational[i] = + normalizedTranslationalError; + // const double test_normalizedTranslationError = + // computeDisplacementError( + // optimizationState.fullPatternResults[simulationScenarioIndex].displacements, + // reducedModelResults.displacements, + // optimizationState.reducedToFullInterfaceViMap, + // optimizationState.translationalDisplacementNormalizationValues[simulationScenarioIndex]); + // Normalized rotational + const double normalizedRotationalError = computeRotationalError( + optimizationState.fullPatternResults[simulationScenarioIndex] + .rotationalDisplacementQuaternion, + reducedModelResults.rotationalDisplacementQuaternion, + optimizationState.reducedToFullInterfaceViMap, + optimizationState.rotationalDisplacementNormalizationValues + [simulationScenarioIndex]); + results.objectiveValue.perSimulationScenario_rotational[i] = + normalizedRotationalError; + // const double test_normalizedRotationalError = + // computeRotationalError( + // optimizationState.fullPatternResults[simulationScenarioIndex].rotationalDisplacementQuaternion, + // reducedModelResults.rotationalDisplacementQuaternion, + // optimizationState.reducedToFullInterfaceViMap, + // optimizationState.rotationalDisplacementNormalizationValues[simulationScenarioIndex]); + // assert(test_normalizedTranslationError == + // normalizedTranslationalError); + // assert(test_normalizedRotationalError == + // normalizedRotationalError); + results.objectiveValue.totalRaw += + rawTranslationalError + rawRotationalError; + results.perScenario_fullPatternPotentialEnergy[i] = + optimizationState.fullPatternResults[simulationScenarioIndex] + .internalPotentialEnergy; +#ifdef POLYSCOPE_DEFINED_ + std::cout << "Simulation scenario:" + << optimizationState + .simulationJobs_reducedModel[simulationScenarioIndex] + ->getLabel() + << std::endl; + std::cout << "raw translational error:" << rawTranslationalError + << std::endl; + std::cout << "translation normalization value:" + << optimizationState.translationalDisplacementNormalizationValues + [simulationScenarioIndex] + << std::endl; + std::cout << "raw Rotational error:" << rawRotationalError << std::endl; + std::cout << "rotational normalization value:" + << optimizationState.rotationalDisplacementNormalizationValues + [simulationScenarioIndex] + << std::endl; + std::cout << "Translational error:" << normalizedTranslationalError + << std::endl; + std::cout << "Rotational error:" << normalizedRotationalError << std::endl; + // results.objectiveValuePerSimulationScenario[simulationScenarioIndex] + // = normalizedTranslationalError + normalizedRotationalError; + std::cout << "Total Error value:" + << results.objectiveValue.perSimulationScenario_total[i] + << std::endl; + std::cout << std::endl; - // reducedModelResults.registerForDrawing(Colors::reducedDeformed); - // optimizationState.fullPatternResults[simulationScenarioIndex].registerForDrawing( - // Colors::patternDeformed); - // polyscope::show(); - // reducedModelResults.unregister(); - // optimizationState.fullPatternResults[simulationScenarioIndex].unregister(); + reducedModelResults.registerForDrawing(Colors::reducedDeformed, true, 0.01); + optimizationState.fullPatternResults[simulationScenarioIndex] + .registerForDrawing(Colors::patternDeformed, true, 0.01); + ChronosEulerNonLinearSimulationModel debug_chronosModel; + auto debug_chronosResults = debug_chronosModel.executeSimulation( + optimizationState.pSimulationJobs_pattern[simulationScenarioIndex]); + debug_chronosResults.registerForDrawing(); + // debug_chronosResults.setLabelPrefix("chron"); + polyscope::show(); + debug_chronosResults.unregister(); + reducedModelResults.unregister(); + optimizationState.fullPatternResults[simulationScenarioIndex].unregister(); #endif - } + } - for (int simulationScenarioIndex : optimizationState.simulationScenarioIndices) { - results.fullPatternSimulationJobs.push_back( - optimizationState.fullPatternSimulationJobs[simulationScenarioIndex]); - results.reducedPatternSimulationJobs.push_back( - optimizationState.reducedPatternSimulationJobs[simulationScenarioIndex]); - // const std::string temp = optimizationState.reducedPatternSimulationJobs[simulationScenarioIndex] - // ->pMesh->getLabel(); - // optimizationState.reducedPatternSimulationJobs[simulationScenarioIndex]->pMesh->setLabel("temp"); - // optimizationState.reducedPatternSimulationJobs[simulationScenarioIndex]->pMesh->registerForDrawing(); - // optimizationState.reducedPatternSimulationJobs[simulationScenarioIndex]->pMesh->setLabel(temp); - } - results.objectiveValueHistory = optimizationState.objectiveValueHistory; - results.objectiveValueHistory_iteration = optimizationState.objectiveValueHistory_iteration; - // results.draw(); + for (int simulationScenarioIndex : + optimizationState.simulationScenarioIndices) { + results.pSimulationJobs_pattern.push_back( + optimizationState.pSimulationJobs_pattern[simulationScenarioIndex]); + results.pSimulationJobs_reducedModel.push_back( + optimizationState.simulationJobs_reducedModel[simulationScenarioIndex]); + // const std::string temp = + // optimizationState.reducedPatternSimulationJobs[simulationScenarioIndex] + // ->pMesh->getLabel(); + // optimizationState.reducedPatternSimulationJobs[simulationScenarioIndex]->pMesh->setLabel("temp"); + // optimizationState.reducedPatternSimulationJobs[simulationScenarioIndex]->pMesh->registerForDrawing(); + // optimizationState.reducedPatternSimulationJobs[simulationScenarioIndex]->pMesh->setLabel(temp); + } + results.objectiveValueHistory = optimizationState.objectiveValueHistory; + results.objectiveValueHistory_iteration = + optimizationState.objectiveValueHistory_iteration; + // results.draw(); } #ifdef DLIB_DEFINED std::array ReducedModelOptimizer::computeFullPatternMaxSimulationForces( - const std::vector &desiredBaseSimulationScenario) const -{ - std::array fullPatternMaxSimulationForces{0}; - for (const BaseSimulationScenario &scenario : desiredBaseSimulationScenario) { - const double maxForce = computeFullPatternMaxSimulationForce(scenario); - fullPatternMaxSimulationForces[scenario] = maxForce; - } + const std::vector& desiredBaseSimulationScenario) + const { + std::array + fullPatternMaxSimulationForces{0}; + for (const BaseSimulationScenario& scenario : desiredBaseSimulationScenario) { + const double maxForce = computeFullPatternMaxSimulationForce(scenario); + fullPatternMaxSimulationForces[scenario] = maxForce; + } - return fullPatternMaxSimulationForces; + return fullPatternMaxSimulationForces; } std::array ReducedModelOptimizer::getFullPatternMaxSimulationForces( - const std::vector &desiredBaseSimulationScenarioIndices, - const std::filesystem::path &intermediateResultsDirectoryPath, - const bool &recomputeForceMagnitudes) -{ - std::array fullPatternSimulationScenarioMaxMagnitudes; - //#ifdef POLYSCOPE_DEFINED - const std::filesystem::path forceMagnitudesDirectoryPath( - std::filesystem::path(intermediateResultsDirectoryPath).append("ForceMagnitudes")); - std::filesystem::path patternMaxForceMagnitudesFilePath( - std::filesystem::path(forceMagnitudesDirectoryPath) - .append(m_pFullPatternSimulationMesh->getLabel() + ".json")); - const bool fullPatternScenarioMagnitudesExist = std::filesystem::exists( - patternMaxForceMagnitudesFilePath); - if (fullPatternScenarioMagnitudesExist && !recomputeForceMagnitudes) { - nlohmann::json json; - std::ifstream ifs(patternMaxForceMagnitudesFilePath.string()); - ifs >> json; - fullPatternSimulationScenarioMaxMagnitudes - = static_cast>(json.at("maxMagn")); - return fullPatternSimulationScenarioMaxMagnitudes; - } - - //#endif - fullPatternSimulationScenarioMaxMagnitudes = computeFullPatternMaxSimulationForces( - desiredBaseSimulationScenarioIndices); - - //#ifdef POLYSCOPE_DEFINED + const std::vector& + desiredBaseSimulationScenarioIndices, + const std::filesystem::path& intermediateResultsDirectoryPath, + const bool& recomputeForceMagnitudes) { + std::array + fullPatternSimulationScenarioMaxMagnitudes; + //#ifdef POLYSCOPE_DEFINED + const std::filesystem::path forceMagnitudesDirectoryPath( + std::filesystem::path(intermediateResultsDirectoryPath) + .append("ForceMagnitudes")); + std::filesystem::path patternMaxForceMagnitudesFilePath( + std::filesystem::path(forceMagnitudesDirectoryPath) + .append(m_pFullPatternSimulationEdgeMesh->getLabel() + ".json")); + const bool fullPatternScenarioMagnitudesExist = + std::filesystem::exists(patternMaxForceMagnitudesFilePath); + if (fullPatternScenarioMagnitudesExist && !recomputeForceMagnitudes) { nlohmann::json json; - json["maxMagn"] = fullPatternSimulationScenarioMaxMagnitudes; + std::ifstream ifs(patternMaxForceMagnitudesFilePath.string()); + ifs >> json; + fullPatternSimulationScenarioMaxMagnitudes = + static_cast>( + json.at("maxMagn")); + return fullPatternSimulationScenarioMaxMagnitudes; + } - std::filesystem::create_directories(forceMagnitudesDirectoryPath); - std::ofstream jsonFile(patternMaxForceMagnitudesFilePath.string()); - jsonFile << json; + //#endif + fullPatternSimulationScenarioMaxMagnitudes = + computeFullPatternMaxSimulationForces( + desiredBaseSimulationScenarioIndices); + + //#ifdef POLYSCOPE_DEFINED + nlohmann::json json; + json["maxMagn"] = fullPatternSimulationScenarioMaxMagnitudes; + + std::filesystem::create_directories(forceMagnitudesDirectoryPath); + std::ofstream jsonFile(patternMaxForceMagnitudesFilePath.string()); + jsonFile << json; #ifdef POLYSCOPE_DEFINED - std::cout << "Saved base scenario max magnitudes to:" << patternMaxForceMagnitudesFilePath - << std::endl; + std::cout << "Saved base scenario max magnitudes to:" + << patternMaxForceMagnitudesFilePath << std::endl; #endif - //#endif - assert(fullPatternSimulationScenarioMaxMagnitudes.size() - == desiredBaseSimulationScenarioIndices.size()); + //#endif + assert(fullPatternSimulationScenarioMaxMagnitudes.size() == + desiredBaseSimulationScenarioIndices.size()); - return fullPatternSimulationScenarioMaxMagnitudes; + return fullPatternSimulationScenarioMaxMagnitudes; } #endif -void ReducedModelOptimizer::runOptimization(const Settings &settings, - ReducedModelOptimization::Results &results) -{ - optimizationState.objectiveValueHistory.clear(); - optimizationState.objectiveValueHistory_iteration.clear(); - optimizationState.objectiveValueHistory.reserve(settings.dlib.numberOfFunctionCalls / 100); - optimizationState.objectiveValueHistory_iteration.reserve(settings.dlib.numberOfFunctionCalls - / 100); - optimizationState.minY = std::numeric_limits::max(); - optimizationState.numOfSimulationCrashes = 0; - optimizationState.numberOfFunctionCalls = 0; - optimizationState.pFullPatternSimulationMesh = m_pFullPatternSimulationMesh; +void ReducedModelOptimizer::runOptimization( + const Settings& settings, + ReducedModelOptimization::Results& results) { + optimizationState.simulationModelLabel_reducedModel = + settings.simulationModelLabel_reducedModel; + optimizationState.objectiveValueHistory.clear(); + optimizationState.objectiveValueHistory_iteration.clear(); + optimizationState.objectiveValueHistory.reserve( + settings.dlib.numberOfFunctionCalls / 100); + optimizationState.objectiveValueHistory_iteration.reserve( + settings.dlib.numberOfFunctionCalls / 100); + optimizationState.minY = std::numeric_limits::max(); + optimizationState.numOfSimulationCrashes = 0; + optimizationState.numberOfFunctionCalls = 0; + optimizationState.pFullPatternSimulationEdgeMesh = + m_pSimulationEdgeMesh_pattern; #if POLYSCOPE_DEFINED // optimizationState.plotColors.reserve(settings.numberOfFunctionCalls); #endif - assert(!settings.optimizationStrategy.empty()); - const std::vector> &optimizationParametersGroups - = settings.optimizationStrategy; + assert(!settings.optimizationStrategy.empty()); + const std::vector>& + optimizationParametersGroups = settings.optimizationStrategy; #ifndef USE_ENSMALLEN - const int totalNumberOfOptimizationParameters - = std::accumulate(optimizationParametersGroups.begin(), - optimizationParametersGroups.end(), - 0, - [](const int &sum, - const std::vector ¶meterGroup) { - return sum + parameterGroup.size(); - }); + const int totalNumberOfOptimizationParameters = std::accumulate( + optimizationParametersGroups.begin(), optimizationParametersGroups.end(), + 0, + [](const int& sum, + const std::vector& parameterGroup) { + return sum + parameterGroup.size(); + }); #endif - FunctionEvaluation optimization_optimalResult; - optimization_optimalResult.x.resize(NumberOfOptimizationVariables, 0); - for (int optimizationParameterIndex = E; - optimizationParameterIndex != NumberOfOptimizationVariables; - optimizationParameterIndex++) { - optimization_optimalResult.x[optimizationParameterIndex] - = optimizationState.optimizationInitialValue[optimizationParameterIndex]; + FunctionEvaluation optimization_optimalResult; + optimization_optimalResult.x.resize(NumberOfOptimizationVariables, 0); + for (int optimizationParameterIndex = E; + optimizationParameterIndex != NumberOfOptimizationVariables; + optimizationParameterIndex++) { + optimization_optimalResult.x[optimizationParameterIndex] = + optimizationState.optimizationInitialValue[optimizationParameterIndex]; + } + + for (int parameterGroupIndex = 0; + parameterGroupIndex < optimizationParametersGroups.size(); + parameterGroupIndex++) { + const std::vector& parameterGroup = + optimizationParametersGroups[parameterGroupIndex]; + FunctionEvaluation parameterGroup_optimalResult; + // Set update function. TODO: Make this function immutable by defining it + // once and using the optimizationState variable to set parameterGroup + function_updateReducedPattern = [&](const std::vector& x, + std::shared_ptr& + pMesh) { + for (int xIndex = 0; xIndex < parameterGroup.size(); xIndex++) { + const OptimizationParameterIndex parameterIndex = + parameterGroup[xIndex]; + // const double + // parameterInitialValue=optimizationSettings.parameterRanges[parameterIndex].initialValue; + const double parameterNewValue = [&]() { + if (parameterIndex == R || parameterIndex == Theta) { + return x[xIndex] /*+ parameterInitialValue*/; + } + // and the material parameters exponentially(?).TODO: Check what + // happens if I make all linear + const double parameterInitialValue = + optimizationState.parametersInitialValue[parameterIndex]; + return x[xIndex] * parameterInitialValue; + }(); + // std::cout << "Optimization parameter:" << + // parameterIndex << std::endl; std::cout << "New + // value:" << parameterNewValue << std::endl; + optimizationState + .functions_updateReducedPatternParameter[parameterIndex]( + parameterNewValue, pMesh); + } + pMesh->reset(); // NOTE: I could put this code into each updateParameter + // function for avoiding unessecary calculations + }; + + std::vector xMin; + std::vector xMax; + xMin.resize(parameterGroup.size()); + xMax.resize(parameterGroup.size()); + for (int xIndex = 0; xIndex < parameterGroup.size(); xIndex++) { + const OptimizationParameterIndex parameterIndex = parameterGroup[xIndex]; + + xMin[xIndex] = settings.variablesRanges[parameterIndex].min; + xMax[xIndex] = settings.variablesRanges[parameterIndex].max; } - for (int parameterGroupIndex=0;parameterGroupIndex ¶meterGroup = - optimizationParametersGroups[parameterGroupIndex]; - FunctionEvaluation parameterGroup_optimalResult; - //Set update function. TODO: Make this function immutable by defining it once and using the optimizationState variable to set parameterGroup - function_updateReducedPattern = [&](const std::vector &x, - std::shared_ptr &pMesh) { - for (int xIndex = 0; xIndex < parameterGroup.size(); xIndex++) { - const OptimizationParameterIndex parameterIndex = parameterGroup[xIndex]; - // const double parameterInitialValue=optimizationSettings.parameterRanges[parameterIndex].initialValue; - const double parameterNewValue = [&]() { - if (parameterIndex == R || parameterIndex == Theta) { - return x[xIndex] /*+ parameterInitialValue*/; - } - //and the material parameters exponentially(?).TODO: Check what happens if I make all linear - const double parameterInitialValue - = optimizationState.parametersInitialValue[parameterIndex]; - return x[xIndex] * parameterInitialValue; - }(); - // std::cout << "Optimization parameter:" << parameterIndex << std::endl; - // std::cout << "New value:" << parameterNewValue << std::endl; - optimizationState - .functions_updateReducedPatternParameter[parameterIndex](parameterNewValue, - pMesh); - } - pMesh->reset(); //NOTE: I could put this code into each updateParameter function for avoiding unessecary calculations - }; - - std::vector xMin; - std::vector xMax; - xMin.resize(parameterGroup.size()); - xMax.resize(parameterGroup.size()); - for (int xIndex = 0; xIndex < parameterGroup.size(); xIndex++) { - const OptimizationParameterIndex parameterIndex = parameterGroup[xIndex]; - - xMin[xIndex] = settings.variablesRanges[parameterIndex].min; - xMax[xIndex] = settings.variablesRanges[parameterIndex].max; - } #ifdef USE_ENSMALLEN #ifdef POLYSCOPE_DEFINED - std::cout << "Optimizing using ensmallen" << std::endl; + std::cout << "Optimizing using ensmallen" << std::endl; #endif - arma::mat x(parameterGroup.size(), 1); - for (int xIndex = 0; xIndex < parameterGroup.size(); xIndex++) { - const OptimizationParameterIndex parameterIndex = parameterGroup[xIndex]; + arma::mat x(parameterGroup.size(), 1); + for (int xIndex = 0; xIndex < parameterGroup.size(); xIndex++) { + const OptimizationParameterIndex parameterIndex = parameterGroup[xIndex]; - x(xIndex, 0) = optimizationState.optimizationInitialValue[parameterIndex]; - } + x(xIndex, 0) = optimizationState.optimizationInitialValue[parameterIndex]; + } - optimizationState.xMin = xMin; - optimizationState.xMax = xMax; + optimizationState.xMin = xMin; + optimizationState.xMax = xMax; - EnsmallenReducedModelOptimizationObjective optimizationFunction(optimizationState); + EnsmallenReducedModelOptimizationObjective optimizationFunction( + optimizationState); // optimizationFunction.optimizationState = optimizationState; -//Set min max values +// Set min max values // ens::CNE optimizer; // ens::DE optimizer; // ens::SPSA optimizer; #ifdef USE_PSO - arma::mat xMin_arma(optimizationState.xMin); - arma::mat xMax_arma(optimizationState.xMax); - // ens::LBestPSO optimizer(64, xMin_arma, xMax_arma, 1000); - ens::LBestPSO optimizer(settings.pso.numberOfParticles, - xMin_arma, - xMax_arma, - 1e5, - 500, - settings.solverAccuracy, - 2.05, - 2.35); + arma::mat xMin_arma(optimizationState.xMin); + arma::mat xMax_arma(optimizationState.xMax); + // ens::LBestPSO optimizer(64, xMin_arma, xMax_arma, 1000); + ens::LBestPSO optimizer(settings.pso.numberOfParticles, xMin_arma, + xMax_arma, 1e5, 500, settings.solverAccuracy, 2.05, + 2.35); #else - ens::SA optimizer; + // ens::SA optimizer; + ens::SA<> optimizer(ens::ExponentialSchedule(), 100000, 10000., 1000, 100, + settings.solverAccuracy, 3, 20, 0.3, 0.3); #endif - // ens::LBestPSO optimizer; - parameterGroup_optimalResult.y = optimizer.Optimize(optimizationFunction, x); - // for (int xIndex = 0; xIndex < parameterGroup.size(); xIndex++) { - // if (x[xIndex] > optimizationState.xMax[xIndex]) { - // x[xIndex] = optimizationState.xMax[xIndex]; - // } else if (x[xIndex] < optimizationState.xMin[xIndex]) { - // x[xIndex] = optimizationState.xMin[xIndex]; - // } - // } + // ens::LBestPSO optimizer; + parameterGroup_optimalResult.y = + optimizer.Optimize(optimizationFunction, x); + // for (int xIndex = 0; xIndex < parameterGroup.size(); xIndex++) { + // if (x[xIndex] > optimizationState.xMax[xIndex]) { + // x[xIndex] = optimizationState.xMax[xIndex]; + // } else if (x[xIndex] < optimizationState.xMin[xIndex]) { + // x[xIndex] = optimizationState.xMin[xIndex]; + // } + // } #ifdef POLYSCOPE_DEFINED - std::cout << "optimal x:" - << "\n" - << x << std::endl; - std::cout << "optimal objective:" << optimizationFunction.Evaluate(x) << std::endl; + std::cout << "optimal x:" + << "\n" + << x << std::endl; + std::cout << "optimal objective:" << optimizationFunction.Evaluate(x) + << std::endl; + std::cout << "optimal objective using state var:" + << optimizationFunction.Evaluate(optimizationState.minX) + << std::endl; #endif - parameterGroup_optimalResult.x.clear(); - parameterGroup_optimalResult.x.resize(parameterGroup.size()); - std::copy(x.begin(), x.end(), parameterGroup_optimalResult.x.begin()); + parameterGroup_optimalResult.x.clear(); + parameterGroup_optimalResult.x.resize(parameterGroup.size()); + // std::copy(x.begin(), x.end(), + // parameterGroup_optimalResult.x.begin()); + std::copy(optimizationState.minX.begin(), optimizationState.minX.end(), + parameterGroup_optimalResult.x.begin()); #else - g_optimizationState = optimizationState; + g_optimizationState = optimizationState; #ifdef POLYSCOPE_DEFINED - std::cout << "Optimizing using dlib" << std::endl; + std::cout << "Optimizing using dlib" << std::endl; #endif - //Set min max values - dlib::matrix xMin_dlib(parameterGroup.size()); - dlib::matrix xMax_dlib(parameterGroup.size()); - for (int xIndex = 0; xIndex < parameterGroup.size(); xIndex++) { - const OptimizationParameterIndex parameterIndex = parameterGroup[xIndex]; + // Set min max values + dlib::matrix xMin_dlib(parameterGroup.size()); + dlib::matrix xMax_dlib(parameterGroup.size()); + for (int xIndex = 0; xIndex < parameterGroup.size(); xIndex++) { + const OptimizationParameterIndex parameterIndex = parameterGroup[xIndex]; - xMin_dlib(xIndex) = settings.variablesRanges[parameterIndex].min; - xMax_dlib(xIndex) = settings.variablesRanges[parameterIndex].max; - } - const double portionOfTotalFunctionCallsBudget = [&]() { - if (settings.optimizationVariablesGroupsWeights.has_value()) { - assert(settings.optimizationVariablesGroupsWeights->size() - == settings.optimizationStrategy.size()); - return settings.optimizationVariablesGroupsWeights.value()[parameterGroupIndex]; + xMin_dlib(xIndex) = settings.variablesRanges[parameterIndex].min; + xMax_dlib(xIndex) = settings.variablesRanges[parameterIndex].max; + } + const double portionOfTotalFunctionCallsBudget = [&]() { + if (settings.optimizationVariablesGroupsWeights.has_value()) { + assert(settings.optimizationVariablesGroupsWeights->size() == + settings.optimizationStrategy.size()); + return settings.optimizationVariablesGroupsWeights + .value()[parameterGroupIndex]; - } else { - return static_cast(parameterGroup.size()) - / totalNumberOfOptimizationParameters; - } - }(); - const int optimizationNumberOfFunctionCalls = portionOfTotalFunctionCallsBudget - * settings.dlib.numberOfFunctionCalls; - const dlib::function_evaluation optimalResult_dlib = [&]() { - if (parameterGroup.size() == 1) { - dlib::function_evaluation result; - double optimalX = optimizationState.optimizationInitialValue[parameterGroup[0]]; - double (*singleVariableObjective)(const double &) = &objective; - try { - result.y = dlib::find_min_single_variable(singleVariableObjective, - optimalX, - xMin_dlib(0), - xMax_dlib(0), - 1e-5, - optimizationNumberOfFunctionCalls); - } catch ( - const std::exception &e) { // reference to the base of a polymorphic object + } else { + return static_cast(parameterGroup.size()) / + totalNumberOfOptimizationParameters; + } + }(); + const int optimizationNumberOfFunctionCalls = + portionOfTotalFunctionCallsBudget * settings.dlib.numberOfFunctionCalls; + const dlib::function_evaluation optimalResult_dlib = [&]() { + if (parameterGroup.size() == 1) { + dlib::function_evaluation result; + double optimalX = + optimizationState.optimizationInitialValue[parameterGroup[0]]; + double (*singleVariableObjective)(const double&) = &objective; + try { + result.y = dlib::find_min_single_variable( + singleVariableObjective, optimalX, xMin_dlib(0), xMax_dlib(0), + 1e-5, optimizationNumberOfFunctionCalls); + } catch (const std::exception& + e) { // reference to the base of a polymorphic object #ifdef POLYSCOPE_DEFINED - std::cout << e.what() << std::endl; + std::cout << e.what() << std::endl; #endif - } + } - result.x.set_size(1); - result.x(0) = optimalX; - return result; - } - double (*objF)(const dlib::matrix &) = &objective; - return dlib::find_min_global(objF, - xMin_dlib, - xMax_dlib, - dlib::max_function_calls( - optimizationNumberOfFunctionCalls), - std::chrono::hours(24 * 365 * 290), - settings.solverAccuracy); - }(); - // constexpr bool useBOBYQA = false; - // if (useBOBYQA) { - // const size_t npt = 2 * optimizationState.numberOfOptimizationParameters; - // // ((n + 2) + ((n + 1) * (n + 2) / 2)) / 2; - // const double rhobeg = 0.1; - // // const double rhobeg = 10; - // const double rhoend = rhobeg * 1e-6; - // // const size_t maxFun = 10 * (x.size() ^ 2); - // const size_t bobyqa_maxFunctionCalls = 10000; - // dlib::matrix x; - // dlib::function_evaluation optimalResult_dlib; - // optimalResult_dlib.x.set_size(parameterGroup.size()); - // for (int xIndex = 0; xIndex < parameterGroup.size(); xIndex++) { - // const OptimizationParameterIndex parameterIndex = parameterGroup[xIndex]; - // optimalResult_dlib.x(xIndex) = optimizationState.optimizationInitialValue[parameterIndex]; + result.x.set_size(1); + result.x(0) = optimalX; + return result; + } + double (*objF)(const dlib::matrix&) = &objective; + return dlib::find_min_global( + objF, xMin_dlib, xMax_dlib, + dlib::max_function_calls(optimizationNumberOfFunctionCalls), + std::chrono::hours(24 * 365 * 290), settings.solverAccuracy); + }(); + // constexpr bool useBOBYQA = false; + // if (useBOBYQA) { + // const size_t npt = 2 * + // optimizationState.numberOfOptimizationParameters; + // // ((n + 2) + ((n + 1) * (n + 2) / 2)) / 2; + // const double rhobeg = 0.1; + // // const double rhobeg = 10; + // const double rhoend = rhobeg * 1e-6; + // // const size_t maxFun = 10 * (x.size() ^ 2); + // const size_t bobyqa_maxFunctionCalls = 10000; + // dlib::matrix x; + // dlib::function_evaluation optimalResult_dlib; + // optimalResult_dlib.x.set_size(parameterGroup.size()); + // for (int xIndex = 0; xIndex < parameterGroup.size(); xIndex++) { + // const OptimizationParameterIndex parameterIndex = + // parameterGroup[xIndex]; optimalResult_dlib.x(xIndex) = + // optimizationState.optimizationInitialValue[parameterIndex]; - // std::cout << "xIndex:" << xIndex << std::endl; - // std::cout << "xInit:" << optimalResult_dlib.x(xIndex) << std::endl; - // } + // std::cout << "xIndex:" << xIndex << std::endl; + // std::cout << "xInit:" << optimalResult_dlib.x(xIndex) << + // std::endl; + // } - // optimalResult_dlib.y = dlib::find_min_bobyqa(objF, - // optimalResult_dlib.x, - // npt, - // xMin, - // xMax, - // rhobeg, - // rhoend, - // bobyqa_maxFunctionCalls); - // } + // optimalResult_dlib.y = dlib::find_min_bobyqa(objF, + // optimalResult_dlib.x, + // npt, + // xMin, + // xMax, + // rhobeg, + // rhoend, + // bobyqa_maxFunctionCalls); + // } - parameterGroup_optimalResult.x.clear(); - parameterGroup_optimalResult.x.resize(parameterGroup.size()); - std::copy(optimalResult_dlib.x.begin(), - optimalResult_dlib.x.end(), - parameterGroup_optimalResult.x.begin()); - parameterGroup_optimalResult.y = optimalResult_dlib.y; + parameterGroup_optimalResult.x.clear(); + parameterGroup_optimalResult.x.resize(parameterGroup.size()); + std::copy(optimalResult_dlib.x.begin(), optimalResult_dlib.x.end(), + parameterGroup_optimalResult.x.begin()); + parameterGroup_optimalResult.y = optimalResult_dlib.y; - optimizationState = g_optimizationState; + optimizationState = g_optimizationState; #endif - const auto firstNonNullReducedSimulationJobIt - = std::find_if(optimizationState.reducedPatternSimulationJobs.begin(), - optimizationState.reducedPatternSimulationJobs.end(), - [](const std::shared_ptr &pJob) { - return pJob != nullptr; - }); - function_updateReducedPattern( - std::vector(parameterGroup_optimalResult.x.begin(), - parameterGroup_optimalResult.x.end()), - (*firstNonNullReducedSimulationJobIt) - ->pMesh); //TODO: Check if its ok to update only the changed parameters + const auto firstNonNullReducedSimulationJobIt = + std::find_if(optimizationState.simulationJobs_reducedModel.begin(), + optimizationState.simulationJobs_reducedModel.end(), + [](const std::shared_ptr& pJob) { + return pJob != nullptr; + }); + function_updateReducedPattern( + std::vector(parameterGroup_optimalResult.x.begin(), + parameterGroup_optimalResult.x.end()), + (*firstNonNullReducedSimulationJobIt) + ->pMesh); // TODO: Check if its ok to update only the changed + // parameters #ifdef POLYSCOPE_DEFINED - std::cout << "Optimal x:" - << "\n"; - for (const auto &x : parameterGroup_optimalResult.x) { - std::cout << x << std::endl; - } - std::cout << "optimal objective:" - << objective(parameterGroup_optimalResult.x, optimizationState) << std::endl; - // std::cout << "Minima:" << minima << std::endl; - std::cout << "optimizationState MIN:" << optimizationState.minY << std::endl; - std::cout << "opt res y:" << parameterGroup_optimalResult.y << std::endl; + std::cout << "Optimal x:" + << "\n"; + for (const auto& x : parameterGroup_optimalResult.x) { + std::cout << x << std::endl; + } + std::cout << "optimal objective:" + << objective(parameterGroup_optimalResult.x, optimizationState) + << std::endl; + // std::cout << "Minima:" << minima << std::endl; + std::cout << "optimizationState MIN:" << optimizationState.minY + << std::endl; + std::cout << "opt res y:" << parameterGroup_optimalResult.y << std::endl; #endif - optimization_optimalResult.y = parameterGroup_optimalResult.y; - for (int xIndex = 0; xIndex < parameterGroup.size(); xIndex++) { - const OptimizationParameterIndex parameterIndex = parameterGroup[xIndex]; - optimization_optimalResult.x[parameterIndex] = parameterGroup_optimalResult.x[xIndex]; - } - } - getResults(optimization_optimalResult, settings, results); + optimization_optimalResult.y = parameterGroup_optimalResult.y; + for (int xIndex = 0; xIndex < parameterGroup.size(); xIndex++) { + const OptimizationParameterIndex parameterIndex = parameterGroup[xIndex]; + optimization_optimalResult.x[parameterIndex] = + parameterGroup_optimalResult.x[xIndex]; + } + } + getResults(optimization_optimalResult, settings, results); } void ReducedModelOptimizer::constructAxialSimulationScenario( - const double &forceMagnitude, - const std::vector> - &oppositeInterfaceViPairs, - SimulationJob &job) -{ - for (auto viPairIt = oppositeInterfaceViPairs.begin(); - viPairIt != oppositeInterfaceViPairs.end(); - viPairIt++) { - if (viPairIt != oppositeInterfaceViPairs.begin()) { - CoordType forceDirection(1, 0, 0); - job.nodalExternalForces[viPairIt->first] - = Vector6d({forceDirection[0], forceDirection[1], forceDirection[2], 0, 0, 0}) - * forceMagnitude; - job.constrainedVertices[viPairIt->second] = std::unordered_set{0, 1, 2, 3, 4, 5}; - } + const double& forceMagnitude, + const std::vector>& + oppositeInterfaceViPairs, + SimulationJob& job) { + for (auto viPairIt = oppositeInterfaceViPairs.begin(); + viPairIt != oppositeInterfaceViPairs.end(); viPairIt++) { + if (viPairIt != oppositeInterfaceViPairs.begin()) { + CoordType forceDirection(1, 0, 0); + job.nodalExternalForces[viPairIt->first] = + Vector6d({forceDirection[0], forceDirection[1], forceDirection[2], 0, + 0, 0}) * + forceMagnitude; + job.constrainedVertices[viPairIt->second] = + std::unordered_set{0, 1, 2, 3, 4, 5}; } + } } void ReducedModelOptimizer::constructSSimulationScenario( - const double &forceMagnitude, - const std::vector> - &oppositeInterfaceViPairs, - SimulationJob &job) -{ - for (auto viPairIt = oppositeInterfaceViPairs.begin(); - viPairIt != oppositeInterfaceViPairs.end(); - viPairIt++) { - if (viPairIt == oppositeInterfaceViPairs.begin()) { - job.constrainedVertices[viPairIt->first] = std::unordered_set{0, 1, 2, 3, 4, 5}; - job.constrainedVertices[viPairIt->second] = std::unordered_set{0, 1, 2, 3, 4, 5}; - } else { - CoordType forceDirection(0, 0, 1); - job.nodalExternalForces[viPairIt->first] = Vector6d({0, 0, 1, 0, 0, 0}) - * forceMagnitude; - job.nodalExternalForces[viPairIt->second] = Vector6d({0, 0, -1, 0, 0, 0}) - * forceMagnitude; - } + const double& forceMagnitude, + const std::vector>& + oppositeInterfaceViPairs, + SimulationJob& job) { + for (auto viPairIt = oppositeInterfaceViPairs.begin(); + viPairIt != oppositeInterfaceViPairs.end(); viPairIt++) { + if (viPairIt == oppositeInterfaceViPairs.begin()) { + job.constrainedVertices[viPairIt->first] = + std::unordered_set{ + 0, 1, 2, 3, 4, 5}; + job.constrainedVertices[viPairIt->second] = + std::unordered_set{ + 0, 1, 2, 3, 4, 5}; + } else { + CoordType forceDirection(0, 0, 1); + job.nodalExternalForces[viPairIt->first] = + Vector6d({0, 0, 1, 0, 0, 0}) * forceMagnitude; + job.nodalExternalForces[viPairIt->second] = + Vector6d({0, 0, -1, 0, 0, 0}) * forceMagnitude; } - job.label = "Axial"; + } + job.label = "Axial"; } void ReducedModelOptimizer::constructShearSimulationScenario( - const double &forceMagnitude, - const std::vector> - &oppositeInterfaceViPairs, - SimulationJob &job) -{ - for (auto viPairIt = oppositeInterfaceViPairs.begin(); - viPairIt != oppositeInterfaceViPairs.end(); - viPairIt++) { - if (viPairIt != oppositeInterfaceViPairs.begin()) { - CoordType forceDirection(0, 1, 0); - const auto viPair = *viPairIt; - job.nodalExternalForces[viPair.first] - = Vector6d({forceDirection[0], forceDirection[1], forceDirection[2], 0, 0, 0}) - * forceMagnitude; - job.constrainedVertices[viPair.second] = std::unordered_set{0, 1, 2, 3, 4, 5}; - } + const double& forceMagnitude, + const std::vector>& + oppositeInterfaceViPairs, + SimulationJob& job) { + for (auto viPairIt = oppositeInterfaceViPairs.begin(); + viPairIt != oppositeInterfaceViPairs.end(); viPairIt++) { + if (viPairIt != oppositeInterfaceViPairs.begin()) { + CoordType forceDirection(0, 1, 0); + const auto viPair = *viPairIt; + job.nodalExternalForces[viPair.first] = + Vector6d({forceDirection[0], forceDirection[1], forceDirection[2], 0, + 0, 0}) * + forceMagnitude; + job.constrainedVertices[viPair.second] = + std::unordered_set{0, 1, 2, 3, 4, 5}; } - job.label = "Shear"; + } + job.label = "Shear"; } void ReducedModelOptimizer::constructBendingSimulationScenario( - const double &forceMagnitude, - const std::vector> - &oppositeInterfaceViPairs, - SimulationJob &job) -{ - for (const auto &viPair : oppositeInterfaceViPairs) { - job.nodalExternalForces[viPair.first] = Vector6d({0, 0, 1, 0, 0, 0}) * forceMagnitude; - job.constrainedVertices[viPair.second] = std::unordered_set{0, 1, 2, 3, 4, 5}; - } - job.label = "Bending"; + const double& forceMagnitude, + const std::vector>& + oppositeInterfaceViPairs, + SimulationJob& job) { + for (const auto& viPair : oppositeInterfaceViPairs) { + job.nodalExternalForces[viPair.first] = + Vector6d({0, 0, 1, 0, 0, 0}) * forceMagnitude; + job.constrainedVertices[viPair.second] = + std::unordered_set{0, 1, 2, 3, 4, 5}; + } + job.label = "Bending"; } -/*NOTE: From the results it seems as if the forced displacements are different in the linear and in the drm +/*NOTE: From the results it seems as if the forced displacements are different + * in the linear and in the drm * */ void ReducedModelOptimizer::constructDomeSimulationScenario( - const double &forceMagnitude, - const std::vector> - &oppositeInterfaceViPairs, - SimulationJob &job) -{ - for (auto viPairIt = oppositeInterfaceViPairs.begin(); - viPairIt != oppositeInterfaceViPairs.end(); - viPairIt++) { - const auto viPair = *viPairIt; - CoordType interfaceVector = (job.pMesh->vert[viPair.first].cP() - - job.pMesh->vert[viPair.second].cP()); - VectorType momentAxis = vcg::RotationMatrix(VectorType(0, 0, 1), vcg::math::ToRad(90.0)) - * interfaceVector.Normalize(); - // if (viPairIt == oppositeInterfaceViPairs.begin()) { - // // job.nodalForcedDisplacements[viPair.first] = Eigen::Vector3d(-interfaceVector[0], - // // -interfaceVector[1], - // // 0) - // // * 0.01 - // /** std::abs( - // forceMagnitude)*/ - // // ; //NOTE:Should the forced displacement change relatively to the magnitude? - // // * std::abs(forceMagnitude / maxForceMagnitude_dome); - // // job.nodalForcedDisplacements[viPair.second] = Eigen::Vector3d(interfaceVector[0], - // // interfaceVector[1], - // // 0) - // // * 0.01 /** std::abs(forceMagnitude)*/; - // // * std::abs(forceMagnitude / maxForceMagnitude_dome); - // // CoordType v = (pMesh->vert[viPair.first].cP() - pMesh->vert[viPair.second].cP()) - // // ^ CoordType(0, 0, -1).Normalize(); - // // nodalForces[viPair.first] = Vector6d({0, 0, 0, v[0], v[1], 0}) * forceMagnitude - // // * 0.0001; - // // nodalForces[viPair.second] = Vector6d({0, 0, 0, -v[0], -v[1], 0}) * forceMagnitude - // // * 0.0001; - // job.constrainedVertices[viPair.first] = {0, 1, 2}; - // job.constrainedVertices[viPair.second] = {2}; - // job.constrainedVertices[viPair.first] = std::unordered_set{0, 1, 2}; - // job.constrainedVertices[viPair.second] = std::unordered_set{0, 2}; - // } else { - // job.nodalExternalForces[viPair.first] - // = Vector6d({0, 0, 0, momentAxis[0], momentAxis[1], momentAxis[2]}) * forceMagnitude - // / 3; - // job.nodalExternalForces[viPair.second] - // = Vector6d({0, 0, 0, -momentAxis[0], -momentAxis[1], -momentAxis[2]}) - // * forceMagnitude / 3; - // job.constrainedVertices[viPair.first] = std::unordered_set{2}; - // job.constrainedVertices[viPair.second] = std::unordered_set{2}; - // } - job.nodalExternalForces[viPair.first] - = Vector6d({0, 0, 0, momentAxis[0], momentAxis[1], momentAxis[2]}) * forceMagnitude / 3; - job.nodalExternalForces[viPair.second] - = Vector6d({0, 0, 0, -momentAxis[0], -momentAxis[1], -momentAxis[2]}) * forceMagnitude - / 3; - job.constrainedVertices[viPair.first] = std::unordered_set{0, 1, 2}; - job.constrainedVertices[viPair.second] = std::unordered_set{2}; - } - job.label = "Dome"; + const double& forceMagnitude, + const std::vector>& + oppositeInterfaceViPairs, + SimulationJob& job) { + for (auto viPairIt = oppositeInterfaceViPairs.begin(); + viPairIt != oppositeInterfaceViPairs.end(); viPairIt++) { + const std::pair viPair = *viPairIt; + const CoordType interfaceVector = (job.pMesh->vert[viPair.first].cP() - + job.pMesh->vert[viPair.second].cP()); + const VectorType momentAxis = + vcg::RotationMatrix(VectorType(0, 0, 1), vcg::math::ToRad(90.0)) * + interfaceVector.normalized(); + // if (viPairIt == oppositeInterfaceViPairs.begin()) { + // // job.nodalForcedDisplacements[viPair.first] = + // Eigen::Vector3d(-interfaceVector[0], + // // -interfaceVector[1], + // // 0) + // // * + // 0.01 + // /** std::abs( + // forceMagnitude)*/ + // // ; //NOTE:Should the forced displacement + // change relatively to the magnitude? + // // * std::abs(forceMagnitude / + // maxForceMagnitude_dome); + // // job.nodalForcedDisplacements[viPair.second] = + // Eigen::Vector3d(interfaceVector[0], + // // interfaceVector[1], + // // 0) + // // * + // 0.01 /** std::abs(forceMagnitude)*/; + // // * std::abs(forceMagnitude / + // maxForceMagnitude_dome); + // // CoordType v = (pMesh->vert[viPair.first].cP() - + // pMesh->vert[viPair.second].cP()) + // // ^ CoordType(0, 0, -1).Normalize(); + // // nodalForces[viPair.first] = Vector6d({0, 0, 0, + // v[0], v[1], 0}) * forceMagnitude + // // * 0.0001; + // // nodalForces[viPair.second] = Vector6d({0, 0, 0, + // -v[0], -v[1], 0}) * forceMagnitude + // // * 0.0001; + // job.constrainedVertices[viPair.first] = {0, 1, 2}; + // job.constrainedVertices[viPair.second] = {2}; + // job.constrainedVertices[viPair.first] = + // std::unordered_set{0, 1, 2}; + // job.constrainedVertices[viPair.second] = + // std::unordered_set{0, 2}; + // } else { + // job.nodalExternalForces[viPair.first] + // = Vector6d({0, 0, 0, momentAxis[0], momentAxis[1], + // momentAxis[2]}) * forceMagnitude + // / 3; + // job.nodalExternalForces[viPair.second] + // = Vector6d({0, 0, 0, -momentAxis[0], -momentAxis[1], + // -momentAxis[2]}) + // * forceMagnitude / 3; + // job.constrainedVertices[viPair.first] = + // std::unordered_set{2}; + // job.constrainedVertices[viPair.second] = + // std::unordered_set{2}; + // } + job.nodalExternalForces[viPair.first] = + Vector6d({0, 0, 0, momentAxis[0], momentAxis[1], momentAxis[2]}) * + forceMagnitude / 3; + job.nodalExternalForces[viPair.second] = + Vector6d({0, 0, 0, -momentAxis[0], -momentAxis[1], -momentAxis[2]}) * + forceMagnitude / 3; + job.constrainedVertices[viPair.first] = + std::unordered_set{0, 1, 2}; + job.constrainedVertices[viPair.second] = + std::unordered_set{2}; + } + job.label = "Dome"; } void ReducedModelOptimizer::constructSaddleSimulationScenario( - const double &forceMagnitude, - const std::vector> - &oppositeInterfaceViPairs, - SimulationJob &job) -{ - for (auto viPairIt = oppositeInterfaceViPairs.begin(); - viPairIt != oppositeInterfaceViPairs.end(); - viPairIt++) { - const auto &viPair = *viPairIt; - CoordType v = (job.pMesh->vert[viPair.first].cP() - job.pMesh->vert[viPair.second].cP()) - ^ CoordType(0, 0, -1).Normalize(); - if (viPairIt == oppositeInterfaceViPairs.begin()) { - job.nodalExternalForces[viPair.first] = Vector6d({0, 0, 0, v[0], v[1], 0}) - * forceMagnitude; - job.nodalExternalForces[viPair.second] = Vector6d({0, 0, 0, -v[0], -v[1], 0}) - * forceMagnitude; - } else { - job.constrainedVertices[viPair.first] = std::unordered_set{2}; - job.constrainedVertices[viPair.second] = std::unordered_set{0, 1, 2}; + const double& forceMagnitude, + const std::vector>& + oppositeInterfaceViPairs, + SimulationJob& job) { + for (auto viPairIt = oppositeInterfaceViPairs.begin(); + viPairIt != oppositeInterfaceViPairs.end(); viPairIt++) { + const auto& viPair = *viPairIt; + CoordType v = (job.pMesh->vert[viPair.first].cP() - + job.pMesh->vert[viPair.second].cP()) ^ + CoordType(0, 0, -1).Normalize(); + if (viPairIt == oppositeInterfaceViPairs.begin()) { + job.nodalExternalForces[viPair.first] = + Vector6d({0, 0, 0, v[0], v[1], 0}) * forceMagnitude; + job.nodalExternalForces[viPair.second] = + Vector6d({0, 0, 0, -v[0], -v[1], 0}) * forceMagnitude; + } else { + job.constrainedVertices[viPair.first] = + std::unordered_set{2}; + job.constrainedVertices[viPair.second] = + std::unordered_set{0, 1, 2}; - job.nodalExternalForces[viPair.first] = Vector6d({0, 0, 0, -v[0], -v[1], 0}) - * forceMagnitude / 2; - job.nodalExternalForces[viPair.second] = Vector6d({0, 0, 0, v[0], v[1], 0}) - * forceMagnitude / 2; - } + job.nodalExternalForces[viPair.first] = + Vector6d({0, 0, 0, -v[0], -v[1], 0}) * forceMagnitude / 2; + job.nodalExternalForces[viPair.second] = + Vector6d({0, 0, 0, v[0], v[1], 0}) * forceMagnitude / 2; } - job.label = "Saddle"; + } + job.label = "Saddle"; } -//double fullPatternMaxSimulationForceRotationalObjective(const double &forceMagnitude) +// double fullPatternMaxSimulationForceRotationalObjective(const double +// &forceMagnitude) //{ // SimulationJob job; -// job.pMesh = g_baseScenarioMaxDisplacementHelperData.pFullPatternSimulationMesh; +// job.pMesh = +// g_baseScenarioMaxDisplacementHelperData.pFullPatternSimulationEdgeMesh; // g_baseScenarioMaxDisplacementHelperData.constructScenarioFunction( // forceMagnitude, // g_baseScenarioMaxDisplacementHelperData.fullPatternOppositeInterfaceViPairs, // job); // // ReducedModelOptimizer::axialSimulationScenario(forceMagnitude, -// // optimizationState.fullPatternInterfaceViPairs, +// // optimizationState.fullPatternInterfaceViPairs, // // job); // ChronosEulerSimulationModel simulator; -// SimulationResults results = simulator.executeSimulation(std::make_shared(job)); +// SimulationResults results = +// simulator.executeSimulation(std::make_shared(job)); // // DRMSimulationModel simulator; // // DRMSimulationModel::Settings settings; -// // // settings.totalExternalForcesNormPercentageTermination = 1e-2; +// // // settings.threshold_averageResidualToExternalForcesNorm = 1e-2; // // settings.totalTranslationalKineticEnergyThreshold = 1e-10; // // // settings.viscousDampingFactor = 1e-2; // // // settings.useKineticDamping = true; // // settings.shouldDraw = false; // // settings.debugModeStep = 200; -// // // settings.averageResidualForcesCriterionThreshold = 1e-5; +// // // settings.threshold_averageResidualToExternalForcesNorm = 1e-5; // // settings.maxDRMIterations = 200000; -// // SimulationResults results = simulator.executeSimulation(std::make_shared(job), +// // SimulationResults results = +// simulator.executeSimulation(std::make_shared(job), // // settings); // const double &desiredRotationAngle // = g_baseScenarioMaxDisplacementHelperData -// .desiredMaxRotationAngle; //TODO: move from OptimizationState to a new struct +// .desiredMaxRotationAngle; //TODO: move from OptimizationState to +// a new struct // double error; // // job.pMesh->setLabel("initial"); // // job.pMesh->registerForDrawing(); @@ -1542,17 +1753,24 @@ void ReducedModelOptimizer::constructSaddleSimulationScenario( // // DRMSimulationModel::Settings debugSimulationSettings; // // debugSimulationSettings.isDebugMode = true; // // debugSimulationSettings.debugModeStep = 1000; -// // // debugSimulationSettings.maxDRMIterations = 100000; +// // // debugSimulationSettings.maxDRMIterations = +// 100000; // // debugSimulationSettings.shouldDraw = true; -// // debugSimulationSettings.drawingStep = debugSimulationSettings.debugModeStep; +// // debugSimulationSettings.drawingStep = +// debugSimulationSettings.debugModeStep; // // debugSimulationSettings.shouldCreatePlots = true; // // // debugSimulationSettings.Dtini = 0.06; // // debugSimulationSettings.beVerbose = true; // // debugSimulationSettings.useAverage = true; -// // // debugSimulationSettings.totalExternalForcesNormPercentageTermination = 1e-3; -// // debugSimulationSettings.shouldUseTranslationalKineticEnergyThreshold = true; -// // auto debugResults = simulator.executeSimulation(std::make_shared(job), -// // debugSimulationSettings); +// // // +// debugSimulationSettings.threshold_averageResidualToExternalForcesNorm +// = 1e-3; +// // +// debugSimulationSettings.shouldUseTranslationalKineticEnergyThreshold = +// true; +// // auto debugResults = +// simulator.executeSimulation(std::make_shared(job), +// // debugSimulationSettings); // // std::terminate(); // saveJobToPath = "../nonConvergingJobs"; // } else { @@ -1564,70 +1782,75 @@ void ReducedModelOptimizer::constructSaddleSimulationScenario( // - desiredRotationAngle); // saveJobToPath = "../convergingJobs"; // } -// // std::filesystem::path outputPath(std::filesystem::path(saveJobToPath) +// // std::filesystem::path +// outputPath(std::filesystem::path(saveJobToPath) // // .append(job.pMesh->getLabel()) -// // .append("mag_" + optimizationState.currentScenarioName)); +// // .append("mag_" + +// optimizationState.currentScenarioName)); // // std::filesystem::create_directories(outputPath); // // job.save(outputPath); // // settings.save(outputPath); //#ifdef POLYSCOPE_DEFINED -// std::cout << "Force:" << forceMagnitude << " Error is:" << vcg::math::ToDeg(error) << std::endl; +// std::cout << "Force:" << forceMagnitude << " Error is:" << +// vcg::math::ToDeg(error) << std::endl; //#endif // return error; //} -void search(const std::function objectiveFunction, - const double &targetY, - double &optimalX, - double &error, - const double &epsilon, - const double &maxIterations) -{ - error = std::numeric_limits::max(); - int iterationIndex = 0; - double low = optimalX / 1e-3, high = optimalX * 1e3; - while (error > epsilon && iterationIndex < maxIterations) { - const double y = objectiveFunction(optimalX); - error = std::abs(targetY - y); - if (y > targetY) { - high = optimalX; - } else { - low = optimalX; - } - optimalX = low + (high - low) / 2; - - iterationIndex++; +void search(const std::function objectiveFunction, + const double& targetY, + double& optimalX, + double& error, + const double& epsilon, + const double& maxIterations) { + error = std::numeric_limits::max(); + int iterationIndex = 0; + double low = optimalX / 1e-3, high = optimalX * 1e3; + while (error > epsilon && iterationIndex < maxIterations) { + const double y = objectiveFunction(optimalX); + error = std::abs(targetY - y); + if (y > targetY) { + high = optimalX; + } else { + low = optimalX; } + optimalX = low + (high - low) / 2; - if (iterationIndex == maxIterations) { - std::cerr << "Max iterations reached." << std::endl; - } + iterationIndex++; + } + + if (iterationIndex == maxIterations) { + std::cerr << "Max iterations reached." << std::endl; + } } -//double fullPatternMaxSimulationForceTranslationalObjective(const double &forceMagnitude) +// double fullPatternMaxSimulationForceTranslationalObjective(const double +// &forceMagnitude) //{ // SimulationJob job; -// job.pMesh = g_baseScenarioMaxDisplacementHelperData.pFullPatternSimulationMesh; +// job.pMesh = +// g_baseScenarioMaxDisplacementHelperData.pFullPatternSimulationEdgeMesh; // g_baseScenarioMaxDisplacementHelperData.constructScenarioFunction( // forceMagnitude, // g_baseScenarioMaxDisplacementHelperData.fullPatternOppositeInterfaceViPairs, // job); // // ReducedModelOptimizer::axialSimulationScenario(forceMagnitude, -// // optimizationState.fullPatternInterfaceViPairs, +// // optimizationState.fullPatternInterfaceViPairs, // // job); // ChronosEulerSimulationModel simulator; -// SimulationResults results = simulator.executeSimulation(std::make_shared(job)); +// SimulationResults results = +// simulator.executeSimulation(std::make_shared(job)); // // DRMSimulationModel simulator; // // DRMSimulationModel::Settings settings; // // // settings.totalResidualForcesNormThreshold = 1e-3; -// // settings.totalExternalForcesNormPercentageTermination = 1e-2; +// // settings.threshold_averageResidualToExternalForcesNorm = 1e-2; // // settings.totalTranslationalKineticEnergyThreshold = 1e-8; // // settings.viscousDampingFactor = 5e-3; // // settings.useTranslationalKineticEnergyForKineticDamping = true; -// // // settings.averageResidualForcesCriterionThreshold = 1e-5; +// // // settings.threshold_averageResidualToExternalForcesNorm = 1e-5; // // // settings.useAverage = true; // // // settings.totalTranslationalKineticEnergyThreshold = 1e-10; // // // settings.shouldUseTranslationalKineticEnergyThreshold = true; @@ -1637,18 +1860,21 @@ void search(const std::function objectiveFunction, // // // settings.beVerbose = true; // // // settings.debugModeStep = 200; // // settings.maxDRMIterations = 200000; -// // SimulationResults results = simulator.executeSimulation(std::make_shared(job), +// // SimulationResults results = +// simulator.executeSimulation(std::make_shared(job), // // settings); // const double &desiredDisplacementValue // = g_baseScenarioMaxDisplacementHelperData -// .desiredMaxDisplacementValue; //TODO: move from OptimizationState to a new struct +// .desiredMaxDisplacementValue; //TODO: move from +// OptimizationState to a new struct // double error; // if (!results.converged) { // error = std::numeric_limits::max(); // std::filesystem::path outputPath( // std::filesystem::path("../nonConvergingJobs") // .append(job.pMesh->getLabel()) -// .append("mag_" + g_baseScenarioMaxDisplacementHelperData.currentScenarioName)); +// .append("mag_" + +// g_baseScenarioMaxDisplacementHelperData.currentScenarioName)); // std::filesystem::create_directories(outputPath); // job.save(outputPath); // // std::terminate(); @@ -1662,102 +1888,106 @@ void search(const std::function objectiveFunction, // } //#ifdef POLYSCOPE_DEFINED -// std::cout << "Force:" << forceMagnitude << " Error is:" << error << std::endl; +// std::cout << "Force:" << forceMagnitude << " Error is:" << error << +// std::endl; //#endif // return error; //} #ifdef USE_ENSMALLEN -struct ForceMagnitudeOptimization -{ - std::function objectiveFunction; - ForceMagnitudeOptimization(std::function &f) : objectiveFunction(f) {} - double Evaluate(const arma::mat &x) { return objectiveFunction(x(0, 0)); } +struct ForceMagnitudeOptimization { + std::function objectiveFunction; + ForceMagnitudeOptimization(std::function& f) + : objectiveFunction(f) {} + double Evaluate(const arma::mat& x) { return objectiveFunction(x(0, 0)); } }; #endif #ifdef DLIB_DEFINED double ReducedModelOptimizer::computeFullPatternMaxSimulationForce( - const BaseSimulationScenario &scenario) const -{ - double forceMagnitude = 1; - double minimumError; - bool wasSuccessful = false; - g_baseScenarioMaxDisplacementHelperData.constructScenarioFunction - = constructBaseScenarioFunctions[scenario]; - const double baseTriangleHeight = vcg::Distance(baseTriangle.cP(0), - (baseTriangle.cP(1) + baseTriangle.cP(2)) / 2); - std::function objectiveFunction; - double translationalOptimizationEpsilon{baseTriangleHeight * 0.001}; - double objectiveEpsilon = translationalOptimizationEpsilon; - objectiveFunction = &fullPatternMaxSimulationForceTranslationalObjective; - g_baseScenarioMaxDisplacementHelperData.interfaceViForComputingScenarioError - = m_fullPatternOppositeInterfaceViPairs[1].first; - g_baseScenarioMaxDisplacementHelperData.desiredMaxDisplacementValue = 0.1 * baseTriangleHeight; - g_baseScenarioMaxDisplacementHelperData.currentScenarioName - = baseSimulationScenarioNames[scenario]; - g_baseScenarioMaxDisplacementHelperData.pFullPatternSimulationMesh = m_pFullPatternSimulationMesh; - double forceMagnitudeEpsilon = 1e-4; + const BaseSimulationScenario& scenario) const { + double forceMagnitude = 1; + double minimumError; + bool wasSuccessful = false; + g_baseScenarioMaxDisplacementHelperData.constructScenarioFunction = + constructBaseScenarioFunctions[scenario]; + const double baseTriangleHeight = vcg::Distance( + baseTriangle.cP(0), (baseTriangle.cP(1) + baseTriangle.cP(2)) / 2); + std::function objectiveFunction; + double translationalOptimizationEpsilon{baseTriangleHeight * 0.001}; + double objectiveEpsilon = translationalOptimizationEpsilon; + objectiveFunction = &fullPatternMaxSimulationForceTranslationalObjective; + g_baseScenarioMaxDisplacementHelperData.interfaceViForComputingScenarioError = + m_fullPatternOppositeInterfaceViPairs[1].first; + g_baseScenarioMaxDisplacementHelperData.desiredMaxDisplacementValue = + 0.1 * baseTriangleHeight; + g_baseScenarioMaxDisplacementHelperData.currentScenarioName = + baseSimulationScenarioNames[scenario]; + g_baseScenarioMaxDisplacementHelperData.pFullPatternSimulationEdgeMesh = + m_pFullPatternSimulationEdgeMesh; + double forceMagnitudeEpsilon = 1e-4; - switch (scenario) { + switch (scenario) { case Axial: - g_baseScenarioMaxDisplacementHelperData.desiredMaxDisplacementValue = 0.03 - * baseTriangleHeight; - break; + g_baseScenarioMaxDisplacementHelperData.desiredMaxDisplacementValue = + 0.03 * baseTriangleHeight; + break; case Shear: - g_baseScenarioMaxDisplacementHelperData.desiredMaxDisplacementValue = 0.04 - * baseTriangleHeight; - break; + g_baseScenarioMaxDisplacementHelperData.desiredMaxDisplacementValue = + 0.04 * baseTriangleHeight; + break; case Bending: - g_baseScenarioMaxDisplacementHelperData.interfaceViForComputingScenarioError - = m_fullPatternOppositeInterfaceViPairs[0].first; - g_baseScenarioMaxDisplacementHelperData.desiredMaxDisplacementValue = 0.05 - * baseTriangleHeight; - break; + g_baseScenarioMaxDisplacementHelperData + .interfaceViForComputingScenarioError = + m_fullPatternOppositeInterfaceViPairs[0].first; + g_baseScenarioMaxDisplacementHelperData.desiredMaxDisplacementValue = + 0.05 * baseTriangleHeight; + break; case Dome: - g_baseScenarioMaxDisplacementHelperData.desiredMaxRotationAngle = vcg::math::ToRad(20.0); - objectiveFunction = &fullPatternMaxSimulationForceRotationalObjective; - forceMagnitudeEpsilon *= 1e-2; - objectiveEpsilon = vcg::math::ToRad(1.0); - forceMagnitude = 0.6; - break; + g_baseScenarioMaxDisplacementHelperData.desiredMaxRotationAngle = + vcg::math::ToRad(20.0); + objectiveFunction = &fullPatternMaxSimulationForceRotationalObjective; + forceMagnitudeEpsilon *= 1e-2; + objectiveEpsilon = vcg::math::ToRad(1.0); + forceMagnitude = 0.6; + break; case Saddle: - g_baseScenarioMaxDisplacementHelperData.interfaceViForComputingScenarioError - = m_fullPatternOppositeInterfaceViPairs[0].first; - g_baseScenarioMaxDisplacementHelperData.desiredMaxDisplacementValue = 0.05 - * baseTriangleHeight; - break; + g_baseScenarioMaxDisplacementHelperData + .interfaceViForComputingScenarioError = + m_fullPatternOppositeInterfaceViPairs[0].first; + g_baseScenarioMaxDisplacementHelperData.desiredMaxDisplacementValue = + 0.05 * baseTriangleHeight; + break; case S: - g_baseScenarioMaxDisplacementHelperData.interfaceViForComputingScenarioError - = m_fullPatternOppositeInterfaceViPairs[1].first; - g_baseScenarioMaxDisplacementHelperData.desiredMaxDisplacementValue = 0.05 - * baseTriangleHeight; - break; + g_baseScenarioMaxDisplacementHelperData + .interfaceViForComputingScenarioError = + m_fullPatternOppositeInterfaceViPairs[1].first; + g_baseScenarioMaxDisplacementHelperData.desiredMaxDisplacementValue = + 0.05 * baseTriangleHeight; + break; default: - std::cerr << "Unrecognized base scenario" << std::endl; - break; - } + std::cerr << "Unrecognized base scenario" << std::endl; + break; + } - constexpr int maxIterations = 1000; - minimumError = dlib::find_min_single_variable(objectiveFunction, - forceMagnitude, - 1e-4, - 1e4, - forceMagnitudeEpsilon, - maxIterations); + constexpr int maxIterations = 1000; + minimumError = + dlib::find_min_single_variable(objectiveFunction, forceMagnitude, 1e-4, + 1e4, forceMagnitudeEpsilon, maxIterations); #ifdef DLIB_DEFINED #else - // ens::SA<> optimizer; - // arma::vec lowerBound("0.00001"); - // arma::vec upperBound("10000"); - // ens::LBestPSO optimizer(64, lowerBound, upperBound, maxIterations, 350, forceMagnitudeEpsilon); - // ForceMagnitudeOptimization f(objectiveFunction); // Create function to be optimized. - // arma::mat forceMagnitude_mat({forceMagnitude}); - // minimumError = optimizer.Optimize(f, forceMagnitude_mat); - // std::cout << ReducedModelOptimization::baseSimulationScenarioNames[scenario] << ": " - // << optimalObjective << std::endl; - // forceMagnitude = forceMagnitude_mat(0, 0); + // ens::SA<> optimizer; + // arma::vec lowerBound("0.00001"); + // arma::vec upperBound("10000"); + // ens::LBestPSO optimizer(64, lowerBound, upperBound, maxIterations, 350, + // forceMagnitudeEpsilon); ForceMagnitudeOptimization f(objectiveFunction); + // // Create function to be optimized. arma::mat + // forceMagnitude_mat({forceMagnitude}); minimumError = + // optimizer.Optimize(f, forceMagnitude_mat); std::cout << + // ReducedModelOptimization::baseSimulationScenarioNames[scenario] << ": " + // << optimalObjective << std::endl; + // forceMagnitude = forceMagnitude_mat(0, 0); // search(objectiveFunction, // optimizationState.desiredMaxDisplacementValue, @@ -1767,452 +1997,587 @@ double ReducedModelOptimizer::computeFullPatternMaxSimulationForce( // maxIterations); #endif - wasSuccessful = minimumError < objectiveEpsilon; + wasSuccessful = minimumError < objectiveEpsilon; #ifdef POLYSCOPE_DEFINED - std::cout << "Max " << ReducedModelOptimization::baseSimulationScenarioNames[scenario] - << " magnitude:" << forceMagnitude << std::endl; - if (!wasSuccessful) { - SimulationJob job; - job.pMesh = optimizationState.pFullPatternSimulationMesh; - g_baseScenarioMaxDisplacementHelperData - .constructScenarioFunction(forceMagnitude, - optimizationState.fullPatternOppositeInterfaceViPairs, - job); - std::cerr << ReducedModelOptimization::baseSimulationScenarioNames[scenario] - + " max scenario magnitude was not succefully determined." - << std::endl; - std::filesystem::path outputPath( - std::filesystem::path("../nonConvergingJobs") - .append(m_pFullPatternSimulationMesh->getLabel()) - .append("magFinal_" - + ReducedModelOptimization::baseSimulationScenarioNames[scenario])); - std::filesystem::create_directories(outputPath); - job.save(outputPath); - std::terminate(); - } + std::cout << "Max " + << ReducedModelOptimization::baseSimulationScenarioNames[scenario] + << " magnitude:" << forceMagnitude << std::endl; + if (!wasSuccessful) { + SimulationJob job; + job.pMesh = optimizationState.pFullPatternSimulationEdgeMesh; + g_baseScenarioMaxDisplacementHelperData.constructScenarioFunction( + forceMagnitude, optimizationState.fullPatternOppositeInterfaceViPairs, + job); + std::cerr + << ReducedModelOptimization::baseSimulationScenarioNames[scenario] + + " max scenario magnitude was not succefully determined." + << std::endl; + std::filesystem::path outputPath( + std::filesystem::path("../nonConvergingJobs") + .append(m_pFullPatternSimulationEdgeMesh->getLabel()) + .append("magFinal_" + ReducedModelOptimization:: + baseSimulationScenarioNames[scenario])); + std::filesystem::create_directories(outputPath); + job.save(outputPath); + std::terminate(); + } #endif - return forceMagnitude; + return forceMagnitude; } #endif void ReducedModelOptimizer::computeScenarioWeights( - const std::vector &baseSimulationScenarios, - const ReducedModelOptimization::Settings &optimizationSettings) -{ - std::array baseScenario_equalizationWeights; - baseScenario_equalizationWeights.fill(0); - std::array baseScenario_userWeights; - baseScenario_userWeights.fill(0); - //Fill only used base scenario weights - for (const BaseSimulationScenario &baseScenario : baseSimulationScenarios) { - baseScenario_equalizationWeights[baseScenario] = static_cast( - simulationScenariosResolution[baseScenario]); - baseScenario_userWeights[baseScenario] = baseScenarioWeights[baseScenario]; + const std::vector& baseSimulationScenarios, + const ReducedModelOptimization::Settings& optimizationSettings) { + std::array + baseScenario_equalizationWeights; + baseScenario_equalizationWeights.fill(0); + std::array baseScenario_userWeights; + baseScenario_userWeights.fill(0); + // Fill only used base scenario weights + for (const BaseSimulationScenario& baseScenario : baseSimulationScenarios) { + baseScenario_equalizationWeights[baseScenario] = + static_cast(simulationScenariosResolution[baseScenario]); + baseScenario_userWeights[baseScenario] = baseScenarioWeights[baseScenario]; + } + + Utilities::normalize(baseScenario_userWeights.begin(), + baseScenario_userWeights.end()); + + Utilities::normalize(baseScenario_equalizationWeights.begin(), + baseScenario_equalizationWeights.end()); + std::transform(baseScenario_equalizationWeights.begin(), + baseScenario_equalizationWeights.end(), + baseScenario_equalizationWeights.begin(), [](const double& d) { + if (d == 0) { + return d; + } + return 1 / d; + }); + Utilities::normalize(baseScenario_equalizationWeights.begin(), + baseScenario_equalizationWeights.end()); + + std::array baseScenarios_weights; + baseScenarios_weights.fill(0); + for (const BaseSimulationScenario& baseScenario : baseSimulationScenarios) { + baseScenarios_weights[baseScenario] = + baseScenario_equalizationWeights[baseScenario] + + 2 * baseScenario_userWeights[baseScenario]; + } + Utilities::normalize(baseScenarios_weights.begin(), + baseScenarios_weights.end()); + + optimizationState.objectiveWeights.resize(totalNumberOfSimulationScenarios); + optimizationState.scenarioWeights.resize( + totalNumberOfSimulationScenarios, + 0); // This essentially holds the base scenario weights but I use + // totalNumberOfSimulationScenarios elements instead in order to have + // O(1) access time during the optimization + for (const BaseSimulationScenario& baseScenario : baseSimulationScenarios) { + const int baseSimulationScenarioIndexOffset = std::accumulate( + simulationScenariosResolution.begin(), + simulationScenariosResolution.begin() + baseScenario, 0); + for (int simulationScenarioIndex = 0; + simulationScenarioIndex < simulationScenariosResolution[baseScenario]; + simulationScenarioIndex++) { + const int globalScenarioIndex = + baseSimulationScenarioIndexOffset + simulationScenarioIndex; + optimizationState.scenarioWeights[globalScenarioIndex] = + baseScenarios_weights[baseScenario]; + + optimizationState.objectiveWeights[globalScenarioIndex] = + optimizationSettings.perBaseScenarioObjectiveWeights[baseScenario]; } + } - Utilities::normalize(baseScenario_userWeights.begin(), baseScenario_userWeights.end()); - - Utilities::normalize(baseScenario_equalizationWeights.begin(), - baseScenario_equalizationWeights.end()); - std::transform(baseScenario_equalizationWeights.begin(), - baseScenario_equalizationWeights.end(), - baseScenario_equalizationWeights.begin(), - [](const double &d) { - if (d == 0) { - return d; - } - return 1 / d; - }); - Utilities::normalize(baseScenario_equalizationWeights.begin(), - baseScenario_equalizationWeights.end()); - - std::array baseScenarios_weights; - baseScenarios_weights.fill(0); - for (const BaseSimulationScenario &baseScenario : baseSimulationScenarios) { - baseScenarios_weights[baseScenario] = baseScenario_equalizationWeights[baseScenario] - + 2 * baseScenario_userWeights[baseScenario]; - } - Utilities::normalize(baseScenarios_weights.begin(), baseScenarios_weights.end()); - - optimizationState.objectiveWeights.resize(totalNumberOfSimulationScenarios); - optimizationState.scenarioWeights.resize( - totalNumberOfSimulationScenarios, - 0); //This essentially holds the base scenario weights but I use totalNumberOfSimulationScenarios elements instead in order to have O(1) access time during the optimization - for (const BaseSimulationScenario &baseScenario : baseSimulationScenarios) { - const int baseSimulationScenarioIndexOffset - = std::accumulate(simulationScenariosResolution.begin(), - simulationScenariosResolution.begin() + baseScenario, - 0); - for (int simulationScenarioIndex = 0; - simulationScenarioIndex < simulationScenariosResolution[baseScenario]; - simulationScenarioIndex++) { - const int globalScenarioIndex = baseSimulationScenarioIndexOffset - + simulationScenarioIndex; - optimizationState.scenarioWeights[globalScenarioIndex] - = baseScenarios_weights[baseScenario]; - - optimizationState.objectiveWeights[globalScenarioIndex] - = optimizationSettings.perBaseScenarioObjectiveWeights[baseScenario]; - } - } - - //Dont normalize since we want the base scenarios to be normalized not the "optimizationState scenarios" - // Utilities::normalize(optimizationState.scenarioWeights.begin(), optimizationState.scenarioWeights.end()); + // Dont normalize since we want the base scenarios to be normalized not the + // "optimizationState scenarios" + // Utilities::normalize(optimizationState.scenarioWeights.begin(), + // optimizationState.scenarioWeights.end()); } -std::vector> ReducedModelOptimizer::createFullPatternSimulationJobs( - const std::shared_ptr &pMesh, - const std::array &baseScenarioMaxForceMagnitudes) const -{ - std::vector> scenarios; - scenarios.resize(totalNumberOfSimulationScenarios); +std::vector> +ReducedModelOptimizer::createFullPatternSimulationJobs( + const std::shared_ptr& pMesh, + const std::array& + baseScenarioMaxForceMagnitudes) const { + std::vector> scenarios; + scenarios.resize(totalNumberOfSimulationScenarios); - SimulationJob job; - job.pMesh = pMesh; + SimulationJob job; + job.pMesh = pMesh; - for (int baseScenario = Axial; baseScenario != NumberOfBaseSimulationScenarios; baseScenario++) { - const double maxForceMagnitude = baseScenarioMaxForceMagnitudes[baseScenario]; - const int numberOfSimulationScenarios = simulationScenariosResolution[baseScenario]; - const double minForceMagnitude = scenarioIsSymmetrical[baseScenario] - ? maxForceMagnitude / numberOfSimulationScenarios - : -maxForceMagnitude; - const double forceMagnitudeStep = numberOfSimulationScenarios == 1 - ? maxForceMagnitude - : (maxForceMagnitude - minForceMagnitude) - / (numberOfSimulationScenarios - 1); - const int baseSimulationScenarioIndexOffset - = std::accumulate(simulationScenariosResolution.begin(), - simulationScenariosResolution.begin() + baseScenario, - 0); - for (int simulationScenarioIndex = 0; simulationScenarioIndex < numberOfSimulationScenarios; - simulationScenarioIndex++) { - const int scenarioIndex = baseSimulationScenarioIndexOffset + simulationScenarioIndex; - if (baseScenarioMaxForceMagnitudes[baseScenario] == -1) { - scenarios[scenarioIndex] = nullptr; - continue; - } - job.nodalExternalForces.clear(); - job.constrainedVertices.clear(); - job.nodalForcedDisplacements.clear(); + for (int baseScenario = Axial; + baseScenario != NumberOfBaseSimulationScenarios; baseScenario++) { + const double maxForceMagnitude = + baseScenarioMaxForceMagnitudes[baseScenario]; + const int numberOfSimulationScenarios = + simulationScenariosResolution[baseScenario]; + const double minForceMagnitude = + scenarioIsSymmetrical[baseScenario] + ? maxForceMagnitude / numberOfSimulationScenarios + : -maxForceMagnitude; + const double forceMagnitudeStep = + numberOfSimulationScenarios == 1 + ? maxForceMagnitude + : (maxForceMagnitude - minForceMagnitude) / + (numberOfSimulationScenarios - 1); + const int baseSimulationScenarioIndexOffset = std::accumulate( + simulationScenariosResolution.begin(), + simulationScenariosResolution.begin() + baseScenario, 0); + for (int simulationScenarioIndex = 0; + simulationScenarioIndex < numberOfSimulationScenarios; + simulationScenarioIndex++) { + const int scenarioIndex = + baseSimulationScenarioIndexOffset + simulationScenarioIndex; + if (baseScenarioMaxForceMagnitudes[baseScenario] == -1) { + scenarios[scenarioIndex] = nullptr; + continue; + } + job.nodalExternalForces.clear(); + job.constrainedVertices.clear(); + job.nodalForcedDisplacements.clear(); - const double forceMagnitude = (forceMagnitudeStep * simulationScenarioIndex - + minForceMagnitude); - constructBaseScenarioFunctions[baseScenario](forceMagnitude, - m_fullPatternOppositeInterfaceViPairs, - job); + const double forceMagnitude = + (forceMagnitudeStep * simulationScenarioIndex + minForceMagnitude); + constructBaseScenarioFunctions[baseScenario]( + forceMagnitude, m_fullPatternOppositeInterfaceViPairs, job); - job.label = baseSimulationScenarioNames[baseScenario] + "_" - + std::to_string(simulationScenarioIndex); + job.label = baseSimulationScenarioNames[baseScenario] + "_" + + std::to_string(simulationScenarioIndex); - scenarios[scenarioIndex] = std::make_shared(job); - } + scenarios[scenarioIndex] = std::make_shared(job); } + } #ifdef POLYSCOPE_DEFINED - std::cout << "Created pattern simulation jobs" << std::endl; + std::cout << "Created pattern simulation jobs" << std::endl; #endif - return scenarios; + return scenarios; } void ReducedModelOptimizer::computeObjectiveValueNormalizationFactors( - const ReducedModelOptimization::Settings &optimizationSettings) -{ - // m_pFullPatternSimulationMesh->registerForDrawing(); - // m_pFullPatternSimulationMesh->save(std::filesystem::current_path().append("initial.ply")); - // Compute the sum of the displacement norms - std::vector fullPatternTranslationalDisplacementNormSum( - totalNumberOfSimulationScenarios); - std::vector fullPatternAngularDistance(totalNumberOfSimulationScenarios); - for (int simulationScenarioIndex : optimizationState.simulationScenarioIndices) { - double translationalDisplacementNormSum = 0; - for (auto interfaceViPair : optimizationState.reducedToFullInterfaceViMap) { - const int fullPatternVi = interfaceViPair.second; - //If the full pattern vertex is translationally constrained dont take it into account - if (optimizationState.fullPatternSimulationJobs[simulationScenarioIndex] - ->constrainedVertices.contains(fullPatternVi)) { - const std::unordered_set constrainedDof - = optimizationState.fullPatternSimulationJobs[simulationScenarioIndex] - ->constrainedVertices.at(fullPatternVi); - if (constrainedDof.contains(0) && constrainedDof.contains(1) - && constrainedDof.contains(2)) { - continue; - } - } - - const Vector6d &vertexDisplacement = optimizationState - .fullPatternResults[simulationScenarioIndex] - .displacements[fullPatternVi]; - // std::cout << "vi:" << fullPatternVi << std::endl; - // std::cout << "displacement:" << vertexDisplacement.getTranslation().norm() << std::endl; - - translationalDisplacementNormSum += vertexDisplacement.getTranslation().norm(); - } - // optimizationState.fullPatternResults[simulationScenarioIndex].saveDeformedModel( - // std::filesystem::current_path()); - // optimizationState.fullPatternResults[simulationScenarioIndex].registerForDrawing(); - // polyscope::show(); - // optimizationState.fullPatternResults[simulationScenarioIndex].unregister(); - double angularDistanceSum = 0; - for (auto interfaceViPair : optimizationState.reducedToFullInterfaceViMap) { - const int fullPatternVi = interfaceViPair.second; - //If the full pattern vertex is rotationally constrained dont take it into account - if (optimizationState.fullPatternSimulationJobs[simulationScenarioIndex] - ->constrainedVertices.contains(fullPatternVi)) { - const std::unordered_set constrainedDof - = optimizationState.fullPatternSimulationJobs[simulationScenarioIndex] - ->constrainedVertices.at(fullPatternVi); - if (constrainedDof.contains(3) && constrainedDof.contains(5) - && constrainedDof.contains(4)) { - continue; - } - } - angularDistanceSum += std::abs( - optimizationState.fullPatternResults[simulationScenarioIndex] - .rotationalDisplacementQuaternion[fullPatternVi] - .angularDistance(Eigen::Quaterniond::Identity())); + const ReducedModelOptimization::Settings& optimizationSettings) { + // m_pFullPatternSimulationEdgeMesh->registerForDrawing(); + // m_pFullPatternSimulationEdgeMesh->save(std::filesystem::current_path().append("initial.ply")); + // Compute the sum of the displacement norms + std::vector fullPatternTranslationalDisplacementNormSum( + totalNumberOfSimulationScenarios); + std::vector fullPatternAngularDistance( + totalNumberOfSimulationScenarios); + for (int simulationScenarioIndex : + optimizationState.simulationScenarioIndices) { + double translationalDisplacementNormSum = 0; + for (auto interfaceViPair : optimizationState.reducedToFullInterfaceViMap) { + const int fullPatternVi = interfaceViPair.second; + // If the full pattern vertex is translationally constrained dont take it + // into account + if (optimizationState.pSimulationJobs_pattern[simulationScenarioIndex] + ->constrainedVertices.contains(fullPatternVi)) { + const std::unordered_set constrainedDof = + optimizationState.pSimulationJobs_pattern[simulationScenarioIndex] + ->constrainedVertices.at(fullPatternVi); + if (constrainedDof.contains(0) && constrainedDof.contains(1) && + constrainedDof.contains(2)) { + continue; } + } - fullPatternTranslationalDisplacementNormSum[simulationScenarioIndex] - = translationalDisplacementNormSum; - fullPatternAngularDistance[simulationScenarioIndex] = angularDistanceSum; + const Vector6d& vertexDisplacement = + optimizationState.fullPatternResults[simulationScenarioIndex] + .displacements[fullPatternVi]; + // std::cout << "vi:" << fullPatternVi << std::endl; + // std::cout << "displacement:" << + // vertexDisplacement.getTranslation().norm() << std::endl; + + translationalDisplacementNormSum += + vertexDisplacement.getTranslation().norm(); + } + // optimizationState.fullPatternResults[simulationScenarioIndex].saveDeformedModel( + // std::filesystem::current_path()); + // optimizationState.fullPatternResults[simulationScenarioIndex].registerForDrawing(); + // polyscope::show(); + // optimizationState.fullPatternResults[simulationScenarioIndex].unregister(); + double angularDistanceSum = 0; + for (auto interfaceViPair : optimizationState.reducedToFullInterfaceViMap) { + const int fullPatternVi = interfaceViPair.second; + // If the full pattern vertex is rotationally constrained dont take it + // into account + if (optimizationState.pSimulationJobs_pattern[simulationScenarioIndex] + ->constrainedVertices.contains(fullPatternVi)) { + const std::unordered_set constrainedDof = + optimizationState.pSimulationJobs_pattern[simulationScenarioIndex] + ->constrainedVertices.at(fullPatternVi); + if (constrainedDof.contains(3) && constrainedDof.contains(5) && + constrainedDof.contains(4)) { + continue; + } + } + angularDistanceSum += + std::abs(optimizationState.fullPatternResults[simulationScenarioIndex] + .rotationalDisplacementQuaternion[fullPatternVi] + .angularDistance(Eigen::Quaterniond::Identity())); } - optimizationState.translationalDisplacementNormalizationValues.resize( - totalNumberOfSimulationScenarios); - optimizationState.rotationalDisplacementNormalizationValues.resize( - totalNumberOfSimulationScenarios); - for (int simulationScenarioIndex : optimizationState.simulationScenarioIndices) { - if (optimizationSettings.normalizationStrategy == Settings::NormalizationStrategy::Epsilon) { - const double epsilon_translationalDisplacement = optimizationSettings.translationEpsilon; - optimizationState.translationalDisplacementNormalizationValues[simulationScenarioIndex] - = std::max(fullPatternTranslationalDisplacementNormSum[simulationScenarioIndex], - epsilon_translationalDisplacement); - const double epsilon_rotationalDisplacement = optimizationSettings.angularDistanceEpsilon; - optimizationState.rotationalDisplacementNormalizationValues[simulationScenarioIndex] - = std::max(fullPatternAngularDistance[simulationScenarioIndex], - epsilon_rotationalDisplacement); - } else { - optimizationState.translationalDisplacementNormalizationValues[simulationScenarioIndex] - = 1; - optimizationState.rotationalDisplacementNormalizationValues[simulationScenarioIndex] = 1; - } + fullPatternTranslationalDisplacementNormSum[simulationScenarioIndex] = + translationalDisplacementNormSum; + fullPatternAngularDistance[simulationScenarioIndex] = angularDistanceSum; + } + + optimizationState.translationalDisplacementNormalizationValues.resize( + totalNumberOfSimulationScenarios); + optimizationState.rotationalDisplacementNormalizationValues.resize( + totalNumberOfSimulationScenarios); + for (int simulationScenarioIndex : + optimizationState.simulationScenarioIndices) { + if (optimizationSettings.normalizationStrategy == + Settings::NormalizationStrategy::Epsilon) { + const double epsilon_translationalDisplacement = + optimizationSettings.translationEpsilon; + optimizationState.translationalDisplacementNormalizationValues + [simulationScenarioIndex] = std::max( + fullPatternTranslationalDisplacementNormSum[simulationScenarioIndex], + epsilon_translationalDisplacement); + const double epsilon_rotationalDisplacement = + optimizationSettings.angularDistanceEpsilon; + optimizationState + .rotationalDisplacementNormalizationValues[simulationScenarioIndex] = + std::max(fullPatternAngularDistance[simulationScenarioIndex], + epsilon_rotationalDisplacement); + } else { + optimizationState.translationalDisplacementNormalizationValues + [simulationScenarioIndex] = 1; + optimizationState + .rotationalDisplacementNormalizationValues[simulationScenarioIndex] = + 1; } + } } void ReducedModelOptimizer::optimize( - Settings &optimizationSettings, - ReducedModelOptimization::Results &results, - const std::vector &desiredBaseSimulationScenarios) -{ - std::unordered_set zeroMagnitudeScenarios; - for (int baseScenario = Axial; baseScenario != NumberOfBaseSimulationScenarios; baseScenario++) { - if (optimizationSettings.baseScenarioMaxMagnitudes[baseScenario] == 0) { - zeroMagnitudeScenarios.insert(static_cast(baseScenario)); - continue; + Settings& optimizationSettings, + ReducedModelOptimization::Results& results, + const std::vector& desiredBaseSimulationScenarios) { + std::unordered_set zeroMagnitudeScenarios; + for (int baseScenario = Axial; + baseScenario != NumberOfBaseSimulationScenarios; baseScenario++) { + if (optimizationSettings.baseScenarioMaxMagnitudes[baseScenario] == 0) { + zeroMagnitudeScenarios.insert( + static_cast(baseScenario)); + continue; + } + } + std::set set_desiredScenarios( + desiredBaseSimulationScenarios.begin(), + desiredBaseSimulationScenarios.end()); + std::set set_zeroScenarios( + zeroMagnitudeScenarios.begin(), zeroMagnitudeScenarios.end()); + std::vector usedBaseSimulationScenarios; + std::set_difference(set_desiredScenarios.begin(), set_desiredScenarios.end(), + set_zeroScenarios.begin(), set_zeroScenarios.end(), + std::back_inserter(usedBaseSimulationScenarios)); + + assert(!optimizationSettings.optimizationStrategy.empty()); + assert( + !optimizationSettings.optimizationVariablesGroupsWeights.has_value() || + (optimizationSettings.optimizationStrategy.size() == + optimizationSettings.optimizationVariablesGroupsWeights->size() && + std::accumulate( + optimizationSettings.optimizationVariablesGroupsWeights->begin(), + optimizationSettings.optimizationVariablesGroupsWeights->end(), 0))); + + for (int baseSimulationScenarioIndex : usedBaseSimulationScenarios) { + // Increase the size of the vector holding the simulation scenario indices + optimizationState.simulationScenarioIndices.resize( + optimizationState.simulationScenarioIndices.size() + + simulationScenariosResolution[baseSimulationScenarioIndex]); + // Add the simulation scenarios indices that correspond to this base + // simulation scenario + std::iota(optimizationState.simulationScenarioIndices.end() - + simulationScenariosResolution[baseSimulationScenarioIndex], + optimizationState.simulationScenarioIndices.end(), + std::accumulate(simulationScenariosResolution.begin(), + simulationScenariosResolution.begin() + + baseSimulationScenarioIndex, + 0)); + } + + // constexpr bool recomputeForceMagnitudes = false; + // std::array + // fullPatternSimulationScenarioMaxMagnitudes + // = getFullPatternMaxSimulationForces(usedBaseSimulationScenarios, + // optimizationSettings.intermediateResultsDirectoryPath, + // recomputeForceMagnitudes); + // for (int baseScenario = Axial; baseScenario != + // NumberOfBaseSimulationScenarios; baseScenario++) { + // fullPatternSimulationScenarioMaxMagnitudes[baseScenario] + // = + // std::min(fullPatternSimulationScenarioMaxMagnitudes[baseScenario], + // optimizationSettings.baseScenarioMaxMagnitudes[baseScenario]); + // } + // optimizationSettings.baseScenarioMaxMagnitudes = + // fullPatternSimulationScenarioMaxMagnitudes; + std::array + fullPatternSimulationScenarioMaxMagnitudes = + optimizationSettings.baseScenarioMaxMagnitudes; + optimizationState.pSimulationJobs_pattern = createFullPatternSimulationJobs( + m_pSimulationEdgeMesh_pattern, + fullPatternSimulationScenarioMaxMagnitudes); + // polyscope::removeAllStructures(); + + // ComputeScenarioWeights({Axial, Shear, Bending, Dome, Saddle}, + computeScenarioWeights(usedBaseSimulationScenarios, optimizationSettings); + + results.baseTriangle = baseTriangle; + + // DRMSimulationModel::Settings drmSettings; + // drmSettings.threshold_averageResidualToExternalForcesNorm = 1e-5; + // drmSettings.maxDRMIterations = 200000; + // drmSettings.totalTranslationalKineticEnergyThreshold = 1e-8; + // drmSettings.totalTranslationalKineticEnergyThreshold = 1e-9; + + // drmSettings.totalTranslationalKineticEnergyThreshold = 1e-10; + // drmSettings.gradualForcedDisplacementSteps = 20; + // drmSettings.linearGuessForceScaleFactor = 1; + // drmSettings.viscousDampingFactor = 5e-3; + // drmSettings.useTotalRotationalKineticEnergyForKineticDamping = true; + // drmSettings.shouldDraw = true; + + // drmSettings.threshold_averageResidualToExternalForcesNorm = 1e-2; + // drmSettings.viscousDampingFactor = 5e-3; + // simulationSettings.viscousDampingFactor = 5e-3; + // simulationSettings.linearGuessForceScaleFactor = 1; + // simulationSettings.gamma = 0.3; + // simulationSettings.xi = 0.9999; + // drmSettings.debugModeStep = 100; + // drmSettings.shouldDraw = true; + // drmSettings.shouldCreatePlots = true; + // drmSettings.beVerbose = true; + // simulationSettings.useKineticDamping = true; + // simulationSettings.save(std::filesystem::path(std::string(__FILE__)) + // .parent_path() + // .parent_path() + // .append("DefaultSettings") + // .append("DRMSettings") + // .append("defaultDRMSimulationSettings.json")); + + // simulationSettings.threshold_averageResidualToExternalForcesNorm = 1e-5; + // simulationSettings.viscousDampingFactor = 1e-3; + // simulationSettings.beVerbose = true; + // simulationSettings.shouldDraw = true; + // simulationSettings.isDebugMode = true; + // simulationSettings.debugModeStep = 100000; + //#ifdef POLYSCOPE_DEFINED + constexpr bool drawPatternSimulationResults = true; + auto t1 = std::chrono::high_resolution_clock::now(); + //#endif + results.wasSuccessful = true; + optimizationState.fullPatternResults.resize(totalNumberOfSimulationScenarios); + optimizationState.simulationJobs_reducedModel.resize( + totalNumberOfSimulationScenarios); + + std::atomic numberOfComputedJobs = 0; + std::for_each( +// std::execution::unseq, +#ifndef POLYSCOPE_DEFINED + std::execution::par_unseq, +#endif + optimizationState.simulationScenarioIndices.begin(), + optimizationState.simulationScenarioIndices.end(), + [&](const int& simulationScenarioIndex) { + const std::shared_ptr& pSimulationJob_pattern = + optimizationState.pSimulationJobs_pattern[simulationScenarioIndex]; + // std::cout << "Executing " << + // pFullPatternSimulationJob->getLabel() << std::endl; + + // std::filesystem::path jobResultsDirectoryPath( + // std::filesystem::path(optimizationSettings.intermediateResultsDirectoryPath) + // .append("FullPatternResults") + // .append(m_pFullPatternSimulationEdgeMesh->getLabel()) + // .append(pPatternSimulationJob->getLabel())); + std::unique_ptr pPatternSimulator = + SimulationModelFactory::create( + optimizationSettings.simulationModelLabel_groundTruth); + pPatternSimulator->setStructure(m_pSimulationEdgeMesh_pattern); + SimulationResults simulationResults_pattern; + SimulationResults debug_chronosResults; + if (optimizationSettings.simulationModelLabel_groundTruth == + DRMSimulationModel::label) { +#ifdef POLYSCOPE_DEFINED + if (drawPatternSimulationResults) { + ChronosEulerNonLinearSimulationModel debug_chronosModel; + debug_chronosResults = + debug_chronosModel.executeSimulation(pSimulationJob_pattern); + debug_chronosResults.registerForDrawing(RGBColor({0, 0, 255}), true, + 0.0001, true); + } +#endif + + DRMSimulationModel::Settings drmSettings; + drmSettings.threshold_averageResidualToExternalForcesNorm = 1e-5; + drmSettings.threshold_totalTranslationalKineticEnergy = 1e-14; + // drmSettings.threshold_residualForcesMovingAverageDerivativeNorm + // = + // 1e-11; + drmSettings.maxDRMIterations = 10000; + drmSettings.Dtini = 1; + // drmSettings.beVerbose = true; + // drmSettings.debugModeStep = 1e4; + // drmSettings.shouldCreatePlots = true; + // drmSettings.shouldDraw = true; + // drmSettings.threshold_totalTranslationalKineticEnergy = + // 1e-8; + pSimulationJob_pattern->pMesh->getLabel(); + simulationResults_pattern = + dynamic_cast(pPatternSimulator.get()) + ->executeSimulation(pSimulationJob_pattern, drmSettings); + if (!simulationResults_pattern.converged) { +#ifdef POLYSCOPE_DEFINED + std::filesystem::path outputPath( + std::filesystem::path("../nonConvergingJobs") + .append(m_pSimulationEdgeMesh_pattern->getLabel()) + .append("final_" + pSimulationJob_pattern->getLabel())); + std::filesystem::create_directories(outputPath); + pSimulationJob_pattern->save(outputPath); + std::cerr << m_pSimulationEdgeMesh_pattern->getLabel() + << " sim scenario " << pSimulationJob_pattern->getLabel() + << " did not converge on first try." << std::endl; +#endif + + // return; + DRMSimulationModel::Settings drmSettings_secondTry = drmSettings; + drmSettings_secondTry.linearGuessForceScaleFactor = 1; + // drmSettings_secondTry.viscousDampingFactor = 4e-8; + // *drmSettings_secondTry.maxDRMIterations *= 5; + drmSettings_secondTry.maxDRMIterations = 2e6; + drmSettings_secondTry.threshold_totalTranslationalKineticEnergy = + 1e-13; + + simulationResults_pattern = + dynamic_cast(pPatternSimulator.get()) + ->executeSimulation(pSimulationJob_pattern, + drmSettings_secondTry); + } + + } else { + simulationResults_pattern = + pPatternSimulator->executeSimulation(pSimulationJob_pattern); } - } - std::set set_desiredScenarios(desiredBaseSimulationScenarios.begin(), - desiredBaseSimulationScenarios.end()); - std::set set_zeroScenarios(zeroMagnitudeScenarios.begin(), - zeroMagnitudeScenarios.end()); - std::vector usedBaseSimulationScenarios; - std::set_difference(set_desiredScenarios.begin(), - set_desiredScenarios.end(), - set_zeroScenarios.begin(), - set_zeroScenarios.end(), - std::back_inserter(usedBaseSimulationScenarios)); - assert(!optimizationSettings.optimizationStrategy.empty()); - assert(!optimizationSettings.optimizationVariablesGroupsWeights.has_value() - || (optimizationSettings.optimizationStrategy.size() - == optimizationSettings.optimizationVariablesGroupsWeights->size() - && std::accumulate(optimizationSettings.optimizationVariablesGroupsWeights->begin(), - optimizationSettings.optimizationVariablesGroupsWeights->end(), - 0))); + // ChronosEulerSimulationModel simulationModel_pattern; + // simulationModel_pattern.settings.analysisType + // = + // ChronosEulerSimulationModel::Settings::AnalysisType::NonLinear; + // const SimulationResults simulationResults_pattern + // = + // simulationModel_pattern.executeSimulation(pPatternSimulationJob); - for (int baseSimulationScenarioIndex : usedBaseSimulationScenarios) { - //Increase the size of the vector holding the simulation scenario indices - optimizationState.simulationScenarioIndices.resize( - optimizationState.simulationScenarioIndices.size() - + simulationScenariosResolution[baseSimulationScenarioIndex]); - //Add the simulation scenarios indices that correspond to this base simulation scenario - std::iota(optimizationState.simulationScenarioIndices.end() - - simulationScenariosResolution[baseSimulationScenarioIndex], - optimizationState.simulationScenarioIndices.end(), - std::accumulate(simulationScenariosResolution.begin(), - simulationScenariosResolution.begin() - + baseSimulationScenarioIndex, - 0)); - } + // double error; + // if + // (!patternSimulationResults.isEqual(debug_eulerPatternSimulationResults, + // error)) { + // std::cerr << "The computed ground truth does not match + // the IGA model results. " + // "Error is:" + // << error << std::endl; + // } - // constexpr bool recomputeForceMagnitudes = false; - // std::array fullPatternSimulationScenarioMaxMagnitudes - // = getFullPatternMaxSimulationForces(usedBaseSimulationScenarios, - // optimizationSettings.intermediateResultsDirectoryPath, - // recomputeForceMagnitudes); - // for (int baseScenario = Axial; baseScenario != NumberOfBaseSimulationScenarios; baseScenario++) { - // fullPatternSimulationScenarioMaxMagnitudes[baseScenario] - // = std::min(fullPatternSimulationScenarioMaxMagnitudes[baseScenario], - // optimizationSettings.baseScenarioMaxMagnitudes[baseScenario]); - // } - // optimizationSettings.baseScenarioMaxMagnitudes = fullPatternSimulationScenarioMaxMagnitudes; - std::array fullPatternSimulationScenarioMaxMagnitudes - = optimizationSettings.baseScenarioMaxMagnitudes; - optimizationState.fullPatternSimulationJobs - = createFullPatternSimulationJobs(m_pFullPatternSimulationMesh, - fullPatternSimulationScenarioMaxMagnitudes); - // polyscope::removeAllStructures(); - - // ComputeScenarioWeights({Axial, Shear, Bending, Dome, Saddle}, - computeScenarioWeights(usedBaseSimulationScenarios, optimizationSettings); - - results.baseTriangle = baseTriangle; - - // DRMSimulationModel::Settings drmSettings; - // drmSettings.totalExternalForcesNormPercentageTermination = 1e-5; - // drmSettings.maxDRMIterations = 200000; - // drmSettings.totalTranslationalKineticEnergyThreshold = 1e-8; - // drmSettings.totalTranslationalKineticEnergyThreshold = 1e-9; - - // drmSettings.totalTranslationalKineticEnergyThreshold = 1e-10; - // drmSettings.gradualForcedDisplacementSteps = 20; - // drmSettings.linearGuessForceScaleFactor = 1; - // drmSettings.viscousDampingFactor = 5e-3; - // drmSettings.useTotalRotationalKineticEnergyForKineticDamping = true; - // drmSettings.shouldDraw = true; - - // drmSettings.totalExternalForcesNormPercentageTermination = 1e-2; - // drmSettings.viscousDampingFactor = 5e-3; - // simulationSettings.viscousDampingFactor = 5e-3; - // simulationSettings.linearGuessForceScaleFactor = 1; - // simulationSettings.gamma = 0.3; - // simulationSettings.xi = 0.9999; - // drmSettings.debugModeStep = 100; - // drmSettings.shouldDraw = true; - // drmSettings.shouldCreatePlots = true; - // drmSettings.beVerbose = true; - // simulationSettings.useKineticDamping = true; - // simulationSettings.save(std::filesystem::path(std::string(__FILE__)) - // .parent_path() - // .parent_path() - // .append("DefaultSettings") - // .append("DRMSettings") - // .append("defaultDRMSimulationSettings.json")); - - // simulationSettings.averageResidualForcesCriterionThreshold = 1e-5; - // simulationSettings.viscousDampingFactor = 1e-3; - // simulationSettings.beVerbose = true; - // simulationSettings.shouldDraw = true; - // simulationSettings.isDebugMode = true; - // simulationSettings.debugModeStep = 100000; - //#ifdef POLYSCOPE_DEFINED - constexpr bool drawFullPatternSimulationResults = true; - auto t1 = std::chrono::high_resolution_clock::now(); - //#endif - results.wasSuccessful = true; - optimizationState.fullPatternResults.resize(totalNumberOfSimulationScenarios); - optimizationState.reducedPatternSimulationJobs.resize(totalNumberOfSimulationScenarios); - - std::for_each( - //#ifndef POLYSCOPE_DEFINED - // std::execution::par_unseq, - //#endif - optimizationState.simulationScenarioIndices.begin(), - optimizationState.simulationScenarioIndices.end(), - [&](const int &simulationScenarioIndex) { - const std::shared_ptr &pPatternSimulationJob - = optimizationState.fullPatternSimulationJobs[simulationScenarioIndex]; - // std::cout << "Executing " << pFullPatternSimulationJob->getLabel() << std::endl; - - std::filesystem::path jobResultsDirectoryPath( - std::filesystem::path(optimizationSettings.intermediateResultsDirectoryPath) - .append("FullPatternResults") - .append(m_pFullPatternSimulationMesh->getLabel()) - .append(pPatternSimulationJob->getLabel())); - std::unique_ptr pPatternSimulator = SimulationModelFactory::create( - optimizationSettings.simulationModelLabel); - pPatternSimulator->setStructure(m_pFullPatternSimulationMesh); - SimulationResults patternSimulationResults = pPatternSimulator->executeSimulation( - pPatternSimulationJob); - - ChronosIGASimulationModel debug_igaSimulationModel; - const SimulationResults debug_igaPatternSimulationResults - = debug_igaSimulationModel.executeSimulation(pPatternSimulationJob); - - double error; - if (!patternSimulationResults - .isEqual(Utilities::toEigenMatrix( - debug_igaPatternSimulationResults.displacements), - error)) { - std::cerr - << "The computed ground truth does not match the IGA model results. Error is:" - << error << std::endl; - } - - if (!patternSimulationResults.converged) { - //#ifdef POLYSCOPE_DEFINED - std::filesystem::path outputPath( - std::filesystem::path("../nonConvergingJobs") - .append(m_pFullPatternSimulationMesh->getLabel()) - .append("final_" + pPatternSimulationJob->getLabel())); - std::filesystem::create_directories(outputPath); - pPatternSimulationJob->save(outputPath); - std::cerr << m_pFullPatternSimulationMesh->getLabel() << " did not converge." - << std::endl; - assert(false); - //#endif - } - - optimizationState.fullPatternResults[simulationScenarioIndex] = patternSimulationResults; - SimulationJob reducedPatternSimulationJob; - reducedPatternSimulationJob.pMesh = m_pReducedModelSimulationMesh; - computeReducedModelSimulationJob(*pPatternSimulationJob, - m_fullToReducedInterfaceViMap, - reducedPatternSimulationJob); - optimizationState.reducedPatternSimulationJobs[simulationScenarioIndex] - = std::make_shared(reducedPatternSimulationJob); - std::cout << "Ran sim scenario:" << simulationScenarioIndex << std::endl; + if (!simulationResults_pattern.converged) { #ifdef POLYSCOPE_DEFINED - if (drawFullPatternSimulationResults) { - optimizationState.fullPatternSimulationJobs[0]->pMesh->registerForDrawing( - ReducedModelOptimization::Colors::patternInitial); - pPatternSimulationJob->registerForDrawing(optimizationState - .fullPatternSimulationJobs[0] - ->pMesh->getLabel(), - true); - patternSimulationResults.registerForDrawing(std::array{0, 255, 0}, true); - // SimulationResults fullPatternResults_linear - // = linearSimulator.executeSimulation(pFullPatternSimulationJob); - // patternDrmResults.registerForDrawing(std::array{0, 255, 0}, true); - // fullPatternResults_linear.labelPrefix += "_linear"; - // fullPatternResults_linear - // .registerForDrawing(std::array{0, 0, 255}, true); - polyscope::show(); - patternSimulationResults.unregister(); - // fullPatternResults_linear.unregister(); - optimizationState.fullPatternSimulationJobs[0]->pMesh->unregister(); - } + std::filesystem::path outputPath( + std::filesystem::path("../nonConvergingJobs") + .append(m_pSimulationEdgeMesh_pattern->getLabel()) + .append("final_" + pSimulationJob_pattern->getLabel())); + std::filesystem::create_directories(outputPath); + pSimulationJob_pattern->save(outputPath); + std::cerr << m_pSimulationEdgeMesh_pattern->getLabel() + << " did not converge." << std::endl; + DRMSimulationModel::Settings drmSettings; + drmSettings.threshold_averageResidualToExternalForcesNorm = 1e-5; + drmSettings.maxDRMIterations = 200000; + // drmSettings.threshold_totalTranslationalKineticEnergy = + // 1e-8; + drmSettings.debugModeStep = 1e2; + // drmSettings.shouldDraw = true; + simulationResults_pattern = + dynamic_cast(pPatternSimulator.get()) + ->executeSimulation(pSimulationJob_pattern, drmSettings); + std::terminate(); + assert(false); #endif - }); + } - auto t2 = std::chrono::high_resolution_clock::now(); - auto s_int = std::chrono::duration_cast(t2 - t1); + optimizationState.fullPatternResults[simulationScenarioIndex] = + simulationResults_pattern; + SimulationJob simulationJob_reducedModel; + simulationJob_reducedModel.pMesh = m_pReducedModelSimulationEdgeMesh; + computeReducedModelSimulationJob(*pSimulationJob_pattern, + m_fullToReducedInterfaceViMap, + simulationJob_reducedModel); + optimizationState.simulationJobs_reducedModel[simulationScenarioIndex] = + std::make_shared(simulationJob_reducedModel); #ifdef POLYSCOPE_DEFINED - std::cout << "Computed ground of truth pattern results in:" << s_int.count() << " seconds." - << std::endl; - if (drawFullPatternSimulationResults) { - optimizationState.fullPatternSimulationJobs[0]->pMesh->unregister(); - } - optimizationState.reducedPatternSimulationJobs[0]->pMesh->updateEigenEdgeAndVertices(); + std::cout << "Ran sim scenario:" << pSimulationJob_pattern->getLabel() + << ". "; + std::cout << ++numberOfComputedJobs << "/" + << optimizationState.simulationScenarioIndices.size() + << std::endl; + + if (drawPatternSimulationResults) { + optimizationState.pSimulationJobs_pattern[0] + ->pMesh->registerForDrawing( + ReducedModelOptimization::Colors::patternInitial, false, + 0.0001); + pSimulationJob_pattern->registerForDrawing( + optimizationState.pSimulationJobs_pattern[0]->pMesh->getLabel(), + true); + simulationResults_pattern.registerForDrawing( + ReducedModelOptimization::Colors::patternDeformed, true, 0.0001, + true); + // SimulationResults fullPatternResults_linear + // = + // linearSimulator.executeSimulation(pFullPatternSimulationJob); + // patternDrmResults.registerForDrawing(std::array{0, 255, 0}, true); + // fullPatternResults_linear.labelPrefix += + // "_linear"; fullPatternResults_linear + // .registerForDrawing(std::array{0, 0, 255}, true); + + // ChronosEulerNonLinearSimulationModel debug_chronosModel; + // auto debug_chronosResults = + // debug_chronosModel.executeSimulation(pSimulationJob_pattern); + // debug_chronosResults.registerForDrawing(RGBColor({0, 0, + // 255}), true); + polyscope::show(); + debug_chronosResults.unregister(); + simulationResults_pattern.unregister(); + // fullPatternResults_linear.unregister(); + optimizationState.pSimulationJobs_pattern[0]->pMesh->unregister(); + // debug_eulerPatternSimulationResults.unregister(); + } #endif - // if (optimizationState.optimizationSettings.normalizationStrategy - // == Settings::NormalizationStrategy::Epsilon) { - computeObjectiveValueNormalizationFactors(optimizationSettings); + }); + + auto t2 = std::chrono::high_resolution_clock::now(); + auto s_int = std::chrono::duration_cast(t2 - t1); +#ifdef POLYSCOPE_DEFINED + std::cout << "Computed ground of truth pattern results in:" << s_int.count() + << " seconds." << std::endl; + if (drawPatternSimulationResults) { + optimizationState.pSimulationJobs_pattern[0]->pMesh->unregister(); + } + optimizationState.simulationJobs_reducedModel[0] + ->pMesh->updateEigenEdgeAndVertices(); +#endif + // if (optimizationState.optimizationSettings.normalizationStrategy + // == Settings::NormalizationStrategy::Epsilon) { + computeObjectiveValueNormalizationFactors(optimizationSettings); // } #ifdef POLYSCOPE_DEFINED - std::cout << "Running reduced model optimization" << std::endl; + std::cout << "Running reduced model optimization" << std::endl; #endif - runOptimization(optimizationSettings, results); + runOptimization(optimizationSettings, results); } diff --git a/reducedmodeloptimizer.hpp b/reducedmodeloptimizer.hpp index 7de94c9..a736970 100644 --- a/reducedmodeloptimizer.hpp +++ b/reducedmodeloptimizer.hpp @@ -1,18 +1,17 @@ #ifndef REDUCEDMODELOPTIMIZER_HPP #define REDUCEDMODELOPTIMIZER_HPP -#include "chronoseulersimulationmodel.hpp" -#include "csvfile.hpp" +//#include "csvfile.hpp" #include "drmsimulationmodel.hpp" #include "edgemesh.hpp" #include "linearsimulationmodel.hpp" #ifdef POLYSCOPE_DEFINED #include "matplot/matplot.h" #endif +#include #include "reducedmodel.hpp" #include "reducedmodeloptimizer_structs.hpp" #include "simulationmesh.hpp" -#include #ifdef DLIB_DEFINED #include #include @@ -20,348 +19,384 @@ #ifdef POLYSCOPE_DEFINED #include "polyscope/color_management.h" -#endif // POLYSCOPE_DEFINED -using FullPatternVertexIndex = VertexIndex; -using ReducedPatternVertexIndex = VertexIndex; +#endif // POLYSCOPE_DEFINED +using PatternVertexIndex = VertexIndex; +using ReducedModelVertexIndex = VertexIndex; -class ReducedModelOptimizer -{ -public: - struct OptimizationState - { - std::vector fullPatternResults; - std::vector translationalDisplacementNormalizationValues; - std::vector rotationalDisplacementNormalizationValues; - std::vector> fullPatternSimulationJobs; - std::vector> reducedPatternSimulationJobs; - std::unordered_map - reducedToFullInterfaceViMap; - std::vector> - fullPatternOppositeInterfaceViPairs; - matplot::line_handle gPlotHandle; - std::vector objectiveValueHistory_iteration; - std::vector objectiveValueHistory; - std::vector plotColors; - std::array - parametersInitialValue; - std::array - optimizationInitialValue; - std::vector simulationScenarioIndices; - double minY{DBL_MAX}; - std::vector minX; - int numOfSimulationCrashes{false}; - int numberOfFunctionCalls{0}; - //Variables for finding the full pattern simulation forces - std::shared_ptr pFullPatternSimulationMesh; - std::array &pReducedPatternSimulationMesh)>, - 7> - functions_updateReducedPatternParameter; - std::vector xMin; - std::vector xMax; - std::vector scenarioWeights; - std::vector objectiveWeights; - }; +class ReducedModelOptimizer { + public: + struct OptimizationState { + std::vector fullPatternResults; + std::vector translationalDisplacementNormalizationValues; + std::vector rotationalDisplacementNormalizationValues; + std::vector> pSimulationJobs_pattern; + std::vector> simulationJobs_reducedModel; + std::unordered_map + reducedToFullInterfaceViMap; + std::vector> + fullPatternOppositeInterfaceViPairs; + matplot::line_handle gPlotHandle; + std::vector objectiveValueHistory_iteration; + std::vector objectiveValueHistory; + std::vector plotColors; + std::array + parametersInitialValue; + std::array + optimizationInitialValue; + std::vector simulationScenarioIndices; + double minY{DBL_MAX}; + std::vector minX; + int numOfSimulationCrashes{false}; + int numberOfFunctionCalls{0}; + // Variables for finding the full pattern simulation forces + std::shared_ptr pFullPatternSimulationEdgeMesh; + std::array& + pReducedPatternSimulationEdgeMesh)>, + 7> + functions_updateReducedPatternParameter; + std::vector xMin; + std::vector xMax; + std::vector scenarioWeights; + std::vector + objectiveWeights; + std::string simulationModelLabel_reducedModel; + }; -private: - OptimizationState optimizationState; - vcg::Triangle3 baseTriangle; - std::function> &, - SimulationJob &)> - constructScenarioFunction; - std::shared_ptr m_pReducedModelSimulationMesh; - std::shared_ptr m_pFullPatternSimulationMesh; - std::unordered_map - m_fullToReducedInterfaceViMap; - std::vector> - m_fullPatternOppositeInterfaceViPairs; - std::unordered_map nodeToSlot; - std::unordered_map> slotToNode; - std::string optimizationNotes; - std::array> &, - SimulationJob &)>, - ReducedModelOptimization::NumberOfBaseSimulationScenarios> - constructBaseScenarioFunctions; - std::vector scenarioIsSymmetrical; - int fullPatternNumberOfEdges; - constexpr static double youngsModulus{1 * 1e9}; - constexpr static double defaultBeamWidth{0.002}; - constexpr static double defaultBeamHeight{0.002}; - std::string fullPatternLabel; - // ReducedModelOptimization::Settings optimizationSettings; + private: + OptimizationState optimizationState; + vcg::Triangle3 baseTriangle; + std::function>&, + SimulationJob&)> + constructScenarioFunction; + std::shared_ptr m_pReducedModelSimulationEdgeMesh; + std::shared_ptr m_pSimulationEdgeMesh_pattern; + std::unordered_map + m_fullToReducedInterfaceViMap; + std::vector> + m_fullPatternOppositeInterfaceViPairs; + std::unordered_map nodeToSlot; + std::unordered_map> slotToNode; + std::string optimizationNotes; + std::array< + std::function>&, + SimulationJob&)>, + ReducedModelOptimization::NumberOfBaseSimulationScenarios> + constructBaseScenarioFunctions; + std::vector scenarioIsSymmetrical; + int fullPatternNumberOfEdges; + std::string fullPatternLabel; + // ReducedModelOptimization::Settings optimizationSettings; -public: - struct FunctionEvaluation - { - FunctionEvaluation() = default; - FunctionEvaluation(const std::vector &x, double y) : x(x), y(y) {} + public: + struct FunctionEvaluation { + FunctionEvaluation() = default; + FunctionEvaluation(const std::vector& x, double y) : x(x), y(y) {} - std::vector x; - double y = std::numeric_limits::quiet_NaN(); - }; + std::vector x; + double y = std::numeric_limits::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 th= {"Theta"}; - // inline const static std::string R = {"R"}; - // }; - // inline constexpr static ParameterLabels parameterLabels(); + // 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 - parameterLabels = {"E", "A", "I2", "I3", "J", "Theta", "R"}; - constexpr static std::array - simulationScenariosResolution = {12, 12, 22, 22, 22, 22}; - constexpr static std::array - baseScenarioWeights = {1, 1, 2, 2, 2}; - inline static int totalNumberOfSimulationScenarios - = std::accumulate(simulationScenariosResolution.begin(), - simulationScenariosResolution.end(), - 0); - inline static int fanSize{6}; - inline static double initialHexagonSize{0.3}; - int interfaceNodeIndex; - double operator()(const Eigen::VectorXd &x, Eigen::VectorXd &) const; + inline static std::array< + std::string, + ReducedModelOptimization::NumberOfOptimizationVariables> + parameterLabels = {"E", "A", "I2", "I3", "J", "Theta", "R"}; + constexpr static std:: + array + simulationScenariosResolution = {12, 12, 22, 22, 22, 22}; + // simulationScenariosResolution = {2, 2, 2, 22, 22, 22}; + constexpr static std:: + array + baseScenarioWeights = {1, 1, 2, 2, 2}; + inline static int totalNumberOfSimulationScenarios = + std::accumulate(simulationScenariosResolution.begin(), + simulationScenariosResolution.end(), + 0); + inline static int fanCardinality{6}; + inline static double initialValue_R{0.3}; + inline static double initialValue_theta{0}; + int interfaceNodeIndex; + double operator()(const Eigen::VectorXd& x, Eigen::VectorXd&) const; - ReducedModelOptimizer(); - static void computeReducedModelSimulationJob( - const SimulationJob &simulationJobOfFullModel, - const std::unordered_map &fullToReducedMap, - SimulationJob &simulationJobOfReducedModel); + ReducedModelOptimizer(); + static void computeReducedModelSimulationJob( + const SimulationJob& simulationJobOfFullModel, + const std::unordered_map& fullToReducedMap, + SimulationJob& simulationJobOfReducedModel); - SimulationJob getReducedSimulationJob(const SimulationJob &fullModelSimulationJob); + SimulationJob getReducedSimulationJob( + const SimulationJob& fullModelSimulationJob); - static void runSimulation(const std::string &filename, std::vector &x); + static void runSimulation(const std::string& filename, + std::vector& x); - static std::vector> createFullPatternSimulationJobs( - const std::shared_ptr &pMesh, - const std::unordered_map &fullPatternOppositeInterfaceViMap); + static std::vector> + createFullPatternSimulationJobs( + const std::shared_ptr& pMesh, + const std::unordered_map& + fullPatternOppositeInterfaceViMap); - static void createSimulationMeshes( - PatternGeometry &pattern, - PatternGeometry &reducedModel, - const RectangularBeamDimensions &beamDimensions, - std::shared_ptr &pFullPatternSimulationMesh, - std::shared_ptr &pReducedPatternSimulationMesh); - void computeMaps(const std::unordered_map> &slotToNode, - PatternGeometry &fullPattern, - ReducedModel &reducedPattern, - std::unordered_map - &reducedToFullInterfaceViMap, - std::unordered_map - &fullToReducedInterfaceViMap, - std::vector> - &fullPatternOppositeInterfaceViMap); - static void visualizeResults( - const std::vector> &fullPatternSimulationJobs, - const std::vector> &reducedPatternSimulationJobs, - const std::vector &simulationScenarios, - const std::unordered_map - &reducedToFullInterfaceViMap); - static void registerResultsForDrawing( - const std::shared_ptr &pFullPatternSimulationJob, - const std::shared_ptr &pReducedPatternSimulationJob, - const std::unordered_map - &reducedToFullInterfaceViMap); + static void createSimulationEdgeMeshes( + PatternGeometry& pattern, + PatternGeometry& reducedModel, + const ReducedModelOptimization::Settings& optimizationSettings, + std::shared_ptr& pFullPatternSimulationEdgeMesh, + std::shared_ptr& pReducedPatternSimulationEdgeMesh); + void computeMaps( + const std::unordered_map>& slotToNode, + PatternGeometry& fullPattern, + ReducedModel& reducedPattern, + std::unordered_map& + reducedToFullInterfaceViMap, + std::unordered_map& + fullToReducedInterfaceViMap, + std::vector>& + fullPatternOppositeInterfaceViMap); + static void visualizeResults( + const std::vector>& + fullPatternSimulationJobs, + const std::vector>& + reducedPatternSimulationJobs, + const std::vector& + simulationScenarios, + const std::unordered_map& + reducedToFullInterfaceViMap); + static void registerResultsForDrawing( + const std::shared_ptr& pFullPatternSimulationJob, + const std::shared_ptr& pReducedPatternSimulationJob, + const std::unordered_map& + reducedToFullInterfaceViMap); - static double computeRawTranslationalError( - const std::vector &fullPatternDisplacements, - const std::vector &reducedPatternDisplacements, - const std::unordered_map - &reducedToFullInterfaceViMap); + static double computeRawTranslationalError( + const std::vector& fullPatternDisplacements, + const std::vector& reducedPatternDisplacements, + const std::unordered_map& + reducedToFullInterfaceViMap); - static double computeDisplacementError( - const std::vector &fullPatternDisplacements, - const std::vector &reducedPatternDisplacements, - const std::unordered_map - &reducedToFullInterfaceViMap, - const double &normalizationFactor); + static double computeDisplacementError( + const std::vector& fullPatternDisplacements, + const std::vector& reducedPatternDisplacements, + const std::unordered_map& + reducedToFullInterfaceViMap, + const double& normalizationFactor); - static double computeRawRotationalError( - const std::vector &rotatedQuaternion_fullPattern, - const std::vector &rotatedQuaternion_reducedPattern, - const std::unordered_map - &reducedToFullInterfaceViMap); + static double computeRawRotationalError( + const std::vector& rotatedQuaternion_fullPattern, + const std::vector& rotatedQuaternion_reducedPattern, + const std::unordered_map& + reducedToFullInterfaceViMap); - static double computeRotationalError(const std::vector &rotatedQuaternion_fullPattern, - const std::vector &rotatedQuaternion_reducedPattern, - const std::unordered_map - &reducedToFullInterfaceViMap, - const double &normalizationFactor); - static double computeError( - const SimulationResults &simulationResults_fullPattern, - const SimulationResults &simulationResults_reducedPattern, - const std::unordered_map - &reducedToFullInterfaceViMap, - const double &normalizationFactor_translationalDisplacement, - const double &normalizationFactor_rotationalDisplacement, - const double &scenarioWeight, - const ReducedModelOptimization::Settings::ObjectiveWeights &objectiveWeights); - static void constructAxialSimulationScenario( - const double &forceMagnitude, - const std::vector> - &oppositeInterfaceViPairs, - SimulationJob &job); + static double computeRotationalError( + const std::vector& rotatedQuaternion_fullPattern, + const std::vector& rotatedQuaternion_reducedPattern, + const std::unordered_map& + reducedToFullInterfaceViMap, + const double& normalizationFactor); + static double computeError( + const SimulationResults& simulationResults_fullPattern, + const SimulationResults& simulationResults_reducedPattern, + const std::unordered_map& + reducedToFullInterfaceViMap, + const double& normalizationFactor_translationalDisplacement, + const double& normalizationFactor_rotationalDisplacement, + const double& scenarioWeight, + const ReducedModelOptimization::Settings::ObjectiveWeights& + objectiveWeights); + static void constructAxialSimulationScenario( + const double& forceMagnitude, + const std::vector>& + oppositeInterfaceViPairs, + SimulationJob& job); - static void constructShearSimulationScenario( - const double &forceMagnitude, - const std::vector> - &oppositeInterfaceViPairs, - SimulationJob &job); + static void constructShearSimulationScenario( + const double& forceMagnitude, + const std::vector>& + oppositeInterfaceViPairs, + SimulationJob& job); - static void constructBendingSimulationScenario( - const double &forceMagnitude, - const std::vector> - &oppositeInterfaceViPairs, - SimulationJob &job); + static void constructBendingSimulationScenario( + const double& forceMagnitude, + const std::vector>& + oppositeInterfaceViPairs, + SimulationJob& job); - static void constructDomeSimulationScenario( - const double &forceMagnitude, - const std::vector> - &oppositeInterfaceViPairs, - SimulationJob &job); + static void constructDomeSimulationScenario( + const double& forceMagnitude, + const std::vector>& + oppositeInterfaceViPairs, + SimulationJob& job); - static void constructSaddleSimulationScenario( - const double &forceMagnitude, - const std::vector> - &oppositeInterfaceViPairs, - SimulationJob &job); - static void constructSSimulationScenario( - const double &forceMagnitude, - const std::vector> - &oppositeInterfaceViPairs, - SimulationJob &job); - static std::function &x, - std::shared_ptr &pReducedPatternSimulationMesh)> - function_updateReducedPattern; - static std::function &pReducedPatternSimulationMesh)> - function_updateReducedPattern_material_E; - static std::function &pReducedPatternSimulationMesh)> - function_updateReducedPattern_material_A; - static std::function &pReducedPatternSimulationMesh)> - function_updateReducedPattern_material_I; - static std::function &pReducedPatternSimulationMesh)> - function_updateReducedPattern_material_I2; - static std::function &pReducedPatternSimulationMesh)> - function_updateReducedPattern_material_I3; - static std::function &pReducedPatternSimulationMesh)> - function_updateReducedPattern_material_J; - static double objective(const std::vector &x); - void initializeUpdateReducedPatternFunctions(); - // static double objective(const double &xValue); + static void constructSaddleSimulationScenario( + const double& forceMagnitude, + const std::vector>& + oppositeInterfaceViPairs, + SimulationJob& job); + static void constructSSimulationScenario( + const double& forceMagnitude, + const std::vector>& + oppositeInterfaceViPairs, + SimulationJob& job); + static std::function& x, + std::shared_ptr& pReducedPatternSimulationEdgeMesh)> + function_updateReducedPattern; + static std::function& pReducedPatternSimulationEdgeMesh)> + function_updateReducedPattern_material_E; + static std::function& pReducedPatternSimulationEdgeMesh)> + function_updateReducedPattern_material_A; + static std::function& pReducedPatternSimulationEdgeMesh)> + function_updateReducedPattern_material_I; + static std::function& pReducedPatternSimulationEdgeMesh)> + function_updateReducedPattern_material_I2; + static std::function& pReducedPatternSimulationEdgeMesh)> + function_updateReducedPattern_material_I3; + static std::function& pReducedPatternSimulationEdgeMesh)> + function_updateReducedPattern_material_J; + static double objective(const std::vector& x); + void initializeUpdateReducedPatternFunctions(); + // static double objective(const double &xValue); - ReducedModelOptimization::Results optimize( - ConstPatternGeometry &fullPattern, - const ReducedModelOptimization::Settings &optimizationSettings); + ReducedModelOptimization::Results optimize( + ConstPatternGeometry& fullPattern, + const ReducedModelOptimization::Settings& optimizationSettings); - void optimize(ConstPatternGeometry &fullPattern, - ReducedModelOptimization::Settings &optimizationSettings, - ReducedModelOptimization::Results &optimizationResults); - static double objective(const std::vector &x, - ReducedModelOptimizer::OptimizationState &optimizationState); + void optimize(ConstPatternGeometry& fullPattern, + ReducedModelOptimization::Settings& optimizationSettings, + ReducedModelOptimization::Results& optimizationResults); + static double objective( + const std::vector& x, + ReducedModelOptimizer::OptimizationState& optimizationState); -private: - void optimize( - ReducedModelOptimization::Settings &optimizationSettings, - ReducedModelOptimization::Results &results, - const std::vector &simulationScenarios - = std::vector( - {ReducedModelOptimization::Axial, - ReducedModelOptimization::Shear, - ReducedModelOptimization::Bending, - ReducedModelOptimization::Dome, - ReducedModelOptimization::Saddle, - ReducedModelOptimization::S})); + private: + void optimize( + ReducedModelOptimization::Settings& optimizationSettings, + ReducedModelOptimization::Results& results, + const std::vector& + simulationScenarios = + std::vector( + {ReducedModelOptimization::Axial, + ReducedModelOptimization::Shear, + ReducedModelOptimization::Bending, + ReducedModelOptimization::Dome, + ReducedModelOptimization::Saddle, + ReducedModelOptimization::S})); - void initializePatterns(PatternGeometry &fullPattern, - ReducedModel &reducedModel, - const ReducedModelOptimization::Settings &optimizationSettings); - static void computeDesiredReducedModelDisplacements( - const SimulationResults &fullModelResults, - const std::unordered_map &displacementsReducedToFullMap, - Eigen::MatrixX3d &optimalDisplacementsOfReducedModel); - void runOptimization(const ReducedModelOptimization::Settings &settings, - ReducedModelOptimization::Results &results); - void computeMaps(PatternGeometry &fullModel, ReducedModel &reducedModel); - void createSimulationMeshes(PatternGeometry &fullModel, - PatternGeometry &reducedModel, - const RectangularBeamDimensions &beamDimensions); - void initializeOptimizationParameters( - const std::shared_ptr &mesh, - const std::array - &optimizationParamters); + void initializePatterns( + PatternGeometry& fullPattern, + ReducedModel& reducedModel, + const ReducedModelOptimization::Settings& optimizationSettings); + static void computeDesiredReducedModelDisplacements( + const SimulationResults& fullModelResults, + const std::unordered_map& displacementsReducedToFullMap, + Eigen::MatrixX3d& optimalDisplacementsOfReducedModel); + void runOptimization(const ReducedModelOptimization::Settings& settings, + ReducedModelOptimization::Results& results); + void computeMaps(PatternGeometry& fullModel, ReducedModel& reducedModel); + void createSimulationEdgeMeshes( + PatternGeometry& fullModel, + PatternGeometry& reducedModel, + const ReducedModelOptimization::Settings& optimizationSettings); + void initializeOptimizationParameters( + const std::shared_ptr& mesh, + const std::array& + optimizationParamters); - ChronosEulerSimulationModel patternSimulator; - LinearSimulationModel reducedModelSimulator; - void computeObjectiveValueNormalizationFactors( - const ReducedModelOptimization::Settings &optimizationSettings); + void computeObjectiveValueNormalizationFactors( + const ReducedModelOptimization::Settings& optimizationSettings); - void getResults(const FunctionEvaluation &optimalObjective, - const ReducedModelOptimization::Settings &settings, - ReducedModelOptimization::Results &results); - double computeFullPatternMaxSimulationForce( - const ReducedModelOptimization::BaseSimulationScenario &scenario) const; + void getResults(const FunctionEvaluation& optimalObjective, + const ReducedModelOptimization::Settings& settings, + ReducedModelOptimization::Results& results); + double computeFullPatternMaxSimulationForce( + const ReducedModelOptimization::BaseSimulationScenario& scenario) const; #ifdef DLIB_DEFINED - static double objective(const dlib::matrix &x); + static double objective(const dlib::matrix& x); #endif - std::array - computeFullPatternMaxSimulationForces( - const std::vector - &desiredBaseSimulationScenario) const; - std::vector> createFullPatternSimulationJobs( - const std::shared_ptr &pMesh, - const std::array - &baseScenarioMaxForceMagnitudes) const; - std::array - getFullPatternMaxSimulationForces( - const std::vector - &desiredBaseSimulationScenarioIndices, - const std::filesystem::path &intermediateResultsDirectoryPath, - const bool &recomputeForceMagnitudes); - std::array - getFullPatternMaxSimulationForces(); - void computeScenarioWeights( - const std::vector &baseSimulationScenarios, - const ReducedModelOptimization::Settings &optimizationSettings); + std::array + computeFullPatternMaxSimulationForces( + const std::vector& + desiredBaseSimulationScenario) const; + std::vector> createFullPatternSimulationJobs( + const std::shared_ptr& pMesh, + const std::array< + double, + ReducedModelOptimization::NumberOfBaseSimulationScenarios>& + baseScenarioMaxForceMagnitudes) const; + std::array + getFullPatternMaxSimulationForces( + const std::vector& + desiredBaseSimulationScenarioIndices, + const std::filesystem::path& intermediateResultsDirectoryPath, + const bool& recomputeForceMagnitudes); + std::array + getFullPatternMaxSimulationForces(); + void computeScenarioWeights( + const std::vector& + baseSimulationScenarios, + const ReducedModelOptimization::Settings& optimizationSettings); }; -inline std::function &pReducedPatternSimulationMesh)> +inline std::function& pReducedPatternSimulationEdgeMesh)> ReducedModelOptimizer::function_updateReducedPattern_material_E; -inline std::function &pReducedPatternSimulationMesh)> +inline std::function& pReducedPatternSimulationEdgeMesh)> ReducedModelOptimizer::function_updateReducedPattern_material_A; -inline std::function &pReducedPatternSimulationMesh)> +inline std::function& pReducedPatternSimulationEdgeMesh)> ReducedModelOptimizer::function_updateReducedPattern_material_I; -inline std::function &pReducedPatternSimulationMesh)> +inline std::function& pReducedPatternSimulationEdgeMesh)> ReducedModelOptimizer::function_updateReducedPattern_material_I2; -inline std::function &pReducedPatternSimulationMesh)> +inline std::function& pReducedPatternSimulationEdgeMesh)> ReducedModelOptimizer::function_updateReducedPattern_material_I3; -inline std::function &pReducedPatternSimulationMesh)> +inline std::function& pReducedPatternSimulationEdgeMesh)> ReducedModelOptimizer::function_updateReducedPattern_material_J; -inline std::function &x, std::shared_ptr &m)> +inline std::function& x, + std::shared_ptr& m)> ReducedModelOptimizer::function_updateReducedPattern; extern ReducedModelOptimizer::OptimizationState global; -#endif // REDUCEDMODELOPTIMIZER_HPP +#endif // REDUCEDMODELOPTIMIZER_HPP diff --git a/reducedmodeloptimizer_structs.hpp b/reducedmodeloptimizer_structs.hpp index 24b61ad..a83ca49 100644 --- a/reducedmodeloptimizer_structs.hpp +++ b/reducedmodeloptimizer_structs.hpp @@ -1,1214 +1,1327 @@ #ifndef REDUCEDMODELOPTIMIZER_STRUCTS_HPP #define REDUCEDMODELOPTIMIZER_STRUCTS_HPP +#include +#include "chronoseulersimulationmodel.hpp" #include "csvfile.hpp" #include "drmsimulationmodel.hpp" #include "linearsimulationmodel.hpp" #include "simulation_structs.hpp" +#include "simulationmodelfactory.hpp" +#include "trianglepatterngeometry.hpp" #include "unordered_map" -#include namespace ReducedModelOptimization { enum BaseSimulationScenario { - Axial, - Shear, - Bending, - Dome, - Saddle, - S, - NumberOfBaseSimulationScenarios + Axial, + Shear, + Bending, + Dome, + Saddle, + S, + NumberOfBaseSimulationScenarios }; -inline static std::vector baseSimulationScenarioNames{"Axial", - "Shear", - "Bending", - "Dome", - "Saddle", - "S"}; +inline static std::vector baseSimulationScenarioNames{ + "Axial", "Shear", "Bending", "Dome", "Saddle", "S"}; -struct Colors -{ - inline static std::array patternInitial{0.518, 0.518, 0.518}; - // inline static std::array fullDeformed{0.583333, 0.890196, 0.109804}; - inline static std::array patternDeformed{0.094, 0.094, 0.094}; - // inline static std::array reducedInitial{0.890196, 0.109804, 0.193138}; - inline static std::array reducedInitial{0.518, 0.518, 0.518}; - inline static std::array reducedDeformed{0.262, 0.627, 0.910}; +struct Colors { + using RGBColor = std::array; + inline static RGBColor patternInitial{0.518, 0.518, 0.518}; + // inline static RGBColor fullDeformed{0.583333, 0.890196, + // 0.109804}; + inline static RGBColor patternDeformed{0.094, 0.094, 0.094}; + // inline static RGBColor reducedInitial{0.890196, 0.109804, + // 0.193138}; + inline static RGBColor reducedInitial{0.518, 0.518, 0.518}; + inline static RGBColor reducedDeformed{0.262, 0.627, 0.910}; }; -struct xRange -{ - std::string label{}; - double min{0}; - double max{0}; +struct xRange { + std::string label{}; + double min{0}; + double max{0}; - inline bool operator<(const xRange &other) { return label < other.label; } - std::string toString() const - { - return label + "=[" + std::to_string(min) + "," + std::to_string(max) + "]"; - } + inline bool operator<(const xRange& other) { return label < other.label; } + std::string toString() const { + return label + "=[" + std::to_string(min) + "," + std::to_string(max) + "]"; + } - void fromString(const std::string &s) - { - const std::size_t equalPos = s.find("="); - label = s.substr(0, equalPos); - const std::size_t commaPos = s.find(","); - const size_t minBeginPos = equalPos + 2; - min = std::stod(s.substr(minBeginPos, commaPos - minBeginPos)); - const size_t maxBeginPos = commaPos + 1; - const std::size_t closingBracketPos = s.find("]"); - max = std::stod(s.substr(maxBeginPos, closingBracketPos - maxBeginPos)); - } + void fromString(const std::string& s) { + const std::size_t equalPos = s.find("="); + label = s.substr(0, equalPos); + const std::size_t commaPos = s.find(","); + const size_t minBeginPos = equalPos + 2; + min = std::stod(s.substr(minBeginPos, commaPos - minBeginPos)); + const size_t maxBeginPos = commaPos + 1; + const std::size_t closingBracketPos = s.find("]"); + max = std::stod(s.substr(maxBeginPos, closingBracketPos - maxBeginPos)); + } - bool operator==(const xRange &xrange) const - { - return label == xrange.label && min == xrange.min && max == xrange.max; - } + bool operator==(const xRange& xrange) const { + return label == xrange.label && min == xrange.min && max == xrange.max; + } - std::tuple toTuple() const - { - return std::make_tuple(label, min, max); - } + std::tuple toTuple() const { + return std::make_tuple(label, min, max); + } - void set(const std::tuple &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)" + void set(const std::tuple& 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; + std::terminate(); + // return; } + std::tie(label, min, max) = inputTuple; + } }; -enum OptimizationParameterIndex { E, A, I2, I3, J, R, Theta, NumberOfOptimizationVariables }; +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; - } +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 -{ - inline static std::string defaultFilename{"OptimizationSettings.json"}; - // std::array baseScenarioMaxMagnitudes{0.590241, - // 0.888372, - // 0.368304, - // 0.0127508, - // 1.18079, - // 0}; //final - // std::array baseScenarioMaxMagnitudes{ - // 0.590241 / 6, 0.588372 / 6, 0.368304 / 2, 0.05, 1.18 / 4, 0}; //final b,h= 0.001 +struct Settings { + inline static std::string defaultFilename{"OptimizationSettings.json"}; + // std::array + // baseScenarioMaxMagnitudes{0.590241, + // 0.888372, + // 0.368304, + // 0.0127508, + // 1.18079, + // 0}; //final + // std::array + // baseScenarioMaxMagnitudes{ + // 0.590241 / 6, 0.588372 / 6, 0.368304 / 2, 0.05, 1.18 / 4, 0}; + // //final b,h= 0.001 - std::array baseScenarioMaxMagnitudes{ - 0.590241 / 3, 0.588372 / 3, 0.368304, 0.1, 1.18 / 2, 0}; //final b,h= 0.002 - // std::array baseScenarioMaxMagnitudes{0, 0, 0, 0.1, 0}; + std::array baseScenarioMaxMagnitudes{ + 0.590241 / 3, 0.588372 / 3, 0.368304, + 0.1, 1.18 / 2, 0}; // final b,h= 0.002 + // std::array + // baseScenarioMaxMagnitudes{0, 0, 0, 0.1, 0}; - // 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 + // 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{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 + // 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}}; - 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", 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}}; - std::string simulationModelLabel{DRMSimulationModel::label}; - struct SettingsPSO - { - int numberOfParticles{200}; + // std::array + // baseScenarioMaxMagnitudes; + + std::string getOptimizationSettingsLabel() const { + return simulationModelLabel_groundTruth + "_" + + simulationModelLabel_reducedModel; + } + std::vector> optimizationStrategy = { + // {E,A, I2, I3, J, R, Theta}}; + {A, I2, I3, J, R, Theta}}; + // {E}}; + // {E, R, Theta}}; + // {A, 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", 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}}; + inline static std::string simulationModelLabel_groundTruth{ + // ChronosEulerNonLinearSimulationModel::label}; + DRMSimulationModel::label}; + inline static std::string simulationModelLabel_reducedModel{ + LinearSimulationModel::label}; + // ChronosEulerLinearSimulationModel::label}; + struct SettingsPSO { + int numberOfParticles{200}; #ifdef USE_PSO - inline static std::string optimizerName{"pso"}; + inline static std::string optimizerName{"pso"}; #else - inline static std::string optimizerName{"sa"}; + inline static std::string optimizerName{"sa"}; #endif - } pso; + } pso; - struct SettingsDlibGlobal - { - int numberOfFunctionCalls{100000}; - } dlib; + 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}; - RectangularBeamDimensions patternBeamDimensions{0.002, 0.002}; - std::filesystem::path intermediateResultsDirectoryPath; - struct ObjectiveWeights - { - double translational{1.2}; - double rotational{0.8}; - bool operator==(const ObjectiveWeights &other) const; - }; - std::array perBaseScenarioObjectiveWeights; - // std::array perBaseScenarioObjectiveWeights{ - // {{1.95, 0.05}, {0.87, 1.13}, {0.37, 1.63}, {0.01, 1.99}, {0.94, 1.06}, {1.2, 0.8}}}; + 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}; + CrossSectionType beamDimensions_pattern{0.002, 0.002}; + double youngsModulus_pattern{1e9}; + std::filesystem::path intermediateResultsDirectoryPath; + struct ObjectiveWeights { + double translational{1.2}; + double rotational{0.8}; + bool operator==(const ObjectiveWeights& other) const; + }; + std::array + perBaseScenarioObjectiveWeights; + // std::array + // perBaseScenarioObjectiveWeights{ + // {{1.95, 0.05}, {0.87, 1.13}, {0.37, 1.63}, {0.01, 1.99}, + // {0.94, 1.06}, {1.2, 0.8}}}; + std::array, NumberOfBaseSimulationScenarios> + convertObjectiveWeightsToPairs() const { std::array, NumberOfBaseSimulationScenarios> - convertObjectiveWeightsToPairs() const - { - std::array, NumberOfBaseSimulationScenarios> objectiveWeightsPairs; - for (int baseScenario = Axial; baseScenario != NumberOfBaseSimulationScenarios; - baseScenario++) { - objectiveWeightsPairs[baseScenario] - = std::make_pair(perBaseScenarioObjectiveWeights[baseScenario].translational, - perBaseScenarioObjectiveWeights[baseScenario].rotational); - } - return objectiveWeightsPairs; + objectiveWeightsPairs; + for (int baseScenario = Axial; + baseScenario != NumberOfBaseSimulationScenarios; baseScenario++) { + objectiveWeightsPairs[baseScenario] = std::make_pair( + perBaseScenarioObjectiveWeights[baseScenario].translational, + perBaseScenarioObjectiveWeights[baseScenario].rotational); } + return objectiveWeightsPairs; + } - struct JsonKeys - { - inline static std::string OptimizationStrategy{"OptimizationStrategy"}; - inline static std::string OptimizationStrategyGroupWeights{ - "OptimizationStrategyGroupWeights"}; - inline static std::string OptimizationVariables{"OptimizationVariables"}; - inline static std::string NumberOfFunctionCalls{"NumberOfFunctionCalls"}; - inline static std::string SolverAccuracy{"SolverAccuracy"}; - inline static std::string ObjectiveWeights{"ObjectiveWeight"}; - }; + struct JsonKeys { + inline static std::string OptimizationStrategy{"OptimizationStrategy"}; + inline static std::string OptimizationStrategyGroupWeights{ + "OptimizationStrategyGroupWeights"}; + inline static std::string OptimizationVariables{"OptimizationVariables"}; + inline static std::string NumberOfFunctionCalls{"NumberOfFunctionCalls"}; + inline static std::string SolverAccuracy{"SolverAccuracy"}; + inline static std::string ObjectiveWeights{"ObjectiveWeight"}; + }; - nlohmann::json toJson() const - { - nlohmann::json json; - json[GET_VARIABLE_NAME(optimizationStrategy)] = optimizationStrategy; - if (optimizationVariablesGroupsWeights.has_value()) { - json[GET_VARIABLE_NAME(ptimizationStrategyGroupWeights)] - = optimizationVariablesGroupsWeights.value(); - } - //write x ranges - const std::array, NumberOfOptimizationVariables> - xRangesAsTuples = [=]() { - std::array, 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(); - // } + nlohmann::json toJson() const { + nlohmann::json json; + json[GET_VARIABLE_NAME(optimizationStrategy)] = optimizationStrategy; + if (optimizationVariablesGroupsWeights.has_value()) { + json[GET_VARIABLE_NAME(ptimizationStrategyGroupWeights)] = + optimizationVariablesGroupsWeights.value(); + } + // write x ranges + const std::array, + NumberOfOptimizationVariables> + xRangesAsTuples = [=]() { + std::array, + 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[GET_VARIABLE_NAME(solverAccuracy)] = solverAccuracy; - //Objective weights - std::array, 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; - json[GET_VARIABLE_NAME(translationEpsilon)] = translationEpsilon; - json[GET_VARIABLE_NAME(angularDistanceEpsilon)] = vcg::math::ToDeg(angularDistanceEpsilon); - json[GET_VARIABLE_NAME(targetBaseTriangleSize)] = targetBaseTriangleSize; - json[GET_VARIABLE_NAME(baseScenarioMaxMagnitudes)] = baseScenarioMaxMagnitudes; - json[GET_VARIABLE_NAME(simulationModelLabel)] = simulationModelLabel; - nlohmann::json json_dimensions; - patternBeamDimensions.to_json(json_dimensions, patternBeamDimensions); - json.update(json_dimensions); + json[GET_VARIABLE_NAME(solverAccuracy)] = solverAccuracy; + // Objective weights + std::array, 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; + json[GET_VARIABLE_NAME(translationEpsilon)] = translationEpsilon; + json[GET_VARIABLE_NAME(angularDistanceEpsilon)] = + vcg::math::ToDeg(angularDistanceEpsilon); + json[GET_VARIABLE_NAME(targetBaseTriangleSize)] = targetBaseTriangleSize; + json[GET_VARIABLE_NAME(baseScenarioMaxMagnitudes)] = + baseScenarioMaxMagnitudes; + json[GET_VARIABLE_NAME(simulationModelLabel_groundTruth)] = + simulationModelLabel_groundTruth; + json[GET_VARIABLE_NAME(simulationModelLabel_reducedModel)] = + simulationModelLabel_reducedModel; + json[GET_VARIABLE_NAME(youngsModulus_pattern)] = youngsModulus_pattern; + nlohmann::json json_dimensions; + beamDimensions_pattern.to_json(json_dimensions, beamDimensions_pattern); + json.update(json_dimensions); #ifdef USE_ENSMALLEN #ifdef USE_PSO - json[GET_VARIABLE_NAME(pso.numberOfParticles)] = pso.numberOfParticles; + json[GET_VARIABLE_NAME(pso.numberOfParticles)] = pso.numberOfParticles; #endif - json[GET_VARIABLE_NAME(pso.optimizerName)] = pso.optimizerName; + json[GET_VARIABLE_NAME(pso.optimizerName)] = pso.optimizerName; #else - json[GET_VARIABLE_NAME(dlib.numberOfFunctionCalls)] = dlib.numberOfFunctionCalls; + json[GET_VARIABLE_NAME(dlib.numberOfFunctionCalls)] = + dlib.numberOfFunctionCalls; #endif - return json; + 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()); + jsonFile << json; + jsonFile.close(); + } + + bool load(const std::filesystem::path& jsonFilePath) { + if (!std::filesystem::exists(jsonFilePath)) { + std::cerr << "Optimization settings could not be loaded because input " + "filepath does " + "not exist:" + << jsonFilePath << std::endl; + assert(false); + return false; } - 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()); - jsonFile << json; - jsonFile.close(); + std::ifstream ifs(jsonFilePath); + nlohmann::json json; + ifs >> json; + + if (json.contains(GET_VARIABLE_NAME(optimizationStrategy))) { + optimizationStrategy = std::vector< + std::vector>( + (json.at(GET_VARIABLE_NAME(optimizationStrategy)))); + } + if (json.contains(GET_VARIABLE_NAME(optimizationStrategyGroupWeights))) { + optimizationVariablesGroupsWeights = std::vector( + json[GET_VARIABLE_NAME(optimizationStrategyGroupWeights)]); + } + // read x ranges + if (json.contains(JsonKeys::OptimizationVariables)) { + const std::array, + NumberOfOptimizationVariables> + xRangesAsTuples = json.at(JsonKeys::OptimizationVariables); + for (const auto& rangeTuple : xRangesAsTuples) { + variablesRanges[getParameterIndex(std::get<0>(rangeTuple))].set( + rangeTuple); + } + } 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; + } } - bool load(const std::filesystem::path &jsonFilePath) - { - if (!std::filesystem::exists(jsonFilePath)) { - std::cerr << "Optimization settings could not be loaded because input filepath does " - "not exist:" - << jsonFilePath << std::endl; - assert(false); - return false; - } - std::ifstream ifs(jsonFilePath); - nlohmann::json json; - ifs >> json; - - if (json.contains(GET_VARIABLE_NAME(optimizationStrategy))) { - optimizationStrategy - = std::vector>( - (json.at(GET_VARIABLE_NAME(optimizationStrategy)))); - } - if (json.contains(GET_VARIABLE_NAME(optimizationStrategyGroupWeights))) { - optimizationVariablesGroupsWeights = std::vector( - json[GET_VARIABLE_NAME(optimizationStrategyGroupWeights)]); - } - //read x ranges - if (json.contains(JsonKeys::OptimizationVariables)) { - const std::array, NumberOfOptimizationVariables> - xRangesAsTuples = json.at(JsonKeys::OptimizationVariables); - for (const auto &rangeTuple : xRangesAsTuples) { - variablesRanges[getParameterIndex(std::get<0>(rangeTuple))].set(rangeTuple); - } - } 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; - } - } - - 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)); - } - //Objective weights - if (json.contains(JsonKeys::ObjectiveWeights)) { - std::array, NumberOfBaseSimulationScenarios> - objectiveWeightsPairs = json.at(JsonKeys::ObjectiveWeights); - std::transform(objectiveWeightsPairs.begin(), - objectiveWeightsPairs.end(), - perBaseScenarioObjectiveWeights.begin(), - [](const std::pair &objectiveWeightsPair) { - return ObjectiveWeights{objectiveWeightsPair.first, - objectiveWeightsPair.second}; - }); - } - if (json.contains(GET_VARIABLE_NAME(translationalNormalizationEpsilon))) { - translationEpsilon - = json[GET_VARIABLE_NAME(translationalNormalizationEpsilon)]; - } - - if (json.contains(GET_VARIABLE_NAME(angularDistanceEpsilon))) { - angularDistanceEpsilon = vcg::math::ToRad( - static_cast(json[GET_VARIABLE_NAME(angularDistanceEpsilon)])); - } - - if (json.contains(GET_VARIABLE_NAME(targetBaseTriangleSize))) { - targetBaseTriangleSize = static_cast( - json[GET_VARIABLE_NAME(targetBaseTriangleSize)]); - } - - if (json.contains(GET_VARIABLE_NAME(pso.numberOfParticles))) { - pso.numberOfParticles = static_cast(json[GET_VARIABLE_NAME(pso.numberOfParticles)]); - } - - if (json.contains(GET_VARIABLE_NAME(simulationModelLabel))) { - simulationModelLabel = static_cast( - json[GET_VARIABLE_NAME(simulationModelLabel)]); - } - - patternBeamDimensions.from_json(json, patternBeamDimensions); - - // perBaseScenarioObjectiveWeights = json.at(JsonKeys::ObjectiveWeights); - // objectiveWeights.translational = json.at(JsonKeys::ObjectiveWeights); - // objectiveWeights.rotational = 2 - objectiveWeights.translational; - return true; + 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)); + } + // Objective weights + if (json.contains(JsonKeys::ObjectiveWeights)) { + std::array, NumberOfBaseSimulationScenarios> + objectiveWeightsPairs = json.at(JsonKeys::ObjectiveWeights); + std::transform(objectiveWeightsPairs.begin(), objectiveWeightsPairs.end(), + perBaseScenarioObjectiveWeights.begin(), + [](const std::pair& objectiveWeightsPair) { + return ObjectiveWeights{objectiveWeightsPair.first, + objectiveWeightsPair.second}; + }); + } + if (json.contains(GET_VARIABLE_NAME(translationalNormalizationEpsilon))) { + translationEpsilon = + json[GET_VARIABLE_NAME(translationalNormalizationEpsilon)]; } - std::string toString() const { return toJson().dump(); } - - void writeHeaderTo(csvFile &os) const - { - if (!variablesRanges.empty()) { - for (const xRange &range : variablesRanges) { - os << range.label + " max"; - os << range.label + " min"; - } - } - os << "Function Calls"; - os << "Solution Accuracy"; - os << "Normalization trans epsilon"; - os << "Normalization rot epsilon(deg)"; - os << JsonKeys::ObjectiveWeights; - os << "Optimization parameters"; - // os << std::endl; + if (json.contains(GET_VARIABLE_NAME(angularDistanceEpsilon))) { + angularDistanceEpsilon = vcg::math::ToRad( + static_cast(json[GET_VARIABLE_NAME(angularDistanceEpsilon)])); } - void writeSettingsTo(csvFile &os) const - { - if (!variablesRanges.empty()) { - for (const xRange &range : variablesRanges) { - os << range.max; - os << range.min; - } - } - os << dlib.numberOfFunctionCalls; - os << solverAccuracy; - os << std::to_string(translationEpsilon); - os << std::to_string(vcg::math::ToDeg(angularDistanceEpsilon)); - std::string objectiveWeightsString; - 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 - std::vector> vv; - for (const std::vector &v : optimizationStrategy) { - std::vector vi; - vi.reserve(v.size()); - for (const OptimizationParameterIndex ¶meter : v) { - vi.emplace_back(parameter); - } - vv.push_back(vi); - } - os << Utilities::toString(vv); + if (json.contains(GET_VARIABLE_NAME(targetBaseTriangleSize))) { + targetBaseTriangleSize = + static_cast(json[GET_VARIABLE_NAME(targetBaseTriangleSize)]); } + + if (json.contains(GET_VARIABLE_NAME(pso.numberOfParticles))) { + pso.numberOfParticles = + static_cast(json[GET_VARIABLE_NAME(pso.numberOfParticles)]); + } + + if (json.contains(GET_VARIABLE_NAME(simulationModelLabel_reducedModel))) { + simulationModelLabel_reducedModel = static_cast( + json[GET_VARIABLE_NAME(simulationModelLabel_reducedModel)]); + } + + beamDimensions_pattern.from_json(json, beamDimensions_pattern); + + if (json.contains(GET_VARIABLE_NAME(youngsModulus_pattern))) { + youngsModulus_pattern = + static_cast(json[GET_VARIABLE_NAME(youngsModulus_pattern)]); + } + // perBaseScenarioObjectiveWeights = + // json.at(JsonKeys::ObjectiveWeights); + // objectiveWeights.translational = + // json.at(JsonKeys::ObjectiveWeights); objectiveWeights.rotational = + // 2 - objectiveWeights.translational; + return true; + } + + std::string toString() const { return toJson().dump(); } + + void writeHeaderTo(csvFile& os) const { + if (!variablesRanges.empty()) { + for (const xRange& range : variablesRanges) { + os << range.label + " max"; + os << range.label + " min"; + } + } + os << "Function Calls"; + os << "Solution Accuracy"; + os << "Normalization trans epsilon"; + os << "Normalization rot epsilon(deg)"; + os << JsonKeys::ObjectiveWeights; + os << "Optimization parameters"; + // os << std::endl; + } + + void writeSettingsTo(csvFile& os) const { + if (!variablesRanges.empty()) { + for (const xRange& range : variablesRanges) { + os << range.max; + os << range.min; + } + } + os << dlib.numberOfFunctionCalls; + os << solverAccuracy; + os << std::to_string(translationEpsilon); + os << std::to_string(vcg::math::ToDeg(angularDistanceEpsilon)); + std::string objectiveWeightsString; + 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 + std::vector> vv; + for (const std::vector& v : + optimizationStrategy) { + std::vector vi; + vi.reserve(v.size()); + for (const OptimizationParameterIndex& parameter : v) { + vi.emplace_back(parameter); + } + vv.push_back(vi); + } + os << Utilities::toString(vv); + } }; - 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.dlib.numberOfFunctionCalls == settings2.dlib.numberOfFunctionCalls - && settings1.variablesRanges == settings2.variablesRanges - && settings1.solverAccuracy == settings2.solverAccuracy && haveTheSameObjectiveWeights - && settings1.translationEpsilon == settings2.translationEpsilon; +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.dlib.numberOfFunctionCalls == + settings2.dlib.numberOfFunctionCalls && + settings1.variablesRanges == settings2.variablesRanges && + settings1.solverAccuracy == settings2.solverAccuracy && + haveTheSameObjectiveWeights && + settings1.translationEpsilon == settings2.translationEpsilon; +} + +inline void updateMeshWithOptimalVariables(const std::vector& x, + SimulationEdgeMesh& m) { + assert(CrossSectionType::name == RectangularBeamDimensions::name); + const double E = x[0]; + const double A = x[1]; + const double beamWidth = std::sqrt(A); + const double beamHeight = beamWidth; + + const double J = x[2]; + const double I2 = x[3]; + const double I3 = x[4]; + for (EdgeIndex ei = 0; ei < m.EN(); ei++) { + Element& e = m.elements[ei]; + e.setDimensions(CrossSectionType(beamWidth, beamHeight)); + e.setMaterial(ElementMaterial(e.material.poissonsRatio, E)); + e.dimensions.inertia.J = J; + e.dimensions.inertia.I2 = I2; + e.dimensions.inertia.I3 = I3; } - inline void updateMeshWithOptimalVariables(const std::vector &x, SimulationMesh &m) - { - assert(CrossSectionType::name == RectangularBeamDimensions::name); - const double E = x[0]; - const double A = x[1]; - const double beamWidth = std::sqrt(A); - const double beamHeight = beamWidth; + CoordType center_barycentric(1, 0, 0); + CoordType interfaceEdgeMiddle_barycentric(0, 0.5, 0.5); + CoordType movableVertex_barycentric( + (center_barycentric + interfaceEdgeMiddle_barycentric) * x[x.size() - 2]); - const double J = x[2]; - const double I2 = x[3]; - const double I3 = x[4]; - for (EdgeIndex ei = 0; ei < m.EN(); ei++) { - Element &e = m.elements[ei]; - e.setDimensions(CrossSectionType(beamWidth, beamHeight)); - e.setMaterial(ElementMaterial(e.material.poissonsRatio, E)); - e.dimensions.inertia.J = J; - e.dimensions.inertia.I2 = I2; - e.dimensions.inertia.I3 = I3; - } + CoordType patternCoord0 = CoordType(0, 0, 0); + double bottomEdgeHalfSize = 0.03 / std::tan(M_PI / 3); + CoordType interfaceNodePosition(0, -0.03, 0); + CoordType patternBottomRight = + interfaceNodePosition + CoordType(bottomEdgeHalfSize, 0, 0); + CoordType patternBottomLeft = + interfaceNodePosition - CoordType(bottomEdgeHalfSize, 0, 0); + vcg::Triangle3 baseTriangle(patternCoord0, patternBottomLeft, + patternBottomRight); + CoordType baseTriangleMovableVertexPosition = + baseTriangle.cP(0) * movableVertex_barycentric[0] + + baseTriangle.cP(1) * movableVertex_barycentric[1] + + baseTriangle.cP(2) * movableVertex_barycentric[2]; + VectorType patternPlaneNormal(0, 0, 1); + baseTriangleMovableVertexPosition = + vcg::RotationMatrix(patternPlaneNormal, + vcg::math::ToRad(x[x.size() - 1])) * + baseTriangleMovableVertexPosition; - CoordType center_barycentric(1, 0, 0); - CoordType interfaceEdgeMiddle_barycentric(0, 0.5, 0.5); - CoordType movableVertex_barycentric((center_barycentric + interfaceEdgeMiddle_barycentric) - * x[x.size() - 2]); - - CoordType patternCoord0 = CoordType(0, 0, 0); - double bottomEdgeHalfSize = 0.03 / std::tan(M_PI / 3); - CoordType interfaceNodePosition(0, -0.03, 0); - CoordType patternBottomRight = interfaceNodePosition + CoordType(bottomEdgeHalfSize, 0, 0); - CoordType patternBottomLeft = interfaceNodePosition - CoordType(bottomEdgeHalfSize, 0, 0); - vcg::Triangle3 baseTriangle(patternCoord0, patternBottomLeft, patternBottomRight); - CoordType baseTriangleMovableVertexPosition = baseTriangle.cP(0) - * movableVertex_barycentric[0] - + baseTriangle.cP(1) - * movableVertex_barycentric[1] - + baseTriangle.cP(2) - * movableVertex_barycentric[2]; - VectorType patternPlaneNormal(0, 0, 1); - baseTriangleMovableVertexPosition = vcg::RotationMatrix(patternPlaneNormal, - vcg::math::ToRad(x[x.size() - 1])) - * baseTriangleMovableVertexPosition; - - const int fanSize = 6; - for (int rotationCounter = 0; rotationCounter < fanSize; rotationCounter++) { - m.vert[2 * rotationCounter + 1].P() = vcg::RotationMatrix(patternPlaneNormal, - vcg::math::ToRad( - 60.0 * rotationCounter)) - * baseTriangleMovableVertexPosition; - } - - m.reset(); + const int fanSize = 6; + for (int rotationCounter = 0; rotationCounter < fanSize; rotationCounter++) { + m.vert[2 * rotationCounter + 1].P() = + vcg::RotationMatrix(patternPlaneNormal, + vcg::math::ToRad(60.0 * rotationCounter)) * + baseTriangleMovableVertexPosition; } - struct Results - { - std::string label{"EmptyLabel"}; - double time{-1}; - bool wasSuccessful{true}; - // int numberOfSimulationCrashes{0}; - Settings settings; + m.reset(); +} - std::vector> optimalXNameValuePairs; - std::vector> fullPatternSimulationJobs; - std::vector> reducedPatternSimulationJobs; - double fullPatternYoungsModulus{0}; +struct Results { + std::string label{"EmptyLabel"}; + double time{-1}; + bool wasSuccessful{true}; + // int numberOfSimulationCrashes{0}; + Settings settings; - //Full pattern - PatternGeometry baseTriangleFullPattern; //non-fanned,non-tiled full pattern - vcg::Triangle3 baseTriangle; - // std::string notes; + std::vector> optimalXNameValuePairs; + std::vector> pSimulationJobs_pattern; + std::vector> pSimulationJobs_reducedModel; - //Data gathered for csv exporting - struct ObjectiveValues - { - double totalRaw; - double total; - std::vector perSimulationScenario_rawTranslational; - std::vector perSimulationScenario_rawRotational; - std::vector perSimulationScenario_translational; - std::vector perSimulationScenario_rotational; - std::vector perSimulationScenario_total; - std::vector perSimulationScenario_total_unweighted; + // Full pattern + PatternGeometry baseTrianglePattern; // non-fanned,non-tiled full pattern + vcg::Triangle3 baseTriangle; + // std::string notes; - } objectiveValue; + // Data gathered for csv exporting + struct ObjectiveValues { + double totalRaw; + double total; + std::vector perSimulationScenario_rawTranslational; + std::vector perSimulationScenario_rawRotational; + std::vector perSimulationScenario_translational; + std::vector perSimulationScenario_rotational; + std::vector perSimulationScenario_total; + std::vector perSimulationScenario_total_unweighted; - std::vector perScenario_fullPatternPotentialEnergy; - std::vector objectiveValueHistory; - std::vector objectiveValueHistory_iteration; + } objectiveValue; - inline static std::string DefaultFileName{"OptimizationResults.json"}; + std::vector perScenario_fullPatternPotentialEnergy; + std::vector objectiveValueHistory; + std::vector objectiveValueHistory_iteration; - struct CSVExportingSettings - { - bool exportPE{false}; - bool exportIterationOfMinima{false}; - bool exportRawObjectiveValue{false}; - CSVExportingSettings() {} - }; + inline static std::string DefaultFileName{"OptimizationResults.json"}; - const CSVExportingSettings exportSettings; - struct JsonKeys - { - inline static std::string optimizationVariables{"OptimizationVariables"}; - inline static std::string baseTriangle{"BaseTriangle"}; - inline static std::string Label{"Label"}; - inline static std::string FullPatternLabel{"FullPatternLabel"}; - inline static std::string Settings{"OptimizationSettings"}; - inline static std::string FullPatternPotentialEnergies{"PE"}; - inline static std::string fullPatternYoungsModulus{"youngsModulus"}; - }; + struct CSVExportingSettings { + bool exportPE{false}; + bool exportIterationOfMinima{false}; + bool exportRawObjectiveValue{false}; + CSVExportingSettings() {} + }; - void saveObjectiveValuePlot(const std::filesystem::path &outputImageDirPath) const - { - std::vector scenarioLabels(objectiveValue.perSimulationScenario_total.size()); - const double colorAxial = 1; - const double colorShear = 3; - const double colorBending = 5; - const double colorDome = 0.1; - const double colorSaddle = 0; - std::vector colors(objectiveValue.perSimulationScenario_total.size()); - for (int scenarioIndex = 0; scenarioIndex < scenarioLabels.size(); scenarioIndex++) { - scenarioLabels[scenarioIndex] = reducedPatternSimulationJobs[scenarioIndex]->getLabel(); - if (scenarioLabels[scenarioIndex].rfind("Axial", 0) == 0) { - colors[scenarioIndex] = colorAxial; + const CSVExportingSettings exportSettings; + struct JsonKeys { + inline static std::string optimizationVariables{"OptimizationVariables"}; + inline static std::string baseTriangle{"BaseTriangle"}; + inline static std::string Label{"Label"}; + inline static std::string FullPatternLabel{"FullPatternLabel"}; + inline static std::string Settings{"OptimizationSettings"}; + inline static std::string FullPatternPotentialEnergies{"PE"}; + inline static std::string fullPatternYoungsModulus{"youngsModulus"}; + }; - } else if (scenarioLabels[scenarioIndex].rfind("Shear", 0) == 0) { - colors[scenarioIndex] = colorShear; + void saveObjectiveValuePlot( + const std::filesystem::path& outputImageDirPath) const { + std::vector scenarioLabels( + objectiveValue.perSimulationScenario_total.size()); + const double colorAxial = 1; + const double colorShear = 3; + const double colorBending = 5; + const double colorDome = 0.1; + const double colorSaddle = 0; + std::vector colors( + objectiveValue.perSimulationScenario_total.size()); + for (int scenarioIndex = 0; scenarioIndex < scenarioLabels.size(); + scenarioIndex++) { + scenarioLabels[scenarioIndex] = + pSimulationJobs_reducedModel[scenarioIndex]->getLabel(); + if (scenarioLabels[scenarioIndex].rfind("Axial", 0) == 0) { + colors[scenarioIndex] = colorAxial; - } else if (scenarioLabels[scenarioIndex].rfind("Bending", 0) == 0) { - colors[scenarioIndex] = colorBending; + } else if (scenarioLabels[scenarioIndex].rfind("Shear", 0) == 0) { + colors[scenarioIndex] = colorShear; - } else if (scenarioLabels[scenarioIndex].rfind("Dome", 0) == 0) { - colors[scenarioIndex] = colorDome; - } else if (scenarioLabels[scenarioIndex].rfind("Saddle", 0) == 0) { - colors[scenarioIndex] = colorSaddle; - } else { - std::cerr << "Label could not be identified" << std::endl; - } - } - std::vector y(objectiveValue.perSimulationScenario_total.size()); - for (int scenarioIndex = 0; scenarioIndex < scenarioLabels.size(); scenarioIndex++) { - y[scenarioIndex] - // = optimizationResults.objectiveValue.perSimulationScenario_rawTranslational[scenarioIndex] - // + optimizationResults.objectiveValue.perSimulationScenario_rawRotational[scenarioIndex]; - = objectiveValue.perSimulationScenario_total_unweighted[scenarioIndex]; - } - std::vector x = matplot::linspace(0, y.size() - 1, y.size()); - std::vector markerSizes(y.size(), 5); - Utilities::createPlot("scenario index", - "error", - x, - y, - markerSizes, - colors, - std::filesystem::path(outputImageDirPath) - .append("perScenarioObjectiveValues.svg")); + } else if (scenarioLabels[scenarioIndex].rfind("Bending", 0) == 0) { + colors[scenarioIndex] = colorBending; + + } else if (scenarioLabels[scenarioIndex].rfind("Dome", 0) == 0) { + colors[scenarioIndex] = colorDome; + } else if (scenarioLabels[scenarioIndex].rfind("Saddle", 0) == 0) { + colors[scenarioIndex] = colorSaddle; + } else { + std::cerr << "Label could not be identified" << std::endl; + } + } + std::vector y(objectiveValue.perSimulationScenario_total.size()); + for (int scenarioIndex = 0; scenarioIndex < scenarioLabels.size(); + scenarioIndex++) { + y[scenarioIndex] + // = + // optimizationResults.objectiveValue.perSimulationScenario_rawTranslational[scenarioIndex] + // + + // optimizationResults.objectiveValue.perSimulationScenario_rawRotational[scenarioIndex]; + = objectiveValue + .perSimulationScenario_total_unweighted[scenarioIndex]; + } + std::vector x = matplot::linspace(0, y.size() - 1, y.size()); + std::vector markerSizes(y.size(), 5); + Utilities::createPlot("scenario index", "error", x, y, markerSizes, colors, + std::filesystem::path(outputImageDirPath) + .append("perScenarioObjectiveValues.svg")); + } + + void save(const std::string& saveToPath, + const bool shouldExportDebugFiles = false) { + // clear directory + if (std::filesystem::exists(saveToPath)) { + for (const auto& entry : + std::filesystem::directory_iterator(saveToPath)) { + std::error_code ec; + std::filesystem::remove_all(entry.path(), ec); + } + } + std::filesystem::create_directories(saveToPath); + + // Save optimal X + nlohmann::json json_optimizationResults; + json_optimizationResults[JsonKeys::Label] = label; + if (wasSuccessful) { + std::string jsonValue_optimizationVariables; + for (const auto& optimalXNameValuePair : optimalXNameValuePairs) { + jsonValue_optimizationVariables.append(optimalXNameValuePair.first + + ","); + } + jsonValue_optimizationVariables + .pop_back(); // for deleting the last comma + json_optimizationResults[JsonKeys::optimizationVariables] = + jsonValue_optimizationVariables; + + for (const auto& optimalXNameValuePair : optimalXNameValuePairs) { + json_optimizationResults[optimalXNameValuePair.first] = + optimalXNameValuePair.second; + } + } + // base triangle + json_optimizationResults[JsonKeys::baseTriangle] = std::vector{ + baseTriangle.cP0(0)[0], baseTriangle.cP0(0)[1], baseTriangle.cP0(0)[2], + baseTriangle.cP1(0)[0], baseTriangle.cP1(0)[1], baseTriangle.cP1(0)[2], + baseTriangle.cP2(0)[0], baseTriangle.cP2(0)[1], baseTriangle.cP2(0)[2]}; + baseTrianglePattern.save(std::filesystem::path(saveToPath).string()); + json_optimizationResults[JsonKeys::FullPatternLabel] = + baseTrianglePattern.getLabel(); + + // potential energies + // const int numberOfSimulationJobs = + // fullPatternSimulationJobs.size(); std::vector + // fullPatternPE(numberOfSimulationJobs); for (int + // simulationScenarioIndex = 0; simulationScenarioIndex < + // numberOfSimulationJobs; + // simulationScenarioIndex++) { + // fullPatternPE[simulationScenarioIndex] + // = + // perScenario_fullPatternPotentialEnergy[simulationScenarioIndex]; + // } + // json_optimizationResults[JsonKeys::FullPatternPotentialEnergies] + // = fullPatternPE; + ////Save to json file + std::filesystem::path jsonFilePath( + std::filesystem::path(saveToPath).append(DefaultFileName)); + std::ofstream jsonFile_optimizationResults(jsonFilePath.string()); + jsonFile_optimizationResults << json_optimizationResults; + + /*TODO: Refactor since the meshes are saved for each simulation scenario + * although they do not change*/ + // Save jobs and meshes for each simulation scenario + + if (shouldExportDebugFiles) { + // Save the reduced and full patterns + const std::filesystem::path simulationJobsPath( + std::filesystem::path(saveToPath).append("SimulationJobs")); + const int numberOfSimulationJobs = pSimulationJobs_pattern.size(); + for (int simulationScenarioIndex = 0; + simulationScenarioIndex < numberOfSimulationJobs; + simulationScenarioIndex++) { + const std::shared_ptr& pFullPatternSimulationJob = + pSimulationJobs_pattern[simulationScenarioIndex]; + std::filesystem::path simulationJobFolderPath( + std::filesystem::path(simulationJobsPath) + .append(std::to_string(simulationScenarioIndex) + "_" + + pFullPatternSimulationJob->label)); + std::filesystem::create_directories(simulationJobFolderPath); + const auto fullPatternDirectoryPath = + std::filesystem::path(simulationJobFolderPath).append("Full"); + std::filesystem::create_directory(fullPatternDirectoryPath); + pFullPatternSimulationJob->save(fullPatternDirectoryPath.string()); + const std::shared_ptr& pReducedPatternSimulationJob = + pSimulationJobs_reducedModel[simulationScenarioIndex]; + const auto reducedPatternDirectoryPath = + std::filesystem::path(simulationJobFolderPath).append("Reduced"); + if (!std::filesystem::exists(reducedPatternDirectoryPath)) { + std::filesystem::create_directory(reducedPatternDirectoryPath); + } + pReducedPatternSimulationJob->save( + reducedPatternDirectoryPath.string()); } - void save(const std::string &saveToPath, const bool shouldExportDebugFiles = false) - { - //clear directory - if (std::filesystem::exists(saveToPath)) { - for (const auto &entry : std::filesystem::directory_iterator(saveToPath)) { - std::error_code ec; - std::filesystem::remove_all(entry.path(), ec); - } - } - std::filesystem::create_directories(saveToPath); + // constexpr bool shouldSaveObjectiveValuePlot = + // shouldExportDebugFiles; if (shouldSaveObjectiveValuePlot) + // { + saveObjectiveValuePlot(saveToPath); + // } + } + csvFile csv_resultsLocalFile( + std::filesystem::path(saveToPath).append("results.csv"), true); + csv_resultsLocalFile << "Name"; + writeHeaderTo(csv_resultsLocalFile); + settings.writeHeaderTo(csv_resultsLocalFile); + csv_resultsLocalFile << endrow; + csv_resultsLocalFile << baseTrianglePattern.getLabel(); + writeResultsTo(csv_resultsLocalFile); + settings.writeSettingsTo(csv_resultsLocalFile); + csv_resultsLocalFile << endrow; - //Save optimal X - nlohmann::json json_optimizationResults; - json_optimizationResults[JsonKeys::Label] = label; - if (wasSuccessful) { - std::string jsonValue_optimizationVariables; - for (const auto &optimalXNameValuePair : optimalXNameValuePairs) { - jsonValue_optimizationVariables.append(optimalXNameValuePair.first + ","); - } - jsonValue_optimizationVariables.pop_back(); // for deleting the last comma - json_optimizationResults[JsonKeys::optimizationVariables] - = jsonValue_optimizationVariables; + // save minima info + // std::filesystem::path csvFilepathMinimaInfo = + // std::filesystem::path(saveToPath) + // .append("minimaInfo.csv"); + // csvFile csv_minimaInfo(csvFilepathMinimaInfo, false); + // writeMinimaInfoTo(csv_minimaInfo); - for (const auto &optimalXNameValuePair : optimalXNameValuePairs) { - json_optimizationResults[optimalXNameValuePair.first] = optimalXNameValuePair - .second; - } - } - //base triangle - json_optimizationResults[JsonKeys::baseTriangle] - = std::vector{baseTriangle.cP0(0)[0], - baseTriangle.cP0(0)[1], - baseTriangle.cP0(0)[2], - baseTriangle.cP1(0)[0], - baseTriangle.cP1(0)[1], - baseTriangle.cP1(0)[2], - baseTriangle.cP2(0)[0], - baseTriangle.cP2(0)[1], - baseTriangle.cP2(0)[2]}; - baseTriangleFullPattern.save(std::filesystem::path(saveToPath).string()); - json_optimizationResults[JsonKeys::FullPatternLabel] = baseTriangleFullPattern.getLabel(); - - //potential energies - // const int numberOfSimulationJobs = fullPatternSimulationJobs.size(); - // std::vector fullPatternPE(numberOfSimulationJobs); - // for (int simulationScenarioIndex = 0; simulationScenarioIndex < numberOfSimulationJobs; - // simulationScenarioIndex++) { - // fullPatternPE[simulationScenarioIndex] - // = perScenario_fullPatternPotentialEnergy[simulationScenarioIndex]; - // } - // json_optimizationResults[JsonKeys::FullPatternPotentialEnergies] = fullPatternPE; - json_optimizationResults[JsonKeys::fullPatternYoungsModulus] = fullPatternYoungsModulus; - ////Save to json file - std::filesystem::path jsonFilePath( - std::filesystem::path(saveToPath).append(DefaultFileName)); - std::ofstream jsonFile_optimizationResults(jsonFilePath.string()); - jsonFile_optimizationResults << json_optimizationResults; - - /*TODO: Refactor since the meshes are saved for each simulation scenario although they do not change*/ - //Save jobs and meshes for each simulation scenario - - if (shouldExportDebugFiles) { - //Save the reduced and full patterns - const std::filesystem::path simulationJobsPath( - std::filesystem::path(saveToPath).append("SimulationJobs")); - const int numberOfSimulationJobs = fullPatternSimulationJobs.size(); - for (int simulationScenarioIndex = 0; - simulationScenarioIndex < numberOfSimulationJobs; - simulationScenarioIndex++) { - const std::shared_ptr &pFullPatternSimulationJob - = fullPatternSimulationJobs[simulationScenarioIndex]; - std::filesystem::path simulationJobFolderPath( - std::filesystem::path(simulationJobsPath) - .append(std::to_string(simulationScenarioIndex) + "_" - + pFullPatternSimulationJob->label)); - std::filesystem::create_directories(simulationJobFolderPath); - const auto fullPatternDirectoryPath - = std::filesystem::path(simulationJobFolderPath).append("Full"); - std::filesystem::create_directory(fullPatternDirectoryPath); - pFullPatternSimulationJob->save(fullPatternDirectoryPath.string()); - const std::shared_ptr &pReducedPatternSimulationJob - = reducedPatternSimulationJobs[simulationScenarioIndex]; - const auto reducedPatternDirectoryPath - = std::filesystem::path(simulationJobFolderPath).append("Reduced"); - if (!std::filesystem::exists(reducedPatternDirectoryPath)) { - std::filesystem::create_directory(reducedPatternDirectoryPath); - } - pReducedPatternSimulationJob->save(reducedPatternDirectoryPath.string()); - } - - // constexpr bool shouldSaveObjectiveValuePlot = shouldExportDebugFiles; - // if (shouldSaveObjectiveValuePlot) { - saveObjectiveValuePlot(saveToPath); - // } - } - csvFile csv_resultsLocalFile(std::filesystem::path(saveToPath).append("results.csv"), - true); - csv_resultsLocalFile << "Name"; - writeHeaderTo(csv_resultsLocalFile); - settings.writeHeaderTo(csv_resultsLocalFile); - csv_resultsLocalFile << endrow; - csv_resultsLocalFile << baseTriangleFullPattern.getLabel(); - writeResultsTo(csv_resultsLocalFile); - settings.writeSettingsTo(csv_resultsLocalFile); - csv_resultsLocalFile << endrow; - - //save minima info - // std::filesystem::path csvFilepathMinimaInfo = std::filesystem::path(saveToPath) - // .append("minimaInfo.csv"); - // csvFile csv_minimaInfo(csvFilepathMinimaInfo, false); - // writeMinimaInfoTo(csv_minimaInfo); - - settings.save(saveToPath); + settings.save(saveToPath); #ifdef POLYSCOPE_DEFINED - std::cout << "Saved optimization results to:" << saveToPath << std::endl; + std::cout << "Saved optimization results to:" << saveToPath << std::endl; #endif + } + + 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(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(DefaultFileName)); + ifs >> json_optimizationResults; + + // std::cout << json_optimizationResults.dump() << std::endl; + + label = json_optimizationResults.at(JsonKeys::Label); + std::string optimizationVariablesString = + *json_optimizationResults.find(JsonKeys::optimizationVariables); + std::string optimizationVariablesDelimeter = ","; + size_t pos = 0; + std::vector optimizationVariablesNames; + while ((pos = optimizationVariablesString.find( + optimizationVariablesDelimeter)) != std::string::npos) { + const std::string variableName = + optimizationVariablesString.substr(0, pos); + optimizationVariablesNames.push_back(variableName); + optimizationVariablesString.erase( + 0, pos + optimizationVariablesDelimeter.length()); + } + optimizationVariablesNames.push_back( + optimizationVariablesString); // add last variable name + + optimalXNameValuePairs.resize(optimizationVariablesNames.size()); + for (int xVariable_index = 0; + xVariable_index < optimizationVariablesNames.size(); + xVariable_index++) { + const std::string xVariable_name = + optimizationVariablesNames[xVariable_index]; + const double xVariable_value = + *json_optimizationResults.find(xVariable_name); + optimalXNameValuePairs[xVariable_index] = + std::make_pair(xVariable_name, xVariable_value); + } + + const std::string fullPatternLabel = + json_optimizationResults.at(JsonKeys::FullPatternLabel); + if (!baseTrianglePattern.load(std::filesystem::path(loadFromPath) + .append(fullPatternLabel + ".ply") + .string())) { + if (!baseTrianglePattern.load( + std::filesystem::path(loadFromPath) + .append(loadFromPath.stem().string() + ".ply") + .string())) { + if (!baseTrianglePattern.load(std::filesystem::path(loadFromPath) + .append(fullPatternLabel + ".obj") + .string())) { + baseTrianglePattern.load( + std::filesystem::path(loadFromPath) + .append(loadFromPath.stem().string() + ".obj") + .string()); + } } + } - 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(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(DefaultFileName)); - ifs >> json_optimizationResults; + std::vector baseTriangleVertices = + json_optimizationResults.at(JsonKeys::baseTriangle); + baseTriangle.P0(0) = + CoordType(baseTriangleVertices[0], baseTriangleVertices[1], + baseTriangleVertices[2]); + baseTriangle.P1(0) = + CoordType(baseTriangleVertices[3], baseTriangleVertices[4], + baseTriangleVertices[5]); + baseTriangle.P2(0) = + CoordType(baseTriangleVertices[6], baseTriangleVertices[7], + baseTriangleVertices[8]); + if (json_optimizationResults.contains(JsonKeys::fullPatternYoungsModulus)) { + settings.youngsModulus_pattern = + json_optimizationResults.at(JsonKeys::fullPatternYoungsModulus); + } else { + settings.youngsModulus_pattern = 1 * 1e9; + } + const std::filesystem::path folderPath_simulationJobs( + std::filesystem::path(loadFromPath).append("SimulationJobs")); + if (shouldLoadDebugFiles && + std::filesystem::exists(folderPath_simulationJobs)) { + const std::vector scenariosSortedByName = [&]() { + std::vector sortedByName; + for (auto& entry : + std::filesystem::directory_iterator(folderPath_simulationJobs)) + sortedByName.push_back(entry.path()); - // std::cout << json_optimizationResults.dump() << std::endl; - - label = json_optimizationResults.at(JsonKeys::Label); - std::string optimizationVariablesString = *json_optimizationResults.find( - JsonKeys::optimizationVariables); - std::string optimizationVariablesDelimeter = ","; - size_t pos = 0; - std::vector optimizationVariablesNames; - while ((pos = optimizationVariablesString.find(optimizationVariablesDelimeter)) - != std::string::npos) { - const std::string variableName = optimizationVariablesString.substr(0, pos); - optimizationVariablesNames.push_back(variableName); - optimizationVariablesString.erase(0, pos + optimizationVariablesDelimeter.length()); - } - optimizationVariablesNames.push_back(optimizationVariablesString); //add last variable name - - optimalXNameValuePairs.resize(optimizationVariablesNames.size()); - for (int xVariable_index = 0; xVariable_index < optimizationVariablesNames.size(); - xVariable_index++) { - const std::string xVariable_name = optimizationVariablesNames[xVariable_index]; - const double xVariable_value = *json_optimizationResults.find(xVariable_name); - optimalXNameValuePairs[xVariable_index] = std::make_pair(xVariable_name, - xVariable_value); - } - - const std::string fullPatternLabel = json_optimizationResults.at( - JsonKeys::FullPatternLabel); - if (!baseTriangleFullPattern.load( - std::filesystem::path(loadFromPath).append(fullPatternLabel + ".ply").string())) { - baseTriangleFullPattern.load(std::filesystem::path(loadFromPath) - .append(loadFromPath.stem().string() + ".ply") - .string()); - } - - std::vector baseTriangleVertices = json_optimizationResults.at( - JsonKeys::baseTriangle); - baseTriangle.P0(0) = CoordType(baseTriangleVertices[0], - baseTriangleVertices[1], - baseTriangleVertices[2]); - baseTriangle.P1(0) = CoordType(baseTriangleVertices[3], - baseTriangleVertices[4], - baseTriangleVertices[5]); - baseTriangle.P2(0) = CoordType(baseTriangleVertices[6], - baseTriangleVertices[7], - baseTriangleVertices[8]); - if (json_optimizationResults.contains(JsonKeys::fullPatternYoungsModulus)) { - fullPatternYoungsModulus = json_optimizationResults.at( - JsonKeys::fullPatternYoungsModulus); - } else { - fullPatternYoungsModulus = 1 * 1e9; - } - if (shouldLoadDebugFiles) { - const std::filesystem::path simulationJobsFolderPath( - std::filesystem::path(loadFromPath).append("SimulationJobs")); - - 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); - return sortedByName; - }(); - for (const auto &simulationScenarioPath : scenariosSortedByName) { - if (!std::filesystem::is_directory(simulationScenarioPath)) { - continue; - } - // 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_elements(*this, reducedJob.pMesh); - reducedPatternSimulationJobs.push_back( - std::make_shared(reducedJob)); - } - } - settings.load(std::filesystem::path(loadFromPath).append(Settings::defaultFilename)); - - return true; + std::sort(sortedByName.begin(), sortedByName.end(), + &Utilities::compareNat); + return sortedByName; + }(); + for (const auto& simulationScenarioPath : scenariosSortedByName) { + if (!std::filesystem::is_directory(simulationScenarioPath)) { + continue; + } + // 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, settings.youngsModulus_pattern); + pSimulationJobs_pattern.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_elements(*this, reducedJob.pMesh); + pSimulationJobs_reducedModel.push_back( + std::make_shared(reducedJob)); } + } + settings.load( + std::filesystem::path(loadFromPath).append(Settings::defaultFilename)); - template - static void applyOptimizationResults_reducedModel_nonFanned( - const ReducedModelOptimization::Results &reducedPattern_optimizationResults, - const vcg::Triangle3 &patternBaseTriangle, - MeshType &reducedModel) - { - std::unordered_map - optimalXVariables(reducedPattern_optimizationResults.optimalXNameValuePairs.begin(), - reducedPattern_optimizationResults.optimalXNameValuePairs.end()); - assert( - (optimalXVariables.contains("R") && optimalXVariables.contains("Theta")) - || (optimalXVariables.contains("HexSize") && optimalXVariables.contains("HexAngle"))); - if (optimalXVariables.contains("HexSize")) { - applyOptimizationResults_reducedModel_nonFanned(optimalXVariables.at("HexSize"), - optimalXVariables.at("HexAngle"), - patternBaseTriangle, - reducedModel); - return; - } - applyOptimizationResults_reducedModel_nonFanned(optimalXVariables.at("R"), - optimalXVariables.at("Theta"), - patternBaseTriangle, - reducedModel); + return true; + } + + template + static void applyOptimizationResults_reducedModel_nonFanned( + const ReducedModelOptimization::Results& + reducedPattern_optimizationResults, + const vcg::Triangle3& patternBaseTriangle, + MeshType& reducedModel) { + std::unordered_map optimalXVariables( + reducedPattern_optimizationResults.optimalXNameValuePairs.begin(), + reducedPattern_optimizationResults.optimalXNameValuePairs.end()); + assert((optimalXVariables.contains("R") && + optimalXVariables.contains("Theta")) || + (optimalXVariables.contains("HexSize") && + optimalXVariables.contains("HexAngle"))); + if (optimalXVariables.contains("HexSize")) { + applyOptimizationResults_reducedModel_nonFanned( + optimalXVariables.at("HexSize"), optimalXVariables.at("HexAngle"), + patternBaseTriangle, reducedModel); + return; + } + applyOptimizationResults_reducedModel_nonFanned( + optimalXVariables.at("R"), optimalXVariables.at("Theta"), + patternBaseTriangle, reducedModel); + } + + template + static void applyOptimizationResults_reducedModel_nonFanned( + const double& hexSize, + const double& hexAngle, + const vcg::Triangle3& patternBaseTriangle, + MeshType& reducedModel) { + // Set optimal geometrical params of the reduced pattern + // CoordType center_barycentric(1, 0, 0); + // CoordType interfaceEdgeMiddle_barycentric(0, 0.5, 0.5); + // CoordType movableVertex_barycentric( + // (center_barycentric * (1 - hexSize) + + // interfaceEdgeMiddle_barycentric)); + CoordType movableVertex_barycentric(1 - hexSize, hexSize / 2, hexSize / 2); + + reducedModel.vert[0].P() = + patternBaseTriangle.cP(0) * movableVertex_barycentric[0] + + patternBaseTriangle.cP(1) * movableVertex_barycentric[1] + + patternBaseTriangle.cP(2) * movableVertex_barycentric[2]; + if (hexAngle != 0) { + reducedModel.vert[0].P() = + vcg::RotationMatrix(CoordType{0, 0, 1}, vcg::math::ToRad(hexAngle)) * + reducedModel.vert[0].cP(); + } + // for (int rotationCounter = 0; + // rotationCounter < ReducedModelOptimizer::fanSize; + // rotationCounter++) { + // pReducedPatternSimulationEdgeMesh->vert[2 * rotationCounter].P() + // = + // vcg::RotationMatrix(ReducedModelOptimizer::patternPlaneNormal, + // vcg::math::ToRad(60.0 * + // rotationCounter)) + // * baseTriangleMovableVertexPosition; + // } + // reducedPattern.registerForDrawing(); + // polyscope::show(); + // CoordType p0 = reducedPattern.vert[0].P(); + // CoordType p1 = reducedPattern.vert[1].P(); + // int i = 0; + // i++; + } + + static void applyOptimizationResults_elements( + const ReducedModelOptimization::Results& + reducedPattern_optimizationResults, + const std::shared_ptr& + pReducedModel_SimulationEdgeMesh) { + assert(CrossSectionType::name == RectangularBeamDimensions::name); + // Set reduced parameters fron the optimization results + std::unordered_map optimalXVariables( + reducedPattern_optimizationResults.optimalXNameValuePairs.begin(), + reducedPattern_optimizationResults.optimalXNameValuePairs.end()); + + const std::string ALabel = "A"; + if (optimalXVariables.contains(ALabel)) { + const double A = optimalXVariables.at(ALabel); + const double beamWidth = std::sqrt(A); + const double beamHeight = beamWidth; + CrossSectionType elementDimensions(beamWidth, beamHeight); + for (int ei = 0; ei < pReducedModel_SimulationEdgeMesh->EN(); ei++) { + Element& e = pReducedModel_SimulationEdgeMesh->elements[ei]; + e.setDimensions(elementDimensions); } + } - template - static void applyOptimizationResults_reducedModel_nonFanned( - const double &hexSize, - const double &hexAngle, - const vcg::Triangle3 &patternBaseTriangle, - MeshType &reducedModel) - { - //Set optimal geometrical params of the reduced pattern - // CoordType center_barycentric(1, 0, 0); - // CoordType interfaceEdgeMiddle_barycentric(0, 0.5, 0.5); - // CoordType movableVertex_barycentric( - // (center_barycentric * (1 - hexSize) + interfaceEdgeMiddle_barycentric)); - CoordType movableVertex_barycentric(1 - hexSize, hexSize / 2, hexSize / 2); - - reducedModel.vert[0].P() = patternBaseTriangle.cP(0) * movableVertex_barycentric[0] - + patternBaseTriangle.cP(1) * movableVertex_barycentric[1] - + patternBaseTriangle.cP(2) * movableVertex_barycentric[2]; - if (hexAngle != 0) { - reducedModel.vert[0].P() = vcg::RotationMatrix(CoordType{0, 0, 1}, - vcg::math::ToRad(hexAngle)) - * reducedModel.vert[0].cP(); - } - // for (int rotationCounter = 0; - // rotationCounter < ReducedModelOptimizer::fanSize; rotationCounter++) { - // pReducedPatternSimulationMesh->vert[2 * rotationCounter].P() - // = vcg::RotationMatrix(ReducedModelOptimizer::patternPlaneNormal, - // vcg::math::ToRad(60.0 * rotationCounter)) - // * baseTriangleMovableVertexPosition; - // } - // reducedPattern.registerForDrawing(); - // polyscope::show(); - // CoordType p0 = reducedPattern.vert[0].P(); - // CoordType p1 = reducedPattern.vert[1].P(); - // int i = 0; - // i++; + const double poissonsRatio = 0.3; + const std::string ymLabel = "E"; + if (optimalXVariables.contains(ymLabel)) { + const double E = optimalXVariables.at(ymLabel); + const ElementMaterial elementMaterial(poissonsRatio, E); + for (int ei = 0; ei < pReducedModel_SimulationEdgeMesh->EN(); ei++) { + Element& e = pReducedModel_SimulationEdgeMesh->elements[ei]; + e.setMaterial(elementMaterial); } + } - static void applyOptimizationResults_elements( - const ReducedModelOptimization::Results &reducedPattern_optimizationResults, - const std::shared_ptr &pReducedPattern_simulationMesh) - { - assert(CrossSectionType::name == RectangularBeamDimensions::name); - // Set reduced parameters fron the optimization results - std::unordered_map - optimalXVariables(reducedPattern_optimizationResults.optimalXNameValuePairs.begin(), - reducedPattern_optimizationResults.optimalXNameValuePairs.end()); - - const std::string ALabel = "A"; - if (optimalXVariables.contains(ALabel)) { - const double A = optimalXVariables.at(ALabel); - const double beamWidth = std::sqrt(A); - const double beamHeight = beamWidth; - CrossSectionType elementDimensions(beamWidth, beamHeight); - for (int ei = 0; ei < pReducedPattern_simulationMesh->EN(); ei++) { - Element &e = pReducedPattern_simulationMesh->elements[ei]; - e.setDimensions(elementDimensions); - } - } - - const double poissonsRatio = 0.3; - const std::string ymLabel = "E"; - if (optimalXVariables.contains(ymLabel)) { - const double E = optimalXVariables.at(ymLabel); - const ElementMaterial elementMaterial(poissonsRatio, E); - for (int ei = 0; ei < pReducedPattern_simulationMesh->EN(); ei++) { - Element &e = pReducedPattern_simulationMesh->elements[ei]; - e.setMaterial(elementMaterial); - } - } - - const std::string JLabel = "J"; - if (optimalXVariables.contains(JLabel)) { - const double J = optimalXVariables.at(JLabel); - for (int ei = 0; ei < pReducedPattern_simulationMesh->EN(); ei++) { - Element &e = pReducedPattern_simulationMesh->elements[ei]; - e.dimensions.inertia.J = J; - } - } - - const std::string I2Label = "I2"; - if (optimalXVariables.contains(I2Label)) { - const double I2 = optimalXVariables.at(I2Label); - for (int ei = 0; ei < pReducedPattern_simulationMesh->EN(); ei++) { - Element &e = pReducedPattern_simulationMesh->elements[ei]; - e.dimensions.inertia.I2 = I2; - } - } - - const std::string I3Label = "I3"; - if (optimalXVariables.contains(I3Label)) { - const double I3 = optimalXVariables.at(I3Label); - for (int ei = 0; ei < pReducedPattern_simulationMesh->EN(); ei++) { - Element &e = pReducedPattern_simulationMesh->elements[ei]; - e.dimensions.inertia.I3 = I3; - } - } - pReducedPattern_simulationMesh->reset(); + const std::string JLabel = "J"; + if (optimalXVariables.contains(JLabel)) { + const double J = optimalXVariables.at(JLabel); + for (int ei = 0; ei < pReducedModel_SimulationEdgeMesh->EN(); ei++) { + Element& e = pReducedModel_SimulationEdgeMesh->elements[ei]; + e.dimensions.inertia.J = J; } + } + + const std::string I2Label = "I2"; + if (optimalXVariables.contains(I2Label)) { + const double I2 = optimalXVariables.at(I2Label); + for (int ei = 0; ei < pReducedModel_SimulationEdgeMesh->EN(); ei++) { + Element& e = pReducedModel_SimulationEdgeMesh->elements[ei]; + e.dimensions.inertia.I2 = I2; + } + } + + const std::string I3Label = "I3"; + if (optimalXVariables.contains(I3Label)) { + const double I3 = optimalXVariables.at(I3Label); + for (int ei = 0; ei < pReducedModel_SimulationEdgeMesh->EN(); ei++) { + Element& e = pReducedModel_SimulationEdgeMesh->elements[ei]; + e.dimensions.inertia.I3 = I3; + } + } + pReducedModel_SimulationEdgeMesh->reset(); + } #if POLYSCOPE_DEFINED - 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::patternInitial); - reducedPatternSimulationJobs[0]->pMesh->registerForDrawing(Colors::reducedInitial, false); + void draw(const std::vector& desiredSimulationScenariosIndices = + std::vector()) const { + PolyscopeInterface::init(); + assert(pSimulationJobs_pattern.size() == + pSimulationJobs_reducedModel.size()); + pSimulationJobs_pattern[0]->pMesh->registerForDrawing( + Colors::patternInitial); + pSimulationJobs_reducedModel[0]->pMesh->registerForDrawing( + Colors::reducedInitial, false); - 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::patternDeformed, 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 = pSimulationJobs_pattern.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; } -#endif // POLYSCOPE_DEFINED - void saveMeshFiles() const { - const int numberOfSimulationJobs = fullPatternSimulationJobs.size(); - assert(numberOfSimulationJobs != 0 && - fullPatternSimulationJobs.size() == - reducedPatternSimulationJobs.size()); + }(); - fullPatternSimulationJobs[0]->pMesh->save( - "undeformed " + fullPatternSimulationJobs[0]->pMesh->getLabel() + ".ply"); - reducedPatternSimulationJobs[0]->pMesh->save( - "undeformed " + reducedPatternSimulationJobs[0]->pMesh->getLabel() + ".ply"); - DRMSimulationModel simulator_drm; - LinearSimulationModel simulator_linear; - for (int simulationJobIndex = 0; simulationJobIndex < numberOfSimulationJobs; - simulationJobIndex++) { - // Drawing of full pattern results - const std::shared_ptr &pFullPatternSimulationJob - = fullPatternSimulationJobs[simulationJobIndex]; - DRMSimulationModel::Settings drmSettings; - SimulationResults fullModelResults - = simulator_drm.executeSimulation(pFullPatternSimulationJob, drmSettings); - fullModelResults.saveDeformedModel(); + for (const int& simulationJobIndex : scenariosToDraw) { + // Drawing of full pattern results + const std::shared_ptr& pSimulationJob_pattern = + pSimulationJobs_pattern[simulationJobIndex]; + pSimulationJob_pattern->registerForDrawing( + pSimulationJobs_pattern[0]->pMesh->getLabel()); - // Drawing of reduced pattern results - const std::shared_ptr &pReducedPatternSimulationJob - = reducedPatternSimulationJobs[simulationJobIndex]; - SimulationResults reducedModelResults = simulator_linear.executeSimulation( - pReducedPatternSimulationJob); - reducedModelResults.saveDeformedModel(); - } + std::unique_ptr pPatternSimulator = + SimulationModelFactory::create( + settings.simulationModelLabel_groundTruth); + pPatternSimulator->setStructure(pSimulationJob_pattern->pMesh); + SimulationResults simulationResults_pattern = + pPatternSimulator->executeSimulation(pSimulationJob_pattern); + // ChronosEulerSimulationModel simulator_pattern; + // simulator_pattern.settings.analysisType = + // ChronosEulerSimulationModel::Settings::AnalysisType::NonLinear; + // SimulationResults simulationResults_pattern = + // simulator_pattern.executeSimulation(pSimulationJob_pattern); + simulationResults_pattern.registerForDrawing(Colors::patternDeformed, + true); + // SimulationResults fullModelLinearResults = + // linearSimulator.executeSimulation(pFullPatternSimulationJob); + // fullModelLinearResults.setLabelPrefix("linear"); + // fullModelLinearResults.registerForDrawing(Colors::fullDeformed,false); + // Drawing of reduced pattern results + const std::shared_ptr& pSimulationJob_reducedModel = + pSimulationJobs_reducedModel[simulationJobIndex]; + // pReducedPatternSimulationJob->pMesh->registerForDrawing(); + // polyscope::show(); + // SimulationResults reducedModelResults = + // drmSimulator.executeSimulation( + // pReducedPatternSimulationJob); + // reducedModelResults.registerForDrawing(Colors::reducedDeformed, + // false); + // SimulationResults reducedModelResults + // = + // drmSimulator.executeSimulation(pReducedPatternSimulationJob, + // DRMSimulationModel::Settings()); + std::unique_ptr pSimulator_reducedModel = + SimulationModelFactory::create( + settings.simulationModelLabel_reducedModel); + pSimulator_reducedModel->setStructure(pSimulationJob_reducedModel->pMesh); + // ChronosEulerSimulationModel simulator_reducedModel; + // simulator_reducedModel.settings.analysisType = + // ChronosEulerSimulationModel::Settings::AnalysisType::Linear; + SimulationResults simulationResults_reducedModel = + pSimulator_reducedModel->executeSimulation( + pSimulationJob_reducedModel); + simulationResults_reducedModel.registerForDrawing(Colors::reducedDeformed, + true); + polyscope::options::programName = + pSimulationJobs_pattern[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/" + + pSimulationJobs_pattern[0]->pMesh->getLabel() + "_" + + pSimulationJob_pattern->getLabel(); + polyscope::screenshot(screenshotFilename, false); + pSimulationJob_pattern->unregister( + pSimulationJobs_pattern[0]->pMesh->getLabel()); + simulationResults_reducedModel.unregister(); + simulationResults_pattern.unregister(); + // double error = + // computeError(reducedModelLinearResults.displacements, + // fullModelResults.displacements); + // std::cout << "Error of simulation scenario " + // << + // simulationScenarioStrings[simulationScenarioIndex] + // << " is " << error + // << std::endl; } - - void writeHeaderTo(csvFile &os) const - { - if (exportSettings.exportRawObjectiveValue) { - os << "Total raw Obj value"; - } - os << "Total Obj value"; - if (exportSettings.exportIterationOfMinima) { - os << "Iteration of minima"; - } - for (int simulationScenarioIndex = 0; - simulationScenarioIndex < fullPatternSimulationJobs.size(); - simulationScenarioIndex++) { - const std::string simulationScenarioName - = fullPatternSimulationJobs[simulationScenarioIndex]->getLabel(); - os << "Obj value Trans " + simulationScenarioName; - os << "Obj value Rot " + simulationScenarioName; - os << "Obj value Total " + simulationScenarioName; - } - - if (exportSettings.exportPE) { - for (int simulationScenarioIndex = 0; - simulationScenarioIndex < fullPatternSimulationJobs.size(); - simulationScenarioIndex++) { - const std::string simulationScenarioName - = fullPatternSimulationJobs[simulationScenarioIndex]->getLabel(); - os << "PE " + simulationScenarioName; - } - } - for (const auto &nameValuePair : optimalXNameValuePairs) { - os << nameValuePair.first; - } - os << "Time(s)"; - // os << "#Crashes"; - // os << "notes"; - } - - void writeHeaderTo(std::vector &vectorOfPointersToOutputStreams) const - { - for (csvFile *outputStream : vectorOfPointersToOutputStreams) { - writeHeaderTo(*outputStream); - } - } - - void writeResultsTo(csvFile &os) const - { - if (exportSettings.exportRawObjectiveValue) { - os << objectiveValue.totalRaw; - } - os << objectiveValue.total; - if (exportSettings.exportIterationOfMinima && !objectiveValueHistory_iteration.empty()) { - os << objectiveValueHistory_iteration.back(); - } - for (int simulationScenarioIndex = 0; - simulationScenarioIndex < fullPatternSimulationJobs.size(); - simulationScenarioIndex++) { - os << objectiveValue.perSimulationScenario_translational[simulationScenarioIndex]; - os << objectiveValue.perSimulationScenario_rotational[simulationScenarioIndex]; - os << objectiveValue.perSimulationScenario_total[simulationScenarioIndex]; - } - if (exportSettings.exportPE) { - for (int simulationScenarioIndex = 0; - simulationScenarioIndex < fullPatternSimulationJobs.size(); - simulationScenarioIndex++) { - os << perScenario_fullPatternPotentialEnergy[simulationScenarioIndex]; - } - } - for (const auto &optimalXNameValuePair : optimalXNameValuePairs) { - os << optimalXNameValuePair.second; - } - - os << time; - // if (numberOfSimulationCrashes == 0) { - // os << "-"; - // } else { - // os << numberOfSimulationCrashes; - // } - // os << notes; - } - - void writeResultsTo(std::vector &vectorOfPointersToOutputStreams) const - { - for (csvFile *&outputStream : vectorOfPointersToOutputStreams) { - writeResultsTo(*outputStream); - } - } - - void writeMinimaInfoTo(csvFile &outputCsv) - { - outputCsv << "Iteration"; - outputCsv << "Objective value"; - for (int objectiveValueIndex = 0; objectiveValueIndex < objectiveValueHistory.size(); - objectiveValueIndex++) { - outputCsv.endrow(); - outputCsv << objectiveValueHistory_iteration[objectiveValueIndex]; - outputCsv << objectiveValueHistory[objectiveValueIndex]; - } - } - }; - enum SimulationModelTag { DRM, Linear }; - - inline bool Settings::ObjectiveWeights::operator==(const ObjectiveWeights &other) const - { - return this->translational == other.translational && this->rotational == other.rotational; } - } // namespace ReducedModelOptimization -#endif // REDUCEDMODELOPTIMIZER_STRUCTS_HPP +#endif // POLYSCOPE_DEFINED + void saveMeshFiles() const { + const int numberOfSimulationJobs = pSimulationJobs_pattern.size(); + assert(numberOfSimulationJobs != 0 && + pSimulationJobs_pattern.size() == + pSimulationJobs_reducedModel.size()); + + pSimulationJobs_pattern[0]->pMesh->save( + "undeformed " + pSimulationJobs_pattern[0]->pMesh->getLabel() + ".ply"); + pSimulationJobs_reducedModel[0]->pMesh->save( + "undeformed " + pSimulationJobs_reducedModel[0]->pMesh->getLabel() + + ".ply"); + DRMSimulationModel simulator_drm; + LinearSimulationModel simulator_linear; + for (int simulationJobIndex = 0; + simulationJobIndex < numberOfSimulationJobs; simulationJobIndex++) { + // Drawing of full pattern results + const std::shared_ptr& pFullPatternSimulationJob = + pSimulationJobs_pattern[simulationJobIndex]; + DRMSimulationModel::Settings drmSettings; + SimulationResults fullModelResults = simulator_drm.executeSimulation( + pFullPatternSimulationJob, drmSettings); + fullModelResults.saveDeformedModel(); + + // Drawing of reduced pattern results + const std::shared_ptr& pReducedPatternSimulationJob = + pSimulationJobs_reducedModel[simulationJobIndex]; + SimulationResults reducedModelResults = + simulator_linear.executeSimulation(pReducedPatternSimulationJob); + reducedModelResults.saveDeformedModel(); + } + } + + void writeHeaderTo(csvFile& os) const { + if (exportSettings.exportRawObjectiveValue) { + os << "Total raw Obj value"; + } + os << "Total Obj value"; + if (exportSettings.exportIterationOfMinima) { + os << "Iteration of minima"; + } + for (int simulationScenarioIndex = 0; + simulationScenarioIndex < pSimulationJobs_pattern.size(); + simulationScenarioIndex++) { + const std::string simulationScenarioName = + pSimulationJobs_pattern[simulationScenarioIndex]->getLabel(); + os << "Obj value Trans " + simulationScenarioName; + os << "Obj value Rot " + simulationScenarioName; + os << "Obj value Total " + simulationScenarioName; + } + + if (exportSettings.exportPE) { + for (int simulationScenarioIndex = 0; + simulationScenarioIndex < pSimulationJobs_pattern.size(); + simulationScenarioIndex++) { + const std::string simulationScenarioName = + pSimulationJobs_pattern[simulationScenarioIndex]->getLabel(); + os << "PE " + simulationScenarioName; + } + } + for (const auto& nameValuePair : optimalXNameValuePairs) { + os << nameValuePair.first; + } + os << "Time(s)"; + // os << "#Crashes"; + // os << "notes"; + } + + void writeHeaderTo( + std::vector& vectorOfPointersToOutputStreams) const { + for (csvFile* outputStream : vectorOfPointersToOutputStreams) { + writeHeaderTo(*outputStream); + } + } + + void writeResultsTo(csvFile& os) const { + if (exportSettings.exportRawObjectiveValue) { + os << objectiveValue.totalRaw; + } + os << objectiveValue.total; + if (exportSettings.exportIterationOfMinima && + !objectiveValueHistory_iteration.empty()) { + os << objectiveValueHistory_iteration.back(); + } + for (int simulationScenarioIndex = 0; + simulationScenarioIndex < pSimulationJobs_pattern.size(); + simulationScenarioIndex++) { + os << objectiveValue + .perSimulationScenario_translational[simulationScenarioIndex]; + os << objectiveValue + .perSimulationScenario_rotational[simulationScenarioIndex]; + os << objectiveValue.perSimulationScenario_total[simulationScenarioIndex]; + } + if (exportSettings.exportPE) { + for (int simulationScenarioIndex = 0; + simulationScenarioIndex < pSimulationJobs_pattern.size(); + simulationScenarioIndex++) { + os << perScenario_fullPatternPotentialEnergy[simulationScenarioIndex]; + } + } + for (const auto& optimalXNameValuePair : optimalXNameValuePairs) { + os << optimalXNameValuePair.second; + } + + os << time; + // if (numberOfSimulationCrashes == 0) { + // os << "-"; + // } else { + // os << numberOfSimulationCrashes; + // } + // os << notes; + } + + void writeResultsTo( + std::vector& vectorOfPointersToOutputStreams) const { + for (csvFile*& outputStream : vectorOfPointersToOutputStreams) { + writeResultsTo(*outputStream); + } + } + + void writeMinimaInfoTo(csvFile& outputCsv) { + outputCsv << "Iteration"; + outputCsv << "Objective value"; + for (int objectiveValueIndex = 0; + objectiveValueIndex < objectiveValueHistory.size(); + objectiveValueIndex++) { + outputCsv.endrow(); + outputCsv << objectiveValueHistory_iteration[objectiveValueIndex]; + outputCsv << objectiveValueHistory[objectiveValueIndex]; + } + } +}; +enum SimulationModelTag { DRM, Linear }; + +inline bool Settings::ObjectiveWeights::operator==( + const ObjectiveWeights& other) const { + return this->translational == other.translational && + this->rotational == other.rotational; +} +} // namespace ReducedModelOptimization +#endif // REDUCEDMODELOPTIMIZER_STRUCTS_HPP diff --git a/topologyenumerator.cpp b/topologyenumerator.cpp index d785670..1931915 100755 --- a/topologyenumerator.cpp +++ b/topologyenumerator.cpp @@ -1,12 +1,13 @@ #include "topologyenumerator.hpp" +#include #include #include #include -#include #include +#include #include -const bool debugIsOn{false}; +const bool debugIsOn{true}; const bool savePlyFiles{true}; // size_t binomialCoefficient(size_t n, size_t m) { @@ -34,797 +35,879 @@ const bool savePlyFiles{true}; // .string()); //} -size_t TopologyEnumerator::getEdgeIndex(size_t ni0, size_t ni1) const -{ - if (ni1 <= ni0) { - std::swap(ni0, ni1); - } - assert(ni1 > ni0); - const size_t &n = numberOfNodes; - return (n * (n - 1) / 2) - (n - ni0) * ((n - ni0) - 1) / 2 + ni1 - ni0 - 1; +size_t TopologyEnumerator::getEdgeIndex(size_t ni0, size_t ni1) const { + if (ni1 <= ni0) { + std::swap(ni0, ni1); + } + assert(ni1 > ni0); + const size_t& n = numberOfNodes; + return (n * (n - 1) / 2) - (n - ni0) * ((n - ni0) - 1) / 2 + ni1 - ni0 - 1; } TopologyEnumerator::TopologyEnumerator() {} -void TopologyEnumerator::computeValidPatterns(const std::vector &reducedNumberOfNodesPerSlot, - const std::string &desiredResultsPath, - const int &numberOfDesiredEdges) -{ - assert(reducedNumberOfNodesPerSlot.size() == 5); - assert(reducedNumberOfNodesPerSlot[0] == 0 || reducedNumberOfNodesPerSlot[0] == 1); - assert(reducedNumberOfNodesPerSlot[1] == 0 || reducedNumberOfNodesPerSlot[1] == 1); - std::vector numberOfNodesPerSlot{reducedNumberOfNodesPerSlot[0], - reducedNumberOfNodesPerSlot[1], - reducedNumberOfNodesPerSlot[1], - reducedNumberOfNodesPerSlot[2], - reducedNumberOfNodesPerSlot[3], - reducedNumberOfNodesPerSlot[2], - reducedNumberOfNodesPerSlot[4]}; - // Generate an edge mesh wih all possible edges - numberOfNodes = std::accumulate(numberOfNodesPerSlot.begin(), numberOfNodesPerSlot.end(), 0); - const size_t numberOfAllPossibleEdges = numberOfNodes * (numberOfNodes - 1) / 2; +void TopologyEnumerator::computeValidPatterns( + const std::vector& reducedNumberOfNodesPerSlot, + const std::string& desiredResultsPath, + const int& numberOfDesiredEdges) { + assert(reducedNumberOfNodesPerSlot.size() == 5); + assert(reducedNumberOfNodesPerSlot[0] == 0 || + reducedNumberOfNodesPerSlot[0] == 1); + assert(reducedNumberOfNodesPerSlot[1] == 0 || + reducedNumberOfNodesPerSlot[1] == 1); + std::vector numberOfNodesPerSlot{ + reducedNumberOfNodesPerSlot[0], reducedNumberOfNodesPerSlot[1], + reducedNumberOfNodesPerSlot[1], reducedNumberOfNodesPerSlot[2], + reducedNumberOfNodesPerSlot[3], reducedNumberOfNodesPerSlot[2], + reducedNumberOfNodesPerSlot[4]}; + // Generate an edge mesh wih all possible edges + numberOfNodes = std::accumulate(numberOfNodesPerSlot.begin(), + numberOfNodesPerSlot.end(), 0); + const size_t numberOfAllPossibleEdges = + numberOfNodes * (numberOfNodes - 1) / 2; - std::vector allPossibleEdges(numberOfAllPossibleEdges); - const int &n = numberOfNodes; - for (size_t edgeIndex = 0; edgeIndex < numberOfAllPossibleEdges; edgeIndex++) { - const int ni0 = n - 2 - - std::floor(std::sqrt(-8 * edgeIndex + 4 * n * (n - 1) - 7) / 2.0 - 0.5); - const int ni1 = edgeIndex + ni0 + 1 - n * (n - 1) / 2 + (n - ni0) * ((n - ni0) - 1) / 2; - allPossibleEdges[edgeIndex] = vcg::Point2i(ni0, ni1); - } - PatternGeometry patternGeometryAllEdges; - patternGeometryAllEdges.add(numberOfNodesPerSlot, allPossibleEdges); - // Create Results path - auto resultPath = std::filesystem::path(desiredResultsPath); - assert(std::filesystem::exists(resultPath)); + std::vector allPossibleEdges(numberOfAllPossibleEdges); + const int& n = numberOfNodes; + for (size_t edgeIndex = 0; edgeIndex < numberOfAllPossibleEdges; + edgeIndex++) { + const int ni0 = + n - 2 - + std::floor(std::sqrt(-8 * edgeIndex + 4 * n * (n - 1) - 7) / 2.0 - 0.5); + const int ni1 = + edgeIndex + ni0 + 1 - n * (n - 1) / 2 + (n - ni0) * ((n - ni0) - 1) / 2; + allPossibleEdges[edgeIndex] = vcg::Point2i(ni0, ni1); + } + PatternGeometry patternGeometryAllEdges; + patternGeometryAllEdges.add(numberOfNodesPerSlot, allPossibleEdges); + // Create Results path + auto resultPath = std::filesystem::path(desiredResultsPath); + assert(std::filesystem::exists(resultPath)); - auto allResultsPath = resultPath.append("Results"); - std::filesystem::create_directory(allResultsPath); - std::string setupString; - // for (size_t numberOfNodes : reducedNumberOfNodesPerSlot) { - for (size_t numberOfNodesPerSlotIndex = 0; - numberOfNodesPerSlotIndex < reducedNumberOfNodesPerSlot.size(); - numberOfNodesPerSlotIndex++) { - std::string elemID; - if (numberOfNodesPerSlotIndex == 0 || numberOfNodesPerSlotIndex == 1) { - elemID = "v"; - } else if (numberOfNodesPerSlotIndex == 2 || numberOfNodesPerSlotIndex == 3) { - elemID = "e"; - } else { - elemID = "c"; - } - setupString += std::to_string(reducedNumberOfNodesPerSlot[numberOfNodesPerSlotIndex]) - + elemID + "_"; - } - setupString += std::to_string(PatternGeometry().getFanSize()) + "fan"; - if (debugIsOn) { - setupString += "_debug"; - } - auto resultsPath = std::filesystem::path(allResultsPath).append(setupString); - // std::filesystem::remove_all(resultsPath); // delete previous results - std::filesystem::create_directory(resultsPath); - - if (debugIsOn) { - patternGeometryAllEdges.save( - std::filesystem::path(resultsPath).append("allPossibleEdges.ply").string()); - } - // statistics.numberOfPossibleEdges = numberOfAllPossibleEdges; - - std::vector validEdges = getValidEdges(numberOfNodesPerSlot, - resultsPath, - patternGeometryAllEdges, - allPossibleEdges); - PatternGeometry patternAllValidEdges; - patternAllValidEdges.add(patternGeometryAllEdges.computeVertices(), validEdges); - if (debugIsOn) { - // Export all valid edges in a ply - patternAllValidEdges.save( - std::filesystem::path(resultsPath).append("allValidEdges.ply").string()); - } - // statistics.numberOfValidEdges = validEdges.size(); - - // Find pairs of intersecting edges - const std::unordered_map> intersectingEdges - = patternAllValidEdges.getIntersectingEdges(statistics.numberOfIntersectingEdgePairs); - if (debugIsOn) { - auto intersectingEdgesPath = std::filesystem::path(resultsPath) - .append("All_intersecting_edge_pairs"); - std::filesystem::create_directory(intersectingEdgesPath); - // Export intersecting pairs in ply files - for (auto mapIt = intersectingEdges.begin(); mapIt != intersectingEdges.end(); mapIt++) { - for (auto setIt = mapIt->second.begin(); setIt != mapIt->second.end(); setIt++) { - PatternGeometry intersectingEdgePair; - const size_t ei0 = mapIt->first; - const size_t ei1 = *setIt; - vcg::tri::Allocator::AddEdge( - intersectingEdgePair, - patternGeometryAllEdges.computeVertices()[validEdges[ei0][0]], - patternGeometryAllEdges.computeVertices()[validEdges[ei0][1]]); - vcg::tri::Allocator::AddEdge( - intersectingEdgePair, - patternGeometryAllEdges.computeVertices()[validEdges[ei1][0]], - patternGeometryAllEdges.computeVertices()[validEdges[ei1][1]]); - intersectingEdgePair.save(std::filesystem::path(intersectingEdgesPath) - .append(std::to_string(mapIt->first) + "_" - + std::to_string(*setIt) + ".ply") - .string()); - } - } - } - - const std::unordered_set interfaceNodes = patternGeometryAllEdges.getInterfaceNodes( - numberOfNodesPerSlot); - - // assert(validEdges.size() == allPossibleEdges.size() - - // coincideEdges.size() - - // duplicateEdges.size()); - - // PatternSet patternSet; - // const std::vector nodes = - // patternGeometryAllEdges.getVertices(); const size_t numberOfNodes = - // nodes.size(); patternSet.nodes.resize(numberOfNodes); for (size_t - // nodeIndex = 0; nodeIndex < numberOfNodes; nodeIndex++) { - // patternSet.nodes[nodeIndex] = - // vcg::Point3d(nodes[nodeIndex][0], nodes[nodeIndex][1],0); - // } - // if (std::filesystem::exists(std::filesystem::path(resultsPath) - // .append("patterns.patt") - // .string())) { - // std::filesystem::remove( - // std::filesystem::path(resultsPath).append("patterns.patt")); - // } - if (numberOfDesiredEdges == -1) { - for (size_t numberOfEdges = 2; numberOfEdges <= validEdges.size(); numberOfEdges++) { - std::cout << "Computing " + setupString << " with " << numberOfEdges << " edges." - << std::endl; - - auto perEdgeResultPath = std::filesystem::path(resultsPath) - .append(std::to_string(numberOfEdges)); - if (std::filesystem::exists(perEdgeResultPath)) { - // if (debugIsOn) { - std::filesystem::remove_all(perEdgeResultPath); - - // } else { - // continue; - // } - } - std::filesystem::create_directory(perEdgeResultPath); - computeValidPatterns(numberOfNodesPerSlot, - numberOfEdges, - perEdgeResultPath, - patternGeometryAllEdges.computeVertices(), - intersectingEdges, - validEdges, - interfaceNodes); - statistics.print(setupString, perEdgeResultPath); - statistics.reset(); - } + auto allResultsPath = resultPath.append("Results"); + std::filesystem::create_directory(allResultsPath); + std::string setupString; + // for (size_t numberOfNodes : reducedNumberOfNodesPerSlot) { + for (size_t numberOfNodesPerSlotIndex = 0; + numberOfNodesPerSlotIndex < reducedNumberOfNodesPerSlot.size(); + numberOfNodesPerSlotIndex++) { + std::string elemID; + if (numberOfNodesPerSlotIndex == 0 || numberOfNodesPerSlotIndex == 1) { + elemID = "v"; + } else if (numberOfNodesPerSlotIndex == 2 || + numberOfNodesPerSlotIndex == 3) { + elemID = "e"; } else { - std::cout << "Computing " + setupString << " with " << numberOfDesiredEdges << " edges." - << std::endl; - - auto perEdgeResultPath = std::filesystem::path(resultsPath) - .append(std::to_string(numberOfDesiredEdges)); - if (std::filesystem::exists(perEdgeResultPath)) { - // return; - std::filesystem::remove_all(perEdgeResultPath); - } - std::filesystem::create_directory(perEdgeResultPath); - computeValidPatterns(numberOfNodesPerSlot, - numberOfDesiredEdges, - perEdgeResultPath, - patternGeometryAllEdges.computeVertices(), - intersectingEdges, - validEdges, - interfaceNodes); - statistics.print(setupString, perEdgeResultPath); + elemID = "c"; } + setupString += + std::to_string(reducedNumberOfNodesPerSlot[numberOfNodesPerSlotIndex]) + + elemID + "_"; + } + setupString += std::to_string(PatternGeometry().getFanSize()) + "fan"; + if (debugIsOn) { + setupString += "_debug"; + } + auto resultsPath = std::filesystem::path(allResultsPath).append(setupString); + // std::filesystem::remove_all(resultsPath); // delete previous results + std::filesystem::create_directory(resultsPath); + + if (debugIsOn) { + patternGeometryAllEdges.save(std::filesystem::path(resultsPath) + .append("allPossibleEdges.ply") + .string()); + } + // statistics.numberOfPossibleEdges = numberOfAllPossibleEdges; + + std::vector validEdges = + getValidEdges(numberOfNodesPerSlot, resultsPath, patternGeometryAllEdges, + allPossibleEdges); + PatternGeometry patternAllValidEdges; + patternAllValidEdges.add(patternGeometryAllEdges.computeVertices(), + validEdges); + if (debugIsOn) { + // Export all valid edges in a ply + patternAllValidEdges.save(std::filesystem::path(resultsPath) + .append("allValidEdges.ply") + .string()); + } + // statistics.numberOfValidEdges = validEdges.size(); + + // Find pairs of intersecting edges + const std::unordered_map> + intersectingEdges = patternAllValidEdges.getIntersectingEdges( + statistics.numberOfIntersectingEdgePairs); + if (debugIsOn) { + auto intersectingEdgesPath = std::filesystem::path(resultsPath) + .append("All_intersecting_edge_pairs"); + std::filesystem::create_directory(intersectingEdgesPath); + // Export intersecting pairs in ply files + for (auto mapIt = intersectingEdges.begin(); + mapIt != intersectingEdges.end(); mapIt++) { + for (auto setIt = mapIt->second.begin(); setIt != mapIt->second.end(); + setIt++) { + PatternGeometry intersectingEdgePair; + const size_t ei0 = mapIt->first; + const size_t ei1 = *setIt; + vcg::tri::Allocator::AddEdge( + intersectingEdgePair, + patternGeometryAllEdges.computeVertices()[validEdges[ei0][0]], + patternGeometryAllEdges.computeVertices()[validEdges[ei0][1]]); + vcg::tri::Allocator::AddEdge( + intersectingEdgePair, + patternGeometryAllEdges.computeVertices()[validEdges[ei1][0]], + patternGeometryAllEdges.computeVertices()[validEdges[ei1][1]]); + intersectingEdgePair.save(std::filesystem::path(intersectingEdgesPath) + .append(std::to_string(mapIt->first) + + "_" + std::to_string(*setIt) + + ".ply") + .string()); + } + } + } + + const std::unordered_set interfaceNodes = + patternGeometryAllEdges.getInterfaceNodes(numberOfNodesPerSlot); + + // assert(validEdges.size() == allPossibleEdges.size() - + // coincideEdges.size() - + // duplicateEdges.size()); + + // PatternSet patternSet; + // const std::vector nodes = + // patternGeometryAllEdges.getVertices(); const size_t numberOfNodes = + // nodes.size(); patternSet.nodes.resize(numberOfNodes); for (size_t + // nodeIndex = 0; nodeIndex < numberOfNodes; nodeIndex++) { + // patternSet.nodes[nodeIndex] = + // vcg::Point3d(nodes[nodeIndex][0], nodes[nodeIndex][1],0); + // } + // if (std::filesystem::exists(std::filesystem::path(resultsPath) + // .append("patterns.patt") + // .string())) { + // std::filesystem::remove( + // std::filesystem::path(resultsPath).append("patterns.patt")); + // } + if (numberOfDesiredEdges == -1) { + for (size_t numberOfEdges = 2; numberOfEdges <= validEdges.size(); + numberOfEdges++) { + std::cout << "Computing " + setupString << " with " << numberOfEdges + << " edges." << std::endl; + + auto perEdgeResultPath = std::filesystem::path(resultsPath) + .append(std::to_string(numberOfEdges)); + if (std::filesystem::exists(perEdgeResultPath)) { + // if (debugIsOn) { + std::filesystem::remove_all(perEdgeResultPath); + + // } else { + // continue; + // } + } + std::filesystem::create_directory(perEdgeResultPath); + computeValidPatterns(numberOfNodesPerSlot, numberOfEdges, + perEdgeResultPath, + patternGeometryAllEdges.computeVertices(), + intersectingEdges, validEdges, interfaceNodes); + statistics.print(setupString, perEdgeResultPath); + statistics.reset(); + } + } else { + std::cout << "Computing " + setupString << " with " << numberOfDesiredEdges + << " edges." << std::endl; + + auto perEdgeResultPath = std::filesystem::path(resultsPath) + .append(std::to_string(numberOfDesiredEdges)); + if (std::filesystem::exists(perEdgeResultPath)) { + // return; + std::filesystem::remove_all(perEdgeResultPath); + } + std::filesystem::create_directory(perEdgeResultPath); + computeValidPatterns(numberOfNodesPerSlot, numberOfDesiredEdges, + perEdgeResultPath, + patternGeometryAllEdges.computeVertices(), + intersectingEdges, validEdges, interfaceNodes); + statistics.print(setupString, perEdgeResultPath); + } } -void TopologyEnumerator::computeEdgeNodes(const std::vector &numberOfNodesPerSlot, - std::vector &nodesEdge0, - std::vector &nodesEdge1, - std::vector &nodesEdge2) -{ - // Create vectors holding the node indices of each pattern node of each - // triangle edge - size_t nodeIndex = 0; - if (numberOfNodesPerSlot[0] != 0) { - nodesEdge0.push_back(nodeIndex++); - } - if (numberOfNodesPerSlot[1] != 0) - nodesEdge1.push_back(nodeIndex++); - if (numberOfNodesPerSlot[2] != 0) - nodesEdge2.push_back(nodeIndex++); +void TopologyEnumerator::computeEdgeNodes( + const std::vector& numberOfNodesPerSlot, + std::vector& nodesEdge0, + std::vector& nodesEdge1, + std::vector& nodesEdge2) { + // Create vectors holding the node indices of each pattern node of each + // triangle edge + size_t nodeIndex = 0; + if (numberOfNodesPerSlot[0] != 0) { + nodesEdge0.push_back(nodeIndex++); + } + if (numberOfNodesPerSlot[1] != 0) + nodesEdge1.push_back(nodeIndex++); + if (numberOfNodesPerSlot[2] != 0) + nodesEdge2.push_back(nodeIndex++); - if (numberOfNodesPerSlot[3] != 0) { - for (size_t edgeNodeIndex = 0; edgeNodeIndex < numberOfNodesPerSlot[3]; edgeNodeIndex++) { - nodesEdge0.push_back(nodeIndex++); - } + if (numberOfNodesPerSlot[3] != 0) { + for (size_t edgeNodeIndex = 0; edgeNodeIndex < numberOfNodesPerSlot[3]; + edgeNodeIndex++) { + nodesEdge0.push_back(nodeIndex++); } - if (numberOfNodesPerSlot[4] != 0) { - for (size_t edgeNodeIndex = 0; edgeNodeIndex < numberOfNodesPerSlot[4]; edgeNodeIndex++) { - nodesEdge1.push_back(nodeIndex++); - } + } + if (numberOfNodesPerSlot[4] != 0) { + for (size_t edgeNodeIndex = 0; edgeNodeIndex < numberOfNodesPerSlot[4]; + edgeNodeIndex++) { + nodesEdge1.push_back(nodeIndex++); } + } - if (numberOfNodesPerSlot[5] != 0) { - for (size_t edgeNodeIndex = 0; edgeNodeIndex < numberOfNodesPerSlot[5]; edgeNodeIndex++) { - nodesEdge2.push_back(nodeIndex++); - } - } - if (numberOfNodesPerSlot[1] != 0) { - assert(numberOfNodesPerSlot[2]); - nodesEdge0.push_back(1); - nodesEdge1.push_back(2); + if (numberOfNodesPerSlot[5] != 0) { + for (size_t edgeNodeIndex = 0; edgeNodeIndex < numberOfNodesPerSlot[5]; + edgeNodeIndex++) { + nodesEdge2.push_back(nodeIndex++); } + } + if (numberOfNodesPerSlot[1] != 0) { + assert(numberOfNodesPerSlot[2]); + nodesEdge0.push_back(1); + nodesEdge1.push_back(2); + } - if (numberOfNodesPerSlot[0] != 0) { - nodesEdge2.push_back(0); - } + if (numberOfNodesPerSlot[0] != 0) { + nodesEdge2.push_back(0); + } } std::unordered_set TopologyEnumerator::computeCoincideEdges( - const std::vector &numberOfNodesPerSlot) -{ - /* + const std::vector& numberOfNodesPerSlot) { + /* * A coincide edge is defined as an edge connection between two nodes that lay * on a triangle edge and which have another node in between * */ - std::vector nodesEdge0; // left edge - std::vector nodesEdge1; // bottom edge - std::vector nodesEdge2; // right edge - computeEdgeNodes(numberOfNodesPerSlot, nodesEdge0, nodesEdge1, nodesEdge2); + std::vector nodesEdge0; // left edge + std::vector nodesEdge1; // bottom edge + std::vector nodesEdge2; // right edge + computeEdgeNodes(numberOfNodesPerSlot, nodesEdge0, nodesEdge1, nodesEdge2); - std::vector coincideEdges0 = getCoincideEdges(nodesEdge0); - std::vector coincideEdges1 = getCoincideEdges(nodesEdge1); - std::vector coincideEdges2 = getCoincideEdges(nodesEdge2); - std::unordered_set coincideEdges{coincideEdges0.begin(), coincideEdges0.end()}; - std::copy(coincideEdges1.begin(), - coincideEdges1.end(), - std::inserter(coincideEdges, coincideEdges.end())); - std::copy(coincideEdges2.begin(), - coincideEdges2.end(), - std::inserter(coincideEdges, coincideEdges.end())); + std::vector coincideEdges0 = getCoincideEdges(nodesEdge0); + std::vector coincideEdges1 = getCoincideEdges(nodesEdge1); + std::vector coincideEdges2 = getCoincideEdges(nodesEdge2); + std::unordered_set coincideEdges{coincideEdges0.begin(), + coincideEdges0.end()}; + std::copy(coincideEdges1.begin(), coincideEdges1.end(), + std::inserter(coincideEdges, coincideEdges.end())); + std::copy(coincideEdges2.begin(), coincideEdges2.end(), + std::inserter(coincideEdges, coincideEdges.end())); - if (numberOfNodesPerSlot[0] && numberOfNodesPerSlot[1]) { - coincideEdges.insert(getEdgeIndex(0, 2)); - } + if (numberOfNodesPerSlot[0] && numberOfNodesPerSlot[1]) { + coincideEdges.insert(getEdgeIndex(0, 2)); + } - if (numberOfNodesPerSlot[0] && numberOfNodesPerSlot[2]) { - assert(numberOfNodesPerSlot[1]); - coincideEdges.insert(getEdgeIndex(0, 3)); - } + if (numberOfNodesPerSlot[0] && numberOfNodesPerSlot[2]) { + assert(numberOfNodesPerSlot[1]); + coincideEdges.insert(getEdgeIndex(0, 3)); + } - return coincideEdges; + return coincideEdges; } std::unordered_set TopologyEnumerator::computeDuplicateEdges( - const std::vector &numberOfNodesPerSlot) -{ - /* + const std::vector& numberOfNodesPerSlot) { + /* * A duplicate edges are all edges the "right" edge since due to rotational * symmetry "left" edge=="right" edge * */ - std::unordered_set duplicateEdges; - std::vector nodesEdge0; // left edge - std::vector nodesEdge1; // bottom edge - std::vector nodesEdge2; // right edge - computeEdgeNodes(numberOfNodesPerSlot, nodesEdge0, nodesEdge1, nodesEdge2); - if (numberOfNodesPerSlot[5]) { - for (size_t edge2NodeIndex = 0; edge2NodeIndex < nodesEdge2.size() - 1; edge2NodeIndex++) { - const size_t nodeIndex = nodesEdge2[edge2NodeIndex]; - const size_t nextNodeIndex = nodesEdge2[edge2NodeIndex + 1]; - duplicateEdges.insert(getEdgeIndex(nodeIndex, nextNodeIndex)); - } + std::unordered_set duplicateEdges; + std::vector nodesEdge0; // left edge + std::vector nodesEdge1; // bottom edge + std::vector nodesEdge2; // right edge + computeEdgeNodes(numberOfNodesPerSlot, nodesEdge0, nodesEdge1, nodesEdge2); + if (numberOfNodesPerSlot[5]) { + for (size_t edge2NodeIndex = 0; edge2NodeIndex < nodesEdge2.size() - 1; + edge2NodeIndex++) { + const size_t nodeIndex = nodesEdge2[edge2NodeIndex]; + const size_t nextNodeIndex = nodesEdge2[edge2NodeIndex + 1]; + duplicateEdges.insert(getEdgeIndex(nodeIndex, nextNodeIndex)); } + } - return duplicateEdges; + return duplicateEdges; } std::vector TopologyEnumerator::getValidEdges( - const std::vector &numberOfNodesPerSlot, - const std::filesystem::path &resultsPath, - const PatternGeometry &patternGeometryAllEdges, - const std::vector &allPossibleEdges) -{ - std::unordered_set coincideEdges = computeCoincideEdges(numberOfNodesPerSlot); - // Export each coincide edge into a ply file - if (!coincideEdges.empty() && debugIsOn) { - auto coincideEdgesPath = std::filesystem::path(resultsPath).append("Coincide_edges"); - std::filesystem::create_directories(coincideEdgesPath); - for (auto coincideEdgeIndex : coincideEdges) { - PatternGeometry::EdgeType e = patternGeometryAllEdges.edge[coincideEdgeIndex]; - PatternGeometry singleEdgeMesh; - vcg::Point3d p0 = e.cP(0); - vcg::Point3d p1 = e.cP(1); - std::vector edgeVertices; - edgeVertices.push_back(p0); - edgeVertices.push_back(p1); - singleEdgeMesh.add(edgeVertices); - singleEdgeMesh.add(std::vector{vcg::Point2i{0, 1}}); - singleEdgeMesh.save(std::filesystem::path(coincideEdgesPath) - .append(std::to_string(coincideEdgeIndex)) - .string() - + ".ply"); - } + const std::vector& numberOfNodesPerSlot, + const std::filesystem::path& resultsPath, + const PatternGeometry& patternGeometryAllEdges, + const std::vector& allPossibleEdges) { + std::unordered_set coincideEdges = + computeCoincideEdges(numberOfNodesPerSlot); + // Export each coincide edge into a ply file + if (!coincideEdges.empty() && debugIsOn) { + auto coincideEdgesPath = + std::filesystem::path(resultsPath).append("Coincide_edges"); + std::filesystem::create_directories(coincideEdgesPath); + for (auto coincideEdgeIndex : coincideEdges) { + PatternGeometry::EdgeType e = + patternGeometryAllEdges.edge[coincideEdgeIndex]; + PatternGeometry singleEdgeMesh; + vcg::Point3d p0 = e.cP(0); + vcg::Point3d p1 = e.cP(1); + std::vector edgeVertices; + edgeVertices.push_back(p0); + edgeVertices.push_back(p1); + singleEdgeMesh.add(edgeVertices); + singleEdgeMesh.add(std::vector{vcg::Point2i{0, 1}}); + singleEdgeMesh.save(std::filesystem::path(coincideEdgesPath) + .append(std::to_string(coincideEdgeIndex)) + .string() + + ".ply"); } - statistics.numberOfCoincideEdges = coincideEdges.size(); + } + statistics.numberOfCoincideEdges = coincideEdges.size(); - // Compute duplicate edges - std::unordered_set duplicateEdges = computeDuplicateEdges(numberOfNodesPerSlot); - if (!duplicateEdges.empty() && debugIsOn) { - // Export duplicate edges in a single ply file - auto duplicateEdgesPath = std::filesystem::path(resultsPath).append("duplicate"); - std::filesystem::create_directory(duplicateEdgesPath); - PatternGeometry patternDuplicateEdges; - for (auto duplicateEdgeIndex : duplicateEdges) { - PatternGeometry::EdgeType e = patternGeometryAllEdges.edge[duplicateEdgeIndex]; - vcg::Point3d p0 = e.cP(0); - vcg::Point3d p1 = e.cP(1); - vcg::tri::Allocator::AddEdge(patternDuplicateEdges, p0, p1); - } - patternDuplicateEdges.save( - std::filesystem::path(duplicateEdgesPath).append("duplicateEdges.ply").string()); + // Compute duplicate edges + std::unordered_set duplicateEdges = + computeDuplicateEdges(numberOfNodesPerSlot); + if (!duplicateEdges.empty() && debugIsOn) { + // Export duplicate edges in a single ply file + auto duplicateEdgesPath = + std::filesystem::path(resultsPath).append("duplicate"); + std::filesystem::create_directory(duplicateEdgesPath); + PatternGeometry patternDuplicateEdges; + for (auto duplicateEdgeIndex : duplicateEdges) { + PatternGeometry::EdgeType e = + patternGeometryAllEdges.edge[duplicateEdgeIndex]; + vcg::Point3d p0 = e.cP(0); + vcg::Point3d p1 = e.cP(1); + vcg::tri::Allocator::AddEdge(patternDuplicateEdges, p0, + p1); } - statistics.numberOfDuplicateEdges = duplicateEdges.size(); + patternDuplicateEdges.save(std::filesystem::path(duplicateEdgesPath) + .append("duplicateEdges.ply") + .string()); + } + statistics.numberOfDuplicateEdges = duplicateEdges.size(); - // Create the set of all possible edges without coincide and duplicate edges - std::vector validEdges; - for (size_t edgeIndex = 0; edgeIndex < allPossibleEdges.size(); edgeIndex++) { - if (coincideEdges.count(edgeIndex) == 0 && duplicateEdges.count(edgeIndex) == 0) { - validEdges.push_back(allPossibleEdges[edgeIndex]); - } + // Create the set of all possible edges without coincide and duplicate edges + std::vector validEdges; + for (size_t edgeIndex = 0; edgeIndex < allPossibleEdges.size(); edgeIndex++) { + if (coincideEdges.count(edgeIndex) == 0 && + duplicateEdges.count(edgeIndex) == 0) { + validEdges.push_back(allPossibleEdges[edgeIndex]); } + } - return validEdges; + return validEdges; } -void TopologyEnumerator::exportPattern(const std::filesystem::path &saveToPath, - PatternGeometry &patternGeometry, - const bool saveTilledPattern) const -{ - const std::string patternName = patternGeometry.getLabel(); - std::filesystem::create_directory(saveToPath); - patternGeometry.save(std::filesystem::path(saveToPath).append(patternName).string() + ".ply"); - if (saveTilledPattern) { - PatternGeometry tiledPatternGeometry = PatternGeometry::createTile(patternGeometry); - tiledPatternGeometry.save( - std::filesystem::path(saveToPath).append(patternName + "_tiled").string() + ".ply"); - } +void TopologyEnumerator::exportPattern(const std::filesystem::path& saveToPath, + PatternGeometry& patternGeometry, + const bool saveTilledPattern) const { + const std::string patternName = patternGeometry.getLabel(); + std::filesystem::create_directory(saveToPath); + patternGeometry.save( + std::filesystem::path(saveToPath).append(patternName).string() + ".ply"); + if (saveTilledPattern) { + PatternGeometry tiledPatternGeometry = + PatternGeometry::createTile(patternGeometry); + tiledPatternGeometry.save(std::filesystem::path(saveToPath) + .append(patternName + "_tiled") + .string() + + ".ply"); + } } void TopologyEnumerator::computeValidPatterns( - const std::vector &numberOfNodesPerSlot, - const size_t &numberOfDesiredEdges, - const std::filesystem::path &resultsPath, - const std::vector &allVertices, - const std::unordered_map> &intersectingEdges, - const std::vector &validEdges, - const std::unordered_set &interfaceNodes) -{ - assert(numberOfNodesPerSlot.size() == 7); - // Iterate over all patterns which have numberOfDesiredEdges edges from - // from the validEdges Identify patterns that contain dangling edges - const bool enoughValidEdgesExist = validEdges.size() >= numberOfDesiredEdges; - if (!enoughValidEdgesExist) { - std::filesystem::remove_all(resultsPath); // delete previous results folder - return; - } - assert(enoughValidEdgesExist); + const std::vector& numberOfNodesPerSlot, + const size_t& numberOfDesiredEdges, + const std::filesystem::path& resultsPath, + const std::vector& allVertices, + const std::unordered_map>& + intersectingEdges, + const std::vector& validEdges, + const std::unordered_set& interfaceNodes) { + assert(numberOfNodesPerSlot.size() == 7); + // Iterate over all patterns which have numberOfDesiredEdges edges from + // from the validEdges Identify patterns that contain dangling edges + const bool enoughValidEdgesExist = validEdges.size() >= numberOfDesiredEdges; + if (!enoughValidEdgesExist) { + std::filesystem::remove_all(resultsPath); // delete previous results folder + return; + } + assert(enoughValidEdgesExist); - // Create pattern result paths - const auto validPatternsPath = std::filesystem::path(resultsPath).append("Valid"); - const bool validPathCreatedSuccesfully = std::filesystem::create_directories(validPatternsPath); - assert(validPathCreatedSuccesfully && std::filesystem::exists(validPatternsPath)); - // std::ofstream validPatternsFileStream; - // validPatternsFileStream.open( - // validPatternsPath.append("patterns.patt").string()); - const std::string compressedPatternsFilePath - = std::filesystem::path(validPatternsPath).append("patterns.patt").string(); - PatternIO::PatternSet patternSet; - patternSet.nodes = allVertices; - const int patternSetBufferSize = 10000; + // Create pattern result paths + const auto validPatternsPath = + std::filesystem::path(resultsPath).append("Valid"); + const bool validPathCreatedSuccesfully = + std::filesystem::create_directories(validPatternsPath); + assert(validPathCreatedSuccesfully && + std::filesystem::exists(validPatternsPath)); + // std::ofstream validPatternsFileStream; + // validPatternsFileStream.open( + // validPatternsPath.append("patterns.patt").string()); + const std::string compressedPatternsFilePath = + std::filesystem::path(validPatternsPath).append("patterns.patt").string(); + PatternIO::PatternSet patternSet; + patternSet.nodes = allVertices; + const int patternSetBufferSize = 10000; - const size_t numberOfPatterns = PatternGeometry::binomialCoefficient(validEdges.size(), - numberOfDesiredEdges); - statistics.numberOfPatterns = numberOfPatterns; + const size_t numberOfPatterns = PatternGeometry::binomialCoefficient( + validEdges.size(), numberOfDesiredEdges); + statistics.numberOfPatterns = numberOfPatterns; - // Initialize pattern binary representation - std::string patternBinaryRepresentation; - patternBinaryRepresentation = std::string(numberOfDesiredEdges, '1'); - patternBinaryRepresentation += std::string(validEdges.size() - numberOfDesiredEdges, '0'); - std::sort(patternBinaryRepresentation.begin(), patternBinaryRepresentation.end()); - /*TODO: Performance could be improved by changing the patternGeometry with + // Initialize pattern binary representation + std::string patternBinaryRepresentation; + patternBinaryRepresentation = std::string(numberOfDesiredEdges, '1'); + patternBinaryRepresentation += + std::string(validEdges.size() - numberOfDesiredEdges, '0'); + std::sort(patternBinaryRepresentation.begin(), + patternBinaryRepresentation.end()); + + /*TODO: Performance could be improved by changing the patternGeometry with * respect to the previous one. Maybe I could xor the binaryRepresentation * to the previous one.*/ - // std::string previousPatternBinaryRepresentation(validEdges.size(),'0'); - size_t patternIndex = 0; - bool validPatternsExist = false; - constexpr bool exportTilledPattern = false; - constexpr bool saveCompressedFormat = false; - do { - patternIndex++; - const std::string patternName = std::to_string(numberOfDesiredEdges) + "_" - + std::to_string(patternIndex); - // std::cout << "Pattern name:" + patternBinaryRepresentation << - // std::endl; isValidPattern(patternBinaryRepresentation, validEdges, - // numberOfDesiredEdges); - // Create the geometry of the pattern - // Compute the pattern edges from the binary representation - std::vector patternEdges(numberOfDesiredEdges); - size_t patternEdgeIndex = 0; - for (size_t validEdgeIndex = 0; validEdgeIndex < patternBinaryRepresentation.size(); - validEdgeIndex++) { - if (patternBinaryRepresentation[validEdgeIndex] == '1') { - assert(patternEdgeIndex < numberOfDesiredEdges); - patternEdges[patternEdgeIndex++] = validEdges[validEdgeIndex]; - } - } + // std::string previousPatternBinaryRepresentation(validEdges.size(),'0'); + size_t patternIndex = 0; + bool validPatternsExist = false; + constexpr bool exportTilledPattern = false; + constexpr bool saveCompressedFormat = false; + do { + patternIndex++; + const std::string patternName = std::to_string(numberOfDesiredEdges) + "_" + + std::to_string(patternIndex); + // std::cout << "Pattern name:" + patternBinaryRepresentation << + // std::endl; isValidPattern(patternBinaryRepresentation, validEdges, + // numberOfDesiredEdges); + // Create the geometry of the pattern + // Compute the pattern edges from the binary representation + std::vector patternEdges(numberOfDesiredEdges); + size_t patternEdgeIndex = 0; + for (size_t validEdgeIndex = 0; + validEdgeIndex < patternBinaryRepresentation.size(); + validEdgeIndex++) { + if (patternBinaryRepresentation[validEdgeIndex] == '1') { + assert(patternEdgeIndex < numberOfDesiredEdges); + patternEdges[patternEdgeIndex++] = validEdges[validEdgeIndex]; + } + } - PatternGeometry patternGeometry; - patternGeometry.add(allVertices, patternEdges); - patternGeometry.setLabel(patternName); + // DEBUG: Export only part of the pattern set + // if (statistics.numberOfValidPatterns > 1e4) { + // break; + // } + // const bool patternContainsCentroid = + // std::find_if(patternEdges.begin(), patternEdges.end(), + // [](const vcg::Point2i& edge) { + // if (edge[0] == 0 || edge[1] == 0) { + // return true; + // } + // return false; + // }) != patternEdges.end(); + // if (!patternContainsCentroid) { + // continue; + // } + + PatternGeometry patternGeometry; + patternGeometry.add(allVertices, patternEdges); + patternGeometry.setLabel(patternName); #ifdef POLYSCOPE_DEFINED - //1st example - // const bool shouldBreak = patternBinaryRepresentation == "00100000100100000"; //398 - // const bool shouldBreak = patternBinaryRepresentation == "10000010101110110";//13036 - // const bool shouldBreak = patternBinaryRepresentation == "00010111000010100"; //2481 - // const bool shouldBreak = patternBinaryRepresentation == "10000101100110010"; //12116 - // const bool shouldBreak = patternBinaryRepresentation == "10010111000000110"; //13915 - //2nd example - // const bool shouldBreak = patternBinaryRepresentation == "00001011100010011"; //7_1203 - // const bool shouldBreak = patternBinaryRepresentation == "00110001100100111"; //4865 - // const bool shouldBreak = patternBinaryRepresentation == "00010000101000110"; //1380 - // const bool shouldBreak = patternBinaryRepresentation == "00000010100010111"; //268 - //3rd - // const bool shouldBreak = patternBinaryRepresentation == "10011011100000010"; //14272 - // const bool shouldBreak = patternBinaryRepresentation == "10000111100110110"; //11877 - // const bool shouldBreak = patternBinaryRepresentation == "00001011100010011"; //1203 - // const bool shouldBreak = patternBinaryRepresentation == "00010101000110000"; //12117 + // 1st example + // const bool shouldBreak = + // patternIndex == 1970494; // 398 const bool shouldBreak = + // patternBinaryRepresentation == "10000010101110110";//13036 const + // bool shouldBreak = patternBinaryRepresentation == + // "00010111000010100"; //2481 const bool shouldBreak = + // patternBinaryRepresentation == "10000101100110010"; //12116 const + // bool shouldBreak = patternBinaryRepresentation == + // "10010111000000110"; //13915 + // 2nd example + // const bool shouldBreak = patternBinaryRepresentation == + // "00001011100010011"; //7_1203 const bool shouldBreak = + // patternBinaryRepresentation == "00110001100100111"; //4865 const + // bool shouldBreak = patternBinaryRepresentation == + // "00010000101000110"; //1380 const bool shouldBreak = + // patternBinaryRepresentation == "00000010100010111"; //268 + // 3rd + // const bool shouldBreak = patternBinaryRepresentation == + // "10011011100000010"; //14272 const bool shouldBreak = + // patternBinaryRepresentation == "10000111100110110"; //11877 const + // bool shouldBreak = patternBinaryRepresentation == + // "00001011100010011"; //1203 const bool shouldBreak = + // patternBinaryRepresentation == "00010101000110000"; //12117 - // const bool shouldBreak = patternBinaryRepresentation == "10000101100110100"; //12117 -// if (shouldBreak) { -// patternGeometry.registerForDrawing(); -// polyscope::show(); -// patternGeometry.unregister(); -// } + // const bool shouldBreak = patternBinaryRepresentation == + // "10000101100110100"; //12117 + // std::thread drawingThread([&]() { +// if (shouldBreak) { +// patternGeometry.registerForDrawing(); +// polyscope::show(); +// patternGeometry.unregister(); +// } +// }); #endif - // Check if pattern contains intersecting edges - const bool isInterfaceConnected = patternGeometry.isInterfaceConnected(interfaceNodes); - // Export the tiled ply file if it contains intersecting edges - if (!isInterfaceConnected) { - // create the tiled geometry of the pattern - statistics.numberOfPatternViolatingInterfaceEnforcement++; - if (debugIsOn) { - if (savePlyFiles) { - exportPattern(std::filesystem::path(resultsPath).append("InterfaceEnforcement"), - patternGeometry, - exportTilledPattern); - } - } else { - continue; // should be uncommented in order to improve performance - } + // Check if pattern contains intersecting edges + const bool isInterfaceConnected = + patternGeometry.isInterfaceConnected(interfaceNodes); + // Export the tiled ply file if it contains intersecting edges + if (!isInterfaceConnected) { + // create the tiled geometry of the pattern + statistics.numberOfPatternViolatingInterfaceEnforcement++; + if (debugIsOn) { + if (savePlyFiles) { + exportPattern( + std::filesystem::path(resultsPath).append("InterfaceEnforcement"), + patternGeometry, exportTilledPattern); } - - // Check if pattern contains intersecting edges - const bool patternContainsIntersectingEdges - = patternGeometry.hasIntersectingEdges(patternBinaryRepresentation, intersectingEdges); - // Export the tiled ply file if it contains intersecting edges - if (patternContainsIntersectingEdges) { - // create the tiled geometry of the pattern - statistics.numberOfPatternsWithIntersectingEdges++; - if (debugIsOn) { - if (savePlyFiles) { - exportPattern(std::filesystem::path(resultsPath).append("Intersecting"), - patternGeometry, - exportTilledPattern); - } - } else { - continue; // should be uncommented in order to improve performance - } - } - - // const bool shouldBreak = numberOfDesiredEdges == 4 && patternIndex == 53; - const bool tiledPatternHasEdgesWithAngleSmallerThanThreshold - = patternGeometry.hasAngleSmallerThanThreshold(numberOfNodesPerSlot, 15); - if (tiledPatternHasEdgesWithAngleSmallerThanThreshold) { - statistics.numberOfPatternsViolatingAngleThreshold++; - if (debugIsOn /*|| savePlyFiles*/) { - if (savePlyFiles) { - exportPattern(std::filesystem::path(resultsPath) - .append("ExceedingAngleThreshold"), - patternGeometry, - exportTilledPattern); - } - } else { - continue; - } - } - - const bool tiledPatternHasNodeWithValenceGreaterThanDesired - = patternGeometry.hasValenceGreaterThan(numberOfNodesPerSlot, 6); - if (tiledPatternHasNodeWithValenceGreaterThanDesired) { - statistics.numberOfPatternsViolatingValenceThreshold++; - if (debugIsOn) { - if (savePlyFiles) { - auto highValencePath = std::filesystem::path(resultsPath) - .append("HighValencePatterns"); - exportPattern(highValencePath, patternGeometry, exportTilledPattern); - } - } else { - continue; - } - } - - // Compute the tiled valence - const bool tiledPatternHasDanglingEdges = patternGeometry.hasDanglingEdges( - numberOfNodesPerSlot); // marks the nodes with valence>=1 - // Create the tiled geometry of the pattern - const bool hasFloatingComponents = !patternGeometry.isFullyConnectedWhenFanned(); - - PatternGeometry fanPatternGeometry = PatternGeometry::createFan(patternGeometry); - const int interfaceNodeVi = 3; - std::vector connectedEdges; - vcg::edge::VEStarVE(&fanPatternGeometry.vert[interfaceNodeVi], connectedEdges); - if (!connectedEdges.empty()) { - for (int i = 1; i < 6; i++) { - vcg::tri::Allocator::AddEdge(fanPatternGeometry, - interfaceNodeVi - + (i - 1) * patternGeometry.VN(), - interfaceNodeVi - + i * patternGeometry.VN()); - } - } - vcg::tri::Clean::MergeCloseVertex(fanPatternGeometry, 0.0000005); - vcg::tri::Allocator::CompactEveryVector(fanPatternGeometry); - vcg::tri::UpdateTopology::VertexEdge(fanPatternGeometry); - vcg::tri::UpdateTopology::EdgeEdge(fanPatternGeometry); - // for (PatternGeometry::VertexType &v : tilledPatternGeometry.vert) { - // std::vector connectedEdges; - // vcg::edge::VEStarVE(&v, connectedEdges); - // if (connectedEdges.size() == 1) { - // vcg::tri::Allocator::DeleteVertex(tilledPatternGeometry, v); - // vcg::tri::Allocator::DeleteEdge(tilledPatternGeometry, - // *connectedEdges[0]); - // } - // } - // // vcg::tri::Allocator::CompactEveryVector(tilledPatternGeometry); - // fanPatternGeometry.updateEigenEdgeAndVertices(); - - BoostGraph fanPatternGraph(fanPatternGeometry.VN()); - // std::cout << "Edges:"; - for (const PatternGeometry::EdgeType &e : fanPatternGeometry.edge) { - if (e.IsD() || e.cV(0)->IsD() || e.cV(1)->IsD()) { - continue; - } - const int vi0 = fanPatternGeometry.getIndex(e.cV(0)); - const int vi1 = fanPatternGeometry.getIndex(e.cV(1)); - boost::add_edge(vi0, vi1, fanPatternGraph); - // std::cout << vi0 << "," << vi1 << " "; - } - // std::cout << std::endl; - - std::vector articulationPoints; - boost::articulation_points(fanPatternGraph, std::back_inserter(articulationPoints)); - const bool hasArticulationPoints = !articulationPoints.empty(); - // if (!hasArticulationPoints && tiledPatternHasDanglingEdges) { - // PatternGeometry tilledPatternGeometry = PatternGeometry::createTile(patternGeometry); - // tilledPatternGeometry.updateEigenEdgeAndVertices(); - // tilledPatternGeometry.registerForDrawing(); - // // ->addNodeColorQuantity("de_noAp_tilled", fanVertexColors) - // // ->setEnabled(true); - // polyscope::show(); - // tilledPatternGeometry.unregister(); - // } - // if (hasArticulationPoints && !tiledPatternHasDanglingEdges/*&& !patternContainsIntersectingEdges - // && !hasFloatingComponents - // && !tiledPatternHasNodeWithValenceGreaterThanDesired - // && !tiledPatternHasEdgesWithAngleSmallerThanThreshold*/) { - // for (PatternGeometry::VertexType &v : patternGeometry.vert) { - // v.C() = vcg::Color4b::Yellow; - // } - // // std::cout << "AP:"; - // for (const int articulationPointVi : articulationPoints) { - // if (articulationPointVi >= patternGeometry.VN()) { - // continue; - // } - // // std::cout << articulationPointVi << " "; - // patternGeometry.vert[articulationPointVi].C() = vcg::Color4b::Red; - // } - // PatternGeometry tilledPatternGeometry = PatternGeometry::createTile(patternGeometry); - // // std::cout << std::endl; - // std::vector fanVertexColors(tilledPatternGeometry.VN(), glm::vec3(0, 0, 1)); - // for (const PatternGeometry::VertexType &v : tilledPatternGeometry.vert) { - // const auto vColor = glm::vec3(v.cC()[0] / 255, v.cC()[1] / 255, v.cC()[2] / 255); - // const auto vi = tilledPatternGeometry.getIndex(v); - // fanVertexColors[vi] = vColor; - // } - // tilledPatternGeometry.updateEigenEdgeAndVertices(); - // tilledPatternGeometry.registerForDrawing() - // ->addNodeColorQuantity("ap_tilled", fanVertexColors) - // ->setEnabled(true); - // polyscope::show(); - // tilledPatternGeometry.unregister(); - // } - // duplicated here - // Check dangling edges with vcg method - // const bool vcg_tiledPatternHasDangling = - // tiledPatternGeometry.hasUntiledDanglingEdges(); - if (tiledPatternHasDanglingEdges /*&& !hasFloatingComponents && !hasArticulationPoints*/) { - statistics.numberOfPatternsWithADanglingEdgeOrNode++; - if (debugIsOn) { - if (savePlyFiles) { - auto danglingEdgesPath = std::filesystem::path(resultsPath).append("Dangling"); - exportPattern(danglingEdgesPath, patternGeometry, exportTilledPattern); - } - } else { - continue; - } - } - - if (hasFloatingComponents /*&& !hasArticulationPoints && !tiledPatternHasDanglingEdges */) { - statistics.numberOfPatternsWithMoreThanASingleCC++; - if (debugIsOn) { - if (savePlyFiles) { - auto moreThanOneCCPath = std::filesystem::path(resultsPath) - .append("MoreThanOneCC"); - std::filesystem::create_directory(moreThanOneCCPath); - patternGeometry.save( - std::filesystem::path(moreThanOneCCPath).append(patternName).string() - + ".ply"); - PatternGeometry tiledPatternGeometry = PatternGeometry::createTile( - patternGeometry); // the marked nodes of hasDanglingEdges are - - std::vector> eCC; - vcg::tri::Clean::edgeMeshConnectedComponents(tiledPatternGeometry, - eCC); - vcg::tri::UpdateFlags::EdgeClear(tiledPatternGeometry); - const size_t numberOfCC_edgeBased = eCC.size(); - std::sort(eCC.begin(), - eCC.end(), - [](const std::pair &a, - const std::pair &b) { - return a.first > b.first; - }); - - PatternGeometry::EdgePointer &ep = eCC[0].second; - size_t colorsRegistered = 0; - std::stack stack; - stack.push(ep); - while (!stack.empty()) { - EdgePointer ep = stack.top(); - stack.pop(); - - for (int i = 0; i < 2; ++i) { - vcg::edge::VEIterator vei(ep->V(i)); - while (!vei.End()) { - if (!vei.E()->IsV()) { - vei.E()->SetV(); - stack.push(vei.E()); - tiledPatternGeometry - .vert[tiledPatternGeometry.getIndex(vei.V1())] - .C() - = vcg::Color4b::Blue; - tiledPatternGeometry - .vert[tiledPatternGeometry.getIndex(vei.V0())] - .C() - = vcg::Color4b::Blue; - colorsRegistered++; - } - ++vei; - } - } - } - - assert(colorsRegistered == eCC[0].first); - - if (exportTilledPattern) { - tiledPatternGeometry.save(std::filesystem::path(moreThanOneCCPath) - .append(patternName + "_tiled") - .string() - + ".ply"); - } - } - } else { - continue; - } - } - - if (hasArticulationPoints /*&& !hasFloatingComponents && !tiledPatternHasDanglingEdges */) { - statistics.numberOfPatternsWithArticulationPoints++; - if (debugIsOn) { - if (savePlyFiles) { - auto articulationPointsPath = std::filesystem::path(resultsPath) - .append("ArticulationPoints"); - exportPattern(articulationPointsPath, patternGeometry, exportTilledPattern); - } - } else { - continue; - } - } - - const bool isValidPattern = !patternContainsIntersectingEdges - && isInterfaceConnected - /*&& !tiledPatternHasDanglingEdges*/ - && !hasFloatingComponents && !hasArticulationPoints - && !tiledPatternHasNodeWithValenceGreaterThanDesired - && !tiledPatternHasEdgesWithAngleSmallerThanThreshold; - // if (!hasArticulationPoints && !patternContainsIntersectingEdges - // && !tiledPatternHasDanglingEdges && !hasFloatingComponents - // && !tiledPatternHasNodeWithValenceGreaterThanDesired - // && tiledPatternHasEdgesWithAngleSmallerThanThreshold && numberOfDesiredEdges > 4) { - // std::cout << "Pattern found:" << patternName << std::endl; - // patternGeometry.registerForDrawing(); - // polyscope::show(); - // patternGeometry.unregister(); - // } - if (isValidPattern) { - // if(patternName=='2055'){ - // PatternGeometry tiledPatternGeometry = PatternGeometry::createTile( - // patternGeometry); // the marked nodes of hasDanglingEdges are - // tiledPatternGeometry.registerForDrawing(std::array{0, 0, 1}); - // polyscope::show(); - // tiledPatternGeometry.unregister(); - // } - statistics.numberOfValidPatterns++; - validPatternsExist = true; - if (savePlyFiles) { - exportPattern(validPatternsPath, patternGeometry, exportTilledPattern); - } - if (saveCompressedFormat) { - PatternIO::Pattern pattern; - pattern.edges = patternEdges; - pattern.name = patternIndex; - patternSet.patterns.emplace_back(pattern); - // Save valid patterns - // if (patternIndex% patternSetBufferSize == 0) { - if (statistics.numberOfValidPatterns % patternSetBufferSize == 0) { - PatternIO::save(compressedPatternsFilePath, patternSet); - patternSet.patterns.clear(); - patternSet.patterns.reserve(patternSetBufferSize); - } - } - } - - // assert(vcg_tiledPatternHasDangling == tiledPatternHasDanglingEdges); - } while (std::next_permutation(patternBinaryRepresentation.begin(), - patternBinaryRepresentation.end())); - if (!patternSet.patterns.empty() && saveCompressedFormat) { - PatternIO::save(compressedPatternsFilePath, patternSet); + } else { + continue; + } } - if (!validPatternsExist) { - std::filesystem::remove_all(validPatternsPath); - if (!debugIsOn) { - std::filesystem::remove_all(resultsPath); + // Check if pattern contains intersecting edges + const bool patternContainsIntersectingEdges = + patternGeometry.hasIntersectingEdges(patternBinaryRepresentation, + intersectingEdges); + // Export the tiled ply file if it contains intersecting edges + if (patternContainsIntersectingEdges) { + // create the tiled geometry of the pattern + statistics.numberOfPatternsWithIntersectingEdges++; + if (debugIsOn) { + if (savePlyFiles) { + exportPattern( + std::filesystem::path(resultsPath).append("Intersecting"), + patternGeometry, exportTilledPattern); } + } else { + continue; + } } + + // const bool shouldBreak = numberOfDesiredEdges == 4 && patternIndex + // == 53; + const bool tiledPatternHasEdgesWithAngleSmallerThanThreshold = + patternGeometry.hasAngleSmallerThanThreshold(numberOfNodesPerSlot, 15); + if (tiledPatternHasEdgesWithAngleSmallerThanThreshold) { + statistics.numberOfPatternsViolatingAngleThreshold++; + if (debugIsOn /*|| savePlyFiles*/) { + if (savePlyFiles) { + exportPattern(std::filesystem::path(resultsPath) + .append("ExceedingAngleThreshold"), + patternGeometry, exportTilledPattern); + } + } else { + continue; + } + } + + const bool tiledPatternHasNodeWithValenceGreaterThanDesired = + patternGeometry.hasValenceGreaterThan(numberOfNodesPerSlot, 6); + if (tiledPatternHasNodeWithValenceGreaterThanDesired) { + statistics.numberOfPatternsViolatingValenceThreshold++; + if (debugIsOn) { + if (savePlyFiles) { + auto highValencePath = + std::filesystem::path(resultsPath).append("HighValencePatterns"); + exportPattern(highValencePath, patternGeometry, exportTilledPattern); + } + } else { + continue; + } + } + + // Compute the tiled valence + const bool tiledPatternHasDanglingEdges = patternGeometry.hasDanglingEdges( + numberOfNodesPerSlot); // marks the nodes with valence>=1 + // Create the tiled geometry of the pattern + const bool hasFloatingComponents = + !patternGeometry.isFullyConnectedWhenFanned(); + + PatternGeometry fanPatternGeometry = + PatternGeometry::createFan(patternGeometry); + const int interfaceNodeVi = 3; + std::vector connectedEdges; + vcg::edge::VEStarVE(&fanPatternGeometry.vert[interfaceNodeVi], + connectedEdges); + if (!connectedEdges.empty()) { + for (int i = 1; i < 6; i++) { + vcg::tri::Allocator::AddEdge( + fanPatternGeometry, + interfaceNodeVi + (i - 1) * patternGeometry.VN(), + interfaceNodeVi + i * patternGeometry.VN()); + } + } + vcg::tri::Clean::MergeCloseVertex(fanPatternGeometry, + 0.0000005); + vcg::tri::Allocator::CompactEveryVector( + fanPatternGeometry); + vcg::tri::UpdateTopology::VertexEdge(fanPatternGeometry); + vcg::tri::UpdateTopology::EdgeEdge(fanPatternGeometry); + // for (PatternGeometry::VertexType &v : tilledPatternGeometry.vert) + // { + // std::vector connectedEdges; + // vcg::edge::VEStarVE(&v, connectedEdges); + // if (connectedEdges.size() == 1) { + // vcg::tri::Allocator::DeleteVertex(tilledPatternGeometry, + // v); + // vcg::tri::Allocator::DeleteEdge(tilledPatternGeometry, + // *connectedEdges[0]); + // } + // } + // // + // vcg::tri::Allocator::CompactEveryVector(tilledPatternGeometry); + // fanPatternGeometry.updateEigenEdgeAndVertices(); + + BoostGraph fanPatternGraph(fanPatternGeometry.VN()); + // std::cout << "Edges:"; + for (const PatternGeometry::EdgeType& e : fanPatternGeometry.edge) { + if (e.IsD() || e.cV(0)->IsD() || e.cV(1)->IsD()) { + continue; + } + const int vi0 = fanPatternGeometry.getIndex(e.cV(0)); + const int vi1 = fanPatternGeometry.getIndex(e.cV(1)); + boost::add_edge(vi0, vi1, fanPatternGraph); + // std::cout << vi0 << "," << vi1 << " "; + } + // std::cout << std::endl; + + std::vector articulationPoints; + boost::articulation_points(fanPatternGraph, + std::back_inserter(articulationPoints)); + const bool hasArticulationPoints = !articulationPoints.empty(); + // if (!hasArticulationPoints && tiledPatternHasDanglingEdges) { + // PatternGeometry tilledPatternGeometry = + // PatternGeometry::createTile(patternGeometry); + // tilledPatternGeometry.updateEigenEdgeAndVertices(); + // tilledPatternGeometry.registerForDrawing(); + // // ->addNodeColorQuantity("de_noAp_tilled", + // fanVertexColors) + // // ->setEnabled(true); + // polyscope::show(); + // tilledPatternGeometry.unregister(); + // } + // if (hasArticulationPoints && !tiledPatternHasDanglingEdges/*&& + // !patternContainsIntersectingEdges + // && !hasFloatingComponents + // && + // !tiledPatternHasNodeWithValenceGreaterThanDesired + // && + // !tiledPatternHasEdgesWithAngleSmallerThanThreshold*/) + // { + // for (PatternGeometry::VertexType &v : patternGeometry.vert) { + // v.C() = vcg::Color4b::Yellow; + // } + // // std::cout << "AP:"; + // for (const int articulationPointVi : articulationPoints) { + // if (articulationPointVi >= patternGeometry.VN()) { + // continue; + // } + // // std::cout << articulationPointVi << " "; + // patternGeometry.vert[articulationPointVi].C() = + // vcg::Color4b::Red; + // } + // PatternGeometry tilledPatternGeometry = + // PatternGeometry::createTile(patternGeometry); + // // std::cout << std::endl; + // std::vector + // fanVertexColors(tilledPatternGeometry.VN(), glm::vec3(0, 0, + // 1)); for (const PatternGeometry::VertexType &v : + // tilledPatternGeometry.vert) { + // const auto vColor = glm::vec3(v.cC()[0] / 255, v.cC()[1] / + // 255, v.cC()[2] / 255); const auto vi = + // tilledPatternGeometry.getIndex(v); fanVertexColors[vi] = + // vColor; + // } + // tilledPatternGeometry.updateEigenEdgeAndVertices(); + // tilledPatternGeometry.registerForDrawing() + // ->addNodeColorQuantity("ap_tilled", fanVertexColors) + // ->setEnabled(true); + // polyscope::show(); + // tilledPatternGeometry.unregister(); + // } + // duplicated here + // Check dangling edges with vcg method + // const bool vcg_tiledPatternHasDangling = + // tiledPatternGeometry.hasUntiledDanglingEdges(); + if (tiledPatternHasDanglingEdges /*&& !hasFloatingComponents && !hasArticulationPoints*/) { + statistics.numberOfPatternsWithADanglingEdgeOrNode++; + if (debugIsOn) { + if (savePlyFiles) { + auto danglingEdgesPath = + std::filesystem::path(resultsPath).append("Dangling"); + exportPattern(danglingEdgesPath, patternGeometry, + exportTilledPattern); + } + } else { + continue; + } + } + + if (hasFloatingComponents /*&& !hasArticulationPoints && !tiledPatternHasDanglingEdges */) { + statistics.numberOfPatternsWithMoreThanASingleCC++; + if (debugIsOn) { + if (savePlyFiles) { + auto moreThanOneCCPath = + std::filesystem::path(resultsPath).append("MoreThanOneCC"); + std::filesystem::create_directory(moreThanOneCCPath); + patternGeometry.save(std::filesystem::path(moreThanOneCCPath) + .append(patternName) + .string() + + ".ply"); + PatternGeometry tiledPatternGeometry = PatternGeometry::createTile( + patternGeometry); // the marked nodes of hasDanglingEdges are + + std::vector> eCC; + vcg::tri::Clean::edgeMeshConnectedComponents( + tiledPatternGeometry, eCC); + vcg::tri::UpdateFlags::EdgeClear( + tiledPatternGeometry); + const size_t numberOfCC_edgeBased = eCC.size(); + std::sort(eCC.begin(), eCC.end(), + [](const std::pair& a, + const std::pair& b) { + return a.first > b.first; + }); + + PatternGeometry::EdgePointer& ep = eCC[0].second; + size_t colorsRegistered = 0; + std::stack stack; + stack.push(ep); + while (!stack.empty()) { + EdgePointer ep = stack.top(); + stack.pop(); + + for (int i = 0; i < 2; ++i) { + vcg::edge::VEIterator vei(ep->V(i)); + while (!vei.End()) { + if (!vei.E()->IsV()) { + vei.E()->SetV(); + stack.push(vei.E()); + tiledPatternGeometry + .vert[tiledPatternGeometry.getIndex(vei.V1())] + .C() = vcg::Color4b::Blue; + tiledPatternGeometry + .vert[tiledPatternGeometry.getIndex(vei.V0())] + .C() = vcg::Color4b::Blue; + colorsRegistered++; + } + ++vei; + } + } + } + + assert(colorsRegistered == eCC[0].first); + + if (exportTilledPattern) { + tiledPatternGeometry.save(std::filesystem::path(moreThanOneCCPath) + .append(patternName + "_tiled") + .string() + + ".ply"); + } + } + } else { + continue; + } + } + + if (hasArticulationPoints /*&& !hasFloatingComponents && !tiledPatternHasDanglingEdges */) { + statistics.numberOfPatternsWithArticulationPoints++; + if (debugIsOn) { + if (savePlyFiles) { + auto articulationPointsPath = + std::filesystem::path(resultsPath).append("ArticulationPoints"); + exportPattern(articulationPointsPath, patternGeometry, + exportTilledPattern); + } + } else { + continue; + } + } + + const bool isValidPattern = + !patternContainsIntersectingEdges && + isInterfaceConnected + /*&& !tiledPatternHasDanglingEdges*/ + && !hasFloatingComponents && !hasArticulationPoints && + !tiledPatternHasNodeWithValenceGreaterThanDesired && + !tiledPatternHasEdgesWithAngleSmallerThanThreshold; + // if (!hasArticulationPoints && !patternContainsIntersectingEdges + // && !tiledPatternHasDanglingEdges && !hasFloatingComponents + // && !tiledPatternHasNodeWithValenceGreaterThanDesired + // && tiledPatternHasEdgesWithAngleSmallerThanThreshold && + // numberOfDesiredEdges > 4) { std::cout << "Pattern found:" << + // patternName << std::endl; + // patternGeometry.registerForDrawing(); + // polyscope::show(); + // patternGeometry.unregister(); + // } + if (isValidPattern) { + // if(patternName=='2055'){ + // PatternGeometry tiledPatternGeometry = + // PatternGeometry::createTile( + // patternGeometry); // the marked nodes of + // hasDanglingEdges are + // tiledPatternGeometry.registerForDrawing(RGBColor{0, 0, 1}); + // polyscope::show(); + // tiledPatternGeometry.unregister(); + // } + statistics.numberOfValidPatterns++; + validPatternsExist = true; + if (savePlyFiles) { + exportPattern(validPatternsPath, patternGeometry, exportTilledPattern); + } + if (saveCompressedFormat) { + PatternIO::Pattern pattern; + pattern.edges = patternEdges; + pattern.name = patternIndex; + patternSet.patterns.emplace_back(pattern); + // Save valid patterns + // if (patternIndex% patternSetBufferSize == 0) { + if (statistics.numberOfValidPatterns % patternSetBufferSize == 0) { + PatternIO::save(compressedPatternsFilePath, patternSet); + patternSet.patterns.clear(); + patternSet.patterns.reserve(patternSetBufferSize); + } + } + } + + // if (drawingThread.joinable()) { + // drawingThread.join(); + // } + + // assert(vcg_tiledPatternHasDangling == tiledPatternHasDanglingEdges); + } while (std::next_permutation(patternBinaryRepresentation.begin(), + patternBinaryRepresentation.end())); + if (!patternSet.patterns.empty() && saveCompressedFormat) { + PatternIO::save(compressedPatternsFilePath, patternSet); + } + + if (!validPatternsExist) { + std::filesystem::remove_all(validPatternsPath); + if (!debugIsOn) { + std::filesystem::remove_all(resultsPath); + } + } } std::vector TopologyEnumerator::getCoincideEdges( - const std::vector &edgeNodeIndices) const -{ - std::vector coincideEdges; - if (edgeNodeIndices.size() < 3) - return coincideEdges; - for (size_t edgeNodeIndex = 0; edgeNodeIndex < edgeNodeIndices.size() - 2; edgeNodeIndex++) { - const size_t &firstNodeIndex = edgeNodeIndices[edgeNodeIndex]; - for (size_t secondEdgeNodeIndex = edgeNodeIndex + 2; - secondEdgeNodeIndex < edgeNodeIndices.size(); - secondEdgeNodeIndex++) { - const size_t &secondNodeIndex = edgeNodeIndices[secondEdgeNodeIndex]; - coincideEdges.push_back(getEdgeIndex(firstNodeIndex, secondNodeIndex)); - } - } + const std::vector& edgeNodeIndices) const { + std::vector coincideEdges; + if (edgeNodeIndices.size() < 3) return coincideEdges; + for (size_t edgeNodeIndex = 0; edgeNodeIndex < edgeNodeIndices.size() - 2; + edgeNodeIndex++) { + const size_t& firstNodeIndex = edgeNodeIndices[edgeNodeIndex]; + for (size_t secondEdgeNodeIndex = edgeNodeIndex + 2; + secondEdgeNodeIndex < edgeNodeIndices.size(); secondEdgeNodeIndex++) { + const size_t& secondNodeIndex = edgeNodeIndices[secondEdgeNodeIndex]; + coincideEdges.push_back(getEdgeIndex(firstNodeIndex, secondNodeIndex)); + } + } + return coincideEdges; } -bool TopologyEnumerator::isValidPattern(const std::string &patternBinaryRepresentation, - const std::vector &validEdges, - const size_t &numberOfDesiredEdges) const -{ - return true; +bool TopologyEnumerator::isValidPattern( + const std::string& patternBinaryRepresentation, + const std::vector& validEdges, + const size_t& numberOfDesiredEdges) const { + return true; } diff --git a/trianglepatterngeometry.cpp b/trianglepatterngeometry.cpp index 6a88cbb..d0b88d6 100755 --- a/trianglepatterngeometry.cpp +++ b/trianglepatterngeometry.cpp @@ -1,19 +1,19 @@ #include "trianglepatterngeometry.hpp" -#include "trianglepattterntopology.hpp" -#include -#include -#include #include #include #include #include +#include +#include +#include +#include "trianglepattterntopology.hpp" /* include the support for half edges */ #include size_t PatternGeometry::computeTiledValence( - const size_t &nodeIndex, - const std::vector &numberOfNodesPerSlot) const { - std::vector connectedEdges; + const size_t& nodeIndex, + const std::vector& numberOfNodesPerSlot) const { + std::vector connectedEdges; vcg::edge::VEStarVE(&vert[nodeIndex], connectedEdges); const size_t nodeValence = connectedEdges.size(); assert(nodeToSlotMap.count(nodeIndex) != 0); @@ -27,7 +27,7 @@ size_t PatternGeometry::computeTiledValence( } else { correspondingNodeIndex = nodeIndex - 1; } - std::vector connectedEdgesCorrespondingNode; + std::vector connectedEdgesCorrespondingNode; vcg::edge::VEStarVE(&vert[correspondingNodeIndex], connectedEdgesCorrespondingNode); size_t correspondingNodeValence = connectedEdgesCorrespondingNode.size(); @@ -56,7 +56,7 @@ size_t PatternGeometry::computeTiledValence( 0); } assert(correspondingNodeIndex < vn); - std::vector connectedEdgesCorrespondingNode; + std::vector connectedEdgesCorrespondingNode; vcg::edge::VEStarVE(&vert[correspondingNodeIndex], connectedEdgesCorrespondingNode); size_t correspondingNodeValence = connectedEdgesCorrespondingNode.size(); @@ -72,61 +72,63 @@ size_t PatternGeometry::computeTiledValence( return 0; } -size_t PatternGeometry::getFanSize() const { return fanSize; } +size_t PatternGeometry::getFanSize() const { + return fanSize; +} -double PatternGeometry::getTriangleEdgeSize() const { return triangleEdgeSize; } +double PatternGeometry::getTriangleEdgeSize() const { + return triangleEdgeSize; +} PatternGeometry::PatternGeometry() {} -std::vector PatternGeometry::computeVertices() const -{ - std::vector verts(VN()); - for (size_t vi = 0; vi < VN(); vi++) { - verts[vi] = vert[vi].cP(); - } - return verts; +std::vector PatternGeometry::computeVertices() const { + std::vector verts(VN()); + for (size_t vi = 0; vi < VN(); vi++) { + verts[vi] = vert[vi].cP(); + } + return verts; } -PatternGeometry PatternGeometry::createTile(PatternGeometry &pattern) -{ - const size_t fanSize = PatternGeometry().getFanSize(); - PatternGeometry fan(createFan(pattern)); - PatternGeometry tile(fan); +PatternGeometry PatternGeometry::createTile(PatternGeometry& pattern) { + const size_t fanSize = PatternGeometry().getFanSize(); + PatternGeometry fan(createFan(pattern)); + PatternGeometry tile(fan); - if (fanSize % 2 == 1) { - vcg::Matrix44d R; - auto rotationAxis = vcg::Point3d(0, 0, 1); - R.SetRotateDeg(180, rotationAxis); - vcg::tri::UpdatePosition::Matrix(fan, R); - } - vcg::Matrix44d T; - // const double centerAngle = 2 * M_PI / fanSize; - // const double triangleHeight = std::sin((M_PI - centerAngle) / 2) - // * PatternGeometry().triangleEdgeSize; - vcg::tri::UpdateBounding::Box(fan); - const double triangleHeight = fan.bbox.DimY() / 2; - T.SetTranslate(0, -2 * triangleHeight, 0); - vcg::tri::UpdatePosition::Matrix(fan, T); - // fan.registerForDrawing(); - // polyscope::show(); + if (fanSize % 2 == 1) { + vcg::Matrix44d R; + auto rotationAxis = vcg::Point3d(0, 0, 1); + R.SetRotateDeg(180, rotationAxis); + vcg::tri::UpdatePosition::Matrix(fan, R); + } + vcg::Matrix44d T; + // const double centerAngle = 2 * M_PI / fanSize; + // const double triangleHeight = std::sin((M_PI - centerAngle) / 2) + // * PatternGeometry().triangleEdgeSize; + vcg::tri::UpdateBounding::Box(fan); + const double triangleHeight = fan.bbox.DimY() / 2; + T.SetTranslate(0, -2 * triangleHeight, 0); + vcg::tri::UpdatePosition::Matrix(fan, T); + // fan.registerForDrawing(); + // polyscope::show(); - PatternGeometry fanOfFan = createFan(fan); - vcg::tri::Append::Mesh(tile, fanOfFan); - vcg::tri::Clean::MergeCloseVertex(tile, 0.0000005); - vcg::tri::Allocator::CompactEveryVector(tile); - vcg::tri::UpdateTopology::VertexEdge(tile); - vcg::tri::UpdateTopology::EdgeEdge(tile); + PatternGeometry fanOfFan = createFan(fan); + vcg::tri::Append::Mesh(tile, fanOfFan); + vcg::tri::Clean::MergeCloseVertex(tile, 0.0000005); + vcg::tri::Allocator::CompactEveryVector(tile); + vcg::tri::UpdateTopology::VertexEdge(tile); + vcg::tri::UpdateTopology::EdgeEdge(tile); - // for (size_t vi = 0; vi < pattern.vn; vi++) { - // tile.vert[vi].C() = vcg::Color4b::Blue; - // } + // for (size_t vi = 0; vi < pattern.vn; vi++) { + // tile.vert[vi].C() = vcg::Color4b::Blue; + // } - tile.setLabel("tilled_" + pattern.getLabel()); - tile.updateEigenEdgeAndVertices(); - return tile; + tile.setLabel("tilled_" + pattern.getLabel()); + tile.updateEigenEdgeAndVertices(); + return tile; } -PatternGeometry PatternGeometry::createFan(PatternGeometry &pattern) { +PatternGeometry PatternGeometry::createFan(PatternGeometry& pattern) { const size_t fanSize = PatternGeometry().getFanSize(); PatternGeometry fan(pattern); PatternGeometry rotatedPattern(pattern); @@ -141,47 +143,44 @@ PatternGeometry PatternGeometry::createFan(PatternGeometry &pattern) { return fan; } -void PatternGeometry::updateBaseTriangle() -{ - baseTriangle = computeBaseTriangle(); +void PatternGeometry::updateBaseTriangle() { + baseTriangle = computeBaseTriangle(); } -PatternGeometry::PatternGeometry(PatternGeometry &other) -{ - vcg::tri::Append::MeshCopy(*this, other); - this->vertices = other.computeVertices(); - baseTriangle = other.getBaseTriangle(); - baseTriangleHeight = computeBaseTriangleHeight(); - vcg::tri::UpdateTopology::VertexEdge(*this); - vcg::tri::UpdateTopology::EdgeEdge(*this); +PatternGeometry::PatternGeometry(PatternGeometry& other) { + vcg::tri::Append::MeshCopy(*this, other); + this->vertices = other.computeVertices(); + baseTriangle = other.getBaseTriangle(); + baseTriangleHeight = computeBaseTriangleHeight(); + vcg::tri::UpdateTopology::VertexEdge(*this); + vcg::tri::UpdateTopology::EdgeEdge(*this); } -bool PatternGeometry::load(const std::filesystem::__cxx11::path &meshFilePath) -{ - if (!VCGEdgeMesh::load(meshFilePath)) { - return false; - } - addNormals(); - vcg::tri::UpdateTopology::VertexEdge(*this); - baseTriangleHeight = computeBaseTriangleHeight(); - baseTriangle = computeBaseTriangle(); +bool PatternGeometry::load(const std::filesystem::__cxx11::path& meshFilePath) { + if (!VCGEdgeMesh::load(meshFilePath)) { + return false; + } + addNormals(); + vcg::tri::UpdateTopology::VertexEdge(*this); + baseTriangleHeight = computeBaseTriangleHeight(); + baseTriangle = computeBaseTriangle(); - updateEigenEdgeAndVertices(); - return true; + updateEigenEdgeAndVertices(); + return true; } -void PatternGeometry::add(const std::vector &vertices) { +void PatternGeometry::add(const std::vector& vertices) { this->vertices = vertices; - std::for_each(vertices.begin(), vertices.end(), [&](const vcg::Point3d &p) { - vcg::tri::Allocator::AddVertex(*this, p, DefaultNormal); + std::for_each(vertices.begin(), vertices.end(), [&](const vcg::Point3d& p) { + vcg::tri::Allocator::AddVertex(*this, p, DefaultNormal); }); vcg::tri::UpdateTopology::VertexEdge(*this); vcg::tri::UpdateTopology::EdgeEdge(*this); updateEigenEdgeAndVertices(); } -void PatternGeometry::add(const std::vector &edges) { - std::for_each(edges.begin(), edges.end(), [&](const vcg::Point2i &e) { +void PatternGeometry::add(const std::vector& edges) { + std::for_each(edges.begin(), edges.end(), [&](const vcg::Point2i& e) { vcg::tri::Allocator::AddEdge(*this, e[0], e[1]); }); vcg::tri::UpdateTopology::VertexEdge(*this); @@ -189,16 +188,15 @@ void PatternGeometry::add(const std::vector &edges) { updateEigenEdgeAndVertices(); } -void PatternGeometry::add(const std::vector &vertices, - const std::vector &edges) -{ - add(vertices); - add(edges); - updateEigenEdgeAndVertices(); +void PatternGeometry::add(const std::vector& vertices, + const std::vector& edges) { + add(vertices); + add(edges); + updateEigenEdgeAndVertices(); } -void PatternGeometry::add(const std::vector &numberOfNodesPerSlot, - const std::vector &edges) { +void PatternGeometry::add(const std::vector& numberOfNodesPerSlot, + const std::vector& edges) { assert(numberOfNodesPerSlot.size() == 7); auto vertices = constructVertexVector(numberOfNodesPerSlot, fanSize, triangleEdgeSize); @@ -209,9 +207,9 @@ void PatternGeometry::add(const std::vector &numberOfNodesPerSlot, } std::vector PatternGeometry::constructVertexVector( - const std::vector &numberOfNodesPerSlot, const size_t &fanSize, - const double &triangleEdgeSize) { - + const std::vector& numberOfNodesPerSlot, + const size_t& fanSize, + const double& triangleEdgeSize) { std::vector vertices; const double centerAngle = 2 * M_PI / fanSize; const double triangleHeight = @@ -244,7 +242,6 @@ std::vector PatternGeometry::constructVertexVector( const vcg::Point3d edgeVector0(triangleV1 - triangleV0); for (size_t vertexIndex = 0; vertexIndex < numberOfNodesPerSlot[3]; vertexIndex++) { - // vertices[std::accumulate(numberOfNodesPerSlot.begin(), // numberOfNodesPerSlot.begin() + 2, 0) + // vertexIndex] = @@ -260,7 +257,6 @@ std::vector PatternGeometry::constructVertexVector( const vcg::Point3d edgeVector1(triangleV2 - triangleV1); for (size_t vertexIndex = 0; vertexIndex < numberOfNodesPerSlot[4]; vertexIndex++) { - // vertices[std::accumulate(numberOfNodesPerSlot.begin(), // numberOfNodesPerSlot.begin() + 3, 0) + // vertexIndex] = @@ -304,7 +300,7 @@ std::vector PatternGeometry::constructVertexVector( } void PatternGeometry::constructNodeToTiledValenceMap( - const std::vector &numberOfNodesPerSlot) { + const std::vector& numberOfNodesPerSlot) { for (size_t nodeIndex = 0; nodeIndex < vn; nodeIndex++) { const size_t tiledValence = computeTiledValence(nodeIndex, numberOfNodesPerSlot); @@ -313,214 +309,244 @@ void PatternGeometry::constructNodeToTiledValenceMap( } std::vector PatternGeometry::getEdgeVectorsWithVertexAsOrigin( - std::vector &edgePointers, const int &vi) -{ - std::vector incidentElementsVectors(edgePointers.size()); - for (int incidentElementsIndex = 0; incidentElementsIndex < edgePointers.size(); - incidentElementsIndex++) { - assert(vi == getIndex(edgePointers[incidentElementsIndex]->cV(0)) - || vi == getIndex(edgePointers[incidentElementsIndex]->cV(1))); + std::vector& edgePointers, + const int& vi) { + std::vector incidentElementsVectors(edgePointers.size()); + for (int incidentElementsIndex = 0; + incidentElementsIndex < edgePointers.size(); incidentElementsIndex++) { + assert(vi == getIndex(edgePointers[incidentElementsIndex]->cV(0)) || + vi == getIndex(edgePointers[incidentElementsIndex]->cV(1))); - incidentElementsVectors[incidentElementsIndex] - = vi == getIndex(edgePointers[incidentElementsIndex]->cV(0)) - ? edgePointers[incidentElementsIndex]->cP(1) - - edgePointers[incidentElementsIndex]->cP(0) - : edgePointers[incidentElementsIndex]->cP(0) - - edgePointers[incidentElementsIndex]->cP(1); - } + incidentElementsVectors[incidentElementsIndex] = + vi == getIndex(edgePointers[incidentElementsIndex]->cV(0)) + ? edgePointers[incidentElementsIndex]->cP(1) - + edgePointers[incidentElementsIndex]->cP(0) + : edgePointers[incidentElementsIndex]->cP(0) - + edgePointers[incidentElementsIndex]->cP(1); + } - return incidentElementsVectors; + return incidentElementsVectors; } -bool PatternGeometry::hasAngleSmallerThanThreshold(const std::vector &numberOfNodesPerSlot, - const double &angleThreshold_degrees) -{ - assert(numberOfNodesPerSlot.size() == 7); - //Initialize helping structs - if (nodeToSlotMap.empty()) { - FlatPatternTopology::constructNodeToSlotMap(numberOfNodesPerSlot, nodeToSlotMap); - } - if (correspondingNode.empty()) { - constructCorrespondingNodeMap(numberOfNodesPerSlot); +bool PatternGeometry::hasAngleSmallerThanThreshold( + const std::vector& numberOfNodesPerSlot, + const double& angleThreshold_degrees, + const bool shouldBreak) { + assert(numberOfNodesPerSlot.size() == 7); + // Initialize helping structs + if (nodeToSlotMap.empty()) { + FlatPatternTopology::constructNodeToSlotMap(numberOfNodesPerSlot, + nodeToSlotMap); + } + if (correspondingNode.empty()) { + constructCorrespondingNodeMap(numberOfNodesPerSlot); + } + + // const double theta0 = vcg::math::ToDeg(vcg::Point2d(1, 0).Angle()); + // const double theta1 = vcg::math::ToDeg(vcg::Point2d(1, 1).Angle()); + // const double theta2 = vcg::math::ToDeg(vcg::Point2d(0, 1).Angle()); + // const double theta3 = vcg::math::ToDeg(vcg::Point2d(-1, 1).Angle()); + // const double theta4 = vcg::math::ToDeg(vcg::Point2d(-1, 0).Angle()); + // const double theta5 = vcg::math::ToDeg(vcg::Point2d(-1, -1).Angle() + 2 + // * M_PI); const double theta6 = vcg::math::ToDeg(vcg::Point2d(0, + // -1).Angle() + 2 * M_PI); const double theta7 = + // vcg::math::ToDeg(vcg::Point2d(1, -1).Angle() + 2 * M_PI); + + // std::set test{theta0, theta1, theta2, theta3, theta4, theta5, + // theta6, theta7}; + + bool hasAngleSmallerThan = false; + // find tiled incident edges for each node + using EdgeIndex = int; + using ThetaWithXAxis = double; + for (size_t vi = 0; vi < VN(); vi++) { + std::vector incidentElementPointers; + vcg::edge::VEStarVE(&vert[vi], incidentElementPointers); + const size_t numberOfIncidentEdges = incidentElementPointers.size(); + if (numberOfIncidentEdges == 0) { + continue; } + std::vector incidentEdgeVectors = + getEdgeVectorsWithVertexAsOrigin(incidentElementPointers, vi); - // const double theta0 = vcg::math::ToDeg(vcg::Point2d(1, 0).Angle()); - // const double theta1 = vcg::math::ToDeg(vcg::Point2d(1, 1).Angle()); - // const double theta2 = vcg::math::ToDeg(vcg::Point2d(0, 1).Angle()); - // const double theta3 = vcg::math::ToDeg(vcg::Point2d(-1, 1).Angle()); - // const double theta4 = vcg::math::ToDeg(vcg::Point2d(-1, 0).Angle()); - // const double theta5 = vcg::math::ToDeg(vcg::Point2d(-1, -1).Angle() + 2 * M_PI); - // const double theta6 = vcg::math::ToDeg(vcg::Point2d(0, -1).Angle() + 2 * M_PI); - // const double theta7 = vcg::math::ToDeg(vcg::Point2d(1, -1).Angle() + 2 * M_PI); - - // std::set test{theta0, theta1, theta2, theta3, theta4, theta5, theta6, theta7}; - - bool hasAngleSmallerThan = false; - //find tiled incident edges for each node - using EdgeIndex = int; - using ThetaWithXAxis = double; - for (size_t vi = 0; vi < VN(); vi++) { - std::vector incidentElementPointers; - vcg::edge::VEStarVE(&vert[vi], incidentElementPointers); - const size_t numberOfIncidentEdges = incidentElementPointers.size(); - if (numberOfIncidentEdges == 0) { - continue; - } - std::vector incidentEdgeVectors - = getEdgeVectorsWithVertexAsOrigin(incidentElementPointers, vi); - - std::vector tiledIncidentVectors = incidentEdgeVectors; - const size_t slotIndex = nodeToSlotMap[vi]; - if (slotIndex == 2) { - //NOTE:I assume that base triangle slots 1,2(bottom triangle nodes) are not used - std::cerr - << "Slot of bottom base triangle nodes detected.This case is not handled.Exiting.." + std::vector tiledIncidentVectors = incidentEdgeVectors; + const size_t slotIndex = nodeToSlotMap[vi]; + if (slotIndex == 2) { + // NOTE:I assume that base triangle slots 1,2(bottom triangle nodes) are + // not used + std::cerr << "Slot of bottom base triangle nodes detected.This case is " + "not handled.Exiting.." << std::endl; - std::terminate(); - } else if (slotIndex == 3 || slotIndex == 5) { - //NOTE: I don't need to check both triangle edges - std::vector correspondingVertexIncidentElementPointers; - vcg::edge::VEStarVE(&vert[correspondingNode[vi]], - correspondingVertexIncidentElementPointers); - std::vector correspondingVertexIncidentVectors - = getEdgeVectorsWithVertexAsOrigin(correspondingVertexIncidentElementPointers, - correspondingNode[vi]); - // const CoordType &correspondingVertexPosition = vert[correspondingNode[vi]].cP(); - vcg::Matrix33d R; - if (slotIndex == 3) { - R = vcg::RotationMatrix(vcg::Point3d(0, 0, 1), vcg::math::ToRad(-360.0 / fanSize)); - } else { - R = vcg::RotationMatrix(vcg::Point3d(0, 0, 1), vcg::math::ToRad(360.0 / fanSize)); - } - // const CoordType &correspondingVertexPosition_rotated = vert[vi].cP(); - std::transform( - correspondingVertexIncidentVectors.begin(), - correspondingVertexIncidentVectors.end(), - correspondingVertexIncidentVectors.begin(), - [&](const VectorType &v) { - // CoordType rotatedTarget = v * R; - // v = rotatedTarget - correspondingVertexPosition_rotated; - return R * v; - }); - tiledIncidentVectors.insert(tiledIncidentVectors.end(), - correspondingVertexIncidentVectors.begin(), - correspondingVertexIncidentVectors.end()); - } else if (slotIndex == 4) { - std::vector reversedIncidentElementVectors(incidentEdgeVectors.size()); - std::transform(incidentEdgeVectors.begin(), - incidentEdgeVectors.end(), - reversedIncidentElementVectors.begin(), - [&](const VectorType &v) { return -v; }); - //NOTE: for checking the angles not all opposite incident element vectors are needed but rather the two "extreme" ones of slot 4 - //here I simply add them all - tiledIncidentVectors.insert(tiledIncidentVectors.end(), - reversedIncidentElementVectors.begin(), - reversedIncidentElementVectors.end()); - } - // std::vector> edgePoints; - // for (int tiledVectorIndex = 0; tiledVectorIndex < tiledIncidentVectors.size(); - // tiledVectorIndex++) { - // edgePoints.push_back( - // std::array{vert[vi].cP()[0], vert[vi].cP()[1], vert[vi].cP()[2]}); - // edgePoints.push_back( - // std::array{(vert[vi].cP() + tiledIncidentVectors[tiledVectorIndex])[0], - // (vert[vi].cP() + tiledIncidentVectors[tiledVectorIndex])[1], - // (vert[vi].cP() + tiledIncidentVectors[tiledVectorIndex])[2]}); - // } - // polyscope::init(); - // polyscope::registerCurveNetworkLine("temp", edgePoints); - // polyscope::removeStructure("temp"); - if (tiledIncidentVectors.size() == 1) { - continue; - } - - std::vector thetaAnglesOfIncidentVectors(tiledIncidentVectors.size()); - std::transform(tiledIncidentVectors.begin(), - tiledIncidentVectors.end(), - thetaAnglesOfIncidentVectors.begin(), - [](const VectorType &v) { return vcg::Point2d(v[0], v[1]).Angle(); }); - //sort them using theta angles - std::sort(thetaAnglesOfIncidentVectors.begin(), thetaAnglesOfIncidentVectors.end()); - // polyscope::show(); - - // std::vector angles_theta(thetaAnglesOfIncidentVectors); - // for (double &theta_rad : angles_theta) { - // theta_rad = vcg::math::ToDeg(theta_rad); - // } - - //find nodes that contain incident edges with relative angles less than the threshold - const double angleThreshold_rad = vcg::math::ToRad(angleThreshold_degrees); - for (int thetaAngleIndex = 0; thetaAngleIndex < thetaAnglesOfIncidentVectors.size(); - thetaAngleIndex++) { - const auto &va_theta - = thetaAnglesOfIncidentVectors[(thetaAngleIndex + 1) - % thetaAnglesOfIncidentVectors.size()]; - const auto &vb_theta = thetaAnglesOfIncidentVectors[thetaAngleIndex]; - // const auto &va - // = tiledIncidentVectors[(thetaAngleIndex + 1) % thetaAnglesOfIncidentVectors.size()]; - // const auto &vb = tiledIncidentVectors[thetaAngleIndex]; - const double absAngleDifference = std::abs(va_theta - vb_theta); - // const double debug_difDegOtherway = vcg::math::ToDeg( - // std::acos((va * vb) / (va.Norm() * vb.Norm()))); - // const double debug_diffDeg = vcg::math::ToDeg(absAngleDifference); - if (absAngleDifference < angleThreshold_rad - /*&& absAngleDifference > vcg::math::ToRad(0.01)*/) { - // std::cout << "Found angDiff:" << absAngleDifference << std::endl; - // vert[vi].C() = vcg::Color4b::Magenta; - // hasAngleSmallerThan = true; - return true; - } - } - const double firstLastPairAngleDiff = std::abs( - thetaAnglesOfIncidentVectors[0] - - thetaAnglesOfIncidentVectors[thetaAnglesOfIncidentVectors.size() - 1]); - if (firstLastPairAngleDiff < angleThreshold_rad && firstLastPairAngleDiff > 0.01) { - return true; - } + std::terminate(); + } else if (slotIndex == 3 || slotIndex == 5) { + // NOTE: I don't need to check both triangle edges + std::vector + correspondingVertexIncidentElementPointers; + vcg::edge::VEStarVE(&vert[correspondingNode[vi]], + correspondingVertexIncidentElementPointers); + std::vector correspondingVertexIncidentVectors = + getEdgeVectorsWithVertexAsOrigin( + correspondingVertexIncidentElementPointers, + correspondingNode[vi]); + // const CoordType &correspondingVertexPosition = + // vert[correspondingNode[vi]].cP(); + vcg::Matrix33d R; + if (slotIndex == 3) { + R = vcg::RotationMatrix(vcg::Point3d(0, 0, 1), + vcg::math::ToRad(-360.0 / fanSize)); + } else { + R = vcg::RotationMatrix(vcg::Point3d(0, 0, 1), + vcg::math::ToRad(360.0 / fanSize)); + } + // const CoordType &correspondingVertexPosition_rotated = + // vert[vi].cP(); + std::transform(correspondingVertexIncidentVectors.begin(), + correspondingVertexIncidentVectors.end(), + correspondingVertexIncidentVectors.begin(), + [&](const VectorType& v) { + // CoordType rotatedTarget + // = v * R; v = + // rotatedTarget - + // correspondingVertexPosition_rotated; + return R * v; + }); + tiledIncidentVectors.insert(tiledIncidentVectors.end(), + correspondingVertexIncidentVectors.begin(), + correspondingVertexIncidentVectors.end()); + } else if (slotIndex == 4) { + std::vector reversedIncidentElementVectors( + incidentEdgeVectors.size()); + std::transform(incidentEdgeVectors.begin(), incidentEdgeVectors.end(), + reversedIncidentElementVectors.begin(), + [&](const VectorType& v) { return -v; }); + // NOTE: for checking the angles not all opposite incident element vectors + // are needed but rather the two "extreme" ones of slot 4 here I simply + // add them all + tiledIncidentVectors.insert(tiledIncidentVectors.end(), + reversedIncidentElementVectors.begin(), + reversedIncidentElementVectors.end()); } - return false; + // if (shouldBreak) { + // std::vector> edgePoints; + // for (int tiledVectorIndex = 0; + // tiledVectorIndex < tiledIncidentVectors.size(); + // tiledVectorIndex++) { + // edgePoints.push_back(std::array{ + // vert[vi].cP()[0], vert[vi].cP()[1], vert[vi].cP()[2]}); + // edgePoints.push_back(std::array{ + // (vert[vi].cP() + + // tiledIncidentVectors[tiledVectorIndex])[0], (vert[vi].cP() + // + tiledIncidentVectors[tiledVectorIndex])[1], + // (vert[vi].cP() + + // tiledIncidentVectors[tiledVectorIndex])[2]}); + // } + // polyscope::init(); + // polyscope::registerCurveNetworkLine("vi:" + std::to_string(vi), + // edgePoints); + + // polyscope::show(); + // polyscope::removeStructure("vi:" + std::to_string(vi)); + // } + + if (tiledIncidentVectors.size() == 1) { + continue; + } + + std::vector thetaAnglesOfIncidentVectors( + tiledIncidentVectors.size()); + std::transform( + tiledIncidentVectors.begin(), tiledIncidentVectors.end(), + thetaAnglesOfIncidentVectors.begin(), + [](const VectorType& v) { return vcg::Point2d(v[0], v[1]).Angle(); }); + // sort them using theta angles + std::sort(thetaAnglesOfIncidentVectors.begin(), + thetaAnglesOfIncidentVectors.end()); + + // std::vector angles_theta(thetaAnglesOfIncidentVectors); + // for (double &theta_rad : angles_theta) { + // theta_rad = vcg::math::ToDeg(theta_rad); + // } + + // find nodes that contain incident edges with relative angles less than the + // threshold + const double angleThreshold_rad = vcg::math::ToRad(angleThreshold_degrees); + for (int thetaAngleIndex = 0; + thetaAngleIndex < thetaAnglesOfIncidentVectors.size(); + thetaAngleIndex++) { + const auto& va_theta = + thetaAnglesOfIncidentVectors[(thetaAngleIndex + 1) % + thetaAnglesOfIncidentVectors.size()]; + const auto& vb_theta = thetaAnglesOfIncidentVectors[thetaAngleIndex]; + // const auto &va + // = tiledIncidentVectors[(thetaAngleIndex + 1) % + // thetaAnglesOfIncidentVectors.size()]; + // const auto &vb = tiledIncidentVectors[thetaAngleIndex]; + const double absAngleDifference = std::abs(va_theta - vb_theta); + // const double debug_difDegOtherway = vcg::math::ToDeg( + // std::acos((va * vb) / (va.Norm() * vb.Norm()))); + // const double debug_diffDeg = + // vcg::math::ToDeg(absAngleDifference); + if (absAngleDifference < angleThreshold_rad + /*&& absAngleDifference > vcg::math::ToRad(0.01)*/) { + // std::cout << "Found angDiff:" << absAngleDifference << + // std::endl; vert[vi].C() = vcg::Color4b::Magenta; + // hasAngleSmallerThan = true; + return true; + } + } + const double firstLastPairAngleDiff = std::abs( + thetaAnglesOfIncidentVectors[0] - + thetaAnglesOfIncidentVectors[thetaAnglesOfIncidentVectors.size() - 1]); + if (firstLastPairAngleDiff < angleThreshold_rad && + firstLastPairAngleDiff > 0.01) { + return true; + } + } + return false; } -bool PatternGeometry::hasValenceGreaterThan(const std::vector &numberOfNodesPerSlot, - const size_t &valenceThreshold) -{ - //Initialize helping structs - if (nodeToSlotMap.empty()) { - FlatPatternTopology::constructNodeToSlotMap(numberOfNodesPerSlot, nodeToSlotMap); - } - if (correspondingNode.empty()) { - constructCorrespondingNodeMap(numberOfNodesPerSlot); - } - if (nodeTiledValence.empty()) { - constructNodeToTiledValenceMap(numberOfNodesPerSlot); - } - - //Check tiled valence of the pattern's nodes - bool hasNodeWithValenceGreaterThanDesired = false; - for (size_t nodeIndex = 0; nodeIndex < vn; nodeIndex++) { - const size_t tiledValence = nodeTiledValence[nodeIndex]; - if (tiledValence > valenceThreshold) { - vert[nodeIndex].C() = vcg::Color4b::LightRed; - hasNodeWithValenceGreaterThanDesired = true; - } - } - return hasNodeWithValenceGreaterThanDesired; -} - -bool PatternGeometry::hasDanglingEdges( - const std::vector &numberOfNodesPerSlot) { - //Initialize helping structs - if (nodeToSlotMap.empty()) { - FlatPatternTopology::constructNodeToSlotMap(numberOfNodesPerSlot, nodeToSlotMap); - } - if (correspondingNode.empty()) { - constructCorrespondingNodeMap(numberOfNodesPerSlot); - } +bool PatternGeometry::hasValenceGreaterThan( + const std::vector& numberOfNodesPerSlot, + const size_t& valenceThreshold) { + // Initialize helping structs + if (nodeToSlotMap.empty()) { + FlatPatternTopology::constructNodeToSlotMap(numberOfNodesPerSlot, + nodeToSlotMap); + } + if (correspondingNode.empty()) { + constructCorrespondingNodeMap(numberOfNodesPerSlot); + } if (nodeTiledValence.empty()) { constructNodeToTiledValenceMap(numberOfNodesPerSlot); } - //Check tiled valence of the pattern's nodes + // Check tiled valence of the pattern's nodes + bool hasNodeWithValenceGreaterThanDesired = false; + for (size_t nodeIndex = 0; nodeIndex < vn; nodeIndex++) { + const size_t tiledValence = nodeTiledValence[nodeIndex]; + if (tiledValence > valenceThreshold) { + vert[nodeIndex].C() = vcg::Color4b::LightRed; + hasNodeWithValenceGreaterThanDesired = true; + } + } + return hasNodeWithValenceGreaterThanDesired; +} + +bool PatternGeometry::hasDanglingEdges( + const std::vector& numberOfNodesPerSlot) { + // Initialize helping structs + if (nodeToSlotMap.empty()) { + FlatPatternTopology::constructNodeToSlotMap(numberOfNodesPerSlot, + nodeToSlotMap); + } + if (correspondingNode.empty()) { + constructCorrespondingNodeMap(numberOfNodesPerSlot); + } + if (nodeTiledValence.empty()) { + constructNodeToTiledValenceMap(numberOfNodesPerSlot); + } + + // Check tiled valence of the pattern's nodes bool hasDanglingEdges = false; for (size_t nodeIndex = 0; nodeIndex < vn; nodeIndex++) { const size_t tiledValence = nodeTiledValence[nodeIndex]; @@ -540,12 +566,11 @@ bool PatternGeometry::hasUntiledDanglingEdges() { // vcg::tri::UpdateTopology::EdgeEdge(*this); bool hasDanglingEdges = false; for (size_t vi = 0; vi < vn; vi++) { - std::vector connectedEdges; + std::vector connectedEdges; vcg::edge::VEStarVE(&vert[vi], connectedEdges); const size_t nodeValence = connectedEdges.size(); if (nodeValence == 1) { if (vert[vi].C().operator==(vcg::Color4b(vcg::Color4b::Red))) { - } else { vert[vi].C() = vcg::Color4b::Blue; } @@ -557,169 +582,170 @@ bool PatternGeometry::hasUntiledDanglingEdges() { // TODO: The function expects that the numberOfNodesPerSlot follows a specific // format and that the vertex container was populated in a particular order. -void PatternGeometry::constructCorrespondingNodeMap(const std::vector &numberOfNodesPerSlot) -{ - assert(vn != 0 && !nodeToSlotMap.empty() && correspondingNode.empty() - && numberOfNodesPerSlot.size() == 7); +void PatternGeometry::constructCorrespondingNodeMap( + const std::vector& numberOfNodesPerSlot) { + assert(vn != 0 && !nodeToSlotMap.empty() && correspondingNode.empty() && + numberOfNodesPerSlot.size() == 7); - for (size_t nodeIndex = 0; nodeIndex < vn; nodeIndex++) { - const size_t slotIndex = nodeToSlotMap[nodeIndex]; - if (slotIndex == 1) { - correspondingNode[nodeIndex] = nodeIndex + 1; - } else if (slotIndex == 2) { - correspondingNode[nodeIndex] = nodeIndex - 1; - } else if (slotIndex == 3) { - const size_t numberOfNodesBefore = nodeIndex - - std::accumulate(numberOfNodesPerSlot.begin(), - numberOfNodesPerSlot.begin() + 3, - 0); - correspondingNode[nodeIndex] = std::accumulate(numberOfNodesPerSlot.begin(), - numberOfNodesPerSlot.begin() + 6, - 0) - - 1 - numberOfNodesBefore; - } else if (slotIndex == 5) { - const size_t numberOfNodesAfter = std::accumulate(numberOfNodesPerSlot.begin(), - numberOfNodesPerSlot.begin() + 6, - 0) - - 1 - nodeIndex; - correspondingNode[nodeIndex] = numberOfNodesAfter - + std::accumulate(numberOfNodesPerSlot.begin(), - numberOfNodesPerSlot.begin() + 3, - 0); - } + for (size_t nodeIndex = 0; nodeIndex < vn; nodeIndex++) { + const size_t slotIndex = nodeToSlotMap[nodeIndex]; + if (slotIndex == 1) { + correspondingNode[nodeIndex] = nodeIndex + 1; + } else if (slotIndex == 2) { + correspondingNode[nodeIndex] = nodeIndex - 1; + } else if (slotIndex == 3) { + const size_t numberOfNodesBefore = + nodeIndex - std::accumulate(numberOfNodesPerSlot.begin(), + numberOfNodesPerSlot.begin() + 3, 0); + correspondingNode[nodeIndex] = + std::accumulate(numberOfNodesPerSlot.begin(), + numberOfNodesPerSlot.begin() + 6, 0) - + 1 - numberOfNodesBefore; + } else if (slotIndex == 5) { + const size_t numberOfNodesAfter = + std::accumulate(numberOfNodesPerSlot.begin(), + numberOfNodesPerSlot.begin() + 6, 0) - + 1 - nodeIndex; + correspondingNode[nodeIndex] = + numberOfNodesAfter + std::accumulate(numberOfNodesPerSlot.begin(), + numberOfNodesPerSlot.begin() + 3, + 0); } + } } -bool PatternGeometry::isFullyConnectedWhenFanned() -{ - assert(vn != 0 /* && !correspondingNode.empty()*/); - // TrianglePatternGeometry copyOfPattern(*this); +bool PatternGeometry::isFullyConnectedWhenFanned() { + assert(vn != 0 /* && !correspondingNode.empty()*/); + // TrianglePatternGeometry copyOfPattern(*this); - // // If bottom interface nodes have a valence of zero there definetely more than - // // a single cc - // bool bottomInterfaceIsConnected = false; - // for (size_t nodeIndex = 0; nodeIndex < vn; nodeIndex++) { - // if (nodeToSlotMap[nodeIndex] == 1 || nodeToSlotMap[nodeIndex] == 4 - // || nodeToSlotMap[nodeIndex] == 2) { - // std::vector connectedEdges; - // vcg::edge::VEStarVE(&vert[nodeIndex], connectedEdges); - // const size_t nodeValence = connectedEdges.size(); - // if (nodeValence != 0) { - // bottomInterfaceIsConnected = true; - // break; - // } - // } - // } - // if (!bottomInterfaceIsConnected) { - // return false; - // } + // // If bottom interface nodes have a valence of zero there definetely more + // than + // // a single cc + // bool bottomInterfaceIsConnected = false; + // for (size_t nodeIndex = 0; nodeIndex < vn; nodeIndex++) { + // if (nodeToSlotMap[nodeIndex] == 1 || nodeToSlotMap[nodeIndex] == 4 + // || nodeToSlotMap[nodeIndex] == 2) { + // std::vector connectedEdges; + // vcg::edge::VEStarVE(&vert[nodeIndex], connectedEdges); + // const size_t nodeValence = connectedEdges.size(); + // if (nodeValence != 0) { + // bottomInterfaceIsConnected = true; + // break; + // } + // } + // } + // if (!bottomInterfaceIsConnected) { + // return false; + // } - PatternGeometry fanedPattern = createFan(*this); - vcg::tri::Clean::MergeCloseVertex(fanedPattern, 0.000000005); - vcg::tri::Allocator::CompactEveryVector(fanedPattern); - vcg::tri::UpdateTopology::VertexEdge(fanedPattern); - vcg::tri::UpdateTopology::EdgeEdge(fanedPattern); - std::vector> eCC; - vcg::tri::Clean::edgeMeshConnectedComponents(fanedPattern, eCC); + PatternGeometry fanedPattern = createFan(*this); + vcg::tri::Clean::MergeCloseVertex(fanedPattern, 0.000000005); + vcg::tri::Allocator::CompactEveryVector(fanedPattern); + vcg::tri::UpdateTopology::VertexEdge(fanedPattern); + vcg::tri::UpdateTopology::EdgeEdge(fanedPattern); + std::vector> eCC; + vcg::tri::Clean::edgeMeshConnectedComponents(fanedPattern, + eCC); - const bool sideInterfaceIsConnected = 1 == eCC.size(); - if (!sideInterfaceIsConnected) { - return false; - } + const bool sideInterfaceIsConnected = 1 == eCC.size(); + if (!sideInterfaceIsConnected) { + return false; + } - // for (size_t nodeIndex = 0; nodeIndex < vn; nodeIndex++) { - // if (nodeTiledValence[nodeIndex] == 0) - // continue; - // const size_t slotIndex = nodeSlot[nodeIndex]; - // // connect nodes belonging to first or third slot(nodes on the first - // // triangle edge) - // // if (nodeTiledValence[nodeIndex] == 0 && slotIndex == 3) { - // // continue; - // // } - // if (slotIndex == 1 || slotIndex == 3) { - // assert(correspondingNode.count(nodeIndex) != 0); - // const size_t correspondingNodeIndex = - // correspondingNode[nodeIndex]; - // std::vector starEdges; - // vcg::edge::VEStarVE(&vert[nodeIndex], starEdges); - // bool containsEdge = false; - // for (TrianglePatternGeometry::EdgeType *e : starEdges) { - // assert(vcg::tri::Index(*this, e->V(0)) == nodeIndex || - // vcg::tri::Index(*this, e->V(1)) == nodeIndex); - // if (vcg::tri::Index(*this, e->V(0)) == nodeIndex) { - // if (vcg::tri::Index(*this, e->V(1)) == correspondingNodeIndex) { - // containsEdge = true; - // break; - // } - // } else if (vcg::tri::Index(*this, e->V(1)) == nodeIndex) { - // if (vcg::tri::Index(*this, e->V(0)) == correspondingNodeIndex) { - // containsEdge = true; - // break; - // } - // } - // } - // if (!containsEdge) { - // vcg::tri::Allocator::AddEdge( - // copyOfPattern, nodeIndex, correspondingNodeIndex); - // } - // } else if (slotIndex == 2 || slotIndex == 5) { - // assert(correspondingNode.count(nodeIndex) != 0); - // } else { - // assert(correspondingNode.count(nodeIndex) == 0); - // } - // } + // for (size_t nodeIndex = 0; nodeIndex < vn; nodeIndex++) { + // if (nodeTiledValence[nodeIndex] == 0) + // continue; + // const size_t slotIndex = nodeSlot[nodeIndex]; + // // connect nodes belonging to first or third slot(nodes on the first + // // triangle edge) + // // if (nodeTiledValence[nodeIndex] == 0 && slotIndex == 3) { + // // continue; + // // } + // if (slotIndex == 1 || slotIndex == 3) { + // assert(correspondingNode.count(nodeIndex) != 0); + // const size_t correspondingNodeIndex = + // correspondingNode[nodeIndex]; + // std::vector starEdges; + // vcg::edge::VEStarVE(&vert[nodeIndex], starEdges); + // bool containsEdge = false; + // for (TrianglePatternGeometry::EdgeType *e : starEdges) { + // assert(vcg::tri::Index(*this, e->V(0)) == nodeIndex || + // vcg::tri::Index(*this, e->V(1)) == nodeIndex); + // if (vcg::tri::Index(*this, e->V(0)) == nodeIndex) { + // if (vcg::tri::Index(*this, e->V(1)) == correspondingNodeIndex) { + // containsEdge = true; + // break; + // } + // } else if (vcg::tri::Index(*this, e->V(1)) == nodeIndex) { + // if (vcg::tri::Index(*this, e->V(0)) == correspondingNodeIndex) { + // containsEdge = true; + // break; + // } + // } + // } + // if (!containsEdge) { + // vcg::tri::Allocator::AddEdge( + // copyOfPattern, nodeIndex, correspondingNodeIndex); + // } + // } else if (slotIndex == 2 || slotIndex == 5) { + // assert(correspondingNode.count(nodeIndex) != 0); + // } else { + // assert(correspondingNode.count(nodeIndex) == 0); + // } + // } - // std::vector> eCC; - // vcg::tri::Clean::edgeMeshConnectedComponents( - // copyOfPattern, eCC); - // size_t numberOfCC_edgeBased = eCC.size(); - // size_t numberOfCC_vertexBased = numberOfCC_edgeBased; - // if (numberOfCC_edgeBased == 1) { - // vcg::tri::UpdateTopology::VertexEdge( - // copyOfPattern); - // vcg::tri::UpdateTopology::EdgeEdge(copyOfPattern); - // vcg::tri::UpdateFlags::VertexSetV(copyOfPattern); - // vcg::tri::UpdateFlags::VertexClear(copyOfPattern); - // for (size_t ei = 0; ei < copyOfPattern.EN(); ei++) { - // copyOfPattern.edge[ei].V(0)->SetV(); - // copyOfPattern.edge[ei].V(1)->SetV(); - // } + // std::vector> eCC; + // vcg::tri::Clean::edgeMeshConnectedComponents( + // copyOfPattern, eCC); + // size_t numberOfCC_edgeBased = eCC.size(); + // size_t numberOfCC_vertexBased = numberOfCC_edgeBased; + // if (numberOfCC_edgeBased == 1) { + // vcg::tri::UpdateTopology::VertexEdge( + // copyOfPattern); + // vcg::tri::UpdateTopology::EdgeEdge(copyOfPattern); + // vcg::tri::UpdateFlags::VertexSetV(copyOfPattern); + // vcg::tri::UpdateFlags::VertexClear(copyOfPattern); + // for (size_t ei = 0; ei < copyOfPattern.EN(); ei++) { + // copyOfPattern.edge[ei].V(0)->SetV(); + // copyOfPattern.edge[ei].V(1)->SetV(); + // } - // for (size_t vi = 0; vi < copyOfPattern.VN(); vi++) { - // if (!copyOfPattern.vert[vi].IsV()) { - // numberOfCC_vertexBased++; - // } - // } - // return numberOfCC_vertexBased; - // } + // for (size_t vi = 0; vi < copyOfPattern.VN(); vi++) { + // if (!copyOfPattern.vert[vi].IsV()) { + // numberOfCC_vertexBased++; + // } + // } + // return numberOfCC_vertexBased; + // } - // return numberOfCC_edgeBased == 1; // TODO: not good - return true; + // return numberOfCC_edgeBased == 1; // TODO: not good + return true; } bool PatternGeometry::hasIntersectingEdges( - const std::string &patternBinaryRepresentation, - const std::unordered_map> - &intersectingEdges) { + const std::string& patternBinaryRepresentation, + const std::unordered_map>& + intersectingEdges) { bool containsIntersectingEdges = false; for (size_t validEdgeIndex = 0; validEdgeIndex < patternBinaryRepresentation.size(); validEdgeIndex++) { - if (patternBinaryRepresentation[validEdgeIndex] == '1' - && intersectingEdges.contains(validEdgeIndex)) { - for (auto edgeIndexIt = intersectingEdges.find(validEdgeIndex)->second.begin(); - edgeIndexIt != intersectingEdges.find(validEdgeIndex)->second.end(); - edgeIndexIt++) { - if (patternBinaryRepresentation[*edgeIndexIt] == '1') { - containsIntersectingEdges = true; - // statistics.numberOfIntersectingEdgesOverAllPatterns++; - break; // should be uncommented in order to improve - // performance - } - } - if (containsIntersectingEdges) { - break; // should be uncommented in order to improve performance - } + if (patternBinaryRepresentation[validEdgeIndex] == '1' && + intersectingEdges.contains(validEdgeIndex)) { + for (auto edgeIndexIt = + intersectingEdges.find(validEdgeIndex)->second.begin(); + edgeIndexIt != intersectingEdges.find(validEdgeIndex)->second.end(); + edgeIndexIt++) { + if (patternBinaryRepresentation[*edgeIndexIt] == '1') { + containsIntersectingEdges = true; + // statistics.numberOfIntersectingEdgesOverAllPatterns++; + break; // should be uncommented in order to improve + // performance + } } + if (containsIntersectingEdges) { + break; // should be uncommented in order to improve performance + } + } } return containsIntersectingEdges; @@ -727,7 +753,7 @@ bool PatternGeometry::hasIntersectingEdges( std::unordered_map> PatternGeometry::getIntersectingEdges( - size_t &numberOfIntersectingEdgePairs) const { + size_t& numberOfIntersectingEdgePairs) const { std::unordered_map> intersectingEdges; numberOfIntersectingEdgePairs = 0; size_t numberOfEdgePairs; @@ -776,85 +802,78 @@ PatternGeometry::getIntersectingEdges( return intersectingEdges; } -PatternGeometry::PatternGeometry(const std::filesystem::path &patternFilePath, - bool addNormalsIfAbsent) -{ - if (!std::filesystem::exists(std::filesystem::path(patternFilePath))) { - assert(false); - std::cerr << "No flat pattern with name " << patternFilePath << std::endl; - return; - } - if (!load(patternFilePath)) { - assert(false); - std::cerr << "File could not be loaded " << patternFilePath << std::endl; - return; - } - if (addNormalsIfAbsent) { - addNormals(); - } +PatternGeometry::PatternGeometry(const std::filesystem::path& patternFilePath, + bool addNormalsIfAbsent) { + if (!std::filesystem::exists(std::filesystem::path(patternFilePath))) { + assert(false); + std::cerr << "No flat pattern with name " << patternFilePath << std::endl; + return; + } + if (!load(patternFilePath)) { + assert(false); + std::cerr << "File could not be loaded " << patternFilePath << std::endl; + return; + } + if (addNormalsIfAbsent) { + addNormals(); + } - vcg::tri::UpdateTopology::VertexEdge(*this); - baseTriangleHeight = computeBaseTriangleHeight(); - baseTriangle = computeBaseTriangle(); + vcg::tri::UpdateTopology::VertexEdge(*this); + baseTriangleHeight = computeBaseTriangleHeight(); + baseTriangle = computeBaseTriangle(); - updateEigenEdgeAndVertices(); + updateEigenEdgeAndVertices(); } -double PatternGeometry::computeBaseTriangleHeight() const -{ - return vcg::Distance(vert[0].cP(), vert[interfaceNodeIndex].cP()); +double PatternGeometry::computeBaseTriangleHeight() const { + return vcg::Distance(vert[0].cP(), vert[interfaceNodeIndex].cP()); } -void PatternGeometry::updateBaseTriangleHeight() -{ - baseTriangleHeight = computeBaseTriangleHeight(); +void PatternGeometry::updateBaseTriangleHeight() { + baseTriangleHeight = computeBaseTriangleHeight(); } -void PatternGeometry::deleteDanglingVertices() -{ - vcg::tri::Allocator::PointerUpdater pu; - VCGEdgeMesh::deleteDanglingVertices(pu); - if (!pu.remap.empty()) { - interfaceNodeIndex = pu.remap[interfaceNodeIndex]; - } +void PatternGeometry::deleteDanglingVertices() { + vcg::tri::Allocator::PointerUpdater pu; + VCGEdgeMesh::deleteDanglingVertices(pu); + if (!pu.remap.empty()) { + interfaceNodeIndex = pu.remap[interfaceNodeIndex]; + } } void PatternGeometry::deleteDanglingVertices( - vcg::tri::Allocator::PointerUpdater &pu) -{ - VCGEdgeMesh::deleteDanglingVertices(pu); + vcg::tri::Allocator::PointerUpdater& pu) { + VCGEdgeMesh::deleteDanglingVertices(pu); } -vcg::Triangle3 PatternGeometry::getBaseTriangle() const -{ - return baseTriangle; +vcg::Triangle3 PatternGeometry::getBaseTriangle() const { + return baseTriangle; } -void PatternGeometry::addNormals() -{ - bool normalsAreAbsent = vert[0].cN().Norm() < 0.000001; - if (normalsAreAbsent) { - for (auto &v : vert) { - v.N() = CoordType(0, 0, 1); - } +void PatternGeometry::addNormals() { + bool normalsAreAbsent = vert[0].cN().Norm() < 0.000001; + if (normalsAreAbsent) { + for (auto& v : vert) { + v.N() = CoordType(0, 0, 1); } + } } -vcg::Triangle3 PatternGeometry::computeBaseTriangle() const -{ - const double baseTriangleHeight = computeBaseTriangleHeight(); - double bottomEdgeHalfSize = baseTriangleHeight / std::tan(M_PI / 3); - CoordType patternCoord0 = vert[0].cP(); - CoordType patternBottomRight = vert[interfaceNodeIndex].cP() - + CoordType(bottomEdgeHalfSize, 0, 0); - CoordType patternBottomLeft = vert[interfaceNodeIndex].cP() - - CoordType(bottomEdgeHalfSize, 0, 0); - return vcg::Triangle3(patternCoord0, patternBottomLeft, patternBottomRight); +vcg::Triangle3 PatternGeometry::computeBaseTriangle() const { + const double baseTriangleHeight = computeBaseTriangleHeight(); + double bottomEdgeHalfSize = baseTriangleHeight / std::tan(M_PI / 3); + CoordType patternCoord0 = vert[0].cP(); + CoordType patternBottomRight = + vert[interfaceNodeIndex].cP() + CoordType(bottomEdgeHalfSize, 0, 0); + CoordType patternBottomLeft = + vert[interfaceNodeIndex].cP() - CoordType(bottomEdgeHalfSize, 0, 0); + return vcg::Triangle3(patternCoord0, patternBottomLeft, + patternBottomRight); } PatternGeometry::PatternGeometry( - const std::vector &numberOfNodesPerSlot, - const std::vector &edges) { + const std::vector& numberOfNodesPerSlot, + const std::vector& edges) { add(numberOfNodesPerSlot, edges); addNormals(); baseTriangleHeight = computeBaseTriangleHeight(); @@ -864,312 +883,320 @@ PatternGeometry::PatternGeometry( updateEigenEdgeAndVertices(); } -//TODO: refactor such that it takes as an input a single pattern and tiles into the desired faces without requiring the each face will contain a single pattern +// TODO: refactor such that it takes as an input a single pattern and tiles into +// the desired faces without requiring the each face will contain a single +// pattern std::shared_ptr PatternGeometry::tilePattern( - std::vector &patterns, - const std::vector &connectToNeighborsVi, - const VCGPolyMesh &tileInto, - const std::vector &perSurfaceFacePatternIndices, - std::vector &tileIntoEdgesToTiledVi, - std::vector> &perPatternIndexToTiledPatternEdgeIndex) -{ - perPatternIndexToTiledPatternEdgeIndex.resize(patterns.size()); - std::shared_ptr pTiledPattern(new PatternGeometry); - std::vector> tileIntoEdgeToInterfaceVi( - tileInto.EN()); //ith element contains all the interface nodes that lay on the ith edge of tileInto - //Compute the barycentric coords of the verts in the base triangle pattern - std::vector> barycentricCoordinates(patterns.size()); - for (size_t patternIndex = 0; patternIndex < patterns.size(); patternIndex++) { - const PatternGeometry &pattern = patterns[patternIndex]; - const vcg::Triangle3 &baseTriangle = pattern.getBaseTriangle(); - barycentricCoordinates[patternIndex].resize(pattern.VN()); - for (int vi = 0; vi < pattern.VN(); vi++) { - CoordType barycentricCoords_vi; - vcg::InterpolationParameters, double>(baseTriangle, - pattern.vert[vi].cP(), - barycentricCoords_vi); - barycentricCoordinates[patternIndex][vi] = barycentricCoords_vi; - } + std::vector& patterns, + const std::vector& connectToNeighborsVi, + const VCGPolyMesh& tileInto, + const std::vector& perSurfaceFacePatternIndices, + std::vector& tileIntoEdgesToTiledVi, + std::vector>& perPatternIndexToTiledPatternEdgeIndex) { + perPatternIndexToTiledPatternEdgeIndex.resize(patterns.size()); + std::shared_ptr pTiledPattern(new PatternGeometry); + std::vector> tileIntoEdgeToInterfaceVi( + tileInto.EN()); // ith element contains all the interface nodes that lay + // on the ith edge of tileInto + // Compute the barycentric coords of the verts in the base triangle pattern + std::vector> barycentricCoordinates(patterns.size()); + for (size_t patternIndex = 0; patternIndex < patterns.size(); + patternIndex++) { + const PatternGeometry& pattern = patterns[patternIndex]; + const vcg::Triangle3& baseTriangle = pattern.getBaseTriangle(); + barycentricCoordinates[patternIndex].resize(pattern.VN()); + for (int vi = 0; vi < pattern.VN(); vi++) { + CoordType barycentricCoords_vi; + vcg::InterpolationParameters, double>( + baseTriangle, pattern.vert[vi].cP(), barycentricCoords_vi); + barycentricCoordinates[patternIndex][vi] = barycentricCoords_vi; } - VCGTriMesh tileIntoEdgeMesh; + } + VCGTriMesh tileIntoEdgeMesh; - assert(vcg::tri::HasFEAdjacency(tileInto)); - assert(vcg::tri::HasFVAdjacency(tileInto)); - for (const VCGPolyMesh::FaceType &f : tileInto.face) { - const int patternIndex = perSurfaceFacePatternIndices[tileInto.getIndex(f)]; - if (patternIndex == -1) { - continue; - } - CoordType centerOfFace(0, 0, 0); - for (size_t vi = 0; vi < f.VN(); vi++) { - centerOfFace = centerOfFace + f.cP(vi); - } - centerOfFace /= f.VN(); - vcg::tri::Allocator::AddVertex(tileIntoEdgeMesh, - centerOfFace, - vcg::Color4b::Yellow); - - std::vector firstInFanConnectToNeighbor_vi(connectToNeighborsVi); - for (int &vi : firstInFanConnectToNeighbor_vi) { - vi += pTiledPattern->VN(); - } - ConstPatternGeometry &pattern = patterns[patternIndex]; - - for (size_t vi = 0; vi < f.VN(); vi++) { - auto ep = f.FEp(vi); - assert(vcg::tri::IsValidPointer(tileInto, ep)); - std::vector meshTrianglePoints{centerOfFace, - f.cP(vi), - vi + 1 == f.VN() ? f.cP(0) : f.cP(vi + 1)}; - // std::vector meshTrianglePoints{centerOfFace, ep->cP(0), ep->cP(1)}; - auto fit = vcg::tri::Allocator::AddFace(tileIntoEdgeMesh, - meshTrianglePoints[0], - meshTrianglePoints[1], - meshTrianglePoints[2]); - // CoordType faceNormal = ((meshTrianglePoints[1] - meshTrianglePoints[0]) - // ^ (meshTrianglePoints[2] - meshTrianglePoints[0])) - // .Normalize(); - //TODO: in planar surfaces I should compute the face of triangle - CoordType faceNormal = f.cN(); - - fit->N() = faceNormal; - PatternGeometry transformedPattern; - transformedPattern.copy(pattern); - // pattern.registerForDrawing(); - // polyscope::show(); - // pattern.unregister(); - //Transform the base triangle nodes to the mesh triangle using barycentric coords - for (int vi = 0; vi < transformedPattern.VN(); vi++) { - transformedPattern.vert[vi].P() = CoordType( - meshTrianglePoints[0] * barycentricCoordinates[patternIndex][vi][0] - + meshTrianglePoints[1] * barycentricCoordinates[patternIndex][vi][1] - + meshTrianglePoints[2] * barycentricCoordinates[patternIndex][vi][2]); - } - - for (VertexType &v : transformedPattern.vert) { - v.N() = faceNormal; - } - - vcg::tri::Append::Remap remap; - vcg::tri::Append::Mesh(*pTiledPattern, - transformedPattern, - remap); - for (size_t ei = 0; ei < pattern.EN(); ei++) { - perPatternIndexToTiledPatternEdgeIndex[patternIndex].push_back(remap.edge[ei]); - } - // pTiledPattern->registerForDrawing(); - // pTiledPattern->markVertices({remap.vert[pattern.interfaceNodeIndex]}); - // polyscope::show(); - // pTiledPattern->unregister(); - const size_t ei = tileInto.getIndex(ep); - tileIntoEdgeToInterfaceVi[ei].push_back(remap.vert[pattern.interfaceNodeIndex]); - //Add edges for connecting the desired vertices - if (!connectToNeighborsVi.empty()) { - if (vi + 1 == f.VN()) { - for (int connectToNeighborIndex = 0; - connectToNeighborIndex < connectToNeighborsVi.size(); - connectToNeighborIndex++) { - auto eIt = vcg::tri::Allocator::AddEdge( - *pTiledPattern, - firstInFanConnectToNeighbor_vi[connectToNeighborIndex], - pTiledPattern->VN() - pattern.VN() - + connectToNeighborsVi[connectToNeighborIndex]); - perPatternIndexToTiledPatternEdgeIndex[patternIndex].push_back( - pTiledPattern->getIndex(*eIt)); - } - } - if (vi != 0) { - for (int connectToNeighborIndex = 0; - connectToNeighborIndex < connectToNeighborsVi.size(); - connectToNeighborIndex++) { - auto eIt = vcg::tri::Allocator::AddEdge( - *pTiledPattern, - pTiledPattern->VN() - 2 * pattern.VN() - + connectToNeighborsVi[connectToNeighborIndex], - pTiledPattern->VN() - pattern.VN() - + connectToNeighborsVi[connectToNeighborIndex]); - perPatternIndexToTiledPatternEdgeIndex[patternIndex].push_back( - pTiledPattern->getIndex(*eIt)); - } - } - } - } + assert(vcg::tri::HasFEAdjacency(tileInto)); + assert(vcg::tri::HasFVAdjacency(tileInto)); + for (const VCGPolyMesh::FaceType& f : tileInto.face) { + const int patternIndex = perSurfaceFacePatternIndices[tileInto.getIndex(f)]; + if (patternIndex == -1) { + continue; } - vcg::tri::Allocator::PointerUpdater pu_vertices; - vcg::tri::Allocator::PointerUpdater pu_edges; - pTiledPattern->removeDuplicateVertices(pu_vertices, pu_edges); - //Update perPattern - // for (std::vector &tiledPatternEdges : perPatternIndexToTiledPatternEdgeIndex) { - // for (size_t &ei : tiledPatternEdges) { - // ei = pu_edges.remap[ei]; - // } - - // auto end = tiledPatternEdges.end(); - // for (auto it = tiledPatternEdges.begin(); it != end; ++it) { - // end = std::remove(it + 1, end, *it); - // } - - // tiledPatternEdges.erase(end, tiledPatternEdges.end()); - // } - - const size_t sumOfEdgeIndices = std::accumulate(perPatternIndexToTiledPatternEdgeIndex.begin(), - perPatternIndexToTiledPatternEdgeIndex.end(), - 0, - [](const size_t &sum, - const std::vector &v) { - return sum + v.size(); - }); - - const int en = pTiledPattern->EN(); - assert(pTiledPattern->EN() == sumOfEdgeIndices); - - tileIntoEdgesToTiledVi.clear(); - tileIntoEdgesToTiledVi.resize(tileInto.EN()); - for (int ei = 0; ei < tileInto.EN(); ei++) { - const std::vector interfaceVis = tileIntoEdgeToInterfaceVi[ei]; - if (interfaceVis.empty()) { - continue; - } - assert(interfaceVis.size() == 1 || interfaceVis.size() == 2); - assert( - interfaceVis.size() == 1 - || (interfaceVis.size() == 2 - && (pu_vertices.remap[interfaceVis[0]] == std::numeric_limits::max() - || pu_vertices.remap[interfaceVis[1]] == std::numeric_limits::max()))); - tileIntoEdgesToTiledVi[ei] = pu_vertices.remap[interfaceVis[0]]; + CoordType centerOfFace(0, 0, 0); + for (size_t vi = 0; vi < f.VN(); vi++) { + centerOfFace = centerOfFace + f.cP(vi); } + centerOfFace /= f.VN(); + vcg::tri::Allocator::AddVertex(tileIntoEdgeMesh, centerOfFace, + vcg::Color4b::Yellow); - pTiledPattern->deleteDanglingVertices(); - vcg::tri::Allocator::CompactEveryVector(*pTiledPattern); - pTiledPattern->updateEigenEdgeAndVertices(); - // pTiledPattern->save(); - return pTiledPattern; + std::vector firstInFanConnectToNeighbor_vi(connectToNeighborsVi); + for (int& vi : firstInFanConnectToNeighbor_vi) { + vi += pTiledPattern->VN(); + } + ConstPatternGeometry& pattern = patterns[patternIndex]; + + for (size_t vi = 0; vi < f.VN(); vi++) { + auto ep = f.FEp(vi); + assert(vcg::tri::IsValidPointer(tileInto, ep)); + std::vector meshTrianglePoints{ + centerOfFace, f.cP(vi), vi + 1 == f.VN() ? f.cP(0) : f.cP(vi + 1)}; + // std::vector meshTrianglePoints{centerOfFace, + // ep->cP(0), ep->cP(1)}; + auto fit = vcg::tri::Allocator::AddFace( + tileIntoEdgeMesh, meshTrianglePoints[0], meshTrianglePoints[1], + meshTrianglePoints[2]); + // CoordType faceNormal = ((meshTrianglePoints[1] - + // meshTrianglePoints[0]) + // ^ (meshTrianglePoints[2] - + // meshTrianglePoints[0])) + // .Normalize(); + // TODO: in planar surfaces I should compute the face of triangle + CoordType faceNormal = f.cN(); + + fit->N() = faceNormal; + PatternGeometry transformedPattern; + transformedPattern.copy(pattern); + // pattern.registerForDrawing(); + // polyscope::show(); + // pattern.unregister(); + // Transform the base triangle nodes to the mesh triangle using + // barycentric coords + for (int vi = 0; vi < transformedPattern.VN(); vi++) { + transformedPattern.vert[vi].P() = + CoordType(meshTrianglePoints[0] * + barycentricCoordinates[patternIndex][vi][0] + + meshTrianglePoints[1] * + barycentricCoordinates[patternIndex][vi][1] + + meshTrianglePoints[2] * + barycentricCoordinates[patternIndex][vi][2]); + } + + for (VertexType& v : transformedPattern.vert) { + v.N() = faceNormal; + } + + vcg::tri::Append::Remap remap; + vcg::tri::Append::Mesh( + *pTiledPattern, transformedPattern, remap); + for (size_t ei = 0; ei < pattern.EN(); ei++) { + perPatternIndexToTiledPatternEdgeIndex[patternIndex].push_back( + remap.edge[ei]); + } + // pTiledPattern->registerForDrawing(); + // pTiledPattern->markVertices({remap.vert[pattern.interfaceNodeIndex]}); + // polyscope::show(); + // pTiledPattern->unregister(); + const size_t ei = tileInto.getIndex(ep); + tileIntoEdgeToInterfaceVi[ei].push_back( + remap.vert[pattern.interfaceNodeIndex]); + // Add edges for connecting the desired vertices + if (!connectToNeighborsVi.empty()) { + if (vi + 1 == f.VN()) { + for (int connectToNeighborIndex = 0; + connectToNeighborIndex < connectToNeighborsVi.size(); + connectToNeighborIndex++) { + auto eIt = vcg::tri::Allocator::AddEdge( + *pTiledPattern, + firstInFanConnectToNeighbor_vi[connectToNeighborIndex], + pTiledPattern->VN() - pattern.VN() + + connectToNeighborsVi[connectToNeighborIndex]); + perPatternIndexToTiledPatternEdgeIndex[patternIndex].push_back( + pTiledPattern->getIndex(*eIt)); + } + } + if (vi != 0) { + for (int connectToNeighborIndex = 0; + connectToNeighborIndex < connectToNeighborsVi.size(); + connectToNeighborIndex++) { + auto eIt = vcg::tri::Allocator::AddEdge( + *pTiledPattern, + pTiledPattern->VN() - 2 * pattern.VN() + + connectToNeighborsVi[connectToNeighborIndex], + pTiledPattern->VN() - pattern.VN() + + connectToNeighborsVi[connectToNeighborIndex]); + perPatternIndexToTiledPatternEdgeIndex[patternIndex].push_back( + pTiledPattern->getIndex(*eIt)); + } + } + } + } + } + vcg::tri::Allocator::PointerUpdater pu_vertices; + vcg::tri::Allocator::PointerUpdater pu_edges; + pTiledPattern->removeDuplicateVertices(pu_vertices, pu_edges); + // Update perPattern + // for (std::vector &tiledPatternEdges : + // perPatternIndexToTiledPatternEdgeIndex) { + // for (size_t &ei : tiledPatternEdges) { + // ei = pu_edges.remap[ei]; + // } + + // auto end = tiledPatternEdges.end(); + // for (auto it = tiledPatternEdges.begin(); it != end; ++it) { + // end = std::remove(it + 1, end, *it); + // } + + // tiledPatternEdges.erase(end, tiledPatternEdges.end()); + // } + + const size_t sumOfEdgeIndices = + std::accumulate(perPatternIndexToTiledPatternEdgeIndex.begin(), + perPatternIndexToTiledPatternEdgeIndex.end(), 0, + [](const size_t& sum, const std::vector& v) { + return sum + v.size(); + }); + + const int en = pTiledPattern->EN(); + assert(pTiledPattern->EN() == sumOfEdgeIndices); + + tileIntoEdgesToTiledVi.clear(); + tileIntoEdgesToTiledVi.resize(tileInto.EN()); + for (int ei = 0; ei < tileInto.EN(); ei++) { + const std::vector interfaceVis = tileIntoEdgeToInterfaceVi[ei]; + if (interfaceVis.empty()) { + continue; + } + assert(interfaceVis.size() == 1 || interfaceVis.size() == 2); + assert( + interfaceVis.size() == 1 || + (interfaceVis.size() == 2 && (pu_vertices.remap[interfaceVis[0]] == + std::numeric_limits::max() || + pu_vertices.remap[interfaceVis[1]] == + std::numeric_limits::max()))); + tileIntoEdgesToTiledVi[ei] = pu_vertices.remap[interfaceVis[0]]; + } + + pTiledPattern->deleteDanglingVertices(); + vcg::tri::Allocator::CompactEveryVector(*pTiledPattern); + pTiledPattern->updateEigenEdgeAndVertices(); + // pTiledPattern->save(); + return pTiledPattern; } -bool PatternGeometry::createHoneycombAtom() -{ - VCGEdgeMesh honeycombQuarter; - const VCGEdgeMesh::CoordType n(0, 0, 1); - const double H = 0.2; - const double height = 1.5 * H; - const double width = 0.2; - const double theta = 70; - const double dy = tan(vcg::math::ToRad(90 - theta)) * width / 2; - vcg::tri::Allocator::AddVertex(honeycombQuarter, - VCGEdgeMesh::CoordType(0, height / 2, 0), - n); - vcg::tri::Allocator::AddVertex(honeycombQuarter, - VCGEdgeMesh::CoordType(0, H / 2 - dy, 0), - n); - vcg::tri::Allocator::AddVertex(honeycombQuarter, - VCGEdgeMesh::CoordType(width / 2, H / 2, 0), - n); - vcg::tri::Allocator::AddVertex(honeycombQuarter, - VCGEdgeMesh::CoordType(width / 2, 0, 0), - n); - vcg::tri::Allocator::AddEdge(honeycombQuarter, 0, 1); - vcg::tri::Allocator::AddEdge(honeycombQuarter, 1, 2); - vcg::tri::Allocator::AddEdge(honeycombQuarter, 2, 3); +bool PatternGeometry::createHoneycombAtom() { + VCGEdgeMesh honeycombQuarter; + const VCGEdgeMesh::CoordType n(0, 0, 1); + const double H = 0.2; + const double height = 1.5 * H; + const double width = 0.2; + const double theta = 70; + const double dy = tan(vcg::math::ToRad(90 - theta)) * width / 2; + vcg::tri::Allocator::AddVertex( + honeycombQuarter, VCGEdgeMesh::CoordType(0, height / 2, 0), n); + vcg::tri::Allocator::AddVertex( + honeycombQuarter, VCGEdgeMesh::CoordType(0, H / 2 - dy, 0), n); + vcg::tri::Allocator::AddVertex( + honeycombQuarter, VCGEdgeMesh::CoordType(width / 2, H / 2, 0), n); + vcg::tri::Allocator::AddVertex( + honeycombQuarter, VCGEdgeMesh::CoordType(width / 2, 0, 0), n); + vcg::tri::Allocator::AddEdge(honeycombQuarter, 0, 1); + vcg::tri::Allocator::AddEdge(honeycombQuarter, 1, 2); + vcg::tri::Allocator::AddEdge(honeycombQuarter, 2, 3); - VCGEdgeMesh honeycombAtom; - // Top right - vcg::tri::Append::MeshCopy(honeycombAtom, honeycombQuarter); - // Bottom right - vcg::Matrix44d rotM; - rotM.SetRotateDeg(180, vcg::Point3d(1, 0, 0)); - vcg::tri::UpdatePosition::Matrix(honeycombQuarter, rotM); - vcg::tri::Append::Mesh(honeycombAtom, honeycombQuarter); - // Bottom left - rotM.SetRotateDeg(180, vcg::Point3d(0, 1, 0)); - vcg::tri::UpdatePosition::Matrix(honeycombQuarter, rotM); - vcg::tri::Append::Mesh(honeycombAtom, honeycombQuarter); - // Top left - rotM.SetRotateDeg(180, vcg::Point3d(1, 0, 0)); - vcg::tri::UpdatePosition::Matrix(honeycombQuarter, rotM); - vcg::tri::Append::Mesh(honeycombAtom, honeycombQuarter); + VCGEdgeMesh honeycombAtom; + // Top right + vcg::tri::Append::MeshCopy(honeycombAtom, + honeycombQuarter); + // Bottom right + vcg::Matrix44d rotM; + rotM.SetRotateDeg(180, vcg::Point3d(1, 0, 0)); + vcg::tri::UpdatePosition::Matrix(honeycombQuarter, rotM); + vcg::tri::Append::Mesh(honeycombAtom, + honeycombQuarter); + // Bottom left + rotM.SetRotateDeg(180, vcg::Point3d(0, 1, 0)); + vcg::tri::UpdatePosition::Matrix(honeycombQuarter, rotM); + vcg::tri::Append::Mesh(honeycombAtom, + honeycombQuarter); + // Top left + rotM.SetRotateDeg(180, vcg::Point3d(1, 0, 0)); + vcg::tri::UpdatePosition::Matrix(honeycombQuarter, rotM); + vcg::tri::Append::Mesh(honeycombAtom, + honeycombQuarter); - for (VertexType &v : honeycombAtom.vert) { - v.P()[2] = 0; + for (VertexType& v : honeycombAtom.vert) { + v.P()[2] = 0; + } + + return true; +} + +void PatternGeometry::copy(PatternGeometry& copyFrom) { + VCGEdgeMesh::copy(copyFrom); + baseTriangleHeight = copyFrom.getBaseTriangleHeight(); + baseTriangle = copyFrom.getBaseTriangle(); + interfaceNodeIndex = copyFrom.interfaceNodeIndex; +} + +void PatternGeometry::scale(const double& desiredBaseTriangleCentralEdgeSize) { + const double baseTriangleCentralEdgeSize = getBaseTriangleHeight(); + const double scaleRatio = + desiredBaseTriangleCentralEdgeSize / baseTriangleCentralEdgeSize; + vcg::tri::UpdatePosition::Scale(*this, scaleRatio); + baseTriangle = computeBaseTriangle(); + baseTriangleHeight = computeBaseTriangleHeight(); + const double debug_baseTriHeight = vcg::Distance( + baseTriangle.cP(0), (baseTriangle.cP(1) + baseTriangle.cP(2)) / 2); + assert(std::abs(desiredBaseTriangleCentralEdgeSize - baseTriangleHeight) < + 1e-10); + int i = 0; + i++; +} + +void PatternGeometry::createFan(const size_t& fanSize) { + PatternGeometry rotatedPattern; + vcg::tri::Append::MeshCopy(rotatedPattern, + *this); + for (int rotationCounter = 1; rotationCounter < fanSize; rotationCounter++) { + vcg::Matrix44d R; + auto rotationAxis = vcg::Point3d(0, 0, 1); + R.SetRotateDeg(360.0 / fanSize, rotationAxis); + vcg::tri::UpdatePosition::Matrix(rotatedPattern, R); + vcg::tri::Append::Mesh(*this, + rotatedPattern); + // Add edges for connecting the desired vertices + removeDuplicateVertices(); + updateEigenEdgeAndVertices(); + } +} + +double PatternGeometry::getBaseTriangleHeight() const { + return baseTriangleHeight; +} + +bool PatternGeometry::isInterfaceConnected( + const std::unordered_set& interfaceNodes) { + std::unordered_set interfaceNodesConnected; + + for (int ei = 0; ei < EN(); ei++) { + const int evi0 = getIndex(edge[ei].cV(0)); + const int evi1 = getIndex(edge[ei].cV(1)); + if (interfaceNodes.contains(evi0) && !interfaceNodes.contains(evi1)) { + interfaceNodesConnected.insert(evi0); + } else if (!interfaceNodes.contains(evi0) && + interfaceNodes.contains(evi1)) { + interfaceNodesConnected.insert(evi1); } + } - return true; -} - -void PatternGeometry::copy(PatternGeometry ©From) -{ - VCGEdgeMesh::copy(copyFrom); - baseTriangleHeight = copyFrom.getBaseTriangleHeight(); - baseTriangle = copyFrom.getBaseTriangle(); - interfaceNodeIndex = copyFrom.interfaceNodeIndex; -} - -void PatternGeometry::scale(const double &desiredBaseTriangleCentralEdgeSize) -{ - const double baseTriangleCentralEdgeSize = getBaseTriangleHeight(); - const double scaleRatio = desiredBaseTriangleCentralEdgeSize / baseTriangleCentralEdgeSize; - vcg::tri::UpdatePosition::Scale(*this, scaleRatio); - baseTriangle = computeBaseTriangle(); - baseTriangleHeight = computeBaseTriangleHeight(); - const double debug_baseTriHeight = vcg::Distance(baseTriangle.cP(0), - (baseTriangle.cP(1) + baseTriangle.cP(2)) / 2); - assert(std::abs(desiredBaseTriangleCentralEdgeSize - baseTriangleHeight) < 1e-10); - int i = 0; - i++; -} - -void PatternGeometry::createFan(const size_t &fanSize) -{ - PatternGeometry rotatedPattern; - vcg::tri::Append::MeshCopy(rotatedPattern, *this); - for (int rotationCounter = 1; rotationCounter < fanSize; rotationCounter++) { - vcg::Matrix44d R; - auto rotationAxis = vcg::Point3d(0, 0, 1); - R.SetRotateDeg(360.0 / fanSize, rotationAxis); - vcg::tri::UpdatePosition::Matrix(rotatedPattern, R); - vcg::tri::Append::Mesh(*this, rotatedPattern); - //Add edges for connecting the desired vertices - removeDuplicateVertices(); - updateEigenEdgeAndVertices(); - } -} - -double PatternGeometry::getBaseTriangleHeight() const -{ - return baseTriangleHeight; -} - -bool PatternGeometry::isInterfaceConnected(const std::unordered_set &interfaceNodes) -{ - std::unordered_set interfaceNodesConnected; - - for (int ei = 0; ei < EN(); ei++) { - const int evi0 = getIndex(edge[ei].cV(0)); - const int evi1 = getIndex(edge[ei].cV(1)); - if (interfaceNodes.contains(evi0) && !interfaceNodes.contains(evi1)) { - interfaceNodesConnected.insert(evi0); - } else if (!interfaceNodes.contains(evi0) && interfaceNodes.contains(evi1)) { - interfaceNodesConnected.insert(evi1); - } - } - - if (interfaceNodesConnected.size() != interfaceNodes.size()) { - return false; - } - return true; + if (interfaceNodesConnected.size() != interfaceNodes.size()) { + return false; + } + return true; } std::unordered_set PatternGeometry::getInterfaceNodes( - const std::vector &numberOfNodesPerSlot) -{ - if (nodeToSlotMap.empty()) { - FlatPatternTopology::constructNodeToSlotMap(numberOfNodesPerSlot, nodeToSlotMap); - } - std::unordered_set interfaceNodes; - for (std::pair viSlotPair : nodeToSlotMap) { - if (viSlotPair.second == 4) { - interfaceNodes.insert(viSlotPair.first); - } + const std::vector& numberOfNodesPerSlot) { + if (nodeToSlotMap.empty()) { + FlatPatternTopology::constructNodeToSlotMap(numberOfNodesPerSlot, + nodeToSlotMap); + } + std::unordered_set interfaceNodes; + for (std::pair viSlotPair : nodeToSlotMap) { + if (viSlotPair.second == 4) { + interfaceNodes.insert(viSlotPair.first); } + } - return interfaceNodes; + return interfaceNodes; } diff --git a/trianglepatterngeometry.hpp b/trianglepatterngeometry.hpp index c4241d2..09ad998 100755 --- a/trianglepatterngeometry.hpp +++ b/trianglepatterngeometry.hpp @@ -1,100 +1,103 @@ #ifndef FLATPATTERNGEOMETRY_HPP #define FLATPATTERNGEOMETRY_HPP -#include "edgemesh.hpp" #include #include #include -#include "vcgtrimesh.hpp" +#include "edgemesh.hpp" #include "polymesh.hpp" +#include "vcgtrimesh.hpp" class PatternGeometry; using ConstPatternGeometry = PatternGeometry; -class PatternGeometry : public VCGEdgeMesh -{ -private: - size_t - computeTiledValence(const size_t &nodeIndex, - const std::vector &numberOfNodesPerSlot) const; - size_t getNodeValence(const size_t &nodeIndex) const; - size_t getNodeSlot(const size_t &nodeIndex) const; +class PatternGeometry : public VCGEdgeMesh { + private: + size_t computeTiledValence( + const size_t& nodeIndex, + const std::vector& numberOfNodesPerSlot) const; + size_t getNodeValence(const size_t& nodeIndex) const; + size_t getNodeSlot(const size_t& nodeIndex) const; void addNormals(); double baseTriangleHeight; inline static size_t fanSize{6}; std::vector vertices; - const double triangleEdgeSize{1}; // radius edge + const double triangleEdgeSize{1}; // radius edge std::unordered_map nodeToSlotMap; std::unordered_map correspondingNode; std::unordered_map nodeTiledValence; vcg::Triangle3 baseTriangle; - void - constructCorrespondingNodeMap(const std::vector &numberOfNodesPerSlot); + void constructCorrespondingNodeMap( + const std::vector& numberOfNodesPerSlot); - void constructNodeToTiledValenceMap(const std::vector &numberOfNodesPerSlot); + void constructNodeToTiledValenceMap( + const std::vector& numberOfNodesPerSlot); - std::vector getEdgeVectorsWithVertexAsOrigin(std::vector &edgePointers, - const int &vi); + std::vector getEdgeVectorsWithVertexAsOrigin( + std::vector& edgePointers, + const int& vi); - public: + public: inline static VectorType DefaultNormal{0.0, 0.0, 1.0}; PatternGeometry(); /*The following function should be a copy constructor with * a const argument but this is impossible due to the * vcglib interface. * */ - PatternGeometry(PatternGeometry &other); - bool load(const std::filesystem::path &meshFilePath) override; - void add(const std::vector &vertices); - void add(const std::vector &edges); - void add(const std::vector &vertices, const std::vector &edges); - void add(const std::vector &numberOfNodesPerSlot, const std::vector &edges); + PatternGeometry(PatternGeometry& other); + bool load(const std::filesystem::path& meshFilePath) override; + void add(const std::vector& vertices); + void add(const std::vector& edges); + void add(const std::vector& vertices, + const std::vector& edges); + void add(const std::vector& numberOfNodesPerSlot, + const std::vector& edges); static std::vector constructVertexVector( - const std::vector &numberOfNodesPerSlot, - const size_t &fanSize, - const double &triangleEdgeSize); - bool hasDanglingEdges(const std::vector &numberOfNodesPerSlot); - bool hasValenceGreaterThan(const std::vector &numberOfNodesPerSlot, - const size_t &valenceThreshold); + const std::vector& numberOfNodesPerSlot, + const size_t& fanSize, + const double& triangleEdgeSize); + bool hasDanglingEdges(const std::vector& numberOfNodesPerSlot); + bool hasValenceGreaterThan(const std::vector& numberOfNodesPerSlot, + const size_t& valenceThreshold); std::vector computeVertices() const; - static PatternGeometry createFan(PatternGeometry &pattern); - static PatternGeometry createTile(PatternGeometry &pattern); + static PatternGeometry createFan(PatternGeometry& pattern); + static PatternGeometry createTile(PatternGeometry& pattern); double getTriangleEdgeSize() const; bool hasUntiledDanglingEdges(); std::unordered_map> getIntersectingEdges( - size_t &numberOfIntersectingEdgePairs) const; + size_t& numberOfIntersectingEdgePairs) const; - static size_t binomialCoefficient(size_t n, size_t m) - { - assert(n >= m); - return tgamma(n + 1) / (tgamma(m + 1) * tgamma(n - m + 1)); + static size_t binomialCoefficient(size_t n, size_t m) { + assert(n >= m); + return tgamma(n + 1) / (tgamma(m + 1) * tgamma(n - m + 1)); } bool isFullyConnectedWhenFanned(); bool hasIntersectingEdges( - const std::string &patternBinaryRepresentation, - const std::unordered_map> - &intersectingEdges); + const std::string& patternBinaryRepresentation, + const std::unordered_map>& + intersectingEdges); bool isPatternValid(); size_t getFanSize() const; - void add(const std::vector &vertices, - const std::vector &edges); + void add(const std::vector& vertices, + const std::vector& edges); - PatternGeometry(const std::vector &numberOfNodesPerSlot, - const std::vector &edges); - PatternGeometry(const std::filesystem::path &patternFilePath, bool addNormalsIfAbsent = true); + PatternGeometry(const std::vector& numberOfNodesPerSlot, + const std::vector& edges); + PatternGeometry(const std::filesystem::path& patternFilePath, + bool addNormalsIfAbsent = true); bool createHoneycombAtom(); - void copy(PatternGeometry ©From); + void copy(PatternGeometry& copyFrom); - void tilePattern(VCGEdgeMesh &pattern, - VCGPolyMesh &tileInto, - const int &interfaceNodeIndex, - const bool &shouldDeleteDanglingEdges); + void tilePattern(VCGEdgeMesh& pattern, + VCGPolyMesh& tileInto, + const int& interfaceNodeIndex, + const bool& shouldDeleteDanglingEdges); - void scale(const double &desiredBaseTriangleCentralEdgeSize); + void scale(const double& desiredBaseTriangleCentralEdgeSize); double getBaseTriangleHeight() const; vcg::Triangle3 computeBaseTriangle() const; @@ -102,35 +105,44 @@ private: double computeBaseTriangleHeight() const; void updateBaseTriangleHeight(); - // PatternGeometry(const std::vector &vertices, const std::vector &edges); - // static std::shared_ptr tilePattern( + // PatternGeometry(const std::vector &vertices, const + // std::vector &edges); static std::shared_ptr + // tilePattern( // std::vector &pattern, // const std::vector &connectToNeighborsVi, // const VCGPolyMesh &tileInto, // std::vector &tileIntoEdgesToTiledVi, // std::vector> &perPatternEdges); - virtual void createFan(/*const std::vector &connectToNeighborsVi = std::vector(),*/ - const size_t &fanSize = 6); - int interfaceNodeIndex{3}; //TODO: Fix this. This should be automatically computed - bool hasAngleSmallerThanThreshold(const std::vector &numberOfNodesPerSlot, - const double &angleThreshold_degrees); + virtual void createFan(/*const std::vector &connectToNeighborsVi = + std::vector(),*/ + const size_t& fanSize = 6); + int interfaceNodeIndex{ + 3}; // TODO: Fix this. This should be automatically computed + bool hasAngleSmallerThanThreshold( + const std::vector& numberOfNodesPerSlot, + const double& angleThreshold_degrees, + const bool shouldBreak = false); vcg::Triangle3 getBaseTriangle() const; - static std::shared_ptr tilePattern(PatternGeometry &pattern, - const std::vector &connectToNeighborsVi, - const VCGPolyMesh &tileInto, - std::vector &tileIntoEdgesToTiledVi); static std::shared_ptr tilePattern( - std::vector &patterns, - const std::vector &connectToNeighborsVi, - const VCGPolyMesh &tileInto, - const std::vector &perSurfaceFacePatternIndices, - std::vector &tileIntoEdgesToTiledVi, - std::vector> &perPatternIndexTiledPatternEdgeIndex); - std::unordered_set getInterfaceNodes(const std::vector &numberOfNodesPerSlot); - bool isInterfaceConnected(const std::unordered_set &interfaceNodes); + PatternGeometry& pattern, + const std::vector& connectToNeighborsVi, + const VCGPolyMesh& tileInto, + std::vector& tileIntoEdgesToTiledVi); + static std::shared_ptr tilePattern( + std::vector& patterns, + const std::vector& connectToNeighborsVi, + const VCGPolyMesh& tileInto, + const std::vector& perSurfaceFacePatternIndices, + std::vector& tileIntoEdgesToTiledVi, + std::vector>& perPatternIndexTiledPatternEdgeIndex); + std::unordered_set getInterfaceNodes( + const std::vector& numberOfNodesPerSlot); + bool isInterfaceConnected( + const std::unordered_set& interfaceNodes); void deleteDanglingVertices() override; void deleteDanglingVertices( - vcg::tri::Allocator::PointerUpdater &pu) override; + vcg::tri::Allocator::PointerUpdater& pu) + override; }; -#endif // FLATPATTERNGEOMETRY_HPP +#endif // FLATPATTERNGEOMETRY_HPP diff --git a/vcgtrimesh.cpp b/vcgtrimesh.cpp index 652a3a9..3c297f4 100755 --- a/vcgtrimesh.cpp +++ b/vcgtrimesh.cpp @@ -121,8 +121,7 @@ bool VCGTriMesh::save(const std::string plyFilename) #ifdef POLYSCOPE_DEFINED -polyscope::SurfaceMesh *VCGTriMesh::registerForDrawing( - const std::optional> &desiredColor, const bool &shouldEnable) const +polyscope::SurfaceMesh *VCGTriMesh::registerForDrawing(const std::optional > &desiredColor, const bool &shouldEnable) const { auto vertices = getVertices(); auto faces = getFaces(); diff --git a/vcgtrimesh.hpp b/vcgtrimesh.hpp index 57252fc..c1226d9 100755 --- a/vcgtrimesh.hpp +++ b/vcgtrimesh.hpp @@ -1,8 +1,8 @@ #ifndef VCGTRIMESH_HPP #define VCGTRIMESH_HPP -#include "mesh.hpp" #include #include +#include "mesh.hpp" #ifdef POLYSCOPE_DEFINED #include @@ -22,40 +22,42 @@ class VCGTriMeshVertex : public vcg::Vertex -{}; -class VCGTriMeshFace - : public vcg::Face {}; -class VCGTriMeshEdge : public vcg::Edge -{}; + vcg::vertex::VEAdj> {}; +class VCGTriMeshFace : public vcg::Face {}; +class VCGTriMeshEdge : public vcg::Edge {}; class VCGTriMesh : public vcg::tri::TriMesh, std::vector, std::vector>, - public Mesh -{ -public: + public Mesh { + public: VCGTriMesh(); - VCGTriMesh(const std::string &filename); - bool load(const std::filesystem::path &meshFilePath) override; - bool load(std::istringstream &offInputStream); + VCGTriMesh(const std::string& filename); + bool load(const std::filesystem::path& meshFilePath) override; + bool load(std::istringstream& offInputStream); Eigen::MatrixX3d getVertices() const; Eigen::MatrixX3i getFaces() const; bool save(const std::string plyFilename); - template size_t getIndex(const MeshElement &element) { + template + size_t getIndex(const MeshElement& element) { return vcg::tri::Index(*this, element); } #ifdef POLYSCOPE_DEFINED - polyscope::SurfaceMesh *registerForDrawing( - const std::optional> &desiredColor = std::nullopt, - const bool &shouldEnable = true) const; + polyscope::SurfaceMesh* registerForDrawing( + const std::optional>& desiredColor = std::nullopt, + const bool& shouldEnable = true) const; #endif Eigen::MatrixX2i getEdges() const; void updateEigenEdgeAndVertices(); void moveToCenter(); }; -#endif // VCGTRIMESH_HPP +#endif // VCGTRIMESH_HPP