12#include <polysolve/linear/FEMSolver.hpp>
28#include <ipc/potentials/friction_potential.hpp>
45 reduced_mat.resize(mat.rows(), mat.cols());
47 std::vector<bool> mask(mat.rows(),
false);
51 std::vector<Eigen::Triplet<double>> coeffs;
52 for (
int k = 0; k < mat.outerSize(); ++k)
54 for (StiffnessMatrix::InnerIterator it(mat, k); it; ++it)
58 if (it.row() == it.col())
59 coeffs.emplace_back(it.row(), it.col(), 1.0);
62 coeffs.emplace_back(it.row(), it.col(), it.value());
65 reduced_mat.setFromTriplets(coeffs.begin(), coeffs.end());
70 assert(force_step > 0);
71 assert(force_step > sol_step);
79 const Eigen::MatrixXd u = diff_cache.
u(force_step);
80 const Eigen::MatrixXd u_prev = diff_cache.
u(sol_step);
89 if (sol_step == force_step - 1)
95 const Eigen::MatrixXd surface_velocities = (surface_solution - surface_solution_prev) / dt;
96 const double dv_dut = -1 / dt;
100 ipc::BarrierPotential bp = barrier_contact->barrier_potential();
101 bp.set_stiffness(barrier_contact->barrier_stiffness());
107 surface_solution_prev,
110 ipc::FrictionPotential::DiffWRT::LAGGED_DISPLACEMENTS)
115 surface_solution_prev,
118 ipc::FrictionPotential::DiffWRT::VELOCITIES)
155 hessian_prev = varform.
collision_mesh().to_full_dof(hessian_prev);
171 if (sol_step == force_step - 1)
179 const Eigen::MatrixXd surface_velocities = (surface_solution - surface_solution_prev) / dt;
180 const double dv_dut = -1 / dt;
182 adhesion_hessian_prev =
187 surface_solution_prev,
190 ipc::TangentialPotential::DiffWRT::LAGGED_DISPLACEMENTS)
195 surface_solution_prev,
198 ipc::TangentialPotential::DiffWRT::VELOCITIES)
201 adhesion_hessian_prev *= -1;
203 adhesion_hessian_prev = varform.
collision_mesh().to_full_dof(adhesion_hessian_prev);
205 hessian_prev += adhesion_hessian_prev;
213 varform.
damping_prev_assembler()->
assemble_hessian(varform.
get_mesh().
is_volume(), varform.
primary_space().
n_bases,
false, varform.
primary_space().
basis_list(), varform.
primary_space().
geometry_basis_list(), varform.
assembly_cache(), force_step * varform.
get_args()[
"time"][
"dt"].get<
double>() + varform.
get_args()[
"time"][
"t0"].get<
double>(), dt, u, u_prev, mat_cache, damping_hessian_prev);
215 hessian_prev += damping_hessian_prev;
218 if (sol_step == force_step - 1)
221 varform.
solve_data()->
body_form->hessian_wrt_u_prev(u_prev, force_step * dt, body_force_hessian);
222 hessian_prev += body_force_hessian;
231 Eigen::MatrixXd
b = adjoint_rhs;
233 Eigen::MatrixXd adjoint;
235 auto solver = polysolve::linear::Solver::create(varform.
get_args()[
"solver"][
"adjoint_linear"],
adjoint_logger());
246 for (
int i = 0; i <
b.cols(); i++)
248 Eigen::VectorXd
tmp =
b.col(i);
252 x.setZero(
tmp.size());
261 solver->analyze_pattern(A, A.rows());
262 solver->factorize(A);
264 adjoint.setZero(adjoint_rhs.rows(), adjoint_rhs.cols());
265 for (
int i = 0; i <
b.cols(); i++)
267 Eigen::MatrixXd
tmp =
b.col(i);
270 x.setZero(
tmp.size());
271 solver->solve(tmp,
x);
272 x.conservativeResize(adjoint.rows());
285 const double dt = varform.
get_args()[
"time"][
"dt"];
286 const int time_steps = varform.
get_args()[
"time"][
"time_steps"];
289 if (varform.
get_args()[
"time"][
"integrator"].is_string())
291 else if (varform.
get_args()[
"time"][
"integrator"][
"type"] ==
"ImplicitEuler")
293 else if (varform.
get_args()[
"time"][
"integrator"][
"type"] ==
"BDF")
294 bdf_order = varform.
get_args()[
"time"][
"integrator"][
"steps"].get<
int>();
298 assert(adjoint_rhs.cols() == time_steps + 1);
300 const int cols_per_adjoint = time_steps + 1;
301 Eigen::MatrixXd adjoints;
308 Eigen::MatrixXd sum_alpha_p, sum_alpha_nu;
309 for (
int i = time_steps; i >= 0; --i)
315 const int num = std::min(bdf_order, time_steps - i);
317 Eigen::VectorXd bdf_coeffs = Eigen::VectorXd::Zero(num);
318 for (
int j = 0; j < bdf_order && i + j < time_steps; ++j)
321 sum_alpha_p = adjoints.middleCols(i + 1, num) * bdf_coeffs;
322 sum_alpha_nu = adjoints.middleCols(cols_per_adjoint + i + 1, num) * bdf_coeffs;
325 Eigen::VectorXd rhs_ = -reduced_mass.transpose() * sum_alpha_nu - adjoint_rhs.col(i);
326 for (
int j = 1; j <= bdf_order; j++)
328 if (i + j > time_steps)
332 compute_force_jacobian_prev(varform, diff_cache, i + j, i, gradu_h_prev);
335 rhs_ += -gradu_h_prev.transpose() *
tmp;
342 rhs_ += (1. / beta_dt) * (diff_cache.
gradu_h(i) - reduced_mass).transpose() * sum_alpha_p;
346 Eigen::VectorXd b_ = rhs_;
349 auto solver = polysolve::linear::Solver::create(varform.
get_args()[
"solver"][
"adjoint_linear"],
adjoint_logger());
353 adjoints.col(i + cols_per_adjoint) =
x;
358 if (i + 1 < cols_per_adjoint)
360 if (i + 2 < cols_per_adjoint)
365 adjoints.col(i) = beta_dt * adjoints.col(i + cols_per_adjoint) - sum_alpha_p;
369 adjoints.col(i) = -reduced_mass.transpose() * sum_alpha_p;
370 adjoints.col(i + cols_per_adjoint) = rhs_;
379 return solve_transient_adjoint(varform, diff_cache, rhs);
381 return solve_static_adjoint(varform, diff_cache, rhs);
387 diff_cache.
cache_adjoints(solve_adjoint(varform, diff_cache, rhs));
422 const int e = lb.element_id();
423 for (
int i = 0; i < lb.size(); ++i)
425 const int primitive_global_id = lb.global_primitive_id(i);
427 const auto nodes = gbases[e].local_nodes_for_primitive(primitive_global_id, varform.
get_mesh());
429 if (boundary_id == surface_selection)
431 for (
long n = 0; n < nodes.size(); ++n)
433 const int g_id = gbases[e].bases[nodes(n)].global()[0].index;
435 if (std::count(node_ids.begin(), node_ids.end(), g_id) == 0)
436 node_ids.push_back(g_id);
451 const int e = lb.element_id();
452 for (
int i = 0; i < lb.size(); ++i)
454 const int primitive_global_id = lb.global_primitive_id(i);
455 const auto nodes = gbases[e].local_nodes_for_primitive(primitive_global_id, varform.
get_mesh());
457 for (
long n = 0; n < nodes.size(); ++n)
459 const int g_id = gbases[e].bases[nodes(n)].global()[0].index;
461 if (std::count(node_ids.begin(), node_ids.end(), g_id) == 0)
462 node_ids.push_back(g_id);
474 for (
int e = 0; e < gbases.size(); e++)
477 if (body_id == volume_selection)
478 for (
const auto &gbs : gbases[e].bases)
479 for (
const auto &g : gbs.global())
480 node_ids.push_back(g.index);
Storage for additional data required by differntial code.
int bdf_order(int step) const
const ipc::TangentialCollisions & friction_collision_set(int step) const
const Eigen::MatrixXd & adjoint_mat() const
Eigen::VectorXd u(int step) const
void cache_adjoints(const Eigen::MatrixXd &adjoint_mat)
const StiffnessMatrix & gradu_h(int step) const
const ipc::TangentialCollisions & tangential_adhesion_collision_set(int step) const
virtual bool is_linear() const =0
virtual bool is_time_dependent() const
Eigen::MatrixXd assemble_hessian(const NonLinearAssemblerData &data) const override
virtual int get_body_id(const int primitive) const
Get the volume selection of an element (cell in 3d, face in 2d)
virtual int get_boundary_id(const int primitive) const
Get the boundary selection of an element (face in 3d, edge in 2d)
virtual bool is_volume() const =0
checks if mesh is volume
int dimension() const
utily for dimension
std::shared_ptr< solver::FrictionForm > friction_form
std::shared_ptr< solver::BodyForm > body_form
std::shared_ptr< solver::NormalAdhesionForm > normal_adhesion_form
std::shared_ptr< solver::ContactForm > contact_form
std::shared_ptr< time_integrator::ImplicitTimeIntegrator > time_integrator
std::shared_ptr< solver::TangentialAdhesionForm > tangential_adhesion_form
static double betas(const int i)
Retrieve the value of beta used for BDF with i steps.
static const std::vector< double > & alphas(const int i)
Retrieve the alphas used for BDF with i steps.
Eigen::MatrixXd unflatten(const Eigen::VectorXd &x, int dim)
Unflatten rowwises, so every dim elements in x become a row.
void compute_surface_node_ids(const varform::DifferentiableVarForm &varform, const int surface_selection, std::vector< int > &node_ids)
spdlog::logger & adjoint_logger()
Retrieves the current logger for adjoint.
void compute_total_surface_node_ids(const varform::DifferentiableVarForm &varform, std::vector< int > &node_ids)
void compute_volume_node_ids(const varform::DifferentiableVarForm &varform, const int volume_selection, std::vector< int > &node_ids)
void log_and_throw_adjoint_error(const std::string &msg)
Eigen::MatrixXd get_adjoint_mat(const varform::DifferentiableVarForm &varform, const DiffCache &diff_cache, int type)
Get adjoint parameter nu or p.
void solve_adjoint_cached(const varform::DifferentiableVarForm &varform, DiffCache &diff_cache, const Eigen::MatrixXd &rhs)
Eigen::SparseMatrix< double, Eigen::ColMajor > StiffnessMatrix