25 bool delta(
int i,
int j)
27 return (i == j) ? true :
false;
30 double dot(
const Eigen::MatrixXd &A,
const Eigen::MatrixXd &B) {
return (A.array() * B.array()).sum(); }
32 Eigen::VectorXd reduced_to_full_shape_derivative(
34 const Eigen::MatrixXd &disp_grad,
35 const Eigen::VectorXd &adjoint_full,
41 assert(adjoint_full.size() == n_bases * dim);
42 assert(basis_nodes_to_gbasis_nodes.cols() == n_bases * dim);
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);
49 return basis_nodes_to_gbasis_nodes * term;
52 class LocalThreadScalarStorage
59 LocalThreadScalarStorage()
65 class LocalThreadVecStorage
72 LocalThreadVecStorage(
const int size)
82 assert(time_step < diff_cache_->size());
88 assert(time_step < diff_cache_->size());
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);
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();
99 const Eigen::VectorXd adjoint_rhs = this->compute_adjoint_rhs_step(time_step, x, *state_, *diff_cache_);
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(),
106 state_->mesh->dimension());
108 term += utils::flatten(utils::unflatten(full_shape_deriv, state_->mesh->dimension())(state_->primitive_to_node(), Eigen::all));
116 if (&state !=
state_.get())
117 return Eigen::VectorXd::Zero(state.
ndof());
119 assert(time_step < diff_cache.
size());
131 const std::string formulation =
state_->formulation();
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 ¶ms, 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++)
140 if (formulation ==
"LinearElasticity")
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();
145 else if (formulation ==
"NeoHookean")
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;
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 ¶ms, 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++)
162 if (formulation ==
"LinearElasticity")
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());
166 else if (formulation ==
"NeoHookean")
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;
185 log_and_throw_adjoint_error(
"[{}] Doesn't support derivatives wrt. material!", name());
186 return Eigen::VectorXd::Zero(0).eval();
194 const std::string formulation =
state_->formulation();
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 ¶ms, 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;
202 Eigen::MatrixXd grad_u_q, stress, grad_unused;
203 for (int q = 0; q < grad_u.rows(); q++)
205 if (formulation ==
"Laplacian")
206 stress = grad_u.row(q);
207 else if (formulation ==
"Electrostatics")
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);
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);
218 val(q) = pow(stress.squaredNorm(), power / 2.);
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 ¶ms, 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;
228 if (formulation ==
"Laplacian")
230 for (int q = 0; q < grad_u.rows(); q++)
232 const double coef = power * pow(grad_u.row(q).squaredNorm(), power / 2. - 1.);
233 val.row(q) = coef * grad_u.row(q);
236 else if (formulation ==
"Electrostatics")
239 for (
int q = 0; q < grad_u.rows(); q++)
242 val.row(q) = power * epsilon * grad_u.row(q);
247 Eigen::MatrixXd grad_u_q, stress, stress_dstress;
248 for (
int q = 0; q < grad_u.rows(); 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);
253 const double coef = power * pow(stress.squaredNorm(), power / 2. - 1.);
266 log_and_throw_adjoint_error(
"[{}] Doesn't support derivatives wrt. material!", name());
267 return Eigen::VectorXd::Zero(0).eval();
275 const std::string formulation =
state_->formulation();
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 ¶ms, Eigen::MatrixXd &
val) {
278 val.setZero(grad_u.rows(), 1);
279 const quadrature::Quadrature &quadrature = vals.quadrature;
281 Eigen::MatrixXd grad_u_q, stress, grad_unused;
282 for (int q = 0; q < grad_u.rows(); q++)
285 if (formulation ==
"Electrostatics")
287 scale = state->assembler->parameters().at(
"epsilon")(quadrature.points.row(q), vals.val.row(q), 0, params.elem);
289 val(q) = scale * grad_u.row(q).squaredNorm();
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 ¶ms, 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;
298 for (int q = 0; q < grad_u.rows(); q++)
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);
314 log_and_throw_adjoint_error(
"[{}] Doesn't support derivatives wrt. material!", name());
315 return Eigen::VectorXd::Zero(0).eval();
323 if (
state_->formulation() !=
"LinearElasticity")
327 val.setZero(grad_u.rows(), 1);
329 Eigen::MatrixXd grad_u_q, stress;
330 for (
int q = 0; q < grad_u.rows(); 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();
339 val.setZero(grad_u.rows(), grad_u.cols());
340 const int dim = u.cols();
342 Eigen::MatrixXd grad_u_q, stress;
343 for (
int q = 0; q < grad_u.rows(); 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());
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;
361 const auto &bases = state_->bases;
362 Eigen::VectorXd term = Eigen::VectorXd::Zero(bases.size() * 2);
363 const int dim = state_->mesh->dimension();
365 for (int e = 0; e < bases.size(); e++)
367 assembler::ElementAssemblyValues vals;
368 state_->ass_vals_cache.compute(e, state_->mesh->is_volume(), bases[e], state_->geom_bases()[e], vals);
370 const quadrature::Quadrature &quadrature = vals.quadrature;
371 Eigen::VectorXd da = vals.det.array() * quadrature.weights.array();
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);
376 Eigen::MatrixXd grad_u_q;
377 for (int q = 0; q < quadrature.weights.size(); q++)
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);
383 vector2matrix(grad_u.row(q), grad_u_q);
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);
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);
399 const int dim =
dim_;
402 val = u.col(dim) + pts.col(dim);
406 val.setZero(u.rows(), u.cols());
407 val.col(dim).setOnes();
411 val.setZero(pts.rows(), pts.cols());
412 val.col(dim).setOnes();
421 const int dim = this->
dim_;
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 ¶ms, 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);
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 ¶ms, Eigen::MatrixXd &
val) {
431 val.setZero(u.rows(), u.cols());
443 Eigen::MatrixXd v, grad_v;
446 val.setZero(u.rows(), 1);
447 for (
int q = 0; q < v.rows(); q++)
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();
455 val.setZero(u.rows(), u.cols());
467 log_and_throw_adjoint_error(
"[{}] Doesn't support derivatives wrt. material!", name());
468 return Eigen::VectorXd::Zero(0).eval();
476 std::string formulation =
state_->formulation();
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 ¶ms, Eigen::MatrixXd &
val) {
480 val.setZero(grad_u.rows(), 1);
482 Eigen::MatrixXd grad_u_q, stress;
483 for (
int q = 0; q < grad_u.rows(); q++)
486 if (formulation ==
"LinearElasticity")
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());
490 else if (formulation ==
"NeoHookean")
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;
498 val(q) = stress(dimensions[0], dimensions[1]);
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 ¶ms, Eigen::MatrixXd &
val) {
503 val.setZero(grad_u.rows(), grad_u.cols());
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++)
509 stiffness.setZero(1, dim * dim * dim * dim);
512 if (formulation ==
"LinearElasticity")
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++)
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);
523 else if (formulation ==
"NeoHookean")
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;
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++)
536 stiffness(idx++) = mu(q) * delta(i, k) * delta(j, l) + tmp1 * FmT(i, l) * FmT(k, j);
538 stiffness += lambda(q) *
utils::flatten(FmT_vec * FmT_vec.transpose()).transpose();
543 val.row(q) = stiffness.block(0, (dimensions[0] * dim + dimensions[1]) * dim * dim, 1, dim * dim);
555 val.setOnes(grad_u.rows(), 1);
ElementAssemblyValues vals
Storage for additional data required by differntial code.
Eigen::VectorXd u(int step) const
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
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)
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.
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
void log_and_throw_adjoint_error(const std::string &msg)
Eigen::SparseMatrix< double, Eigen::ColMajor > StiffnessMatrix
Parameters for the functional evaluation.