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(std::shared_ptr<NLSolver> nl_solver, NLProblem &nl_problem, Eigen::MatrixXd &sol)
24 {
25 assert(sol.size() == nl_problem.full_size());
26
27 const Eigen::VectorXd initial_sol = sol;
28 Eigen::VectorXd tmp_sol = nl_problem.full_to_reduced(sol);
29 assert(tmp_sol.size() == nl_problem.reduced_size());
30
31 // --------------------------------------------------------------------
32
33 double al_weight = initial_al_weight;
34 int al_steps = 0;
35 const int iters = nl_solver->stop_criteria().iterations;
36
37 double initial_error = 0;
38 for (const auto &f : alagr_forms)
39 initial_error += f->compute_error(sol);
40
41 nl_problem.line_search_begin(sol, tmp_sol);
42
43 for (auto &f : alagr_forms)
44 f->set_initial_weight(al_weight);
45
46 while (!std::isfinite(nl_problem.value(tmp_sol))
47 || !nl_problem.is_step_valid(sol, tmp_sol)
48 || !nl_problem.is_step_collision_free(sol, tmp_sol))
49 {
50 nl_problem.line_search_end();
51
52 set_al_weight(nl_problem, sol, al_weight);
53 logger().debug("Solving AL Problem with weight {}", al_weight);
54
55 nl_problem.init(sol);
57 tmp_sol = sol;
58
59 try
60 {
61 nl_solver->minimize(nl_problem, tmp_sol);
62 nl_problem.finish();
63 }
64 catch (const std::runtime_error &e)
65 {
66 std::string err_msg = e.what();
67 // if the nonlinear solve fails due to invalid energy at the current solution, changing the weights would not help
68 if (err_msg.find("f(x) is nan or inf; stopping") != std::string::npos)
69 log_and_throw_error("Failed to solve with AL; f(x) is nan or inf");
70 if (err_msg.find("Reached iteration limit") != std::string::npos)
71 log_and_throw_error("Reached iteration limit in AL");
72 }
73
74 sol = tmp_sol;
75 set_al_weight(nl_problem, sol, -1);
76
77 double current_error = 0;
78 for (const auto &f : alagr_forms)
79 f->compute_error(sol);
80 const double eta = 1 - sqrt(current_error / initial_error);
81
82 logger().debug("Current eta = {}", eta);
83
84 if (eta < 0)
85 {
86 logger().debug("Higher error than initial, increase weight and revert to previous solution");
87 sol = initial_sol;
88 }
89
90 tmp_sol = nl_problem.full_to_reduced(sol);
91 nl_problem.line_search_begin(sol, tmp_sol);
92
93 if (eta < eta_tol && al_weight < max_al_weight)
94 al_weight *= scaling;
95 else
96 {
97 for (auto &f : alagr_forms)
98 f->update_lagrangian(sol, al_weight);
99 }
100
101 post_subsolve(al_weight);
102 ++al_steps;
103 }
104 nl_problem.line_search_end();
105 nl_solver->stop_criteria().iterations = iters;
106 }
107
108 void ALSolver::solve_reduced(std::shared_ptr<NLSolver> nl_solver, NLProblem &nl_problem, Eigen::MatrixXd &sol)
109 {
110 assert(sol.size() == nl_problem.full_size());
111
112 Eigen::VectorXd tmp_sol = nl_problem.full_to_reduced(sol);
113 nl_problem.line_search_begin(sol, tmp_sol);
114
115 if (!std::isfinite(nl_problem.value(tmp_sol))
116 || !nl_problem.is_step_valid(sol, tmp_sol)
117 || !nl_problem.is_step_collision_free(sol, tmp_sol))
118 log_and_throw_error("Failed to apply constraints conditions; solve with augmented lagrangian first!");
119
120 // --------------------------------------------------------------------
121 // Perform one final solve with the DBC projected out
122
123 logger().debug("Successfully applied constraints conditions; solving in reduced space");
124
125 nl_problem.init(sol);
127 try
128 {
129 nl_solver->minimize(nl_problem, tmp_sol);
130 nl_problem.finish();
131 }
132 catch (const std::runtime_error &e)
133 {
134 sol = nl_problem.reduced_to_full(tmp_sol);
135 throw e;
136 }
137 sol = nl_problem.reduced_to_full(tmp_sol);
138
139 post_subsolve(0);
140 }
141
142 void ALSolver::set_al_weight(NLProblem &nl_problem, const Eigen::VectorXd &x, const double weight)
143 {
144 if (alagr_forms.empty())
145 return;
146 if (weight > 0)
147 {
148 for (auto &f : alagr_forms)
149 f->enable();
150
151 nl_problem.use_full_size();
152 }
153 else
154 {
155 for (auto &f : alagr_forms)
156 f->disable();
157
158 nl_problem.use_reduced_size();
159 }
160 }
161
162} // namespace polyfem::solver
int x
const double max_al_weight
Definition ALSolver.hpp:40
std::vector< std::shared_ptr< AugmentedLagrangianForm > > alagr_forms
Definition ALSolver.hpp:37
void set_al_weight(NLProblem &nl_problem, const Eigen::VectorXd &x, const double weight)
Definition ALSolver.cpp:142
std::function< void(const Eigen::VectorXd &)> update_barrier_stiffness
Definition ALSolver.hpp:44
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:32
const double initial_al_weight
Definition ALSolver.hpp:38
void solve_reduced(std::shared_ptr< NLSolver > nl_solver, NLProblem &nl_problem, Eigen::MatrixXd &sol)
Definition ALSolver.cpp:108
void solve_al(std::shared_ptr< NLSolver > nl_solver, NLProblem &nl_problem, Eigen::MatrixXd &sol)
Definition ALSolver.cpp:23
virtual void line_search_end() override
virtual void init(const TVector &x0) override
void line_search_begin(const TVector &x0, const TVector &x1) override
Definition NLProblem.cpp:88
virtual bool is_step_valid(const TVector &x0, const TVector &x1) override
Definition NLProblem.cpp:98
virtual TVector full_to_reduced(const TVector &full) const
virtual bool is_step_collision_free(const TVector &x0, const TVector &x1) override
virtual 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:42
void log_and_throw_error(const std::string &msg)
Definition Logger.cpp:71