#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 #include #include #include #include #include //#define USE_SCENARIO_WEIGHTS #include using namespace ReducedModelOptimization; struct BaseScenarioMaxDisplacementHelperData { std::function>&, SimulationJob&)> constructScenarioFunction; double desiredMaxDisplacementValue; double desiredMaxRotationAngle; PatternVertexIndex interfaceViForComputingScenarioError; std::string currentScenarioName; std::shared_ptr pFullPatternSimulationEdgeMesh; 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 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; } 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; } 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; } 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; } 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); // 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 innerHexagonSize, // double innerHexagonRotationAngle) { // 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); } }; #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) //{ // 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; // 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); // 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& 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); 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; // pReducedPatternSimulationEdgeMesh->registerForDrawing(); // polyscope::show(); // pReducedPatternSimulationEdgeMesh->unregister(); // std::filesystem::create_directories("failedJob"); // reducedJob->save("failedJob"); // Results debugRes; #endif } else { // const double simulationScenarioError_PE = std::abs( // (reducedModelResults.internalPotentialEnergy // - // optimizationState.fullPatternResults[simulationScenarioIndex].internalPotentialEnergy) // / // optimizationState.fullPatternResults[simulationScenarioIndex].internalPotentialEnergy); // else { #ifdef POLYSCOPE_DEFINED #ifdef USE_SCENARIO_WEIGHTS const double scenarioWeight = optimizationState.scenarioWeights[simulationScenarioIndex]; #else const double scenarioWeight = 1; #endif #else 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]); 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 } }); 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; } #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; } #endif #endif // compute error and return it return totalError; } 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 pFullPatternSimulationEdgeMesh = std::make_shared(pattern); pFullPatternSimulationEdgeMesh->setBeamCrossSection( optimizationSettings.beamDimensions_pattern); pFullPatternSimulationEdgeMesh->setBeamMaterial( 0.3, optimizationSettings.youngsModulus_pattern); pFullPatternSimulationEdgeMesh->reset(); // Reduced pattern pReducedPatternSimulationEdgeMesh = std::make_shared(reducedModel); pReducedPatternSimulationEdgeMesh->setBeamCrossSection( optimizationSettings.beamDimensions_pattern); pReducedPatternSimulationEdgeMesh->setBeamMaterial( 0.3, optimizationSettings.youngsModulus_pattern); pReducedPatternSimulationEdgeMesh->reset(); } 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& 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< 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); // } // } // 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(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) { 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 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); } 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; #ifdef POLYSCOPE_DEFINED polyscope::removeAllStructures(); #endif // Create copies of the input models PatternGeometry copyFullPattern; ReducedModel copyReducedModel; copyFullPattern.copy(fullPattern); copyReducedModel.copy(reducedModel); #ifdef POLYSCOPE_DEFINED copyFullPattern.updateEigenEdgeAndVertices(); #endif copyReducedModel.updateEigenEdgeAndVertices(); baseTriangle = copyReducedModel.getBaseTriangle(); 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.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& 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::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& pReducedModelSimulationEdgeMesh) { // std::shared_ptr pReducedModel_edgeMesh // = // std::dynamic_pointer_cast(pReducedModelSimulationEdgeMesh); // ReducedModel::updateFannedGeometry_theta(newTheta_degrees, // pReducedModel_edgeMesh); 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& 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& 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::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 &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]; #else const double scenarioWeight = 1; #endif #else 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_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; // 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, 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.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; } 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_pFullPatternSimulationEdgeMesh->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 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; #endif //#endif assert(fullPatternSimulationScenarioMaxMagnitudes.size() == desiredBaseSimulationScenarioIndices.size()); return fullPatternSimulationScenarioMaxMagnitudes; } #endif 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; #ifndef USE_ENSMALLEN 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]; } 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; } #ifdef USE_ENSMALLEN #ifdef POLYSCOPE_DEFINED 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]; x(xIndex, 0) = optimizationState.optimizationInitialValue[parameterIndex]; } optimizationState.xMin = xMin; optimizationState.xMax = xMax; EnsmallenReducedModelOptimizationObjective optimizationFunction( optimizationState); // optimizationFunction.optimizationState = optimizationState; // 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); #else // 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]; // } // } #ifdef POLYSCOPE_DEFINED 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()); std::copy(optimizationState.minX.begin(), optimizationState.minX.end(), parameterGroup_optimalResult.x.begin()); #else g_optimizationState = optimizationState; #ifdef POLYSCOPE_DEFINED 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]; 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 #ifdef POLYSCOPE_DEFINED 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]; // 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); // } 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; #endif 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; #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); } 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}; } } } 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; } } 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}; } } 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"; } /*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 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}; 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"; } // double fullPatternMaxSimulationForceRotationalObjective(const double // &forceMagnitude) //{ // SimulationJob job; // job.pMesh = // g_baseScenarioMaxDisplacementHelperData.pFullPatternSimulationEdgeMesh; // g_baseScenarioMaxDisplacementHelperData.constructScenarioFunction( // forceMagnitude, // g_baseScenarioMaxDisplacementHelperData.fullPatternOppositeInterfaceViPairs, // job); // // ReducedModelOptimizer::axialSimulationScenario(forceMagnitude, // // optimizationState.fullPatternInterfaceViPairs, // // job); // ChronosEulerSimulationModel simulator; // SimulationResults results = // simulator.executeSimulation(std::make_shared(job)); // // DRMSimulationModel simulator; // // DRMSimulationModel::Settings settings; // // // settings.threshold_averageResidualToExternalForcesNorm = 1e-2; // // settings.totalTranslationalKineticEnergyThreshold = 1e-10; // // // settings.viscousDampingFactor = 1e-2; // // // settings.useKineticDamping = true; // // settings.shouldDraw = false; // // settings.debugModeStep = 200; // // // settings.threshold_averageResidualToExternalForcesNorm = 1e-5; // // settings.maxDRMIterations = 200000; // // SimulationResults results = // simulator.executeSimulation(std::make_shared(job), // // settings); // const double &desiredRotationAngle // = g_baseScenarioMaxDisplacementHelperData // .desiredMaxRotationAngle; //TODO: move from OptimizationState to // a new struct // double error; // // job.pMesh->setLabel("initial"); // // job.pMesh->registerForDrawing(); // // results.registerForDrawing(); // // polyscope::show(); // std::string saveJobToPath; // if (!results.converged) { // // std::cout << "Force used:" << forceMagnitude << std::endl; // error = std::numeric_limits::max(); // // DRMSimulationModel::Settings debugSimulationSettings; // // debugSimulationSettings.isDebugMode = true; // // debugSimulationSettings.debugModeStep = 1000; // // // debugSimulationSettings.maxDRMIterations = // 100000; // // debugSimulationSettings.shouldDraw = true; // // debugSimulationSettings.drawingStep = // debugSimulationSettings.debugModeStep; // // debugSimulationSettings.shouldCreatePlots = true; // // // debugSimulationSettings.Dtini = 0.06; // // debugSimulationSettings.beVerbose = true; // // debugSimulationSettings.useAverage = true; // // // // debugSimulationSettings.threshold_averageResidualToExternalForcesNorm // = 1e-3; // // // debugSimulationSettings.shouldUseTranslationalKineticEnergyThreshold = // true; // // auto debugResults = // simulator.executeSimulation(std::make_shared(job), // // debugSimulationSettings); // // std::terminate(); // saveJobToPath = "../nonConvergingJobs"; // } else { // error = std::abs( // results // .rotationalDisplacementQuaternion[g_baseScenarioMaxDisplacementHelperData // .interfaceViForComputingScenarioError] // .angularDistance(Eigen::Quaterniond::Identity()) // - desiredRotationAngle); // saveJobToPath = "../convergingJobs"; // } // // std::filesystem::path // outputPath(std::filesystem::path(saveJobToPath) // // .append(job.pMesh->getLabel()) // // .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; //#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++; } if (iterationIndex == maxIterations) { std::cerr << "Max iterations reached." << std::endl; } } // double fullPatternMaxSimulationForceTranslationalObjective(const double // &forceMagnitude) //{ // SimulationJob job; // job.pMesh = // g_baseScenarioMaxDisplacementHelperData.pFullPatternSimulationEdgeMesh; // g_baseScenarioMaxDisplacementHelperData.constructScenarioFunction( // forceMagnitude, // g_baseScenarioMaxDisplacementHelperData.fullPatternOppositeInterfaceViPairs, // job); // // ReducedModelOptimizer::axialSimulationScenario(forceMagnitude, // // optimizationState.fullPatternInterfaceViPairs, // // job); // ChronosEulerSimulationModel simulator; // SimulationResults results = // simulator.executeSimulation(std::make_shared(job)); // // DRMSimulationModel simulator; // // DRMSimulationModel::Settings settings; // // // settings.totalResidualForcesNormThreshold = 1e-3; // // settings.threshold_averageResidualToExternalForcesNorm = 1e-2; // // settings.totalTranslationalKineticEnergyThreshold = 1e-8; // // settings.viscousDampingFactor = 5e-3; // // settings.useTranslationalKineticEnergyForKineticDamping = true; // // // settings.threshold_averageResidualToExternalForcesNorm = 1e-5; // // // settings.useAverage = true; // // // settings.totalTranslationalKineticEnergyThreshold = 1e-10; // // // settings.shouldUseTranslationalKineticEnergyThreshold = true; // // // settings.shouldDraw = true; // // // settings.isDebugMode = true; // // // settings.drawingStep = 200000; // // // settings.beVerbose = true; // // // settings.debugModeStep = 200; // // settings.maxDRMIterations = 200000; // // SimulationResults results = // simulator.executeSimulation(std::make_shared(job), // // settings); // const double &desiredDisplacementValue // = g_baseScenarioMaxDisplacementHelperData // .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)); // std::filesystem::create_directories(outputPath); // job.save(outputPath); // // std::terminate(); // } else { // error = std::abs(results // .displacements[g_baseScenarioMaxDisplacementHelperData // .interfaceViForComputingScenarioError] // .getTranslation() // .norm() // - desiredDisplacementValue); // } //#ifdef POLYSCOPE_DEFINED // 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)); } }; #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.pFullPatternSimulationEdgeMesh = m_pFullPatternSimulationEdgeMesh; double forceMagnitudeEpsilon = 1e-4; switch (scenario) { case Axial: g_baseScenarioMaxDisplacementHelperData.desiredMaxDisplacementValue = 0.03 * baseTriangleHeight; break; case Shear: g_baseScenarioMaxDisplacementHelperData.desiredMaxDisplacementValue = 0.04 * baseTriangleHeight; break; case Bending: 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; case Saddle: 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; default: 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); #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); // search(objectiveFunction, // optimizationState.desiredMaxDisplacementValue, // forceMagnitude, // minimumError, // objectiveEpsilon, // maxIterations); #endif wasSuccessful = minimumError < objectiveEpsilon; #ifdef POLYSCOPE_DEFINED 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; } #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]; } 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()); } 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; 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); job.label = baseSimulationScenarioNames[baseScenario] + "_" + std::to_string(simulationScenarioIndex); scenarios[scenarioIndex] = std::make_shared(job); } } #ifdef POLYSCOPE_DEFINED std::cout << "Created pattern simulation jobs" << std::endl; #endif return scenarios; } void ReducedModelOptimizer::computeObjectiveValueNormalizationFactors( 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; } } 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())); } 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; } } 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); } // ChronosEulerSimulationModel simulationModel_pattern; // simulationModel_pattern.settings.analysisType // = // ChronosEulerSimulationModel::Settings::AnalysisType::NonLinear; // const SimulationResults simulationResults_pattern // = // simulationModel_pattern.executeSimulation(pPatternSimulationJob); // 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; // } 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() << " 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 } 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 << "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 }); 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; #endif runOptimization(optimizationSettings, results); }