PolyFEM
Loading...
Searching...
No Matches
NLHomoProblem.cpp
Go to the documentation of this file.
1#include "NLHomoProblem.hpp"
6
7namespace polyfem::solver
8{
10 const int full_size,
11 const assembler::MacroStrainValue &macro_strain_constraint,
12 const int n_bases,
13 std::shared_ptr<mesh::MeshNodes> mesh_nodes,
14 const double t,
15 const std::vector<std::shared_ptr<Form>> &forms,
16 const std::vector<std::shared_ptr<AugmentedLagrangianForm>> &penalty_forms,
17 const bool solve_symmetric_macro_strain,
18 const std::shared_ptr<polysolve::linear::Solver> &solver,
19 const double char_length,
20 const double char_force,
21 StiffnessMatrix lumped_mass,
22 const int dimension)
23 : NLProblem(full_size, t, forms, penalty_forms, solver, char_length, char_force, lumped_mass, dimension),
24 n_bases_(n_bases),
25 dimension_(dimension),
26 mesh_nodes_(std::move(mesh_nodes)),
27 only_symmetric(solve_symmetric_macro_strain),
28 macro_strain_constraint_(macro_strain_constraint)
29 {
30 assert(mesh_nodes_);
32 }
33
35 {
36 const int dim = dimension_;
38 {
39 macro_mid_to_full_.setZero(dim * dim, (dim * (dim + 1)) / 2);
40 macro_full_to_mid_.setZero((dim * (dim + 1)) / 2, dim * dim);
41 for (int i = 0, idx = 0; i < dim; i++)
42 {
43 for (int j = i; j < dim; j++)
44 {
45 macro_full_to_mid_(idx, i * dim + j) = 1;
46
47 macro_mid_to_full_(j * dim + i, idx) = 1;
48 macro_mid_to_full_(i * dim + j, idx) = 1;
49
50 idx++;
51 }
52 }
53 }
54 else
55 {
56 macro_mid_to_full_.setIdentity(dim * dim, dim * dim);
57 macro_full_to_mid_.setIdentity(dim * dim, dim * dim);
58 }
60 }
61
62 Eigen::VectorXd NLHomoProblem::extended_to_reduced(const Eigen::VectorXd &extended) const
63 {
64 const int dim = dimension_;
65 const int dof2 = macro_reduced_size();
66 const int dof1 = reduced_size();
67
68 Eigen::VectorXd reduced(dof1 + dof2);
69 reduced.head(dof1) = NLProblem::full_to_reduced(extended.head(extended.size() - dim * dim));
70 reduced.tail(dof2) = macro_full_to_reduced(extended.tail(dim * dim));
71
72 return reduced;
73 }
74
75 Eigen::VectorXd NLHomoProblem::reduced_to_extended(const Eigen::VectorXd &reduced, bool homogeneous) const
76 {
77 const int dim = dimension_;
78 const int dof2 = macro_reduced_size();
79 const int dof1 = reduced_size();
80 assert(reduced.size() == dof1 + dof2);
81
82 Eigen::VectorXd full = NLProblem::reduced_to_full(reduced.head(dof1));
83 Eigen::VectorXd disp_grad = macro_reduced_to_full(reduced.tail(dof2), homogeneous);
84 Eigen::VectorXd extended(full.size() + disp_grad.size());
85 extended << full, disp_grad;
86
87 return extended;
88 }
89
90 Eigen::VectorXd NLHomoProblem::extended_to_reduced_grad(const Eigen::VectorXd &extended) const
91 {
92 const int dim = dimension_;
93 const int dof2 = macro_reduced_size();
94 const int dof1 = reduced_size();
95
96 Eigen::VectorXd grad(dof1 + dof2);
97 grad.head(dof1) = NLProblem::full_to_reduced_grad(extended.head(extended.size() - dim * dim));
98 grad.tail(dof2) = macro_full_to_reduced_grad(extended.tail(dim * dim));
99
100 return grad;
101 }
102
103 double NLHomoProblem::value(const TVector &x)
104 {
106
108 {
109 val += penalty_problem_->value(x);
110 }
111
112 for (auto &form : homo_forms)
113 if (form->enabled())
114 val += form->value(reduced_to_extended(x));
115
116 return val;
117 }
118 void NLHomoProblem::gradient(const TVector &x, TVector &gradv)
119 {
121
122 if (full_size() != current_size())
123 {
124 gradv = full_to_reduced_grad(gradv);
125 }
126 else if (penalty_problem_)
127 {
128 TVector tmp;
129 penalty_problem_->gradient(x, tmp);
130 gradv += tmp;
131 }
132
133 for (auto &form : homo_forms)
134 if (form->enabled())
135 {
136 Eigen::VectorXd grad_extended;
137 form->first_derivative(reduced_to_extended(x), grad_extended);
138 gradv += extended_to_reduced_grad(grad_extended);
139 }
140 }
141 void NLHomoProblem::extended_hessian_to_reduced_hessian(const THessian &extended, THessian &reduced) const
142 {
143 const int dim = dimension_;
144 const int dof2 = macro_reduced_size();
145 const int dof1 = reduced_size();
146
147 Eigen::MatrixXd A12, A22;
148 {
149 Eigen::MatrixXd tmp = Eigen::MatrixXd(extended.rightCols(dim * dim));
150 A12 = macro_full_to_reduced_grad(tmp.topRows(tmp.rows() - dim * dim).transpose()).transpose();
151 A22 = macro_full_to_reduced_grad(macro_full_to_reduced_grad(tmp.bottomRows(dim * dim)).transpose());
152 }
153
154 std::vector<Eigen::Triplet<double>> entries;
155 entries.reserve(extended.nonZeros() + A12.size() * 2 + A22.size());
156
157 for (int k = 0; k < full_size_; ++k)
158 for (StiffnessMatrix::InnerIterator it(extended, k); it; ++it)
159 if (it.row() < full_size_ && it.col() < full_size_)
160 entries.emplace_back(it.row(), it.col(), it.value());
161
162 for (int i = 0; i < A12.rows(); i++)
163 {
164 for (int j = 0; j < A12.cols(); j++)
165 {
166 entries.emplace_back(i, full_size_ + j, A12(i, j));
167 entries.emplace_back(full_size_ + j, i, A12(i, j));
168 }
169 }
170
171 for (int i = 0; i < A22.rows(); i++)
172 for (int j = 0; j < A22.cols(); j++)
173 entries.emplace_back(i + full_size_, j + full_size_, A22(i, j));
174
175 // Eigen::VectorXd tmp = macro_full_to_reduced_grad(Eigen::VectorXd::Ones(dim*dim));
176 // for (int i = 0; i < tmp.size(); i++)
177 // entries.emplace_back(i + full_size_, i + full_size_, 1 - tmp(i));
178
179 reduced.resize(0, 0);
180 reduced.resize(full_size_ + dof2, full_size_ + dof2);
181 reduced.setFromTriplets(entries.begin(), entries.end());
182
183 {
184 assert(dof1 == Q2_.cols());
185 StiffnessMatrix Q2_extended(Q2_.rows() + dof2, Q2_.cols() + dof2);
186
187 {
188 entries.clear();
189 for (int k = 0; k < Q2_.cols(); ++k)
190 for (StiffnessMatrix::InnerIterator it(Q2_, k); it; ++it)
191 {
192 entries.emplace_back(it.row(), it.col(), it.value());
193 }
194
195 for (int k = 0; k < dof2; k++)
196 {
197 entries.emplace_back(Q2_.rows() + k, dof1 + k, 1);
198 }
199
200 Q2_extended.setFromTriplets(entries.begin(), entries.end());
201 }
202
203 reduced = Q2_extended.transpose() * reduced * Q2_extended;
204 // remove numerical zeros
205 reduced.prune([](const Eigen::Index &row, const Eigen::Index &col, const Scalar &value) {
206 return std::abs(value) > 1e-10;
207 });
208 }
209 }
210 Eigen::MatrixXd NLHomoProblem::reduced_to_disp_grad(const TVector &reduced, bool homogeneous) const
211 {
212 const int dim = dimension_;
213 const int dof2 = macro_reduced_size();
214 const int dof1 = reduced_size();
215
216 return utils::unflatten(macro_reduced_to_full(reduced.tail(dof2), homogeneous), dim);
217 }
218 void NLHomoProblem::hessian(const TVector &x, THessian &hessian)
219 {
221
223
224 for (auto &form : homo_forms)
225 if (form->enabled())
226 {
227 THessian hess_extended;
228 form->second_derivative(reduced_to_extended(x), hess_extended);
229
230 THessian hess;
231 extended_hessian_to_reduced_hessian(hess_extended, hess);
232 hessian += hess;
233 }
234 }
235
236 void NLHomoProblem::set_fixed_entry(const Eigen::VectorXi &fixed_entry)
237 {
238 const int dim = dimension_;
239
240 Eigen::VectorXd fixed_mask;
241 fixed_mask.setZero(dim * dim);
242 fixed_mask(fixed_entry.array()).setOnes();
243 fixed_mask = (macro_full_to_mid_ * fixed_mask).eval();
244
245 fixed_mask_.setZero(fixed_mask.size());
246 for (int i = 0; i < fixed_mask.size(); i++)
247 if (abs(fixed_mask(i)) > 1e-8)
248 fixed_mask_(i) = true;
249
250 const int new_reduced_size = fixed_mask_.size() - fixed_mask_.sum();
251 macro_mid_to_reduced_.setZero(new_reduced_size, fixed_mask_.size());
252 for (int i = 0, j = 0; i < fixed_mask_.size(); i++)
253 if (!fixed_mask_(i))
254 macro_mid_to_reduced_(j++, i) = 1;
255 }
256
258 {
259 const int dim = dimension_;
260 const int dof2 = macro_reduced_size();
261 const int dof1 = reduced_size();
262 const int full_size = hessian.rows();
263
264 Eigen::MatrixXd tmp = constraint_grad();
265 Eigen::MatrixXd A12 = hessian * tmp.transpose();
266 Eigen::MatrixXd A22 = tmp * A12;
267
268 std::vector<Eigen::Triplet<double>> entries;
269 entries.reserve(hessian.nonZeros() + A12.size() * 2 + A22.size());
270
271 for (int k = 0; k < hessian.outerSize(); ++k)
272 for (StiffnessMatrix::InnerIterator it(hessian, k); it; ++it)
273 entries.emplace_back(it.row(), it.col(), it.value());
274
275 for (int i = 0; i < A12.rows(); i++)
276 for (int j = 0; j < A12.cols(); j++)
277 {
278 entries.emplace_back(i, full_size + j, A12(i, j));
279 entries.emplace_back(full_size + j, i, A12(i, j));
280 }
281
282 for (int i = 0; i < A22.rows(); i++)
283 for (int j = 0; j < A22.cols(); j++)
284 entries.emplace_back(i + full_size, j + full_size, A22(i, j));
285
286 hessian.resize(0, 0);
287 hessian.resize(full_size + dof2, full_size + dof2);
288 hessian.setFromTriplets(entries.begin(), entries.end());
289 // NLProblem::full_hessian_to_reduced_hessian(hessian);
290
291 {
292 assert(dof1 == Q2_.cols());
293 StiffnessMatrix Q2_extended(Q2_.rows() + dof2, Q2_.cols() + dof2);
294
295 {
296 entries.clear();
297 for (int k = 0; k < Q2_.cols(); ++k)
298 for (StiffnessMatrix::InnerIterator it(Q2_, k); it; ++it)
299 {
300 entries.emplace_back(it.row(), it.col(), it.value());
301 }
302
303 for (int k = 0; k < dof2; k++)
304 {
305 entries.emplace_back(Q2_.rows() + k, dof1 + k, 1);
306 }
307
308 Q2_extended.setFromTriplets(entries.begin(), entries.end());
309 }
310
311 hessian = Q2_extended.transpose() * hessian * Q2_extended;
312 // remove numerical zeros
313 hessian.prune([](const Eigen::Index &row, const Eigen::Index &col, const Scalar &value) {
314 return std::abs(value) > 1e-10;
315 });
316 }
317 }
318
319 NLHomoProblem::TVector NLHomoProblem::full_to_reduced(const TVector &full) const
320 {
321 log_and_throw_error("Invalid function!");
322 return TVector();
323 }
324
325 NLHomoProblem::TVector NLHomoProblem::full_to_reduced(const TVector &full, const Eigen::MatrixXd &disp_grad) const
326 {
327 const int dim = dimension_;
328 const int dof2 = macro_reduced_size();
329 const int dof1 = reduced_size();
330
331 TVector reduced;
332 reduced.setZero(dof1 + dof2);
333
335 reduced.tail(dof2) = macro_full_to_reduced(utils::flatten(disp_grad));
336
337 return reduced;
338 }
339 NLHomoProblem::TVector NLHomoProblem::full_to_reduced_grad(const TVector &full) const
340 {
341 const int dim = dimension_;
342 const int dof2 = macro_reduced_size();
343 const int dof1 = reduced_size();
344
345 TVector reduced;
346 reduced.setZero(dof1 + dof2);
347 reduced.head(dof1) = NLProblem::full_to_reduced_grad(full);
348 reduced.tail(dof2) = constraint_grad() * full;
349
350 return reduced;
351 }
352 NLHomoProblem::TVector NLHomoProblem::full_to_reduced_diag(const TVector &full_diag) const
353 {
354 const int dof2 = macro_reduced_size();
355 const int dof1 = reduced_size();
356
357 TVector reduced_diag;
358 reduced_diag.setZero(dof1 + dof2);
359 reduced_diag.head(dof1) = NLProblem::full_to_reduced_diag(full_diag);
360 reduced_diag.tail(dof2) = constraint_grad().cwiseAbs2() * full_diag;
361
362 return reduced_diag;
363 }
364 NLHomoProblem::TVector NLHomoProblem::reduced_to_full(const TVector &reduced) const
365 {
366 const int dim = dimension_;
367 const int dof2 = macro_reduced_size();
368 const int dof1 = reduced_size();
369
370 Eigen::MatrixXd disp_grad = utils::unflatten(macro_reduced_to_full(reduced.tail(dof2)), dim);
372 }
373
375 {
376 return macro_mid_to_reduced_.rows();
377 }
378 NLHomoProblem::TVector NLHomoProblem::macro_full_to_reduced(const TVector &full) const
379 {
381 }
382 Eigen::MatrixXd NLHomoProblem::macro_full_to_reduced_grad(const Eigen::MatrixXd &full) const
383 {
384 return macro_mid_to_reduced_ * macro_mid_to_full_.transpose() * full;
385 }
386 NLHomoProblem::TVector NLHomoProblem::macro_reduced_to_full(const TVector &reduced, bool homogeneous) const
387 {
388 TVector mid = macro_mid_to_reduced_.transpose() * reduced;
389 const TVector fixed_values = homogeneous ? TVector::Zero(macro_full_to_mid_.rows()) : TVector(macro_full_to_mid_ * utils::flatten(macro_strain_constraint_.eval(t_)));
390 for (int i = 0; i < fixed_mask_.size(); i++)
391 if (fixed_mask_(i))
392 mid(i) = fixed_values(i);
393
394 return macro_mid_to_full_ * mid;
395 }
396
397 void NLHomoProblem::init(const TVector &x0)
398 {
399 for (auto &form : homo_forms)
400 form->init(reduced_to_extended(x0));
402 }
403
404 bool NLHomoProblem::is_step_valid(const TVector &x0, const TVector &x1)
405 {
406 bool flag = NLProblem::is_step_valid(x0.head(reduced_size()), x1.head(reduced_size()));
407 for (auto &form : homo_forms)
408 if (form->enabled())
409 flag &= form->is_step_valid(reduced_to_extended(x0), reduced_to_extended(x1));
410
411 return flag;
412 }
413 bool NLHomoProblem::is_step_collision_free(const TVector &x0, const TVector &x1)
414 {
415 bool flag = NLProblem::is_step_collision_free(x0.head(reduced_size()), x1.head(reduced_size()));
416 for (auto &form : homo_forms)
417 if (form->enabled())
418 flag &= form->is_step_collision_free(reduced_to_extended(x0), reduced_to_extended(x1));
419
420 return flag;
421 }
422 double NLHomoProblem::max_step_size(const TVector &x0, const TVector &x1)
423 {
424 double size = NLProblem::max_step_size(x0.head(reduced_size()), x1.head(reduced_size()));
425 for (auto &form : homo_forms)
426 if (form->enabled())
427 size = std::min(size, form->max_step_size(reduced_to_extended(x0), reduced_to_extended(x1)));
428 return size;
429 }
430
431 void NLHomoProblem::line_search_begin(const TVector &x0, const TVector &x1)
432 {
434 for (auto &form : homo_forms)
435 form->line_search_begin(reduced_to_extended(x0), reduced_to_extended(x1));
436 }
437 void NLHomoProblem::post_step(const polysolve::nonlinear::PostStepData &data)
438 {
439 NLProblem::post_step(polysolve::nonlinear::PostStepData(data.iter_num, data.solver_info, reduced_to_full(data.x.head(reduced_size())), reduced_to_full(data.grad.head(reduced_size()))));
440 for (auto &form : homo_forms)
441 form->post_step(polysolve::nonlinear::PostStepData(
442 data.iter_num, data.solver_info, reduced_to_extended(data.x), reduced_to_extended(data.grad)));
443 }
444
445 void NLHomoProblem::solution_changed(const TVector &new_x)
446 {
448 for (auto &form : homo_forms)
449 form->solution_changed(reduced_to_extended(new_x));
450 }
451
452 void NLHomoProblem::init_lagging(const TVector &x)
453 {
455 for (auto &form : homo_forms)
456 form->init_lagging(reduced_to_extended(x));
457 }
458 void NLHomoProblem::update_lagging(const TVector &x, const int iter_num)
459 {
460 NLProblem::update_lagging(x.head(reduced_size()), iter_num);
461 for (auto &form : homo_forms)
462 form->update_lagging(reduced_to_extended(x), iter_num);
463 }
464
465 void NLHomoProblem::update_quantities(const double t, const TVector &x)
466 {
468 for (auto &form : homo_forms)
469 form->update_quantities(t, reduced_to_extended(x));
470 }
471
472 Eigen::MatrixXd NLHomoProblem::constraint_grad() const
473 {
474 const int dim = dimension_;
475 Eigen::MatrixXd jac; // (dim*dim) x (dim*n_bases)
476
478
479 jac.setZero(dim * dim, full_size_);
480 for (int i = 0; i < X.rows(); i++)
481 for (int j = 0; j < dim; j++)
482 for (int k = 0; k < dim; k++)
483 jac(j * dim + k, i * dim + j) = X(i, k);
484
485 return macro_full_to_reduced_grad(jac);
486 }
487} // namespace polyfem::solver
double val
Definition Assembler.cpp:90
std::vector< Eigen::Triplet< double > > entries
int x
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 hessian(const TVector &x, THessian &hessian) override
virtual double value(const TVector &x) override
virtual void init(const TVector &x0) override
virtual void gradient(const TVector &x, TVector &gradv) override
std::shared_ptr< mesh::MeshNodes > mesh_nodes_
Eigen::MatrixXd reduced_to_disp_grad(const TVector &reduced, bool homogeneous=false) const
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
NLHomoProblem(const int full_size, const assembler::MacroStrainValue &macro_strain_constraint, int n_bases, std::shared_ptr< mesh::MeshNodes > mesh_nodes, double t, const std::vector< std::shared_ptr< Form > > &forms, const std::vector< std::shared_ptr< AugmentedLagrangianForm > > &penalty_forms, bool solve_symmetric_macro_strain, const std::shared_ptr< polysolve::linear::Solver > &solver, double char_length, double char_force, StiffnessMatrix lumped_mass, int dimension)
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 full_to_reduced_diag(const TVector &full_diag) const override
TVector reduced_to_extended(const TVector &reduced, bool homogeneous=false) const
TVector reduced_to_full(const TVector &reduced) const
TVector extended_to_reduced(const TVector &extended) const
std::vector< std::shared_ptr< Form > > homo_forms
Eigen::MatrixXd constraint_grad() const
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 full_hessian_to_reduced_hessian(THessian &hessian) const
void solution_changed(const TVector &new_x) override
double max_step_size(const TVector &x0, const TVector &x1) override
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
TVector macro_reduced_to_full(const TVector &reduced, bool homogeneous=false) const
const int full_size_
Size of the full problem.
Definition NLProblem.hpp:84
void line_search_begin(const TVector &x0, const TVector &x1) override
StiffnessMatrix Q2_
Q2 block of the QR decomposition of the constraints matrix.
virtual bool is_step_valid(const TVector &x0, const TVector &x1) override
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_diag(const TVector &full_diag) const
TVector full_to_reduced(const TVector &full) const
virtual void update_quantities(const double t, const TVector &x)
void init_lagging(const TVector &x) override
virtual bool is_step_collision_free(const TVector &x0, const TVector &x1) override
TVector reduced_to_full(const TVector &reduced) const
void update_lagging(const TVector &x, const int iter_num) override
virtual double max_step_size(const TVector &x0, const TVector &x1) override
void solution_changed(const TVector &new_x) override
std::shared_ptr< FullNLProblem > penalty_problem_
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:73
Eigen::SparseMatrix< double, Eigen::ColMajor > StiffnessMatrix
Definition Types.hpp:24