72 if (varform.
get_args()[
"time"][
"integrator"].is_string())
74 if (varform.
get_args()[
"time"][
"integrator"][
"type"] ==
"ImplicitEuler")
76 if (varform.
get_args()[
"time"][
"integrator"][
"type"] ==
"BDF")
77 return varform.
get_args()[
"time"][
"integrator"][
"steps"].get<
int>();
83 double dot(
const Eigen::MatrixXd &A,
const Eigen::MatrixXd &B) {
return (A.array() * B.array()).sum(); }
85 class LocalThreadScalarStorage
92 LocalThreadScalarStorage()
98 class LocalThreadVecStorage
105 LocalThreadVecStorage(
const int size)
114 template <
typename T>
115 T triangle_area(
const Eigen::Matrix<T, Eigen::Dynamic, Eigen::Dynamic> &
V)
117 Eigen::Matrix<T, Eigen::Dynamic, 1> l1 =
V.row(1) -
V.row(0);
118 Eigen::Matrix<T, Eigen::Dynamic, 1> l2 =
V.row(2) -
V.row(0);
119 T area = 0.5 * sqrt(pow(l1(1) * l2(2) - l1(2) * l2(1), 2) + pow(l1(0) * l2(2) - l1(2) * l2(0), 2) + pow(l1(1) * l2(0) - l1(0) * l2(1), 2));
123 Eigen::MatrixXd triangle_area_grad(
const Eigen::MatrixXd &
F)
126 Eigen::Matrix<Diff, Eigen::Dynamic, Eigen::Dynamic> full_diff(
F.rows(),
F.cols());
127 for (
int i = 0; i <
F.rows(); i++)
128 for (
int j = 0; j <
F.cols(); j++)
129 full_diff(i, j) =
Diff(i + j *
F.rows(),
F(i, j));
132 Eigen::MatrixXd
grad(
F.rows(),
F.cols());
133 for (
int i = 0; i <
F.rows(); ++i)
134 for (
int j = 0; j <
F.cols(); ++j)
135 grad(i, j) = reduced_diff.getGradient()(i + j *
F.rows());
140 template <
typename T>
141 T line_length(
const Eigen::Matrix<T, Eigen::Dynamic, Eigen::Dynamic> &
V)
143 Eigen::Matrix<T, Eigen::Dynamic, 1> L =
V.row(1) -
V.row(0);
148 Eigen::MatrixXd line_length_grad(
const Eigen::MatrixXd &
F)
151 Eigen::Matrix<Diff, Eigen::Dynamic, Eigen::Dynamic> full_diff(
F.rows(),
F.cols());
152 for (
int i = 0; i <
F.rows(); i++)
153 for (
int j = 0; j <
F.cols(); j++)
154 full_diff(i, j) =
Diff(i + j *
F.rows(),
F(i, j));
155 auto reduced_diff = line_length(full_diff);
157 Eigen::MatrixXd
grad(
F.rows(),
F.cols());
158 for (
int i = 0; i <
F.rows(); ++i)
159 for (
int j = 0; j <
F.cols(); ++j)
160 grad(i, j) = reduced_diff.getGradient()(i + j *
F.rows());
165 template <
typename T>
166 Eigen::Matrix<T, 2, 1> edge_normal(
const Eigen::Matrix<T, 4, 1> &
V)
168 Eigen::Matrix<T, 2, 1> v1 =
V.segment(0, 2);
169 Eigen::Matrix<T, 2, 1> v2 =
V.segment(2, 2);
170 Eigen::Matrix<T, 2, 1> normal = v1 - v2;
172 normal = normal / normal.norm();
176 template <
typename T>
177 Eigen::Matrix<T, 3, 1> face_normal(
const Eigen::Matrix<T, 9, 1> &
V)
179 Eigen::Matrix<T, 3, 1> v1 =
V.segment(0, 3);
180 Eigen::Matrix<T, 3, 1> v2 =
V.segment(3, 3);
181 Eigen::Matrix<T, 3, 1> v3 =
V.segment(6, 3);
182 Eigen::Matrix<T, 3, 1> normal = (v2 - v1).
cross(v3 - v1);
183 normal = normal / normal.norm();
187 Eigen::MatrixXd extract_lame_params(
const std::map<std::string, Assembler::ParamFunc> &lame_params,
const int e,
const int t,
const Eigen::MatrixXd &local_pts,
const Eigen::MatrixXd &pts)
189 Eigen::MatrixXd params = Eigen::MatrixXd::Zero(local_pts.rows(), 2);
191 auto search_lambda = lame_params.find(
"lambda");
192 auto search_mu = lame_params.find(
"mu");
194 if (search_lambda == lame_params.end() || search_mu == lame_params.end())
197 for (
int p = 0; p < local_pts.rows(); p++)
199 params(p, 0) = search_lambda->second(local_pts.row(p), pts.row(p), t, e);
200 params(p, 1) = search_mu->second(local_pts.row(p), pts.row(p), t, e);
210 const Eigen::MatrixXd &solution,
211 const std::set<int> &interested_ids,
220 const int n_elements = int(bases.size());
232 params.
t = dt * cur_step + t0;
233 params.
step = cur_step;
235 Eigen::MatrixXd u, grad_u;
236 Eigen::MatrixXd result;
238 for (
int e = start; e < end; ++e)
240 if (interested_ids.size() != 0 && interested_ids.find(varform.
get_mesh().
get_body_id(e)) == interested_ids.end())
256 local_storage.val += dot(result, local_storage.da);
259 for (
const LocalThreadScalarStorage &local_storage : storage)
260 integral += local_storage.val;
266 LocalThreadScalarStorage &local_storage = utils::get_local_thread_storage(storage, thread_id);
269 Eigen::MatrixXd points, normal;
270 Eigen::VectorXd weights;
272 Eigen::MatrixXd u, grad_u;
273 Eigen::MatrixXd result;
274 IntegrableFunctional::ParameterType params;
275 params.t = dt * cur_step + t0;
276 params.step = cur_step;
278 for (int lb_id = start; lb_id < end; ++lb_id)
280 const auto &lb = varform.boundary_state().total_local_boundary[lb_id];
281 const int e = lb.element_id();
283 for (int i = 0; i < lb.size(); i++)
285 const int global_primitive_id = lb.global_primitive_id(i);
286 if (interested_ids.size() != 0 && interested_ids.find(varform.get_mesh().get_boundary_id(global_primitive_id)) == interested_ids.end())
289 utils::BoundarySampler::boundary_quadrature(lb, varform.n_boundary_samples(), varform.get_mesh(), i, false, uv, points, normal, weights);
291 assembler::ElementAssemblyValues &vals = local_storage.vals;
292 vals.compute(e, varform.get_mesh().is_volume(), points, bases[e], gbases[e]);
293 io::Evaluator::interpolate_at_local_vals(e, dim, actual_dim, vals, solution, u, grad_u);
295 const Eigen::MatrixXd lame_params = extract_lame_params(varform.primary_assembler().parameters(), e, params.t, points, vals.val);
298 params.body_id = varform.get_mesh().get_body_id(e);
299 params.boundary_id = varform.get_mesh().get_boundary_id(global_primitive_id);
300 j.evaluate(lame_params, points, vals.val, u, grad_u, normal, vals, params, result);
302 local_storage.val += dot(result, weights);
306 for (
const LocalThreadScalarStorage &local_storage : storage)
307 integral += local_storage.val;
313 params.
t = dt * cur_step + t0;
314 params.
step = cur_step;
315 for (
int e = 0; e < bases.size(); e++)
317 const auto &bs = bases[e];
318 for (
int i = 0; i < bs.bases.size(); i++)
320 const auto &b = bs.bases[i];
321 assert(b.global().size() == 1);
322 const auto &g = b.global()[0];
323 if (traversed[g.index])
326 const Eigen::MatrixXd lame_params = extract_lame_params(varform.
primary_assembler().
parameters(), e, params.
t, Eigen::MatrixXd::Zero(1, dim) , g.node);
328 params.
node = g.index;
332 j.evaluate(lame_params, Eigen::MatrixXd::Zero(1, dim) , g.node, solution.block(g.index * dim, 0, dim, 1).transpose(), Eigen::MatrixXd::Zero(1, dim * actual_dim) , Eigen::MatrixXd::Zero(0, 0) ,
assembler::ElementAssemblyValues(), params,
val);
334 traversed[g.index] =
true;
342 void AdjointTools::compute_shape_derivative_functional_term(
344 const Eigen::MatrixXd &solution,
346 const std::set<int> &interested_ids,
348 Eigen::VectorXd &term,
349 const int cur_time_step)
358 const int n_elements = int(bases.size());
361 auto storage = utils::create_thread_storage(LocalThreadVecStorage(term.size()));
363 if (spatial_integral_type == SpatialIntegralType::Volume)
365 utils::maybe_parallel_for(n_elements, [&](
int start,
int end,
int thread_id) {
366 LocalThreadVecStorage &local_storage = utils::get_local_thread_storage(storage, thread_id);
368 Eigen::MatrixXd u, grad_u, j_val, dj_dgradu, dj_dx;
371 params.
t = cur_time_step * dt + t0;
372 params.
step = cur_time_step;
374 for (
int e = start; e < end; ++e)
376 if (interested_ids.size() != 0 && interested_ids.find(varform.
get_mesh().
get_body_id(e)) == interested_ids.end())
381 io::Evaluator::interpolate_at_local_vals(e, dim, actual_dim,
vals, solution, u, grad_u);
402 Eigen::MatrixXd tau_q, grad_u_q;
403 for (
auto &v :
gvals.basis_values)
405 for (
int q = 0; q < local_storage.da.size(); ++q)
407 local_storage.vec.block(v.global[0].index * dim, 0, dim, 1) += (j_val(q) * local_storage.da(q)) * v.grad_t_m.row(q).transpose();
410 local_storage.vec.block(v.global[0].index * dim, 0, dim, 1) += (v.val(q) * local_storage.da(q)) * dj_dx.row(q).transpose();
414 if (dim == actual_dim)
421 tau_q = dj_dgradu.row(q);
422 grad_u_q = grad_u.row(q);
424 for (
int d = 0; d < dim; d++)
425 local_storage.vec(v.global[0].index * dim + d) += -dot(tau_q, grad_u_q.col(d) * v.grad_t_m.row(q)) * local_storage.da(q);
432 else if (spatial_integral_type == SpatialIntegralType::Surface)
435 LocalThreadVecStorage &local_storage = utils::get_local_thread_storage(storage, thread_id);
437 Eigen::MatrixXd uv, points, normal;
438 Eigen::VectorXd &weights = local_storage.da;
440 Eigen::MatrixXd u, grad_u, x, grad_x, j_val, dj_dgradu, dj_dgradx, dj_dx;
442 IntegrableFunctional::ParameterType params;
443 params.t = cur_time_step * dt + t0;
444 params.step = cur_time_step;
446 for (int lb_id = start; lb_id < end; ++lb_id)
448 const auto &lb = varform.boundary_state().total_local_boundary[lb_id];
449 const int e = lb.element_id();
451 for (int i = 0; i < lb.size(); i++)
453 const int global_primitive_id = lb.global_primitive_id(i);
454 if (interested_ids.size() != 0 && interested_ids.find(varform.get_mesh().get_boundary_id(global_primitive_id)) == interested_ids.end())
457 utils::BoundarySampler::boundary_quadrature(lb, varform.n_boundary_samples(), varform.get_mesh(), i, false, uv, points, normal, weights);
459 assembler::ElementAssemblyValues &vals = local_storage.vals;
460 io::Evaluator::interpolate_at_local_vals(varform.get_mesh(), varform.get_problem().is_scalar(), bases, gbases, e, points, solution, u, grad_u);
463 vals.compute(e, varform.get_mesh().is_volume(), points, gbases[e], gbases[e]);
467 const int n_loc_bases_ = int(vals.basis_values.size());
469 const Eigen::MatrixXd lame_params = extract_lame_params(varform.primary_assembler().parameters(), e, params.t, points, vals.val);
472 params.body_id = varform.get_mesh().get_body_id(e);
473 params.boundary_id = varform.get_mesh().get_boundary_id(global_primitive_id);
475 j.evaluate(lame_params, points, vals.val, u, grad_u, normal, vals, params, j_val);
476 j_val = j_val.array().colwise() * weights.array();
478 if (j.depend_on_gradu())
480 j.dj_dgradu(lame_params, points, vals.val, u, grad_u, normal, vals, params, dj_dgradu);
481 dj_dgradu = dj_dgradu.array().colwise() * weights.array();
484 if (j.depend_on_gradx())
486 j.dj_dgradx(lame_params, points, vals.val, u, grad_u, normal, vals, params, dj_dgradx);
487 dj_dgradx = dj_dgradx.array().colwise() * weights.array();
492 j.dj_dx(lame_params, points, vals.val, u, grad_u, normal, vals, params, dj_dx);
493 dj_dx = dj_dx.array().colwise() * weights.array();
496 const auto nodes = gbases[e].local_nodes_for_primitive(lb.global_primitive_id(i), varform.get_mesh());
498 if (nodes.size() != dim)
499 log_and_throw_adjoint_error(
"Only linear geometry is supported in differentiable surface integral functional!");
501 Eigen::MatrixXd velocity_div_mat;
502 if (varform.get_mesh().is_volume())
505 for (int d = 0; d < 3; d++)
506 V.row(d) = gbases[e].bases[nodes(d)].global()[0].node;
507 velocity_div_mat = face_velocity_divergence(V);
512 for (int d = 0; d < 2; d++)
513 V.row(d) = gbases[e].bases[nodes(d)].global()[0].node;
514 velocity_div_mat = edge_velocity_divergence(V);
517 Eigen::MatrixXd grad_u_q, tau_q, grad_x_q;
518 for (long n = 0; n < nodes.size(); ++n)
520 const assembler::AssemblyValues &v = vals.basis_values[nodes(n)];
522 local_storage.vec.block(v.global[0].index * dim, 0, dim, 1) += j_val.sum() * velocity_div_mat.row(n).transpose();
525 for (long n = 0; n < n_loc_bases_; ++n)
527 const assembler::AssemblyValues &v = vals.basis_values[n];
530 local_storage.vec.block(v.global[0].index * dim, 0, dim, 1) += dj_dx.transpose() * v.val;
533 if (j.depend_on_gradu())
535 for (int q = 0; q < weights.size(); ++q)
537 if (dim == actual_dim)
539 vector2matrix(grad_u.row(q), grad_u_q);
540 vector2matrix(dj_dgradu.row(q), tau_q);
544 grad_u_q = grad_u.row(q);
545 tau_q = dj_dgradu.row(q);
548 for (int d = 0; d < dim; d++)
549 local_storage.vec(v.global[0].index * dim + d) += -dot(tau_q, grad_u_q.col(d) * v.grad_t_m.row(q));
553 if (j.depend_on_gradx())
555 for (int d = 0; d < dim; d++)
557 for (int q = 0; q < weights.size(); ++q)
558 local_storage.vec(v.global[0].index * dim + d) += dot(dj_dgradx.block(q, d * dim, 1, dim), v.grad.row(q));
566 else if (spatial_integral_type == SpatialIntegralType::VertexSum)
570 for (
const LocalThreadVecStorage &local_storage : storage)
571 term += local_storage.
vec;
573 term = utils::flatten(utils::unflatten(term, dim)(varform.
primitive_to_node(), Eigen::all));
576 void AdjointTools::dJ_shape_static_adjoint_term(
579 const Eigen::MatrixXd &sol,
580 const Eigen::MatrixXd &adjoint,
581 Eigen::VectorXd &one_form)
583 Eigen::VectorXd elasticity_term, rhs_term, pressure_term, contact_term, adhesion_term;
586 Eigen::MatrixXd adjoint_zeroed = adjoint;
595 rhs_term.setZero(one_form.size());
603 pressure_term.setZero(one_form.size());
609 BarrierContactForceDerivative::force_shape_derivative(*barrier_contact, diff_cache.
collision_set(0), sol, adjoint_zeroed, contact_term);
613 SmoothContactForceDerivative::force_shape_derivative(*smooth_contact, diff_cache.
smooth_collision_set(0), sol, adjoint_zeroed, contact_term);
619 contact_term.setZero(elasticity_term.size());
628 adhesion_term.setZero(elasticity_term.size());
632 one_form -= elasticity_term + rhs_term + pressure_term + contact_term + adhesion_term;
636 void AdjointTools::dJ_shape_homogenization_adjoint_term(
639 const Eigen::MatrixXd &sol,
640 const Eigen::MatrixXd &adjoint,
641 Eigen::VectorXd &one_form)
643 Eigen::VectorXd elasticity_term, contact_term, adhesion_term;
645 std::shared_ptr<NLHomoProblem> homo_problem = std::dynamic_pointer_cast<NLHomoProblem>(varform.
solve_data()->
nl_problem);
646 assert(homo_problem);
651 const Eigen::MatrixXd affine_adjoint = homo_problem->reduced_to_disp_grad(adjoint,
true);
652 const Eigen::VectorXd full_adjoint = homo_problem->NLProblem::reduced_to_full(adjoint.topRows(homo_problem->reduced_size())) + io::Evaluator::generate_linear_field(varform.
primary_space().
n_bases, varform.
primary_space().
mesh_nodes, affine_adjoint);
660 BarrierContactForceDerivative::force_shape_derivative(*barrier_contact, diff_cache.
collision_set(0), sol, full_adjoint, contact_term);
664 SmoothContactForceDerivative::force_shape_derivative(*smooth_contact, diff_cache.
smooth_collision_set(0), sol, full_adjoint, contact_term);
670 contact_term.setZero(elasticity_term.size());
679 adhesion_term.setZero(elasticity_term.size());
682 one_form = -(elasticity_term + contact_term + adhesion_term);
684 Eigen::VectorXd force;
685 homo_problem->FullNLProblem::gradient(sol, force);
688 one_form = utils::flatten(utils::unflatten(one_form, dim)(varform.
primitive_to_node(), Eigen::all));
691 void AdjointTools::dJ_periodic_shape_adjoint_term(
695 const Eigen::VectorXd &periodic_mesh_representation,
696 const Eigen::MatrixXd &sol,
697 const Eigen::MatrixXd &adjoint,
698 Eigen::VectorXd &one_form)
700 std::shared_ptr<NLHomoProblem> homo_problem = std::dynamic_pointer_cast<NLHomoProblem>(varform.
solve_data()->
nl_problem);
701 assert(homo_problem);
703 const Eigen::MatrixXd reduced_sol = homo_problem->full_to_reduced(sol, diff_cache.
disp_grad());
704 const Eigen::VectorXd extended_sol = homo_problem->reduced_to_extended(reduced_sol);
706 const Eigen::VectorXd extended_adjoint = homo_problem->reduced_to_extended(adjoint,
true);
707 const Eigen::MatrixXd affine_adjoint = homo_problem->reduced_to_disp_grad(adjoint,
true);
708 const Eigen::VectorXd full_adjoint = homo_problem->NLProblem::reduced_to_full(adjoint.topRows(homo_problem->reduced_size())) + io::Evaluator::generate_linear_field(varform.
primary_space().
n_bases, varform.
primary_space().
mesh_nodes, affine_adjoint);
715 homo_problem->set_project_to_psd(
false);
716 homo_problem->FullNLProblem::hessian(sol, hessian);
717 Eigen::VectorXd partial_term = full_adjoint.transpose() * hessian;
719 one_form -= utils::flatten(utils::unflatten(partial_term, dim)(varform.
primitive_to_node(), Eigen::all));
721 one_form = periodic_mesh_map.
apply_jacobian(one_form, periodic_mesh_representation);
725 Eigen::VectorXd contact_term;
728 one_form -= contact_term;
732 void AdjointTools::dJ_shape_transient_adjoint_term(
735 const Eigen::MatrixXd &adjoint_nu,
736 const Eigen::MatrixXd &adjoint_p,
737 Eigen::VectorXd &one_form)
739 const double t0 = varform.
get_args()[
"time"][
"t0"];
740 const double dt = varform.
get_args()[
"time"][
"dt"];
741 const int time_steps = varform.
get_args()[
"time"][
"time_steps"];
742 const int bdf_order = get_bdf_order(varform);
744 Eigen::VectorXd elasticity_term, rhs_term, pressure_term, damping_term, mass_term, contact_term, friction_term, adhesion_term, tangential_adhesion_term;
747 Eigen::VectorXd cur_p, cur_nu;
748 for (
int i = time_steps; i > 0; --i)
750 const int real_order = std::min(bdf_order, i);
751 double beta = time_integrator::BDF::betas(real_order - 1);
752 double beta_dt = beta * dt;
753 const double t = i * dt + t0;
755 Eigen::MatrixXd velocity = diff_cache.
v(i);
757 cur_p = adjoint_p.col(i);
758 cur_nu = adjoint_nu.col(i);
763 InertiaForceDerivative::force_shape_derivative(*varform.
solve_data()->
inertia_form, varform.
get_mesh().
is_volume(), varform.
primary_space().
geometry->n_bases, t, varform.
primary_space().
basis_list(), varform.
primary_space().
geometry_basis_list(), varform.
mass_assembler(), varform.
mass_assembly_cache(), velocity, cur_nu, mass_term);
772 damping_term.setZero(mass_term.size());
778 BarrierContactForceDerivative::force_shape_derivative(*barrier_contact, diff_cache.
collision_set(i), diff_cache.
u(i), cur_p, contact_term);
782 SmoothContactForceDerivative::force_shape_derivative(*smooth_contact, diff_cache.
smooth_collision_set(i), diff_cache.
u(i), cur_p, contact_term);
788 contact_term.setZero(mass_term.size());
797 friction_term.setZero(mass_term.size());
806 adhesion_term.setZero(mass_term.size());
816 tangential_adhesion_term.setZero(mass_term.size());
819 one_form += beta_dt * (elasticity_term + rhs_term + pressure_term + damping_term + contact_term + friction_term + mass_term + adhesion_term + tangential_adhesion_term);
823 Eigen::VectorXd sum_alpha_p;
825 sum_alpha_p.setZero(adjoint_p.rows());
826 int num = std::min(bdf_order, time_steps);
827 for (
int j = 0; j < num; ++j)
829 int order = std::min(bdf_order - 1, j);
830 sum_alpha_p -= time_integrator::BDF::alphas(order)[j] * adjoint_p.col(j + 1);
834 InertiaForceDerivative::force_shape_derivative(*varform.
solve_data()->
inertia_form, varform.
get_mesh().
is_volume(), varform.
primary_space().
geometry->n_bases, t0, varform.
primary_space().
basis_list(), varform.
primary_space().
geometry_basis_list(), varform.
mass_assembler(), varform.
mass_assembly_cache(), diff_cache.
v(0), sum_alpha_p, mass_term);
836 one_form += mass_term;
841 void AdjointTools::dJ_material_static_adjoint_term(
843 const Eigen::MatrixXd &sol,
844 const Eigen::MatrixXd &adjoint,
845 Eigen::VectorXd &one_form)
847 Eigen::MatrixXd adjoint_zeroed = adjoint;
849 ElasticForceDerivative::force_material_derivative(*varform.
solve_data()->
elastic_form, 0, sol, sol, adjoint_zeroed, one_form);
852 void AdjointTools::dJ_material_transient_adjoint_term(
855 const Eigen::MatrixXd &adjoint_nu,
856 const Eigen::MatrixXd &adjoint_p,
857 Eigen::VectorXd &one_form)
859 const double t0 = varform.
get_args()[
"time"][
"t0"];
860 const double dt = varform.
get_args()[
"time"][
"dt"];
861 const int time_steps = varform.
get_args()[
"time"][
"time_steps"];
862 const int bdf_order = get_bdf_order(varform);
866 auto storage = utils::create_thread_storage(LocalThreadVecStorage(one_form.size()));
868 utils::maybe_parallel_for(time_steps, [&](
int start,
int end,
int thread_id) {
869 LocalThreadVecStorage &local_storage = utils::get_local_thread_storage(storage, thread_id);
870 Eigen::VectorXd elasticity_term;
871 for (
int i_aux = start; i_aux < end; ++i_aux)
873 const int i = time_steps - i_aux;
874 const int real_order = std::min(bdf_order, i);
875 double beta_dt = time_integrator::BDF::betas(real_order - 1) * dt;
877 Eigen::VectorXd cur_p = adjoint_p.col(i);
880 ElasticForceDerivative::force_material_derivative(*varform.
solve_data()->
elastic_form, t0 + dt * i, diff_cache.
u(i), diff_cache.
u(i - 1), -cur_p, elasticity_term);
881 local_storage.vec += beta_dt * elasticity_term;
885 for (
const LocalThreadVecStorage &local_storage : storage)
886 one_form += local_storage.vec;
889 void AdjointTools::dJ_friction_transient_adjoint_term(
892 const Eigen::MatrixXd &adjoint_nu,
893 const Eigen::MatrixXd &adjoint_p,
894 Eigen::VectorXd &one_form)
896 const double dt = varform.
get_args()[
"time"][
"dt"];
898 const int time_steps = varform.
get_args()[
"time"][
"time_steps"];
900 const int bdf_order = get_bdf_order(varform);
904 std::shared_ptr<time_integrator::ImplicitTimeIntegrator> time_integrator =
905 time_integrator::ImplicitTimeIntegrator::construct_time_integrator(varform.
get_args()[
"time"][
"integrator"]);
907 Eigen::MatrixXd solution, velocity, acceleration;
912 solution = diff_cache.
u(0);
915 const double dt = varform.
get_args()[
"time"][
"dt"];
916 time_integrator->init(solution, velocity, acceleration, dt);
919 for (
int t = 1; t <= time_steps; ++t)
921 const int real_order = std::min(bdf_order, t);
922 double beta = time_integrator::BDF::betas(real_order - 1);
924 const Eigen::MatrixXd surface_solution_prev = varform.
collision_mesh().vertices(utils::unflatten(diff_cache.
u(t - 1), dim));
927 const Eigen::MatrixXd surface_velocities = varform.
collision_mesh().map_displacements(utils::unflatten(time_integrator->compute_velocity(diff_cache.
u(t)), varform.
collision_mesh().dim()));
928 time_integrator->update_quantities(diff_cache.
u(t));
932 ipc::BarrierPotential bp = barrier_contact->barrier_potential();
933 bp.set_stiffness(barrier_contact->barrier_stiffness());
939 surface_solution_prev,
944 Eigen::VectorXd cur_p = adjoint_p.col(t);
947 one_form(0) += dot(cur_p, force) * beta * dt;
952 void AdjointTools::dJ_damping_transient_adjoint_term(
955 const Eigen::MatrixXd &adjoint_nu,
956 const Eigen::MatrixXd &adjoint_p,
957 Eigen::VectorXd &one_form)
959 const double t0 = varform.
get_args()[
"time"][
"t0"];
960 const double dt = varform.
get_args()[
"time"][
"dt"];
961 const int time_steps = varform.
get_args()[
"time"][
"time_steps"];
962 const int bdf_order = get_bdf_order(varform);
966 auto storage = utils::create_thread_storage(LocalThreadVecStorage(one_form.size()));
968 utils::maybe_parallel_for(time_steps, [&](
int start,
int end,
int thread_id) {
969 LocalThreadVecStorage &local_storage = utils::get_local_thread_storage(storage, thread_id);
970 Eigen::VectorXd damping_term;
971 for (
int t_aux = start; t_aux < end; ++t_aux)
973 const int t = time_steps - t_aux;
974 const int real_order = std::min(bdf_order, t);
975 const double beta = time_integrator::BDF::betas(real_order - 1);
977 Eigen::VectorXd cur_p = adjoint_p.col(t);
980 ElasticForceDerivative::force_material_derivative(*varform.
solve_data()->
damping_form, t * dt + t0, diff_cache.
u(t), diff_cache.
u(t - 1), -cur_p, damping_term);
981 local_storage.vec += (beta * dt) * damping_term;
985 for (
const LocalThreadVecStorage &local_storage : storage)
986 one_form += local_storage.vec;
989 void AdjointTools::dJ_initial_condition_adjoint_term(
991 const Eigen::MatrixXd &adjoint_nu,
992 const Eigen::MatrixXd &adjoint_p,
993 Eigen::VectorXd &one_form)
996 one_form.setZero(ndof * 2);
999 one_form.segment(0, ndof) = -adjoint_nu.col(0);
1000 one_form.segment(ndof, ndof) = -adjoint_p.col(0);
1005 one_form(ndof + b) = 0;
1009 void AdjointTools::dJ_dirichlet_static_adjoint_term(
1012 const Eigen::MatrixXd &adjoint,
1013 Eigen::VectorXd &one_form)
1018 gradd_h.prune([&boundary_nodes_set](
const Eigen::Index &row,
const Eigen::Index &col,
const FullNLProblem::Scalar &value) {
1021 if (boundary_nodes_set.find(row) == boundary_nodes_set.end())
1031 void AdjointTools::dJ_dirichlet_transient_adjoint_term(
1033 const Eigen::MatrixXd &adjoint_nu,
1034 const Eigen::MatrixXd &adjoint_p,
1035 Eigen::VectorXd &one_form)
1037 const double dt = varform.
get_args()[
"time"][
"dt"];
1038 const int time_steps = varform.
get_args()[
"time"][
"time_steps"];
1039 const int bdf_order = get_bdf_order(varform);
1044 one_form.setZero(time_steps * n_dirichlet_dof);
1045 for (
int i = 1; i <= time_steps; ++i)
1047 const int real_order = std::min(bdf_order, i);
1048 const double beta_dt = time_integrator::BDF::betas(real_order - 1) * dt;
1050 one_form.segment((i - 1) * n_dirichlet_dof, n_dirichlet_dof) = -(1. / beta_dt) * adjoint_p(varform.
boundary_state().
boundary_nodes, i);
1054 void AdjointTools::dJ_pressure_static_adjoint_term(
1056 const std::vector<int> &boundary_ids,
1057 const Eigen::MatrixXd &sol,
1058 const Eigen::MatrixXd &adjoint,
1059 Eigen::VectorXd &one_form)
1061 const int n_pressure_dof = boundary_ids.size();
1063 one_form.setZero(n_pressure_dof);
1065 for (
int i = 0; i < boundary_ids.size(); ++i)
1067 double pressure_term = PressureForceDerivative::force_pressure_derivative(
1074 one_form(i) = pressure_term;
1078 void AdjointTools::dJ_pressure_transient_adjoint_term(
1081 const std::vector<int> &boundary_ids,
1082 const Eigen::MatrixXd &adjoint_nu,
1083 const Eigen::MatrixXd &adjoint_p,
1084 Eigen::VectorXd &one_form)
1086 const double t0 = varform.
get_args()[
"time"][
"t0"];
1087 const double dt = varform.
get_args()[
"time"][
"dt"];
1088 const int time_steps = varform.
get_args()[
"time"][
"time_steps"];
1089 const int bdf_order = get_bdf_order(varform);
1091 const int n_pressure_dof = boundary_ids.size();
1093 one_form.setZero(time_steps * n_pressure_dof);
1094 Eigen::VectorXd cur_p, cur_nu;
1095 for (
int i = time_steps; i > 0; --i)
1097 const int real_order = std::min(bdf_order, i);
1098 double beta = time_integrator::BDF::betas(real_order - 1);
1099 double beta_dt = beta * dt;
1100 const double t = i * dt + t0;
1102 cur_p = adjoint_p.col(i);
1103 cur_nu = adjoint_nu.col(i);
1107 for (
int b = 0; b < boundary_ids.size(); ++b)
1109 double pressure_term = PressureForceDerivative::force_pressure_derivative(
1116 one_form((i - 1) * n_pressure_dof + b) = -beta_dt * pressure_term;
1121 void AdjointTools::dJ_du_step(
1124 const Eigen::MatrixXd &solution,
1125 const std::set<int> &interested_ids,
1128 Eigen::VectorXd &term)
1135 const int n_elements = int(bases.size());
1144 if (spatial_integral_type == SpatialIntegralType::Volume)
1146 auto storage = utils::create_thread_storage(LocalThreadVecStorage(term.size()));
1147 utils::maybe_parallel_for(n_elements, [&](
int start,
int end,
int thread_id) {
1148 LocalThreadVecStorage &local_storage = utils::get_local_thread_storage(storage, thread_id);
1150 Eigen::MatrixXd u, grad_u;
1151 Eigen::MatrixXd lambda, mu;
1152 Eigen::MatrixXd dj_du, dj_dgradu, dj_dgradx;
1155 params.
t = dt * cur_step + t0;
1156 params.
step = cur_step;
1158 for (
int e = start; e < end; ++e)
1160 if (interested_ids.size() != 0 && interested_ids.find(varform.
get_mesh().
get_body_id(e)) == interested_ids.end())
1171 const int n_loc_bases_ = int(
vals.basis_values.size());
1173 io::Evaluator::interpolate_at_local_vals(e, dim, actual_dim,
vals, solution, u, grad_u);
1178 dj_dgradu.resize(0, 0);
1182 for (
int q = 0; q < dj_dgradu.rows(); q++)
1183 dj_dgradu.row(q) *= local_storage.da(q);
1190 for (
int q = 0; q < dj_du.rows(); q++)
1191 dj_du.row(q) *= local_storage.da(q);
1194 for (
int i = 0; i < n_loc_bases_; ++i)
1197 assert(v.
global.size() == 1);
1198 for (
int d = 0; d < actual_dim; d++)
1205 for (
int q = 0; q < local_storage.da.size(); ++q)
1206 val += dot(dj_dgradu.block(q, d * dim, 1, dim), v.
grad_t_m.row(q));
1212 for (
int q = 0; q < local_storage.da.size(); ++q)
1213 val += dj_du(q, d) * v.
val(q);
1215 local_storage.vec(v.
global[0].index * actual_dim + d) +=
val;
1220 for (
const LocalThreadVecStorage &local_storage : storage)
1221 term += local_storage.vec;
1223 else if (spatial_integral_type == SpatialIntegralType::Surface)
1225 auto storage = utils::create_thread_storage(LocalThreadVecStorage(term.size()));
1227 LocalThreadVecStorage &local_storage = utils::get_local_thread_storage(storage, thread_id);
1229 Eigen::MatrixXd uv, samples, gtmp;
1230 Eigen::MatrixXd points, normal;
1231 Eigen::VectorXd weights;
1233 Eigen::MatrixXd u, grad_u;
1234 Eigen::MatrixXd lambda, mu;
1235 Eigen::MatrixXd dj_du, dj_dgradu, dj_dgradu_local;
1237 IntegrableFunctional::ParameterType params;
1238 params.t = dt * cur_step + t0;
1239 params.step = cur_step;
1241 for (int lb_id = start; lb_id < end; ++lb_id)
1243 const auto &lb = varform.boundary_state().total_local_boundary[lb_id];
1244 const int e = lb.element_id();
1246 for (int i = 0; i < lb.size(); i++)
1248 const int global_primitive_id = lb.global_primitive_id(i);
1249 if (interested_ids.size() != 0 && interested_ids.find(varform.get_mesh().get_boundary_id(global_primitive_id)) == interested_ids.end())
1252 utils::BoundarySampler::boundary_quadrature(lb, varform.n_boundary_samples(), varform.get_mesh(), i, false, uv, points, normal, weights);
1254 assembler::ElementAssemblyValues &vals = local_storage.vals;
1255 vals.compute(e, varform.get_mesh().is_volume(), points, bases[e], gbases[e]);
1256 io::Evaluator::interpolate_at_local_vals(e, dim, actual_dim, vals, solution, u, grad_u);
1258 const Eigen::MatrixXd lame_params = extract_lame_params(varform.primary_assembler().parameters(), e, params.t, points, vals.val);
1262 const int n_loc_bases_ = int(vals.basis_values.size());
1265 params.body_id = varform.get_mesh().get_body_id(e);
1266 params.boundary_id = varform.get_mesh().get_boundary_id(global_primitive_id);
1268 dj_dgradu.resize(0, 0);
1269 if (j.depend_on_gradu())
1271 j.dj_dgradu(lame_params, points, vals.val, u, grad_u, normal, vals, params, dj_dgradu);
1272 for (int q = 0; q < dj_dgradu.rows(); q++)
1273 dj_dgradu.row(q) *= weights(q);
1276 dj_dgradu_local.resize(0, 0);
1277 if (j.depend_on_gradu_local())
1279 j.dj_dgradu_local(lame_params, points, vals.val, u, grad_u, normal, vals, params, dj_dgradu_local);
1280 for (int q = 0; q < dj_dgradu_local.rows(); q++)
1281 dj_dgradu_local.row(q) *= weights(q);
1285 if (j.depend_on_u())
1287 j.dj_du(lame_params, points, vals.val, u, grad_u, normal, vals, params, dj_du);
1288 for (int q = 0; q < dj_du.rows(); q++)
1289 dj_du.row(q) *= weights(q);
1292 for (int l = 0; l < lb.size(); ++l)
1294 const auto nodes = bases[e].local_nodes_for_primitive(lb.global_primitive_id(l), varform.get_mesh());
1296 for (long n = 0; n < nodes.size(); ++n)
1298 const assembler::AssemblyValues &v = vals.basis_values[nodes(n)];
1299 assert(v.global.size() == 1);
1300 for (int d = 0; d < actual_dim; d++)
1305 if (j.depend_on_gradu())
1307 for (int q = 0; q < weights.size(); ++q)
1308 val += dot(dj_dgradu.block(q, d * dim, 1, dim), v.grad_t_m.row(q));
1311 if (j.depend_on_gradu_local())
1313 for (int q = 0; q < weights.size(); ++q)
1314 val += dot(dj_dgradu_local.block(q, d * dim, 1, dim), v.grad.row(q));
1317 if (j.depend_on_u())
1319 for (int q = 0; q < weights.size(); ++q)
1320 val += dj_du(q, d) * v.val(q);
1322 local_storage.vec(v.global[0].index * actual_dim + d) += val;
1329 for (
const LocalThreadVecStorage &local_storage : storage)
1330 term += local_storage.vec;
1332 else if (spatial_integral_type == SpatialIntegralType::VertexSum)
1336 params.
t = dt * cur_step + t0;
1337 params.
step = cur_step;
1338 for (
int e = 0; e < bases.size(); e++)
1340 const auto &bs = bases[e];
1341 for (
int i = 0; i < bs.bases.size(); i++)
1343 const auto &b = bs.bases[i];
1344 assert(b.global().size() == 1);
1345 const auto &g = b.global()[0];
1346 if (traversed[g.index])
1349 const Eigen::MatrixXd lame_params = extract_lame_params(varform.
primary_assembler().
parameters(), e, params.
t, Eigen::MatrixXd::Zero(1, dim) , g.node);
1351 params.
node = g.index;
1354 Eigen::MatrixXd
val;
1355 j.dj_du(lame_params, Eigen::MatrixXd::Zero(1, dim) , g.node, solution.block(g.index * dim, 0, dim, 1).transpose(), Eigen::MatrixXd::Zero(1, dim * actual_dim) , Eigen::MatrixXd::Zero(0, 0) ,
assembler::ElementAssemblyValues(), params,
val);
1356 term.block(g.index * actual_dim, 0, actual_dim, 1) +=
val.transpose();
1357 traversed[g.index] =
true;
1367 Eigen::VectorXd nodes(primitives.size());
1370 nodes.segment(map[v] * dim, dim) = primitives.segment(v * dim, dim);
1378 Eigen::VectorXd primitives(nodes.size());
1381 primitives.segment(map[v] * dim, dim) = nodes.segment(v * dim, dim);
1385 Eigen::MatrixXd AdjointTools::edge_normal_gradient(
const Eigen::MatrixXd &
V)
1388 Eigen::Matrix<Diff, 4, 1> full_diff(4, 1);
1389 for (
int i = 0; i < 2; i++)
1390 for (
int j = 0; j < 2; j++)
1391 full_diff(i * 2 + j) =
Diff(i * 2 + j,
V(i, j));
1392 auto reduced_diff = edge_normal(full_diff);
1394 Eigen::MatrixXd grad(2, 4);
1395 for (
int i = 0; i < 2; ++i)
1396 grad.row(i) = reduced_diff[i].getGradient();
1401 Eigen::MatrixXd AdjointTools::face_normal_gradient(
const Eigen::MatrixXd &
V)
1404 Eigen::Matrix<Diff, 9, 1> full_diff(9, 1);
1405 for (
int i = 0; i < 3; i++)
1406 for (
int j = 0; j < 3; j++)
1407 full_diff(i * 3 + j) =
Diff(i * 3 + j,
V(i, j));
1408 auto reduced_diff = face_normal(full_diff);
1410 Eigen::MatrixXd grad(3, 9);
1411 for (
int i = 0; i < 3; ++i)
1412 grad.row(i) = reduced_diff[i].getGradient();
1417 Eigen::MatrixXd AdjointTools::edge_velocity_divergence(
const Eigen::MatrixXd &
V)
1419 return line_length_grad(
V) / line_length<double>(
V);
1422 Eigen::MatrixXd AdjointTools::face_velocity_divergence(
const Eigen::MatrixXd &
V)
1424 return triangle_area_grad(
V) / triangle_area<double>(
V);
1427 void AdjointTools::scaled_jacobian(
const Eigen::MatrixXd &
V,
const Eigen::MatrixXi &
F, Eigen::VectorXd &quality)
1429 const int dim =
F.cols() - 1;
1431 quality.setZero(
F.rows());
1434 for (
int i = 0; i <
F.rows(); i++)
1436 Eigen::RowVector3d e0;
1438 e0.head(2) =
V.row(
F(i, 2)) -
V.row(
F(i, 1));
1439 Eigen::RowVector3d e1;
1441 e1.head(2) =
V.row(
F(i, 0)) -
V.row(
F(i, 2));
1442 Eigen::RowVector3d e2;
1444 e2.head(2) =
V.row(
F(i, 1)) -
V.row(
F(i, 0));
1446 double l0 = e0.norm();
1447 double l1 = e1.norm();
1448 double l2 = e2.norm();
1450 double A = 0.5 * (e0.cross(e1)).norm();
1451 double Lmax = std::max(l0 * l1, std::max(l1 * l2, l0 * l2));
1453 quality(i) = 2 * A * (2 / sqrt(3)) / Lmax;
1458 for (
int i = 0; i <
F.rows(); i++)
1460 Eigen::RowVector3d e0 =
V.row(
F(i, 1)) -
V.row(
F(i, 0));
1461 Eigen::RowVector3d e1 =
V.row(
F(i, 2)) -
V.row(
F(i, 1));
1462 Eigen::RowVector3d e2 =
V.row(
F(i, 0)) -
V.row(
F(i, 2));
1463 Eigen::RowVector3d e3 =
V.row(
F(i, 3)) -
V.row(
F(i, 0));
1464 Eigen::RowVector3d e4 =
V.row(
F(i, 3)) -
V.row(
F(i, 1));
1465 Eigen::RowVector3d e5 =
V.row(
F(i, 3)) -
V.row(
F(i, 2));
1467 double l0 = e0.norm();
1468 double l1 = e1.norm();
1469 double l2 = e2.norm();
1470 double l3 = e3.norm();
1471 double l4 = e4.norm();
1472 double l5 = e5.norm();
1474 double J = std::abs((e0.cross(e3)).dot(e2));
1476 double a1 = l0 * l2 * l3;
1477 double a2 = l0 * l1 * l4;
1478 double a3 = l1 * l2 * l5;
1479 double a4 = l3 * l4 * l5;
1481 double a = std::max({a1, a2, a3, a4,
J});
1482 quality(i) =
J * sqrt(2) / a;
ElementAssemblyValues vals
assembler::ElementAssemblyValues gvals
Storage for additional data required by differntial code.
const ipc::NormalCollisions & collision_set(int step) const
Eigen::MatrixXd disp_grad(int step=0) const
std::optional< varform::InitialConditionOverride > initial_condition_override
Initial-condition override storage for initial condition optimization.
Eigen::VectorXd v(int step) const
const ipc::TangentialCollisions & friction_collision_set(int step) const
const StiffnessMatrix & basis_nodes_to_gbasis_nodes() const
const ipc::SmoothCollisions & smooth_collision_set(int step) const
Eigen::VectorXd u(int step) const
const StiffnessMatrix & gradu_h(int step) const
const ipc::NormalCollisions & normal_adhesion_collision_set(int step) const
const ipc::TangentialCollisions & tangential_adhesion_collision_set(int step) const
bool depend_on_gradu_local() const
void dj_du(const Eigen::MatrixXd &elastic_params, const Eigen::MatrixXd &local_pts, const Eigen::MatrixXd &pts, const Eigen::MatrixXd &u, const Eigen::MatrixXd &grad_u, const Eigen::MatrixXd &reference_normals, const assembler::ElementAssemblyValues &vals, ParameterType ¶ms, Eigen::MatrixXd &val) const
bool depend_on_gradu() const
void dj_dgradu(const Eigen::MatrixXd &elastic_params, const Eigen::MatrixXd &local_pts, const Eigen::MatrixXd &pts, const Eigen::MatrixXd &u, const Eigen::MatrixXd &grad_u, const Eigen::MatrixXd &reference_normals, const assembler::ElementAssemblyValues &vals, ParameterType ¶ms, Eigen::MatrixXd &val) const
void evaluate(const Eigen::MatrixXd &elastic_params, const Eigen::MatrixXd &local_pts, const Eigen::MatrixXd &pts, const Eigen::MatrixXd &u, const Eigen::MatrixXd &grad_u, const Eigen::MatrixXd &reference_normals, const assembler::ElementAssemblyValues &vals, ParameterType ¶ms, Eigen::MatrixXd &val) const
void dj_dx(const Eigen::MatrixXd &elastic_params, const Eigen::MatrixXd &local_pts, const Eigen::MatrixXd &pts, const Eigen::MatrixXd &u, const Eigen::MatrixXd &grad_u, const Eigen::MatrixXd &reference_normals, const assembler::ElementAssemblyValues &vals, ParameterType ¶ms, Eigen::MatrixXd &val) const
virtual std::map< std::string, ParamFunc > parameters() const =0
void compute(const int el_index, const bool is_volume, const basis::ElementBases &basis, const basis::ElementBases &gbasis, ElementAssemblyValues &vals) const
retrieves cached basis evaluation and geometric for the given element if it doesn't exist,...
stores per local bases evaluations
std::vector< basis::Local2Global > global
stores per element basis values at given quadrature points and geometric mapping
void compute(const int el_index, const bool is_volume, const Eigen::MatrixXd &pts, const basis::ElementBases &basis, const basis::ElementBases &gbasis)
computes the per element values at the local (ref el) points (pts) sets basis_values,...
quadrature::Quadrature quadrature
virtual bool is_scalar() const =0
virtual bool is_time_dependent() const
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 int get_body_id(const int primitive) const
Get the volume selection of an element (cell in 3d, face in 2d)
virtual bool is_volume() const =0
checks if mesh is volume
int dimension() const
utily for dimension
Eigen::VectorXd apply_jacobian(const Eigen::VectorXd &grad, const Eigen::VectorXd &x) const override
Apply jacobian for chain rule.
std::shared_ptr< solver::FrictionForm > friction_form
std::shared_ptr< solver::InertiaForm > inertia_form
std::shared_ptr< solver::PeriodicContactForm > periodic_contact_form
std::shared_ptr< solver::PressureForm > pressure_form
std::shared_ptr< solver::BodyForm > body_form
std::shared_ptr< solver::NLProblem > nl_problem
std::shared_ptr< solver::NormalAdhesionForm > normal_adhesion_form
std::shared_ptr< solver::ContactForm > contact_form
std::shared_ptr< solver::ElasticForm > damping_form
std::shared_ptr< solver::ElasticForm > elastic_form
std::shared_ptr< solver::TangentialAdhesionForm > tangential_adhesion_form
Eigen::Matrix< double, dim, 1 > cross(const Eigen::Matrix< double, dim, 1 > &x, const Eigen::Matrix< double, dim, 1 > &y)
DScalar1< double, Eigen::Matrix< double, Eigen::Dynamic, 1 > > Diff
void vector2matrix(const Eigen::VectorXd &vec, Eigen::MatrixXd &mat)
auto & get_local_thread_storage(Storages &storage, int thread_id)
auto create_thread_storage(const LocalStorage &initial_local_storage)
double triangle_area(const Eigen::MatrixXd V)
Compute the signed area of a triangle defined by three points.
void maybe_parallel_for(int size, const std::function< void(int, int, int)> &partial_for)
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
Automatic differentiation scalar with first-order derivatives.
static void setVariableCount(size_t value)
Set the independent variable count used by the automatic differentiation layer.
Parameters for the functional evaluation.