Loading [MathJax]/extensions/tex2jax.js
PolyFEM
All Classes Namespaces Files Functions Variables Typedefs Enumerations Enumerator Friends Macros Pages
ALSolver.cpp
Go to the documentation of this file.
1#include "ALSolver.hpp"
2
4
5namespace polyfem::solver
6{
8 const std::vector<std::shared_ptr<AugmentedLagrangianForm>> &alagr_form,
9 const double initial_al_weight,
10 const double scaling,
11 const double max_al_weight,
12 const double eta_tol,
13 const std::function<void(const Eigen::VectorXd &)> &update_barrier_stiffness)
14 : alagr_forms{alagr_form},
15 initial_al_weight(initial_al_weight),
16 scaling(scaling),
17 max_al_weight(max_al_weight),
18 eta_tol(eta_tol),
19 update_barrier_stiffness(update_barrier_stiffness)
20 {
21 }
22
23 void ALSolver::solve_al(NLProblem &nl_problem, Eigen::MatrixXd &sol,
24 const json &nl_solver_params,
25 const json &linear_solver,
26 const double characteristic_length,
27 std::shared_ptr<polysolve::nonlinear::Solver> nl_solverin)
28 {
29 assert(sol.size() == nl_problem.full_size());
30
31 const Eigen::VectorXd initial_sol = sol;
32 Eigen::VectorXd tmp_sol = nl_problem.full_to_reduced(sol);
33 assert(tmp_sol.size() == nl_problem.reduced_size());
34
35 // --------------------------------------------------------------------
36
37 double al_weight = initial_al_weight;
38 int al_steps = 0;
39
40 double initial_error = 0;
41 for (const auto &f : alagr_forms)
42 initial_error += f->compute_error(sol);
43
44 nl_problem.use_reduced_size();
45 nl_problem.line_search_begin(sol, tmp_sol);
46
47 for (auto &f : alagr_forms)
48 f->set_initial_weight(al_weight);
49
50 double current_error = 0;
51 for (const auto &f : alagr_forms)
52 current_error += f->compute_error(sol);
53
54 logger().debug("Initial error = {}", current_error);
55
56 while (!std::isfinite(nl_problem.value(tmp_sol))
57 || !nl_problem.is_step_valid(sol, tmp_sol)
58 || !nl_problem.is_step_collision_free(sol, tmp_sol))
59 {
60 nl_problem.line_search_end();
61
62 nl_problem.use_full_size();
63 logger().debug("Solving AL Problem with weight {}", al_weight);
64
65 nl_problem.init(sol);
67 tmp_sol = sol;
68
69 try
70 {
71 const auto scale = nl_problem.normalize_forms();
72 auto nl_solver = nl_solverin == nullptr ? polysolve::nonlinear::Solver::create(
73 nl_solver_params, linear_solver, characteristic_length * scale, logger())
74 : nl_solverin;
75 nl_solver->minimize(nl_problem, tmp_sol);
76 nl_problem.finish();
77 }
78 catch (const std::runtime_error &e)
79 {
80 std::string err_msg = e.what();
81 // if the nonlinear solve fails due to invalid energy at the current solution, changing the weights would not help
82 if (err_msg.find("f(x) is nan or inf; stopping") != std::string::npos)
83 log_and_throw_error("Failed to solve with AL; f(x) is nan or inf");
84 if (err_msg.find("Reached iteration limit") != std::string::npos)
85 log_and_throw_error("Reached iteration limit in AL");
86 }
87
88 sol = tmp_sol;
89
90 current_error = 0;
91 for (const auto &f : alagr_forms)
92 current_error += f->compute_error(sol);
93 logger().debug("Current error = {}", current_error);
94 const double eta = 1 - sqrt(current_error / initial_error);
95
96 logger().debug("Current eta = {}", eta);
97
98 if (eta < 0)
99 {
100 logger().debug("Higher error than initial, increase weight and revert to previous solution");
101 sol = initial_sol;
102 }
103
104 nl_problem.use_reduced_size();
105 tmp_sol = nl_problem.full_to_reduced(sol);
106 nl_problem.line_search_begin(sol, tmp_sol);
107
108 if (eta < eta_tol && al_weight < max_al_weight)
109 al_weight *= scaling;
110
111 for (auto &f : alagr_forms)
112 f->update_lagrangian(sol, al_weight);
113
114 post_subsolve(al_weight);
115 ++al_steps;
116 }
117 nl_problem.line_search_end();
118 }
119
120 void ALSolver::solve_reduced(NLProblem &nl_problem, Eigen::MatrixXd &sol,
121 const json &nl_solver_params,
122 const json &linear_solver,
123 const double characteristic_length,
124 std::shared_ptr<polysolve::nonlinear::Solver> nl_solverin)
125 {
126 assert(sol.size() == nl_problem.full_size());
127
128 Eigen::VectorXd tmp_sol = nl_problem.full_to_reduced(sol);
129 nl_problem.use_reduced_size();
130 nl_problem.line_search_begin(sol, tmp_sol);
131
132 if (!std::isfinite(nl_problem.value(tmp_sol))
133 || !nl_problem.is_step_valid(sol, tmp_sol)
134 || !nl_problem.is_step_collision_free(sol, tmp_sol))
135 log_and_throw_error("Failed to apply constraints conditions; solve with augmented lagrangian first!");
136 nl_problem.line_search_end();
137 // --------------------------------------------------------------------
138 // Perform one final solve with the DBC projected out
139
140 logger().debug("Successfully applied constraints conditions; solving in reduced space");
141
142 nl_problem.init(sol);
144 try
145 {
146 const auto scale = nl_problem.normalize_forms();
147 auto nl_solver = nl_solverin == nullptr ? polysolve::nonlinear::Solver::create(
148 nl_solver_params, linear_solver, characteristic_length * scale, logger())
149 : nl_solverin;
150 nl_solver->minimize(nl_problem, tmp_sol);
151 nl_problem.finish();
152 }
153 catch (const std::runtime_error &e)
154 {
155 sol = nl_problem.reduced_to_full(tmp_sol);
156 throw e;
157 }
158 sol = nl_problem.reduced_to_full(tmp_sol);
159
160 post_subsolve(0);
161 }
162
163} // namespace polyfem::solver
void solve_reduced(NLProblem &nl_problem, Eigen::MatrixXd &sol, std::shared_ptr< polysolve::nonlinear::Solver > nl_solver)
Definition ALSolver.hpp:41
const double max_al_weight
Definition ALSolver.hpp:59
std::vector< std::shared_ptr< AugmentedLagrangianForm > > alagr_forms
Definition ALSolver.hpp:56
std::function< void(const Eigen::VectorXd &)> update_barrier_stiffness
Definition ALSolver.hpp:63
ALSolver(const std::vector< std::shared_ptr< AugmentedLagrangianForm > > &alagr_form, const double initial_al_weight, const double scaling, const double max_al_weight, const double eta_tol, const std::function< void(const Eigen::VectorXd &)> &update_barrier_stiffness)
Definition ALSolver.cpp:7
std::function< void(const double)> post_subsolve
Definition ALSolver.hpp:53
const double initial_al_weight
Definition ALSolver.hpp:57
void solve_al(NLProblem &nl_problem, Eigen::MatrixXd &sol, std::shared_ptr< polysolve::nonlinear::Solver > nl_solver)
Definition ALSolver.hpp:29
virtual void line_search_end() override
virtual void init(const TVector &x0) override
void line_search_begin(const TVector &x0, const TVector &x1) override
double normalize_forms() override
virtual bool is_step_valid(const TVector &x0, const TVector &x1) override
TVector full_to_reduced(const TVector &full) const
virtual bool is_step_collision_free(const TVector &x0, const TVector &x1) override
TVector reduced_to_full(const TVector &reduced) const
virtual double value(const TVector &x) override
spdlog::logger & logger()
Retrieves the current logger.
Definition Logger.cpp:44
nlohmann::json json
Definition Common.hpp:9
void log_and_throw_error(const std::string &msg)
Definition Logger.cpp:73