PolyFEM
Loading...
Searching...
No Matches
NLHomoProblem.cpp
Go to the documentation of this file.
1#include "NLHomoProblem.hpp"
2#include <polyfem/State.hpp>
8
9namespace polyfem::solver
10{
11 NLHomoProblem::NLHomoProblem(const int full_size,
12 const std::vector<int> &boundary_nodes,
13 const std::vector<mesh::LocalBoundary> &local_boundary,
14 const int n_boundary_samples,
15 const assembler::RhsAssembler &rhs_assembler,
16 const assembler::MacroStrainValue &macro_strain_constraint,
17 const State &state,
18 const double t, const std::vector<std::shared_ptr<Form>> &forms,
19 const bool solve_symmetric_macro_strain)
20 : NLProblem(full_size, boundary_nodes, local_boundary, n_boundary_samples, rhs_assembler, state.periodic_bc, t, forms), state_(state), only_symmetric(solve_symmetric_macro_strain), macro_strain_constraint_(macro_strain_constraint)
21 {
23 }
24
26 {
27 const int dim = state_.mesh->dimension();
29 {
30 macro_mid_to_full_.setZero(dim * dim, (dim * (dim + 1)) / 2);
31 macro_full_to_mid_.setZero((dim * (dim + 1)) / 2, dim * dim);
32 for (int i = 0, idx = 0; i < dim; i++)
33 {
34 for (int j = i; j < dim; j++)
35 {
36 macro_full_to_mid_(idx, i * dim + j) = 1;
37
38 macro_mid_to_full_(j * dim + i, idx) = 1;
39 macro_mid_to_full_(i * dim + j, idx) = 1;
40
41 idx++;
42 }
43 }
44 }
45 else
46 {
47 macro_mid_to_full_.setIdentity(dim * dim, dim * dim);
48 macro_full_to_mid_.setIdentity(dim * dim, dim * dim);
49 }
51 }
52
53 Eigen::VectorXd NLHomoProblem::extended_to_reduced(const Eigen::VectorXd &extended) const
54 {
55 const int dim = state_.mesh->dimension();
56 const int dof2 = macro_reduced_size();
57 const int dof1 = reduced_size();
58
59 Eigen::VectorXd reduced(dof1 + dof2);
60 reduced.head(dof1) = NLProblem::full_to_reduced(extended.head(extended.size() - dim * dim));
61 reduced.tail(dof2) = macro_full_to_reduced(extended.tail(dim * dim));
62
63 return reduced;
64 }
65
66 Eigen::VectorXd NLHomoProblem::reduced_to_extended(const Eigen::VectorXd &reduced) const
67 {
68 const int dim = state_.mesh->dimension();
69 const int dof2 = macro_reduced_size();
70 const int dof1 = reduced_size();
71 assert(reduced.size() == dof1 + dof2);
72
73 Eigen::VectorXd fluctuation = NLProblem::reduced_to_full(reduced.head(dof1));
74 Eigen::VectorXd disp_grad = macro_reduced_to_full(reduced.tail(dof2));
75 Eigen::VectorXd extended(fluctuation.size() + disp_grad.size());
76 extended << fluctuation, disp_grad;
77
78 return extended;
79 }
80
81 Eigen::VectorXd NLHomoProblem::extended_to_reduced_grad(const Eigen::VectorXd &extended) const
82 {
83 const int dim = state_.mesh->dimension();
84 const int dof2 = macro_reduced_size();
85 const int dof1 = reduced_size();
86
87 Eigen::VectorXd grad(dof1 + dof2);
88 grad.head(dof1) = NLProblem::full_to_reduced_grad(extended.head(extended.size() - dim * dim));
89 grad.tail(dof2) = macro_full_to_reduced_grad(extended.tail(dim * dim));
90
91 return grad;
92 }
93
94 double NLHomoProblem::value(const TVector &x)
95 {
96 double val = NLProblem::value(x);
97 for (auto &form : homo_forms)
98 if (form->enabled())
99 val += form->value(reduced_to_extended(x));
100
101 return val;
102 }
103 void NLHomoProblem::gradient(const TVector &x, TVector &gradv)
104 {
105 NLProblem::gradient(x, gradv);
106
107 for (auto &form : homo_forms)
108 if (form->enabled())
109 {
110 Eigen::VectorXd grad_extended;
111 form->first_derivative(reduced_to_extended(x), grad_extended);
112 gradv += extended_to_reduced_grad(grad_extended);
113 }
114 }
115 void NLHomoProblem::extended_hessian_to_reduced_hessian(const THessian &extended, THessian &reduced) const
116 {
117 const int dim = state_.mesh->dimension();
118 const int dof2 = macro_reduced_size();
119 const int dof1 = reduced_size();
120
121 Eigen::MatrixXd A12, A22;
122 {
123 Eigen::MatrixXd tmp = Eigen::MatrixXd(extended.rightCols(dim * dim));
124 A12 = macro_full_to_reduced_grad(tmp.topRows(tmp.rows() - dim * dim).transpose()).transpose();
125 A22 = macro_full_to_reduced_grad(macro_full_to_reduced_grad(tmp.bottomRows(dim * dim)).transpose());
126 }
127
128 std::vector<Eigen::Triplet<double>> entries;
129 entries.reserve(extended.nonZeros() + A12.size() * 2 + A22.size());
130
131 for (int k = 0; k < full_size_; ++k)
132 for (StiffnessMatrix::InnerIterator it(extended, k); it; ++it)
133 if (it.row() < full_size_ && it.col() < full_size_)
134 entries.emplace_back(it.row(), it.col(), it.value());
135
136 for (int i = 0; i < A12.rows(); i++)
137 {
138 for (int j = 0; j < A12.cols(); j++)
139 {
140 entries.emplace_back(i, full_size_ + j, A12(i, j));
141 entries.emplace_back(full_size_ + j, i, A12(i, j));
142 }
143 }
144
145 for (int i = 0; i < A22.rows(); i++)
146 for (int j = 0; j < A22.cols(); j++)
147 entries.emplace_back(i + full_size_, j + full_size_, A22(i, j));
148
149 // Eigen::VectorXd tmp = macro_full_to_reduced_grad(Eigen::VectorXd::Ones(dim*dim));
150 // for (int i = 0; i < tmp.size(); i++)
151 // entries.emplace_back(i + full_size_, i + full_size_, 1 - tmp(i));
152
153 THessian mid(full_size_ + dof2, full_size_ + dof2);
154 mid.setFromTriplets(entries.begin(), entries.end());
155
157 }
158 void NLHomoProblem::hessian(const TVector &x, THessian &hessian)
159 {
161
162 for (auto &form : homo_forms)
163 if (form->enabled())
164 {
165 THessian hess_extended;
166 form->second_derivative(reduced_to_extended(x), hess_extended);
167
168 THessian hess;
169 extended_hessian_to_reduced_hessian(hess_extended, hess);
170 hessian += hess;
171 }
172 }
173
174 void NLHomoProblem::set_fixed_entry(const Eigen::VectorXi &fixed_entry)
175 {
176 const int dim = state_.mesh->dimension();
177
178 Eigen::VectorXd fixed_mask;
179 fixed_mask.setZero(dim * dim);
180 fixed_mask(fixed_entry.array()).setOnes();
181 fixed_mask = (macro_full_to_mid_ * fixed_mask).eval();
182
183 fixed_mask_.setZero(fixed_mask.size());
184 for (int i = 0; i < fixed_mask.size(); i++)
185 if (abs(fixed_mask(i)) > 1e-8)
186 fixed_mask_(i) = true;
187
188 const int new_reduced_size = fixed_mask_.size() - fixed_mask_.sum();
189 macro_mid_to_reduced_.setZero(new_reduced_size, fixed_mask_.size());
190 for (int i = 0, j = 0; i < fixed_mask_.size(); i++)
191 if (!fixed_mask_(i))
192 macro_mid_to_reduced_(j++, i) = 1;
193 }
194
195 void NLHomoProblem::full_hessian_to_reduced_hessian(const THessian &full, THessian &reduced) const
196 {
197 const int dim = state_.mesh->dimension();
198 const int dof2 = macro_reduced_size();
199 const int dof1 = reduced_size();
200
201 Eigen::MatrixXd tmp = constraint_grad();
202 Eigen::MatrixXd A12 = full * tmp.transpose();
203 Eigen::MatrixXd A22 = tmp * A12;
204
205 std::vector<Eigen::Triplet<double>> entries;
206 entries.reserve(full.nonZeros() + A12.size() * 2 + A22.size());
207
208 for (int k = 0; k < full.outerSize(); ++k)
209 for (StiffnessMatrix::InnerIterator it(full, k); it; ++it)
210 entries.emplace_back(it.row(), it.col(), it.value());
211
212 for (int i = 0; i < A12.rows(); i++)
213 for (int j = 0; j < A12.cols(); j++)
214 {
215 entries.emplace_back(i, full.cols() + j, A12(i, j));
216 entries.emplace_back(full.rows() + j, i, A12(i, j));
217 }
218
219 for (int i = 0; i < A22.rows(); i++)
220 for (int j = 0; j < A22.cols(); j++)
221 entries.emplace_back(i + full.rows(), j + full.cols(), A22(i, j));
222
223 THessian mid(full.rows() + dof2, full.cols() + dof2);
224 mid.setFromTriplets(entries.begin(), entries.end());
225
227 }
228
229 NLHomoProblem::TVector NLHomoProblem::full_to_reduced(const TVector &full) const
230 {
231 log_and_throw_error("Invalid function!");
232 return TVector();
233 }
234
235 NLHomoProblem::TVector NLHomoProblem::full_to_reduced(const TVector &full, const Eigen::MatrixXd &disp_grad) const
236 {
237 const int dim = state_.mesh->dimension();
238 const int dof2 = macro_reduced_size();
239 const int dof1 = reduced_size();
240
241 TVector reduced;
242 reduced.setZero(dof1 + dof2);
243
245 reduced.tail(dof2) = macro_full_to_reduced(utils::flatten(disp_grad));
246
247 return reduced;
248 }
249 NLHomoProblem::TVector NLHomoProblem::full_to_reduced_grad(const TVector &full) const
250 {
251 const int dim = state_.mesh->dimension();
252 const int dof2 = macro_reduced_size();
253 const int dof1 = reduced_size();
254
255 TVector reduced;
256 reduced.setZero(dof1 + dof2);
257
258 reduced.head(dof1) = NLProblem::full_to_reduced_grad(full);
259 reduced.tail(dof2) = constraint_grad() * full;
260
261 return reduced;
262 }
263 NLHomoProblem::TVector NLHomoProblem::reduced_to_full(const TVector &reduced) const
264 {
265 const int dim = state_.mesh->dimension();
266 const int dof2 = macro_reduced_size();
267 const int dof1 = reduced_size();
268
269 Eigen::MatrixXd disp_grad = utils::unflatten(macro_reduced_to_full(reduced.tail(dof2)), dim);
271 }
272
274 {
275 return macro_mid_to_reduced_.rows();
276 }
277 NLHomoProblem::TVector NLHomoProblem::macro_full_to_reduced(const TVector &full) const
278 {
280 }
281 Eigen::MatrixXd NLHomoProblem::macro_full_to_reduced_grad(const Eigen::MatrixXd &full) const
282 {
283 return macro_mid_to_reduced_ * macro_mid_to_full_.transpose() * full;
284 }
285 NLHomoProblem::TVector NLHomoProblem::macro_reduced_to_full(const TVector &reduced) const
286 {
287 TVector mid = macro_mid_to_reduced_.transpose() * reduced;
288 const TVector fixed_values = macro_full_to_mid_ * utils::flatten(macro_strain_constraint_.eval(t_));
289 for (int i = 0; i < fixed_mask_.size(); i++)
290 if (fixed_mask_(i))
291 mid(i) = fixed_values(i);
292
293 return macro_mid_to_full_ * mid;
294 }
295
296 void NLHomoProblem::init(const TVector &x0)
297 {
298 for (auto &form : homo_forms)
299 form->init(reduced_to_extended(x0));
301 }
302
303 bool NLHomoProblem::is_step_valid(const TVector &x0, const TVector &x1)
304 {
305 bool flag = NLProblem::is_step_valid(x0, x1);
306 for (auto &form : homo_forms)
307 if (form->enabled())
308 flag &= form->is_step_valid(reduced_to_extended(x0), reduced_to_extended(x1));
309
310 return flag;
311 }
312 bool NLHomoProblem::is_step_collision_free(const TVector &x0, const TVector &x1)
313 {
314 bool flag = NLProblem::is_step_collision_free(x0, x1);
315 for (auto &form : homo_forms)
316 if (form->enabled())
317 flag &= form->is_step_collision_free(reduced_to_extended(x0), reduced_to_extended(x1));
318
319 return flag;
320 }
321 double NLHomoProblem::max_step_size(const TVector &x0, const TVector &x1)
322 {
323 double size = NLProblem::max_step_size(x0, x1);
324 for (auto &form : homo_forms)
325 if (form->enabled())
326 size = std::min(size, form->max_step_size(reduced_to_extended(x0), reduced_to_extended(x1)));
327 return size;
328 }
329
330 void NLHomoProblem::line_search_begin(const TVector &x0, const TVector &x1)
331 {
333 for (auto &form : homo_forms)
334 form->line_search_begin(reduced_to_extended(x0), reduced_to_extended(x1));
335 }
336 void NLHomoProblem::post_step(const polysolve::nonlinear::PostStepData &data)
337 {
339 for (auto &form : homo_forms)
340 form->post_step(polysolve::nonlinear::PostStepData(
341 data.iter_num, data.solver_info, reduced_to_extended(data.x), reduced_to_extended(data.grad)));
342 }
343
344 void NLHomoProblem::solution_changed(const TVector &new_x)
345 {
347 for (auto &form : homo_forms)
348 form->solution_changed(reduced_to_extended(new_x));
349 }
350
351 void NLHomoProblem::init_lagging(const TVector &x)
352 {
354 for (auto &form : homo_forms)
355 form->init_lagging(reduced_to_extended(x));
356 }
357 void NLHomoProblem::update_lagging(const TVector &x, const int iter_num)
358 {
359 NLProblem::update_lagging(x, iter_num);
360 for (auto &form : homo_forms)
361 form->update_lagging(reduced_to_extended(x), iter_num);
362 }
363
364 void NLHomoProblem::update_quantities(const double t, const TVector &x)
365 {
367 for (auto &form : homo_forms)
368 form->update_quantities(t, reduced_to_extended(x));
369 }
370
371 Eigen::MatrixXd NLHomoProblem::constraint_grad() const
372 {
373 const int dim = state_.mesh->dimension();
374 Eigen::MatrixXd jac; // (dim*dim) x (dim*n_bases)
375
377
378 jac.setZero(dim * dim, full_size_);
379 for (int i = 0; i < X.rows(); i++)
380 for (int j = 0; j < dim; j++)
381 for (int k = 0; k < dim; k++)
382 jac(j * dim + k, i * dim + j) = X(i, k);
383
384 return macro_full_to_reduced_grad(jac);
385 }
386
387 Eigen::MatrixXd NLHomoProblem::boundary_values() const
388 {
389 Eigen::MatrixXd result = Eigen::MatrixXd::Zero(full_size(), 1);
390 return result;
391 }
392}
double val
Definition Assembler.cpp:86
std::vector< Eigen::Triplet< double > > entries
int x
main class that contains the polyfem solver and all its state
Definition State.hpp:79
int n_bases
number of bases
Definition State.hpp:178
std::unique_ptr< mesh::Mesh > mesh
current mesh, it can be a Mesh2D or Mesh3D
Definition State.hpp:466
std::shared_ptr< polyfem::mesh::MeshNodes > mesh_nodes
Mapping from input nodes to FE nodes.
Definition State.hpp:193
Eigen::MatrixXd eval(const double t) const
static Eigen::MatrixXd generate_linear_field(const int n_bases, const std::shared_ptr< mesh::MeshNodes > mesh_nodes, const Eigen::MatrixXd &grad)
static Eigen::MatrixXd get_bases_position(const int n_bases, const std::shared_ptr< mesh::MeshNodes > mesh_nodes)
virtual void init(const TVector &x0) override
void gradient(const TVector &x, TVector &gradv) override
void init(const TVector &x0) override
void post_step(const polysolve::nonlinear::PostStepData &data) override
void set_fixed_entry(const Eigen::VectorXi &fixed_entry)
TVector macro_full_to_reduced(const TVector &full) const
bool is_step_valid(const TVector &x0, const TVector &x1) override
const assembler::MacroStrainValue & macro_strain_constraint_
void line_search_begin(const TVector &x0, const TVector &x1) override
void update_quantities(const double t, const TVector &x) override
TVector extended_to_reduced_grad(const TVector &extended) const
void hessian(const TVector &x, THessian &hessian) override
void init_lagging(const TVector &x) override
TVector extended_to_reduced(const TVector &extended) const
std::vector< std::shared_ptr< Form > > homo_forms
Eigen::MatrixXd constraint_grad() const
void full_hessian_to_reduced_hessian(const THessian &full, THessian &reduced) const override
TVector reduced_to_full(const TVector &reduced) const override
Eigen::MatrixXd macro_full_to_reduced_grad(const Eigen::MatrixXd &full) const
double value(const TVector &x) override
TVector full_to_reduced(const TVector &full, const Eigen::MatrixXd &disp_grad) const
TVector full_to_reduced_grad(const TVector &full) const override
void solution_changed(const TVector &new_x) override
Eigen::MatrixXd boundary_values() const override
TVector macro_reduced_to_full(const TVector &reduced) const
double max_step_size(const TVector &x0, const TVector &x1) override
NLHomoProblem(const int full_size, const std::vector< int > &boundary_nodes, const std::vector< mesh::LocalBoundary > &local_boundary, const int n_boundary_samples, const assembler::RhsAssembler &rhs_assembler, const assembler::MacroStrainValue &macro_strain_constraint, const State &state, const double t, const std::vector< std::shared_ptr< Form > > &forms, const bool solve_symmetric_macro_strain)
TVector reduced_to_extended(const TVector &reduced) const
void extended_hessian_to_reduced_hessian(const THessian &extended, THessian &reduced) const
bool is_step_collision_free(const TVector &x0, const TVector &x1) override
void update_lagging(const TVector &x, const int iter_num) override
const int full_size_
Size of the full problem.
Definition NLProblem.hpp:72
void line_search_begin(const TVector &x0, const TVector &x1) override
Definition NLProblem.cpp:80
virtual bool is_step_valid(const TVector &x0, const TVector &x1) override
Definition NLProblem.cpp:90
virtual void post_step(const polysolve::nonlinear::PostStepData &data) override
virtual TVector full_to_reduced_grad(const TVector &full) const
virtual TVector full_to_reduced(const TVector &full) const
virtual void update_quantities(const double t, const TVector &x)
Definition NLProblem.cpp:72
virtual void gradient(const TVector &x, TVector &gradv) override
void init_lagging(const TVector &x) override
Definition NLProblem.cpp:62
virtual bool is_step_collision_free(const TVector &x0, const TVector &x1) override
Definition NLProblem.cpp:95
virtual TVector reduced_to_full(const TVector &reduced) const
void update_lagging(const TVector &x, const int iter_num) override
Definition NLProblem.cpp:67
virtual void full_hessian_to_reduced_hessian(const THessian &full, THessian &reduced) const
virtual double value(const TVector &x) override
virtual double max_step_size(const TVector &x0, const TVector &x1) override
Definition NLProblem.cpp:85
virtual void hessian(const TVector &x, THessian &hessian) override
void solution_changed(const TVector &new_x) override
Eigen::MatrixXd unflatten(const Eigen::VectorXd &x, int dim)
Unflatten rowwises, so every dim elements in x become a row.
Eigen::VectorXd flatten(const Eigen::MatrixXd &X)
Flatten rowwises.
void log_and_throw_error(const std::string &msg)
Definition Logger.cpp:71