PolyFEM
Loading...
Searching...
No Matches
SpatialIntegralForms.cpp
Go to the documentation of this file.
2
3#include <polyfem/State.hpp>
12
13#include <Eigen/Core>
14
15#include <cassert>
16#include <memory>
17#include <string>
18
19using namespace polyfem::utils;
20
21namespace polyfem::solver
22{
23 namespace
24 {
25 bool delta(int i, int j)
26 {
27 return (i == j) ? true : false;
28 }
29
30 double dot(const Eigen::MatrixXd &A, const Eigen::MatrixXd &B) { return (A.array() * B.array()).sum(); }
31
32 Eigen::VectorXd reduced_to_full_shape_derivative(
33 const StiffnessMatrix &basis_nodes_to_gbasis_nodes,
34 const Eigen::MatrixXd &disp_grad,
35 const Eigen::VectorXd &adjoint_full,
36 const int n_bases,
37 const int dim)
38 {
39 assert(disp_grad.rows() == dim);
40 assert(disp_grad.cols() == dim);
41 assert(adjoint_full.size() == n_bases * dim);
42 assert(basis_nodes_to_gbasis_nodes.cols() == n_bases * dim);
43
44 Eigen::VectorXd term;
45 term.setZero(n_bases * dim);
46 for (int i = 0; i < n_bases; i++)
47 term.segment(i * dim, dim) += disp_grad.transpose() * adjoint_full.segment(i * dim, dim);
48
49 return basis_nodes_to_gbasis_nodes * term;
50 }
51
52 class LocalThreadScalarStorage
53 {
54 public:
55 double val;
58
59 LocalThreadScalarStorage()
60 {
61 val = 0;
62 }
63 };
64
65 class LocalThreadVecStorage
66 {
67 public:
68 Eigen::MatrixXd vec;
71
72 LocalThreadVecStorage(const int size)
73 {
74 vec.resize(size, 1);
75 vec.setZero();
76 }
77 };
78 } // namespace
79
80 double SpatialIntegralForm::value_unweighted_step(const int time_step, const Eigen::VectorXd &x) const
81 {
82 assert(time_step < diff_cache_->size());
84 }
85
86 void SpatialIntegralForm::compute_partial_gradient_step(const int time_step, const Eigen::VectorXd &x, Eigen::VectorXd &gradv) const
87 {
88 assert(time_step < diff_cache_->size());
90 Eigen::VectorXd term;
91 AdjointTools::compute_shape_derivative_functional_term(*this->state_, this->diff_cache_->u(time_step), this->get_integral_functional(), this->ids_, this->spatial_integral_type_, term, time_step);
92 return term;
93 });
95 Eigen::VectorXd term;
96 AdjointTools::compute_shape_derivative_functional_term(*this->state_, this->diff_cache_->u(time_step), this->get_integral_functional(), this->ids_, this->spatial_integral_type_, term, time_step);
97 term *= this->weight();
98
99 const Eigen::VectorXd adjoint_rhs = this->compute_adjoint_rhs_step(time_step, x, *state_, *diff_cache_);
100
101 const Eigen::VectorXd full_shape_deriv = reduced_to_full_shape_derivative(
102 diff_cache_->basis_nodes_to_gbasis_nodes(),
103 diff_cache_->disp_grad(),
104 adjoint_rhs,
105 state_->n_bases,
106 state_->mesh->dimension());
107
108 term += utils::flatten(utils::unflatten(full_shape_deriv, state_->mesh->dimension())(state_->primitive_to_node(), Eigen::all));
109
110 return term;
111 });
112 }
113
114 Eigen::VectorXd SpatialIntegralForm::compute_adjoint_rhs_step(const int time_step, const Eigen::VectorXd &x, const State &state, const DiffCache &diff_cache) const
115 {
116 if (&state != state_.get())
117 return Eigen::VectorXd::Zero(state.ndof());
118
119 assert(time_step < diff_cache.size());
120
121 Eigen::VectorXd rhs;
122 AdjointTools::dJ_du_step(state, get_integral_functional(), diff_cache.u(time_step), ids_, spatial_integral_type_, time_step, rhs);
123
124 return rhs * weight();
125 }
126
128 {
130
131 const std::string formulation = state_->formulation();
132
133 j.set_j([formulation, this](const Eigen::MatrixXd &local_pts, const Eigen::MatrixXd &pts, const Eigen::MatrixXd &u, const Eigen::MatrixXd &grad_u, const Eigen::VectorXd &lambda, const Eigen::VectorXd &mu, const Eigen::MatrixXd &reference_normals, const assembler::ElementAssemblyValues &vals, const IntegrableFunctional::ParameterType &params, Eigen::MatrixXd &val) {
134 val.setZero(grad_u.rows(), 1);
135 const int dim = u.cols();
136 Eigen::MatrixXd grad_u_q;
137 for (int q = 0; q < grad_u.rows(); q++)
138 {
139 grad_u_q = utils::unflatten(grad_u.row(q), u.cols());
140 if (formulation == "LinearElasticity")
141 {
142 grad_u_q = (grad_u_q + grad_u_q.transpose()).eval() / 2.;
143 val(q) = mu(q) * (grad_u_q.transpose() * grad_u_q).trace() + lambda(q) / 2. * grad_u_q.trace() * grad_u_q.trace();
144 }
145 else if (formulation == "NeoHookean")
146 {
147 Eigen::MatrixXd def_grad = grad_u_q + Eigen::MatrixXd::Identity(dim, dim);
148 double log_det_j = log(def_grad.determinant());
149 val(q) = mu(q) / 2 * ((def_grad.transpose() * def_grad).trace() - dim - 2 * log_det_j) + lambda(q) / 2 * log_det_j * log_det_j;
150 }
151 else
152 log_and_throw_adjoint_error("[{}] Unknown formulation {}!", name(), formulation);
153 }
154 });
155
156 j.set_dj_dgradu([formulation, this](const Eigen::MatrixXd &local_pts, const Eigen::MatrixXd &pts, const Eigen::MatrixXd &u, const Eigen::MatrixXd &grad_u, const Eigen::VectorXd &lambda, const Eigen::VectorXd &mu, const Eigen::MatrixXd &reference_normals, const assembler::ElementAssemblyValues &vals, const IntegrableFunctional::ParameterType &params, Eigen::MatrixXd &val) {
157 val.setZero(grad_u.rows(), grad_u.cols());
158 Eigen::MatrixXd grad_u_q, def_grad, FmT, stress;
159 for (int q = 0; q < grad_u.rows(); q++)
160 {
161 grad_u_q = utils::unflatten(grad_u.row(q), u.cols());
162 if (formulation == "LinearElasticity")
163 {
164 stress = mu(q) * (grad_u_q + grad_u_q.transpose()) + lambda(q) * grad_u_q.trace() * Eigen::MatrixXd::Identity(grad_u_q.rows(), grad_u_q.cols());
165 }
166 else if (formulation == "NeoHookean")
167 {
168 def_grad = Eigen::MatrixXd::Identity(grad_u_q.rows(), grad_u_q.cols()) + grad_u_q;
169 FmT = def_grad.inverse().transpose();
170 stress = mu(q) * (def_grad - FmT) + lambda(q) * std::log(def_grad.determinant()) * FmT;
171 }
172 else
173 log_and_throw_adjoint_error("[{}] Unknown formulation {}!", name(), formulation);
174 val.row(q) = utils::flatten(stress);
175 }
176 });
177
178 return j;
179 }
180
181 void ElasticEnergyForm::compute_partial_gradient_step(const int time_step, const Eigen::VectorXd &x, Eigen::VectorXd &gradv) const
182 {
185 log_and_throw_adjoint_error("[{}] Doesn't support derivatives wrt. material!", name());
186 return Eigen::VectorXd::Zero(0).eval();
187 });
188 }
189
191 {
193
194 const std::string formulation = state_->formulation();
195 const int power = in_power_;
196
197 j.set_j([formulation, power, state = state_.get()](const Eigen::MatrixXd &local_pts, const Eigen::MatrixXd &pts, const Eigen::MatrixXd &u, const Eigen::MatrixXd &grad_u, const Eigen::VectorXd &lambda, const Eigen::VectorXd &mu, const Eigen::MatrixXd &reference_normals, const assembler::ElementAssemblyValues &vals, const IntegrableFunctional::ParameterType &params, Eigen::MatrixXd &val) {
198 val.setZero(grad_u.rows(), 1);
199 const double dt = state->problem->is_time_dependent() ? state->args["time"]["dt"].get<double>() : 0;
200 const quadrature::Quadrature &quadrature = vals.quadrature;
201
202 Eigen::MatrixXd grad_u_q, stress, grad_unused;
203 for (int q = 0; q < grad_u.rows(); q++)
204 {
205 if (formulation == "Laplacian")
206 stress = grad_u.row(q);
207 else if (formulation == "Electrostatics")
208 {
209 assert(power == 2);
210 double epsilon = state->assembler->parameters().at("epsilon")(quadrature.points.row(q), vals.val.row(q), 0, params.elem);
211 stress = pow(epsilon, 1. / power) * grad_u.row(q);
212 }
213 else
214 {
215 vector2matrix(grad_u.row(q), grad_u_q);
216 state->assembler->compute_stress_grad_multiply_mat(OptAssemblerData(params.t, dt, params.elem, local_pts.row(q), pts.row(q), grad_u_q), Eigen::MatrixXd::Zero(grad_u_q.rows(), grad_u_q.cols()), stress, grad_unused);
217 }
218 val(q) = pow(stress.squaredNorm(), power / 2.);
219 }
220 });
221
222 j.set_dj_dgradu([formulation, power, state = state_.get()](const Eigen::MatrixXd &local_pts, const Eigen::MatrixXd &pts, const Eigen::MatrixXd &u, const Eigen::MatrixXd &grad_u, const Eigen::VectorXd &lambda, const Eigen::VectorXd &mu, const Eigen::MatrixXd &reference_normals, const assembler::ElementAssemblyValues &vals, const IntegrableFunctional::ParameterType &params, Eigen::MatrixXd &val) {
223 val.setZero(grad_u.rows(), grad_u.cols());
224 const double dt = state->problem->is_time_dependent() ? state->args["time"]["dt"].get<double>() : 0;
225 const int dim = state->mesh->dimension();
226 const quadrature::Quadrature &quadrature = vals.quadrature;
227
228 if (formulation == "Laplacian")
229 {
230 for (int q = 0; q < grad_u.rows(); q++)
231 {
232 const double coef = power * pow(grad_u.row(q).squaredNorm(), power / 2. - 1.);
233 val.row(q) = coef * grad_u.row(q);
234 }
235 }
236 else if (formulation == "Electrostatics")
237 {
238 assert(power == 2);
239 for (int q = 0; q < grad_u.rows(); q++)
240 {
241 double epsilon = state->assembler->parameters().at("epsilon")(quadrature.points.row(q), vals.val.row(q), 0, params.elem);
242 val.row(q) = power * epsilon * grad_u.row(q);
243 }
244 }
245 else
246 {
247 Eigen::MatrixXd grad_u_q, stress, stress_dstress;
248 for (int q = 0; q < grad_u.rows(); q++)
249 {
250 vector2matrix(grad_u.row(q), grad_u_q);
251 state->assembler->compute_stress_grad_multiply_stress(OptAssemblerData(params.t, dt, params.elem, local_pts.row(q), pts.row(q), grad_u_q), stress, stress_dstress);
252
253 const double coef = power * pow(stress.squaredNorm(), power / 2. - 1.);
254 val.row(q) = coef * utils::flatten(stress_dstress);
255 }
256 }
257 });
258
259 return j;
260 }
261
262 void StressNormForm::compute_partial_gradient_step(const int time_step, const Eigen::VectorXd &x, Eigen::VectorXd &gradv) const
263 {
266 log_and_throw_adjoint_error("[{}] Doesn't support derivatives wrt. material!", name());
267 return Eigen::VectorXd::Zero(0).eval();
268 });
269 }
270
272 {
274
275 const std::string formulation = state_->formulation();
276
277 j.set_j([formulation, state = state_.get()](const Eigen::MatrixXd &local_pts, const Eigen::MatrixXd &pts, const Eigen::MatrixXd &u, const Eigen::MatrixXd &grad_u, const Eigen::VectorXd &lambda, const Eigen::VectorXd &mu, const Eigen::MatrixXd &reference_normals, const assembler::ElementAssemblyValues &vals, const IntegrableFunctional::ParameterType &params, Eigen::MatrixXd &val) {
278 val.setZero(grad_u.rows(), 1);
279 const quadrature::Quadrature &quadrature = vals.quadrature;
280
281 Eigen::MatrixXd grad_u_q, stress, grad_unused;
282 for (int q = 0; q < grad_u.rows(); q++)
283 {
284 double scale = 1.;
285 if (formulation == "Electrostatics")
286 {
287 scale = state->assembler->parameters().at("epsilon")(quadrature.points.row(q), vals.val.row(q), 0, params.elem);
288 }
289 val(q) = scale * grad_u.row(q).squaredNorm();
290 }
291 });
292
293 j.set_dj_dgradu([formulation, state = state_.get()](const Eigen::MatrixXd &local_pts, const Eigen::MatrixXd &pts, const Eigen::MatrixXd &u, const Eigen::MatrixXd &grad_u, const Eigen::VectorXd &lambda, const Eigen::VectorXd &mu, const Eigen::MatrixXd &reference_normals, const assembler::ElementAssemblyValues &vals, const IntegrableFunctional::ParameterType &params, Eigen::MatrixXd &val) {
294 val.setZero(grad_u.rows(), grad_u.cols());
295 const int dim = state->mesh->dimension();
296 const quadrature::Quadrature &quadrature = vals.quadrature;
297
298 for (int q = 0; q < grad_u.rows(); q++)
299 {
300 double scale = 1.;
301 if (formulation == "Electrostatics")
302 scale = state->assembler->parameters().at("epsilon")(quadrature.points.row(q), vals.val.row(q), 0, params.elem);
303 val.row(q) = 2. * scale * grad_u.row(q);
304 }
305 });
306
307 return j;
308 }
309
310 void DirichletEnergyForm::compute_partial_gradient_step(const int time_step, const Eigen::VectorXd &x, Eigen::VectorXd &gradv) const
311 {
314 log_and_throw_adjoint_error("[{}] Doesn't support derivatives wrt. material!", name());
315 return Eigen::VectorXd::Zero(0).eval();
316 });
317 }
318
320 {
322
323 if (state_->formulation() != "LinearElasticity")
324 log_and_throw_adjoint_error("[{}] Only Linear Elasticity formulation is supported!", name());
325
326 j.set_j([this](const Eigen::MatrixXd &local_pts, const Eigen::MatrixXd &pts, const Eigen::MatrixXd &u, const Eigen::MatrixXd &grad_u, const Eigen::VectorXd &lambda, const Eigen::VectorXd &mu, const Eigen::MatrixXd &reference_normals, const assembler::ElementAssemblyValues &vals, const IntegrableFunctional::ParameterType &params, Eigen::MatrixXd &val) {
327 val.setZero(grad_u.rows(), 1);
328
329 Eigen::MatrixXd grad_u_q, stress;
330 for (int q = 0; q < grad_u.rows(); q++)
331 {
332 vector2matrix(grad_u.row(q), grad_u_q);
333 stress = mu(q) * (grad_u_q + grad_u_q.transpose()) + lambda(q) * grad_u_q.trace() * Eigen::MatrixXd::Identity(grad_u_q.rows(), grad_u_q.cols());
334 val(q) = (stress.array() * grad_u_q.array()).sum();
335 }
336 });
337
338 j.set_dj_dgradu([](const Eigen::MatrixXd &local_pts, const Eigen::MatrixXd &pts, const Eigen::MatrixXd &u, const Eigen::MatrixXd &grad_u, const Eigen::VectorXd &lambda, const Eigen::VectorXd &mu, const Eigen::MatrixXd &reference_normals, const assembler::ElementAssemblyValues &vals, const IntegrableFunctional::ParameterType &params, Eigen::MatrixXd &val) {
339 val.setZero(grad_u.rows(), grad_u.cols());
340 const int dim = u.cols();
341
342 Eigen::MatrixXd grad_u_q, stress;
343 for (int q = 0; q < grad_u.rows(); q++)
344 {
345 vector2matrix(grad_u.row(q), grad_u_q);
346 stress = mu(q) * (grad_u_q + grad_u_q.transpose()) + lambda(q) * grad_u_q.trace() * Eigen::MatrixXd::Identity(grad_u_q.rows(), grad_u_q.cols());
347 val.row(q) = 2 * utils::flatten(stress);
348 }
349 });
350
351 return j;
352 }
353
354 void ComplianceForm::compute_partial_gradient_step(const int time_step, const Eigen::VectorXd &x, Eigen::VectorXd &gradv) const
355 {
356 const double dt = state_->problem->is_time_dependent() ? state_->args["time"]["dt"].get<double>() : 0;
357 const double t = state_->problem->is_time_dependent() ? dt * time_step + state_->args["time"]["t0"].get<double>() : 0;
358
361 const auto &bases = state_->bases;
362 Eigen::VectorXd term = Eigen::VectorXd::Zero(bases.size() * 2);
363 const int dim = state_->mesh->dimension();
364
365 for (int e = 0; e < bases.size(); e++)
366 {
367 assembler::ElementAssemblyValues vals;
368 state_->ass_vals_cache.compute(e, state_->mesh->is_volume(), bases[e], state_->geom_bases()[e], vals);
369
370 const quadrature::Quadrature &quadrature = vals.quadrature;
371 Eigen::VectorXd da = vals.det.array() * quadrature.weights.array();
372
373 Eigen::MatrixXd u, grad_u;
374 io::Evaluator::interpolate_at_local_vals(e, dim, dim, vals, diff_cache_->u(time_step), u, grad_u);
375
376 Eigen::MatrixXd grad_u_q;
377 for (int q = 0; q < quadrature.weights.size(); q++)
378 {
379 double lambda, mu;
380 lambda = state_->assembler->parameters().at("lambda")(quadrature.points.row(q), vals.val.row(q), t, e);
381 mu = state_->assembler->parameters().at("mu")(quadrature.points.row(q), vals.val.row(q), t, e);
382
383 vector2matrix(grad_u.row(q), grad_u_q);
384
385 Eigen::MatrixXd f_prime_dmu, f_prime_dlambda;
386 state_->assembler->compute_dstress_dmu_dlambda(OptAssemblerData(t, dt, e, quadrature.points.row(q), vals.val.row(q), grad_u_q), f_prime_dmu, f_prime_dlambda);
387
388 term(e + bases.size()) += dot(f_prime_dmu, grad_u_q) * da(q);
389 term(e) += dot(f_prime_dlambda, grad_u_q) * da(q);
390 }
391 }
392 return term;
393 });
394 }
395
397 {
399 const int dim = dim_;
400
401 j.set_j([dim](const Eigen::MatrixXd &local_pts, const Eigen::MatrixXd &pts, const Eigen::MatrixXd &u, const Eigen::MatrixXd &grad_u, const Eigen::VectorXd &lambda, const Eigen::VectorXd &mu, const Eigen::MatrixXd &reference_normals, const assembler::ElementAssemblyValues &vals, const IntegrableFunctional::ParameterType &params, Eigen::MatrixXd &val) {
402 val = u.col(dim) + pts.col(dim);
403 });
404
405 j.set_dj_du([dim](const Eigen::MatrixXd &local_pts, const Eigen::MatrixXd &pts, const Eigen::MatrixXd &u, const Eigen::MatrixXd &grad_u, const Eigen::VectorXd &lambda, const Eigen::VectorXd &mu, const Eigen::MatrixXd &reference_normals, const assembler::ElementAssemblyValues &vals, const IntegrableFunctional::ParameterType &params, Eigen::MatrixXd &val) {
406 val.setZero(u.rows(), u.cols());
407 val.col(dim).setOnes();
408 });
409
410 j.set_dj_dx([dim](const Eigen::MatrixXd &local_pts, const Eigen::MatrixXd &pts, const Eigen::MatrixXd &u, const Eigen::MatrixXd &grad_u, const Eigen::VectorXd &lambda, const Eigen::VectorXd &mu, const Eigen::MatrixXd &reference_normals, const assembler::ElementAssemblyValues &vals, const IntegrableFunctional::ParameterType &params, Eigen::MatrixXd &val) {
411 val.setZero(pts.rows(), pts.cols());
412 val.col(dim).setOnes();
413 });
414
415 return j;
416 }
417
419 {
421 const int dim = this->dim_;
422
423 j.set_j([dim, state = this->state_.get(), diff_cache = this->diff_cache_.get()](const Eigen::MatrixXd &local_pts, const Eigen::MatrixXd &pts, const Eigen::MatrixXd &u, const Eigen::MatrixXd &grad_u, const Eigen::VectorXd &lambda, const Eigen::VectorXd &mu, const Eigen::MatrixXd &reference_normals, const assembler::ElementAssemblyValues &vals, const IntegrableFunctional::ParameterType &params, Eigen::MatrixXd &val) {
424 Eigen::MatrixXd acc, grad_acc;
425 io::Evaluator::interpolate_at_local_vals(*(state->mesh), state->problem->is_scalar(), state->bases, state->geom_bases(), params.elem, local_pts, diff_cache->acc(params.step), acc, grad_acc);
426
427 val = acc.col(dim);
428 });
429
430 j.set_dj_du([dim, this](const Eigen::MatrixXd &local_pts, const Eigen::MatrixXd &pts, const Eigen::MatrixXd &u, const Eigen::MatrixXd &grad_u, const Eigen::VectorXd &lambda, const Eigen::VectorXd &mu, const Eigen::MatrixXd &reference_normals, const assembler::ElementAssemblyValues &vals, const IntegrableFunctional::ParameterType &params, Eigen::MatrixXd &val) {
431 val.setZero(u.rows(), u.cols());
432 log_and_throw_adjoint_error("[{}] Gradient not implemented!", name());
433 });
434
435 return j;
436 }
437
439 {
441
442 j.set_j([this](const Eigen::MatrixXd &local_pts, const Eigen::MatrixXd &pts, const Eigen::MatrixXd &u, const Eigen::MatrixXd &grad_u, const Eigen::VectorXd &lambda, const Eigen::VectorXd &mu, const Eigen::MatrixXd &reference_normals, const assembler::ElementAssemblyValues &vals, const IntegrableFunctional::ParameterType &params, Eigen::MatrixXd &val) {
443 Eigen::MatrixXd v, grad_v;
444 io::Evaluator::interpolate_at_local_vals(*(state_->mesh), state_->problem->is_scalar(), state_->bases, state_->geom_bases(), params.elem, local_pts, diff_cache_->v(params.step), v, grad_v);
445
446 val.setZero(u.rows(), 1);
447 for (int q = 0; q < v.rows(); q++)
448 {
449 const double rho = state_->mass_matrix_assembler->density()(local_pts.row(q), pts.row(q), params.t, params.elem);
450 val(q) = 0.5 * rho * v.row(q).squaredNorm();
451 }
452 });
453
454 j.set_dj_du([this](const Eigen::MatrixXd &local_pts, const Eigen::MatrixXd &pts, const Eigen::MatrixXd &u, const Eigen::MatrixXd &grad_u, const Eigen::VectorXd &lambda, const Eigen::VectorXd &mu, const Eigen::MatrixXd &reference_normals, const assembler::ElementAssemblyValues &vals, const IntegrableFunctional::ParameterType &params, Eigen::MatrixXd &val) {
455 val.setZero(u.rows(), u.cols());
456
457 log_and_throw_adjoint_error("[{}] Gradient not implemented!", name());
458 });
459
460 return j;
461 }
462
463 void StressForm::compute_partial_gradient_step(const int time_step, const Eigen::VectorXd &x, Eigen::VectorXd &gradv) const
464 {
467 log_and_throw_adjoint_error("[{}] Doesn't support derivatives wrt. material!", name());
468 return Eigen::VectorXd::Zero(0).eval();
469 });
470 }
471
473 {
475
476 std::string formulation = state_->formulation();
477 auto dimensions = dimensions_;
478
479 j.set_j([formulation, dimensions, this](const Eigen::MatrixXd &local_pts, const Eigen::MatrixXd &pts, const Eigen::MatrixXd &u, const Eigen::MatrixXd &grad_u, const Eigen::VectorXd &lambda, const Eigen::VectorXd &mu, const Eigen::MatrixXd &reference_normals, const assembler::ElementAssemblyValues &vals, const IntegrableFunctional::ParameterType &params, Eigen::MatrixXd &val) {
480 val.setZero(grad_u.rows(), 1);
481
482 Eigen::MatrixXd grad_u_q, stress;
483 for (int q = 0; q < grad_u.rows(); q++)
484 {
485 vector2matrix(grad_u.row(q), grad_u_q);
486 if (formulation == "LinearElasticity")
487 {
488 stress = mu(q) * (grad_u_q + grad_u_q.transpose()) + lambda(q) * grad_u_q.trace() * Eigen::MatrixXd::Identity(grad_u_q.rows(), grad_u_q.cols());
489 }
490 else if (formulation == "NeoHookean")
491 {
492 Eigen::MatrixXd def_grad = Eigen::MatrixXd::Identity(grad_u_q.rows(), grad_u_q.cols()) + grad_u_q;
493 Eigen::MatrixXd FmT = def_grad.inverse().transpose();
494 stress = mu(q) * (def_grad - FmT) + lambda(q) * std::log(def_grad.determinant()) * FmT;
495 }
496 else
497 log_and_throw_adjoint_error("[{}] Unknown formulation {}!", name(), formulation);
498 val(q) = stress(dimensions[0], dimensions[1]);
499 }
500 });
501
502 j.set_dj_dgradu([formulation, dimensions, this](const Eigen::MatrixXd &local_pts, const Eigen::MatrixXd &pts, const Eigen::MatrixXd &u, const Eigen::MatrixXd &grad_u, const Eigen::VectorXd &lambda, const Eigen::VectorXd &mu, const Eigen::MatrixXd &reference_normals, const assembler::ElementAssemblyValues &vals, const IntegrableFunctional::ParameterType &params, Eigen::MatrixXd &val) {
503 val.setZero(grad_u.rows(), grad_u.cols());
504
505 const int dim = state_->mesh->dimension();
506 Eigen::MatrixXd grad_u_q, stiffness, stress;
507 for (int q = 0; q < grad_u.rows(); q++)
508 {
509 stiffness.setZero(1, dim * dim * dim * dim);
510 vector2matrix(grad_u.row(q), grad_u_q);
511
512 if (formulation == "LinearElasticity")
513 {
514 stress = mu(q) * (grad_u_q + grad_u_q.transpose()) + lambda(q) * grad_u_q.trace() * Eigen::MatrixXd::Identity(grad_u_q.rows(), grad_u_q.cols());
515 for (int i = 0, idx = 0; i < dim; i++)
516 for (int j = 0; j < dim; j++)
517 for (int k = 0; k < dim; k++)
518 for (int l = 0; l < dim; l++)
519 {
520 stiffness(idx++) = mu(q) * delta(i, k) * delta(j, l) + mu(q) * delta(i, l) * delta(j, k) + lambda(q) * delta(i, j) * delta(k, l);
521 }
522 }
523 else if (formulation == "NeoHookean")
524 {
525 Eigen::MatrixXd def_grad = Eigen::MatrixXd::Identity(grad_u_q.rows(), grad_u_q.cols()) + grad_u_q;
526 Eigen::MatrixXd FmT = def_grad.inverse().transpose();
527 stress = mu(q) * (def_grad - FmT) + lambda(q) * std::log(def_grad.determinant()) * FmT;
528 Eigen::VectorXd FmT_vec = utils::flatten(FmT);
529 double J = def_grad.determinant();
530 double tmp1 = mu(q) - lambda(q) * std::log(J);
531 for (int i = 0, idx = 0; i < dim; i++)
532 for (int j = 0; j < dim; j++)
533 for (int k = 0; k < dim; k++)
534 for (int l = 0; l < dim; l++)
535 {
536 stiffness(idx++) = mu(q) * delta(i, k) * delta(j, l) + tmp1 * FmT(i, l) * FmT(k, j);
537 }
538 stiffness += lambda(q) * utils::flatten(FmT_vec * FmT_vec.transpose()).transpose();
539 }
540 else
541 log_and_throw_adjoint_error("[{}] Unknown formulation {}!", name(), formulation);
542
543 val.row(q) = stiffness.block(0, (dimensions[0] * dim + dimensions[1]) * dim * dim, 1, dim * dim);
544 }
545 });
546
547 return j;
548 }
549
551 {
553
554 j.set_j([](const Eigen::MatrixXd &local_pts, const Eigen::MatrixXd &pts, const Eigen::MatrixXd &u, const Eigen::MatrixXd &grad_u, const Eigen::VectorXd &lambda, const Eigen::VectorXd &mu, const Eigen::MatrixXd &reference_normals, const assembler::ElementAssemblyValues &vals, const IntegrableFunctional::ParameterType &params, Eigen::MatrixXd &val) {
555 val.setOnes(grad_u.rows(), 1);
556 });
557
558 return j;
559 }
560} // namespace polyfem::solver
Eigen::MatrixXd vec
Definition Assembler.cpp:72
double val
Definition Assembler.cpp:86
QuadratureVector da
Definition Assembler.cpp:23
ElementAssemblyValues vals
Definition Assembler.cpp:22
Quadrature quadrature
int x
Storage for additional data required by differntial code.
Definition DiffCache.hpp:21
int size() const
Definition DiffCache.hpp:47
Eigen::VectorXd u(int step) const
Definition DiffCache.hpp:64
void set_dj_du(const functionalType &dj_du)
void set_dj_dgradu(const functionalType &dj_dgradu)
void set_j(const functionalType &j)
void set_dj_dx(const functionalType &dj_dx)
main class that contains the polyfem solver and all its state
Definition State.hpp:113
int ndof() const
Definition State.hpp:309
stores per element basis values at given quadrature points and geometric mapping
static void interpolate_at_local_vals(const mesh::Mesh &mesh, const bool is_problem_scalar, const std::vector< basis::ElementBases > &bases, const std::vector< basis::ElementBases > &gbases, const int el_index, const Eigen::MatrixXd &local_pts, const Eigen::MatrixXd &fun, Eigen::MatrixXd &result, Eigen::MatrixXd &result_grad)
interpolate solution and gradient at element (calls interpolate_at_local_vals with sol)
IntegrableFunctional get_integral_functional() const override
const VariableToSimulationGroup variable_to_simulations_
IntegrableFunctional get_integral_functional() const override
std::string name() const override
void compute_partial_gradient_step(const int time_step, const Eigen::VectorXd &x, Eigen::VectorXd &gradv) const override
void compute_partial_gradient_step(const int time_step, const Eigen::VectorXd &x, Eigen::VectorXd &gradv) const override
IntegrableFunctional get_integral_functional() const override
void compute_partial_gradient_step(const int time_step, const Eigen::VectorXd &x, Eigen::VectorXd &gradv) const override
IntegrableFunctional get_integral_functional() const override
virtual double weight() const
Get the form's multiplicative constant weight.
Definition Form.hpp:128
IntegrableFunctional get_integral_functional() const override
IntegrableFunctional get_integral_functional() const override
std::shared_ptr< const State > state_
double value_unweighted_step(const int time_step, const Eigen::VectorXd &x) const override
virtual IntegrableFunctional get_integral_functional() const =0
void compute_partial_gradient_step(const int time_step, const Eigen::VectorXd &x, Eigen::VectorXd &gradv) const override
std::shared_ptr< const DiffCache > diff_cache_
Eigen::VectorXd compute_adjoint_rhs_step(const int time_step, const Eigen::VectorXd &x, const State &state, const DiffCache &diff_cache) const override
void compute_partial_gradient_step(const int time_step, const Eigen::VectorXd &x, Eigen::VectorXd &gradv) const override
IntegrableFunctional get_integral_functional() const override
std::string name() const override
IntegrableFunctional get_integral_functional() const override
void compute_partial_gradient_step(const int time_step, const Eigen::VectorXd &x, Eigen::VectorXd &gradv) const override
virtual Eigen::VectorXd apply_parametrization_jacobian(const ParameterType type, const State *state_ptr, const Eigen::VectorXd &x, const std::function< Eigen::VectorXd()> &grad) const
Maps the partial gradient wrt.
IntegrableFunctional get_integral_functional() const override
double integrate_objective(const State &state, const IntegrableFunctional &j, const Eigen::MatrixXd &solution, const std::set< int > &interested_ids, const SpatialIntegralType spatial_integral_type, const int cur_step=0)
void dJ_du_step(const State &state, const IntegrableFunctional &j, const Eigen::MatrixXd &solution, const std::set< int > &interested_ids, const SpatialIntegralType spatial_integral_type, const int cur_step, Eigen::VectorXd &term)
void vector2matrix(const Eigen::VectorXd &vec, Eigen::MatrixXd &mat)
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.
Eigen::Matrix< double, Eigen::Dynamic, 1, 0, MAX_QUAD_POINTS, 1 > QuadratureVector
Definition Types.hpp:17
void log_and_throw_adjoint_error(const std::string &msg)
Definition Logger.cpp:79
Eigen::SparseMatrix< double, Eigen::ColMajor > StiffnessMatrix
Definition Types.hpp:24
Parameters for the functional evaluation.