#include "reducedmodeloptimizer.hpp" #include "linearsimulationmodel.hpp" #include "simulationhistoryplotter.hpp" #include "trianglepatterngeometry.hpp" #include "trianglepattterntopology.hpp" #include #include #include using namespace ReducedModelOptimization; struct GlobalOptimizationVariables { std::vector g_optimalReducedModelDisplacements; // std::vector> fullPatternDisplacements; std::vector fullPatternResults; std::vector translationalDisplacementNormalizationValues; std::vector rotationalDisplacementNormalizationValues; std::vector> fullPatternSimulationJobs; std::vector> reducedPatternSimulationJobs; std::unordered_map reducedToFullInterfaceViMap; matplot::line_handle gPlotHandle; std::vector objectiveValueHistory; Eigen::VectorXd initialParameters; std::vector simulationScenarioIndices; std::vector g_innerHexagonVectors{6, VectorType(0, 0, 0)}; double innerHexagonInitialRotationAngle{30}; double innerHexagonInitialPos{0}; double minY{DBL_MAX}; std::vector minX; int numOfSimulationCrashes{false}; int numberOfFunctionCalls{0}; int numberOfOptimizationParameters{5}; ReducedModelOptimization::Settings optimizationSettings; vcg::Triangle3 baseTriangle; } global; std::vector reducedPatternMaximumDisplacementSimulationJobs; double ReducedModelOptimizer::computeDisplacementError( const std::vector &reducedPatternDisplacements, const std::vector &fullPatternDisplacements, const std::unordered_map &reducedToFullInterfaceViMap, const double &normalizationFactor) { const double rawError = computeRawDisplacementError(reducedPatternDisplacements, fullPatternDisplacements, reducedToFullInterfaceViMap); if (global.optimizationSettings.normalizationStrategy != Settings::NormalizationStrategy::NonNormalized) { return rawError / normalizationFactor; } return rawError; } double ReducedModelOptimizer::computeRawDisplacementError( const std::vector &reducedPatternDisplacements, const std::vector &fullPatternDisplacements, const std::unordered_map &reducedToFullInterfaceViMap) { double error = 0; for (const auto reducedFullViPair : reducedToFullInterfaceViMap) { const VertexIndex reducedModelVi = reducedFullViPair.first; Eigen::Vector3d reducedVertexDisplacement( reducedPatternDisplacements[reducedModelVi][0], reducedPatternDisplacements[reducedModelVi][1], reducedPatternDisplacements[reducedModelVi][2]); const VertexIndex fullModelVi = reducedFullViPair.second; Eigen::Vector3d fullVertexDisplacement( fullPatternDisplacements[fullModelVi][0], fullPatternDisplacements[fullModelVi][1], fullPatternDisplacements[fullModelVi][2]); Eigen::Vector3d errorVector = fullVertexDisplacement - reducedVertexDisplacement; // error += errorVector.squaredNorm(); error += errorVector.norm(); } return error; } 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()); } double ReducedModelOptimizer::objective(long n, const double *x) { // std::cout.precision(17); // for (int i = 0; i < n; i++) { // std::cout << x[i] << " "; // } // std::cout << std::endl; // const Element &e = // global.reducedPatternSimulationJobs[0]->pMesh->elements[0]; std::cout << // e.axialConstFactor << " " << e.torsionConstFactor << " " // << e.firstBendingConstFactor << " " << // e.secondBendingConstFactor // << std::endl; updateMesh(n, x); // std::cout << e.axialConstFactor << " " << e.torsionConstFactor << " " // << e.firstBendingConstFactor << " " << // e.secondBendingConstFactor // << std::endl; // run simulations double totalError = 0; LinearSimulationModel simulator; // FormFinder simulator; for (const int simulationScenarioIndex : global.simulationScenarioIndices) { SimulationResults reducedModelResults = simulator.executeSimulation( global.reducedPatternSimulationJobs[simulationScenarioIndex]); // std::string filename; if (!reducedModelResults.converged) { totalError += std::numeric_limits::max(); global.numOfSimulationCrashes++; #ifdef POLYSCOPE_DEFINED std::cout << "Failed simulation" << std::endl; #endif } else { const bool usePotentialEnergy = false; double simulationScenarioError; if (usePotentialEnergy) { simulationScenarioError = std::abs( reducedModelResults.internalPotentialEnergy - global.fullPatternResults[simulationScenarioIndex].internalPotentialEnergy); } else { const double translationalError = computeDisplacementError( reducedModelResults.displacements, global.fullPatternResults[simulationScenarioIndex].displacements, global.reducedToFullInterfaceViMap, global.translationalDisplacementNormalizationValues[simulationScenarioIndex]); double rotationalError = 0; for (const auto &reducedToFullInterfaceViPair : global.reducedToFullInterfaceViMap) { const double vertexRotationalError = global.fullPatternResults[simulationScenarioIndex] .rotationalDisplacementQuaternion[reducedToFullInterfaceViPair.second] .angularDistance(reducedModelResults.rotationalDisplacementQuaternion [reducedToFullInterfaceViPair.first]); rotationalError += vertexRotationalError; } simulationScenarioError += translationalError + rotationalError / global.rotationalDisplacementNormalizationValues [simulationScenarioIndex]; } //#ifdef POLYSCOPE_DEFINED // std::cout << "sim error:" << simulationScenarioError << std::endl; // global.reducedPatternSimulationJobs[simulationScenarioIndex]->pMesh->registerForDrawing( // ReducedModelOptimization::Colors::reducedInitial); // reducedModelResults.registerForDrawing( // ReducedModelOptimization::Colors::reducedDeformed); // polyscope::show(); // reducedModelResults.unregister(); //#endif // if (global.optimizationSettings.normalizationStrategy != // NormalizationStrategy::Epsilon && // simulationScenarioError > 1) { // std::cout << "Simulation scenario " // << // simulationScenarioStrings[simulationScenarioIndex] // << " results in an error bigger than one." << // std::endl; // for (size_t parameterIndex = 0; parameterIndex < n; // parameterIndex++) { // std::cout << "x[" + std::to_string(parameterIndex) + "]=" // << x[parameterIndex] << std::endl; // } // } //#ifdef POLYSCOPE_DEFINED // ReducedModelOptimizer::visualizeResults( // global.fullPatternSimulationJobs[simulationScenarioIndex], // global.reducedPatternSimulationJobs[simulationScenarioIndex], // global.reducedToFullInterfaceViMap, false); // ReducedModelOptimizer::visualizeResults( // global.fullPatternSimulationJobs[simulationScenarioIndex], // std::make_shared( // reducedPatternMaximumDisplacementSimulationJobs // [simulationScenarioIndex]), // global.reducedToFullInterfaceViMap, true); // polyscope::removeAllStructures(); //#endif // POLYSCOPE_DEFINED totalError += simulationScenarioError; } } // std::cout << error << std::endl; if (totalError < global.minY) { global.minY = totalError; global.minX.assign(x, x + n); } #ifdef POLYSCOPE_DEFINED // if (++global.numberOfFunctionCalls % 100 == 0) { // std::cout << "Number of function calls:" << global.numberOfFunctionCalls // << std::endl; // } #endif // compute error and return it // global.objectiveValueHistory.push_back(totalError); // auto xPlot = matplot::linspace(0, global.objectiveValueHistory.size(), // global.objectiveValueHistory.size()); // std::vector colors(global.gObjectiveValueHistory.size(), 2); // if (global.g_firstRoundIterationIndex != 0) { // for_each(colors.begin() + g_firstRoundIterationIndex, colors.end(), // [](double &c) { c = 0.7; }); // } // global.gPlotHandle = matplot::scatter(xPlot, global.objectiveValueHistory); // SimulationResultsReporter::createPlot("Number of Steps", "Objective value", // global.objectiveValueHistory); return totalError; } void ReducedModelOptimizer::createSimulationMeshes( PatternGeometry &fullModel, PatternGeometry &reducedModel, std::shared_ptr &pFullPatternSimulationMesh, std::shared_ptr &pReducedPatternSimulationMesh) { if (typeid(CrossSectionType) != typeid(RectangularBeamDimensions)) { std::cerr << "Error: A rectangular cross section is expected." << std::endl; terminate(); } // Full pattern pFullPatternSimulationMesh = std::make_shared(fullModel); pFullPatternSimulationMesh->setBeamCrossSection( CrossSectionType{0.002, 0.002}); pFullPatternSimulationMesh->setBeamMaterial(0.3, 1 * 1e9); // Reduced pattern pReducedPatternSimulationMesh = std::make_shared(reducedModel); pReducedPatternSimulationMesh->setBeamCrossSection( CrossSectionType{0.002, 0.002}); pReducedPatternSimulationMesh->setBeamMaterial(0.3, 1 * 1e9); } void ReducedModelOptimizer::createSimulationMeshes( PatternGeometry &fullModel, PatternGeometry &reducedModel) { ReducedModelOptimizer::createSimulationMeshes( fullModel, reducedModel, m_pFullPatternSimulationMesh, m_pReducedPatternSimulationMesh); } void ReducedModelOptimizer::computeMaps( const std::unordered_set &reducedModelExcludedEdges, const std::unordered_map> &slotToNode, PatternGeometry &fullPattern, PatternGeometry &reducedPattern, std::unordered_map &reducedToFullInterfaceViMap, std::unordered_map &fullToReducedInterfaceViMap, std::unordered_map &fullPatternOppositeInterfaceViMap) { // 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; // Save excluded edges TODO:this changes the global object. Should this be a // function parameter? // global.reducedPatternExludedEdges.clear(); // const size_t reducedBaseTriangleNumberOfEdges = reducedPattern.EN(); // for (size_t fanIndex = 0; fanIndex < fanSize; fanIndex++) { // for (const size_t ei : reducedModelExcludedEdges) { // global.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*/; reducedPattern.createFan({1}); //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); // Create opposite vertex map fullPatternOppositeInterfaceViMap.clear(); for (int fanIndex = fanSize / 2 - 1; fanIndex >= 0; fanIndex--) { const size_t vi0 = fullModelBaseTriangleInterfaceVi + fanIndex * fullPatternInterfaceVertexOffset; const size_t vi1 = vi0 + (fanSize / 2) * fullPatternInterfaceVertexOffset; assert(vi0 < fullPattern.VN() && vi1 < fullPattern.VN()); fullPatternOppositeInterfaceViMap[vi0] = vi1; } const bool debugMapping = false; if (debugMapping) { #if POLYSCOPE_DEFINED reducedPattern.registerForDrawing(); // std::vector colors_reducedPatternExcludedEdges( // reducedPattern.EN(), glm::vec3(0, 0, 0)); // for (const size_t ei : global.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 : fullPatternOppositeInterfaceViMap) { 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 (global.reducedToFullInterfaceViMap.contains(vi)) { auto color = polyscope::getNextUniqueColor(); nodeColorsReducedToFull_reduced[vi] = color; nodeColorsReducedToFull_full[global.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(); #endif } } void ReducedModelOptimizer::computeMaps( PatternGeometry &fullPattern, PatternGeometry &reducedPattern, const std::unordered_set &reducedModelExcludedEdges) { ReducedModelOptimizer::computeMaps( reducedModelExcludedEdges, slotToNode, fullPattern, reducedPattern, global.reducedToFullInterfaceViMap, m_fullToReducedInterfaceViMap, m_fullPatternOppositeInterfaceViMap); } ReducedModelOptimizer::ReducedModelOptimizer( const std::vector &numberOfNodesPerSlot) { FlatPatternTopology::constructNodeToSlotMap(numberOfNodesPerSlot, nodeToSlot); FlatPatternTopology::constructSlotToNodeMap(nodeToSlot, slotToNode); } void ReducedModelOptimizer::initializePatterns( PatternGeometry &fullPattern, PatternGeometry &reducedPattern, const std::unordered_set &reducedModelExcludedEdges,const int& optimizationParameters) { // fullPattern.setLabel("full_pattern_" + fullPattern.getLabel()); // reducedPattern.setLabel("reduced_pattern_" + reducedPattern.getLabel()); assert(fullPattern.VN() == reducedPattern.VN() && fullPattern.EN() >= reducedPattern.EN()); #if POLYSCOPE_DEFINED polyscope::removeAllStructures(); #endif // Create copies of the input models PatternGeometry copyFullPattern; PatternGeometry copyReducedPattern; copyFullPattern.copy(fullPattern); copyReducedPattern.copy(reducedPattern); global.baseTriangle = copyReducedPattern.getBaseTriangle(); /* * Here we create the vector that connects the central node with the bottom * left node of the base triangle. During the optimization the vi%2==0 nodes * move on these vectors. * */ // const double h = copyReducedPattern.getBaseTriangleHeight(); // double baseTriangle_bottomEdgeSize = 2 * h / tan(vcg::math::ToRad(60.0)); // VectorType baseTriangle_leftBottomNode(-baseTriangle_bottomEdgeSize / 2, -h, // 0); // for (int rotationCounter = 0; rotationCounter < fanSize; rotationCounter++) { // VectorType rotatedVector = // vcg::RotationMatrix(patternPlaneNormal, // vcg::math::ToRad(rotationCounter * 60.0)) * // baseTriangle_leftBottomNode; // global.g_innerHexagonVectors[rotationCounter] = rotatedVector; // } // const double innerHexagonInitialPos_x = // copyReducedPattern.vert[0].cP()[0] / global.g_innerHexagonVectors[0][0]; // const double innerHexagonInitialPos_y = // copyReducedPattern.vert[0].cP()[1] / global.g_innerHexagonVectors[0][1]; // global.innerHexagonInitialPos = innerHexagonInitialPos_x; // global.innerHexagonInitialRotationAngle = // 30; /* NOTE: Here I assume that the CW reduced pattern is given as input. // This is not very generic */ computeMaps(copyFullPattern, copyReducedPattern, reducedModelExcludedEdges); createSimulationMeshes(copyFullPattern, copyReducedPattern); initializeOptimizationParameters(m_pReducedPatternSimulationMesh,optimizationParameters); } void updateMesh(long n, const double *x) { std::shared_ptr &pReducedPatternSimulationMesh = global.reducedPatternSimulationJobs[global.simulationScenarioIndices[0]] ->pMesh; const double E=global.initialParameters(0)*x[0]; const double A=global.initialParameters(1) * x[1]; const double beamWidth=std::sqrt(A); const double beamHeight=beamWidth; const double J=global.initialParameters(2) * x[2]; const double I2=global.initialParameters(3) * x[3]; const double I3=global.initialParameters(4) * x[4]; for (EdgeIndex ei = 0; ei < pReducedPatternSimulationMesh->EN(); ei++) { Element &e = pReducedPatternSimulationMesh->elements[ei]; e.setDimensions( RectangularBeamDimensions(beamWidth, beamHeight)); e.setMaterial(ElementMaterial(e.material.poissonsRatio, E)); e.J = J; e.I2 = I2; e.I3 = I3; } assert(pReducedPatternSimulationMesh->EN() == 12); assert(n>=2); CoordType center_barycentric(1, 0, 0); CoordType interfaceEdgeMiddle_barycentric(0, 0.5, 0.5); CoordType movableVertex_barycentric((center_barycentric + interfaceEdgeMiddle_barycentric) * x[n - 2]); CoordType baseTriangleMovableVertexPosition = global.baseTriangle.cP(0) * movableVertex_barycentric[0] + global.baseTriangle.cP(1) * movableVertex_barycentric[1] + global.baseTriangle.cP(2) * movableVertex_barycentric[2]; baseTriangleMovableVertexPosition = vcg::RotationMatrix(ReducedModelOptimizer::patternPlaneNormal, vcg::math::ToRad(x[n - 1])) * baseTriangleMovableVertexPosition; for (int rotationCounter = 0; rotationCounter < ReducedModelOptimizer::fanSize; rotationCounter++) { pReducedPatternSimulationMesh->vert[2 * rotationCounter + 1].P() = vcg::RotationMatrix(ReducedModelOptimizer::patternPlaneNormal, vcg::math::ToRad(60.0 * rotationCounter)) * baseTriangleMovableVertexPosition; } pReducedPatternSimulationMesh->reset(); //#ifdef POLYSCOPE_DEFINED // pReducedPatternSimulationMesh->updateEigenEdgeAndVertices(); // pReducedPatternSimulationMesh->registerForDrawing(); // std::cout << "Angle:" + std::to_string(x[n - 1]) + " size:" + std::to_string(x[n - 2]) // << std::endl; // std::cout << "Verts:" << pReducedPatternSimulationMesh->VN() << std::endl; // polyscope::show(); //#endif } void ReducedModelOptimizer::initializeOptimizationParameters( const std::shared_ptr &mesh,const int& optimizationParamters) { global.numberOfOptimizationParameters = optimizationParamters; global.initialParameters.resize(global.numberOfOptimizationParameters); global.initialParameters(0) = mesh->elements[0].material.youngsModulus; global.initialParameters(1) = mesh->elements[0].A; global.initialParameters(2) = mesh->elements[0].J; global.initialParameters(3) = mesh->elements[0].I2; global.initialParameters(4) = mesh->elements[0].I3; global.initialParameters(optimizationParamters-2) = global.innerHexagonInitialPos; global.innerHexagonInitialRotationAngle = 30; global.initialParameters(optimizationParamters-1) = global.innerHexagonInitialRotationAngle; } 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; } #if POLYSCOPE_DEFINED void ReducedModelOptimizer::visualizeResults( const std::vector> &fullPatternSimulationJobs, const std::vector> &reducedPatternSimulationJobs, const std::vector &simulationScenarios, const std::unordered_map &reducedToFullInterfaceViMap) { DRMSimulationModel simulator; std::shared_ptr pFullPatternSimulationMesh = fullPatternSimulationJobs[0]->pMesh; pFullPatternSimulationMesh->registerForDrawing(); pFullPatternSimulationMesh->save(pFullPatternSimulationMesh->getLabel() + "_undeformed.ply"); reducedPatternSimulationJobs[0]->pMesh->save(reducedPatternSimulationJobs[0]->pMesh->getLabel() + "_undeformed.ply"); double totalError = 0; for (const int simulationScenarioIndex : simulationScenarios) { const std::shared_ptr &pFullPatternSimulationJob = fullPatternSimulationJobs[simulationScenarioIndex]; pFullPatternSimulationJob->registerForDrawing( pFullPatternSimulationMesh->getLabel()); SimulationResults fullModelResults = simulator.executeSimulation(pFullPatternSimulationJob); fullModelResults.registerForDrawing(); // fullModelResults.saveDeformedModel(); const std::shared_ptr &pReducedPatternSimulationJob = reducedPatternSimulationJobs[simulationScenarioIndex]; SimulationResults reducedModelResults = simulator.executeSimulation(pReducedPatternSimulationJob); double normalizationFactor = 1; if (global.optimizationSettings.normalizationStrategy != ReducedModelOptimization::Settings::NormalizationStrategy::NonNormalized) { normalizationFactor = global.translationalDisplacementNormalizationValues[simulationScenarioIndex]; } reducedModelResults.saveDeformedModel(); fullModelResults.saveDeformedModel(); double error = computeDisplacementError(reducedModelResults.displacements, fullModelResults.displacements, reducedToFullInterfaceViMap, normalizationFactor); std::cout << "Error of simulation scenario " << ReducedModelOptimization::simulationScenarioStrings[simulationScenarioIndex] << " is " << error << std::endl; totalError += error; reducedModelResults.registerForDrawing(); // firstOptimizationRoundResults[simulationScenarioIndex].registerForDrawing(); // registerWorldAxes(); const std::string screenshotFilename = "/home/iason/Coding/Projects/Approximating shapes with flat " "patterns/RodModelOptimizationForPatterns/build/OptimizationResults/" "Images/" + pFullPatternSimulationMesh->getLabel() + "_" + ReducedModelOptimization::simulationScenarioStrings[simulationScenarioIndex]; polyscope::show(); polyscope::screenshot(screenshotFilename, false); fullModelResults.unregister(); reducedModelResults.unregister(); // firstOptimizationRoundResults[simulationScenarioIndex].unregister(); } std::cout << "Total error:" << totalError << std::endl; } void ReducedModelOptimizer::registerResultsForDrawing( const std::shared_ptr &pFullPatternSimulationJob, const std::shared_ptr &pReducedPatternSimulationJob, const std::unordered_map &reducedToFullInterfaceViMap) { DRMSimulationModel simulator; std::shared_ptr pFullPatternSimulationMesh = pFullPatternSimulationJob->pMesh; pFullPatternSimulationMesh->registerForDrawing(); // pFullPatternSimulationMesh->savePly(pFullPatternSimulationMesh->getLabel() // + // "_undeformed.ply"); // reducedPatternSimulationJobs[0]->pMesh->savePly( // reducedPatternSimulationJobs[0]->pMesh->getLabel() + // "_undeformed.ply"); pFullPatternSimulationJob->registerForDrawing( pFullPatternSimulationMesh->getLabel()); SimulationResults fullModelResults = simulator.executeSimulation(pFullPatternSimulationJob); fullModelResults.registerForDrawing(); // fullModelResults.saveDeformedModel(); SimulationResults reducedModelResults = simulator.executeSimulation(pReducedPatternSimulationJob); // reducedModelResults.saveDeformedModel(); // fullModelResults.saveDeformedModel(); double error = computeRawDisplacementError( reducedModelResults.displacements, fullModelResults.displacements, reducedToFullInterfaceViMap/*, global.reducedPatternMaximumDisplacementNormSum[simulationScenarioIndex]*/); std::cout << "Error is " << error << std::endl; reducedModelResults.registerForDrawing(); } #endif // POLYSCOPE_DEFINED 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]); } } ReducedModelOptimization::Results ReducedModelOptimizer::runOptimization(const Settings &settings) { global.objectiveValueHistory.clear(); dlib::matrix xMin(global.numberOfOptimizationParameters); dlib::matrix xMax(global.numberOfOptimizationParameters); for (int i = 0; i < global.numberOfOptimizationParameters; i++) { xMin(i) = settings.xRanges[i].min; xMax(i) = settings.xRanges[i].max; } auto start = std::chrono::system_clock::now(); dlib::function_evaluation result; double (*objF)(double, double, double, double, double,double,double) = &objective; result = dlib::find_min_global( objF, xMin, xMax, dlib::max_function_calls(settings.numberOfFunctionCalls), std::chrono::hours(24 * 365 * 290), settings.solutionAccuracy); auto end = std::chrono::system_clock::now(); auto elapsed = std::chrono::duration_cast(end - start); ReducedModelOptimization::Results results; results.numberOfSimulationCrashes = global.numOfSimulationCrashes; results.optimalXNameValuePairs.resize(settings.xRanges.size()); for(int xVariableIndex=0;xVariableIndex optimalX(results.optimalXNameValuePairs.size()); for(int xVariableIndex=0;xVariableIndex> ReducedModelOptimizer::createScenarios( const std::shared_ptr &pMesh) { std::vector> scenarios; scenarios.resize(SimulationScenario::NumberOfSimulationScenarios); std::unordered_map> fixedVertices; std::unordered_map nodalForces; const double forceMagnitude = 10; //// Axial SimulationScenario scenarioName = SimulationScenario::Axial; // NewMethod for (auto viPairIt = m_fullPatternOppositeInterfaceViMap.begin(); viPairIt != m_fullPatternOppositeInterfaceViMap.end(); viPairIt++) { if (viPairIt != m_fullPatternOppositeInterfaceViMap.begin()) { CoordType forceDirection(1, 0, 0); const auto viPair = *viPairIt; nodalForces[viPair.first] = Vector6d({forceDirection[0], forceDirection[1], forceDirection[2], 0, 0, 0}) * forceMagnitude * 10; fixedVertices[viPair.second] = std::unordered_set{0, 1, 2, 3, 4, 5}; } } scenarios[scenarioName] = std::make_shared( SimulationJob(pMesh, simulationScenarioStrings[scenarioName], fixedVertices, nodalForces, {})); //// Shear scenarioName = SimulationScenario::Shear; fixedVertices.clear(); nodalForces.clear(); // NewMethod for (auto viPairIt = m_fullPatternOppositeInterfaceViMap.begin(); viPairIt != m_fullPatternOppositeInterfaceViMap.end(); viPairIt++) { if (viPairIt != m_fullPatternOppositeInterfaceViMap.begin()) { CoordType forceDirection(0, 1, 0); const auto viPair = *viPairIt; nodalForces[viPair.first] = Vector6d({forceDirection[0], forceDirection[1], forceDirection[2], 0, 0, 0}) * forceMagnitude * 4; fixedVertices[viPair.second] = std::unordered_set{0, 1, 2, 3, 4, 5}; } } scenarios[scenarioName] = std::make_shared( SimulationJob(pMesh, simulationScenarioStrings[scenarioName], fixedVertices, nodalForces, {})); //// Bending scenarioName = SimulationScenario::Bending; fixedVertices.clear(); nodalForces.clear(); for (const auto &viPair : m_fullPatternOppositeInterfaceViMap) { nodalForces[viPair.first] = Vector6d({0, 0, forceMagnitude, 0, 0, 0}) * 0.0005; fixedVertices[viPair.second] = std::unordered_set{0, 1, 2, 3, 4, 5}; } scenarios[scenarioName] = std::make_shared( SimulationJob(pMesh, simulationScenarioStrings[scenarioName], fixedVertices, nodalForces, {})); //// Dome scenarioName = SimulationScenario::Dome; fixedVertices.clear(); nodalForces.clear(); std::unordered_map nodalForcedDisplacements; for (auto viPairIt = m_fullPatternOppositeInterfaceViMap.begin(); viPairIt != m_fullPatternOppositeInterfaceViMap.end(); viPairIt++) { const auto viPair = *viPairIt; if (viPairIt == m_fullPatternOppositeInterfaceViMap.begin()) { CoordType interfaceV = (pMesh->vert[viPair.first].cP() - pMesh->vert[viPair.second].cP()); nodalForcedDisplacements[viPair.first] = Eigen::Vector3d(-interfaceV[0], -interfaceV[1], 0) * 0.025; nodalForcedDisplacements[viPair.second] = Eigen::Vector3d(interfaceV[0], interfaceV[1], 0) * 0.025; // 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; } else { fixedVertices[viPair.first] = std::unordered_set{2}; fixedVertices[viPair.second] = std::unordered_set{2}; 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.0005; nodalForces[viPair.second] = Vector6d({0, 0, 0, -v[0], -v[1], 0}) * forceMagnitude * 0.0005; } } scenarios[scenarioName] = std::make_shared( SimulationJob(pMesh, simulationScenarioStrings[scenarioName], fixedVertices, nodalForces, nodalForcedDisplacements)); //// Saddle scenarioName = SimulationScenario::Saddle; fixedVertices.clear(); nodalForces.clear(); for (auto viPairIt = m_fullPatternOppositeInterfaceViMap.begin(); viPairIt != m_fullPatternOppositeInterfaceViMap.end(); viPairIt++) { const auto &viPair = *viPairIt; CoordType v = (pMesh->vert[viPair.first].cP() - pMesh->vert[viPair.second].cP()) ^ CoordType(0, 0, -1).Normalize(); if (viPairIt == m_fullPatternOppositeInterfaceViMap.begin()) { nodalForces[viPair.first] = Vector6d({0, 0, 0, v[0], v[1], 0}) * 0.0002 * forceMagnitude; nodalForces[viPair.second] = Vector6d({0, 0, 0, -v[0], -v[1], 0}) * 0.0002 * forceMagnitude; } else { fixedVertices[viPair.first] = std::unordered_set{2}; fixedVertices[viPair.second] = std::unordered_set{0, 1, 2}; nodalForces[viPair.first] = Vector6d({0, 0, 0, -v[0], -v[1], 0}) * 0.0001 * forceMagnitude; nodalForces[viPair.second] = Vector6d({0, 0, 0, v[0], v[1], 0}) * 0.0001 * forceMagnitude; } } scenarios[scenarioName] = std::make_shared( SimulationJob(pMesh, simulationScenarioStrings[scenarioName], fixedVertices, nodalForces, {})); return scenarios; } void ReducedModelOptimizer::computeObjectiveValueNormalizationFactors() { if (global.optimizationSettings.normalizationStrategy == Settings::NormalizationStrategy::Epsilon) { // Compute the sum of the displacement norms std::vector fullPatternTranslationalDisplacementNormSum(NumberOfSimulationScenarios); std::vector fullPatternAngularDistance(NumberOfSimulationScenarios); for (int simulationScenarioIndex : global.simulationScenarioIndices) { double translationalDisplacementNormSum = 0; double angularDistanceSum = 0; for (auto interfaceViPair : global.reducedToFullInterfaceViMap) { const int fullPatternVi = interfaceViPair.second; //If the full pattern vertex is translationally constrained dont take it into account if (global.fullPatternSimulationJobs[simulationScenarioIndex] ->constrainedVertices.contains(fullPatternVi)) { const std::unordered_set constrainedDof = global.fullPatternSimulationJobs[simulationScenarioIndex] ->constrainedVertices.at(fullPatternVi); if (constrainedDof.contains(0) && constrainedDof.contains(1) && constrainedDof.contains(2)) { continue; } } const Vector6d &vertexDisplacement = global .fullPatternResults[simulationScenarioIndex] .displacements[fullPatternVi]; translationalDisplacementNormSum += vertexDisplacement.getTranslation().norm(); //If the full pattern vertex is rotationally constrained dont take it into account if (global.fullPatternSimulationJobs[simulationScenarioIndex] ->constrainedVertices.contains(fullPatternVi)) { const std::unordered_set constrainedDof = global.fullPatternSimulationJobs[simulationScenarioIndex] ->constrainedVertices.at(fullPatternVi); if (constrainedDof.contains(3) && constrainedDof.contains(5) && constrainedDof.contains(4)) { continue; } } angularDistanceSum += global.fullPatternResults[simulationScenarioIndex] .rotationalDisplacementQuaternion[fullPatternVi] .angularDistance(Eigen::Quaterniond::Identity()); } fullPatternTranslationalDisplacementNormSum[simulationScenarioIndex] = translationalDisplacementNormSum; fullPatternAngularDistance[simulationScenarioIndex] = angularDistanceSum; } for (int simulationScenarioIndex : global.simulationScenarioIndices) { if (global.optimizationSettings.normalizationStrategy == Settings::NormalizationStrategy::Epsilon) { const double epsilon_translationalDisplacement = global.optimizationSettings .normalizationParameter; global.translationalDisplacementNormalizationValues[simulationScenarioIndex] = std::max(fullPatternTranslationalDisplacementNormSum[simulationScenarioIndex], epsilon_translationalDisplacement); const double epsilon_rotationalDisplacement = vcg::math::ToRad(2.0); global.rotationalDisplacementNormalizationValues[simulationScenarioIndex] = std::max(fullPatternAngularDistance[simulationScenarioIndex], epsilon_rotationalDisplacement); } } } } Results ReducedModelOptimizer::optimize( const Settings &optimizationSettings, const std::vector &simulationScenarios) { global.simulationScenarioIndices = simulationScenarios; if (global.simulationScenarioIndices.empty()) { global.simulationScenarioIndices = {SimulationScenario::Axial, SimulationScenario::Shear, SimulationScenario::Bending, SimulationScenario::Dome, SimulationScenario::Saddle}; } global.g_optimalReducedModelDisplacements.resize(NumberOfSimulationScenarios); global.reducedPatternSimulationJobs.resize(NumberOfSimulationScenarios); global.fullPatternResults.resize(NumberOfSimulationScenarios); global.translationalDisplacementNormalizationValues.resize(NumberOfSimulationScenarios); global.rotationalDisplacementNormalizationValues.resize(NumberOfSimulationScenarios); global.minY = std::numeric_limits::max(); global.numOfSimulationCrashes = 0; global.numberOfFunctionCalls = 0; global.optimizationSettings = optimizationSettings; global.fullPatternSimulationJobs = createScenarios(m_pFullPatternSimulationMesh); reducedPatternMaximumDisplacementSimulationJobs.resize( NumberOfSimulationScenarios); // polyscope::removeAllStructures(); DRMSimulationModel::Settings simulationSettings; simulationSettings.shouldDraw = false; // global.fullPatternSimulationJobs[0]->pMesh->registerForDrawing( // ReducedModelOptimization::Colors::fullInitial); for (int simulationScenarioIndex : global.simulationScenarioIndices) { const std::shared_ptr &pFullPatternSimulationJob = global.fullPatternSimulationJobs[simulationScenarioIndex]; SimulationResults fullPatternResults = simulator.executeSimulation(pFullPatternSimulationJob, simulationSettings); // fullPatternResults.registerForDrawing(ReducedModelOptimization::Colors::fullDeformed); // polyscope::show(); // fullPatternResults.unregister(); global.fullPatternResults[simulationScenarioIndex] = fullPatternResults; SimulationJob reducedPatternSimulationJob; reducedPatternSimulationJob.pMesh = m_pReducedPatternSimulationMesh; computeReducedModelSimulationJob(*pFullPatternSimulationJob, m_fullToReducedInterfaceViMap, reducedPatternSimulationJob); global.reducedPatternSimulationJobs[simulationScenarioIndex] = std::make_shared(reducedPatternSimulationJob); } // global.fullPatternSimulationJobs[0]->pMesh->unregister(); if (global.optimizationSettings.normalizationStrategy != Settings::NormalizationStrategy::NonNormalized) { computeObjectiveValueNormalizationFactors(); } Results optResults = runOptimization(optimizationSettings); for (int simulationScenarioIndex : global.simulationScenarioIndices) { optResults.fullPatternSimulationJobs.push_back( global.fullPatternSimulationJobs[simulationScenarioIndex]); optResults.reducedPatternSimulationJobs.push_back( global.reducedPatternSimulationJobs[simulationScenarioIndex]); } return optResults; }