PolyFEM
Loading...
Searching...
No Matches
DiffCache.cpp
Go to the documentation of this file.
2
4
6
9
12
21
23
26
27#include <ipc/ipc.hpp>
28#include <Eigen/Core>
29
30#include <memory>
31#include <vector>
32#include <map>
33#include <array>
34#include <cmath>
35
36namespace polyfem
37{
38 namespace
39 {
40 void replace_rows_by_identity(StiffnessMatrix &reduced_mat, const StiffnessMatrix &mat, const std::vector<int> &rows)
41 {
42 reduced_mat.resize(mat.rows(), mat.cols());
43
44 std::vector<bool> mask(mat.rows(), false);
45 for (int i : rows)
46 mask[i] = true;
47
48 std::vector<Eigen::Triplet<double>> coeffs;
49 for (int k = 0; k < mat.outerSize(); ++k)
50 {
51 for (StiffnessMatrix::InnerIterator it(mat, k); it; ++it)
52 {
53 if (mask[it.row()])
54 {
55 if (it.row() == it.col())
56 coeffs.emplace_back(it.row(), it.col(), 1.0);
57 }
58 else
59 coeffs.emplace_back(it.row(), it.col(), it.value());
60 }
61 }
62 reduced_mat.setFromTriplets(coeffs.begin(), coeffs.end());
63 }
64
65 void compute_force_jacobian(varform::DifferentiableVarForm &varform, const Eigen::MatrixXd &sol, const Eigen::MatrixXd &disp_grad, StiffnessMatrix &hessian)
66 {
67 const solver::SolveData *solve_data = varform.solve_data();
68 assert(solve_data && "Optimization varforms must expose solve data");
69
70 if (varform.get_problem().is_time_dependent())
71 {
72 StiffnessMatrix tmp_hess;
73 assert(solve_data->nl_problem && "Transient differentiation requires an initialized nonlinear problem");
74 solve_data->nl_problem->set_project_to_psd(false);
75 solve_data->nl_problem->FullNLProblem::solution_changed(sol);
76 solve_data->nl_problem->FullNLProblem::hessian(sol, tmp_hess);
77 hessian.setZero();
78 replace_rows_by_identity(hessian, tmp_hess, varform.boundary_state().boundary_nodes);
79 }
80 else // static formulation
81 {
82 if (varform.primary_assembler().is_linear() && !varform.is_contact_enabled() && !varform.is_homogenization())
83 {
84 hessian.setZero();
85 StiffnessMatrix stiffness;
86 varform.build_stiffness_matrix(stiffness);
87 replace_rows_by_identity(hessian, stiffness, varform.boundary_state().boundary_nodes);
88 }
89 else
90 {
91 assert(solve_data->nl_problem && "Nonlinear differentiation requires an initialized nonlinear problem");
92 solve_data->nl_problem->set_project_to_psd(false);
93 if (varform.is_homogenization())
94 {
95 Eigen::VectorXd reduced;
96 std::shared_ptr<solver::NLHomoProblem> homo_problem = std::dynamic_pointer_cast<solver::NLHomoProblem>(solve_data->nl_problem);
97 assert(homo_problem && "Homogenization requires NLHomoProblem solve data");
98 reduced = homo_problem->full_to_reduced(sol, disp_grad);
99 solve_data->nl_problem->solution_changed(reduced);
100 solve_data->nl_problem->hessian(reduced, hessian);
101 }
102 else
103 {
104 StiffnessMatrix tmp_hess;
105 solve_data->nl_problem->FullNLProblem::solution_changed(sol);
106 solve_data->nl_problem->FullNLProblem::hessian(sol, tmp_hess);
107 hessian.setZero();
108 replace_rows_by_identity(hessian, tmp_hess, varform.boundary_state().boundary_nodes);
109 }
110 }
111 }
112 }
113
114 StiffnessMatrix compute_basis_nodes_to_gbasis_nodes(const varform::DifferentiableVarForm &varform)
115 {
116 auto &gbases = varform.primary_space().geometry_basis_list();
117 auto &bases = varform.primary_space().basis_list();
118
119 std::map<std::array<int, 2>, double> pairs;
120 for (int e = 0; e < gbases.size(); e++)
121 {
122 auto &gbs = gbases[e].bases;
123 auto &bs = bases[e].bases;
124 assert(!bs.empty());
125
126 Eigen::MatrixXd local_pts;
127 int order = bs.front().order();
128 if (varform.get_mesh().is_volume())
129 {
130 if (varform.get_mesh().is_simplex(e))
131 {
132 autogen::p_nodes_3d(order, local_pts);
133 }
134 else
135 {
136 autogen::q_nodes_3d(order, local_pts);
137 }
138 }
139 else
140 {
141 if (varform.get_mesh().is_simplex(e))
142 {
143 autogen::p_nodes_2d(order, local_pts);
144 }
145 else
146 {
147 autogen::q_nodes_2d(order, local_pts);
148 }
149 }
150
151 assembler::ElementAssemblyValues vals;
152 vals.compute(e, varform.get_mesh().is_volume(), local_pts, gbases[e], gbases[e]);
153
154 for (int i = 0; i < bs.size(); i++)
155 {
156 for (int j = 0; j < gbs.size(); j++)
157 {
158 if (std::abs(vals.basis_values[j].val(i)) > 1e-7)
159 {
160 std::array<int, 2> index = {{gbs[j].global()[0].index, bs[i].global()[0].index}};
161 pairs.insert({index, vals.basis_values[j].val(i)});
162 }
163 }
164 }
165 }
166
167 int dim = varform.get_mesh().dimension();
168 std::vector<Eigen::Triplet<double>> coeffs;
169 coeffs.reserve(pairs.size() * dim);
170 for (const auto &iter : pairs)
171 {
172 for (int d = 0; d < dim; d++)
173 {
174 coeffs.emplace_back(iter.first[0] * dim + d, iter.first[1] * dim + d, iter.second);
175 }
176 }
177
178 StiffnessMatrix mapping;
179 mapping.resize(varform.primary_space().geometry->n_bases * dim, varform.primary_space().n_bases * dim);
180 mapping.setFromTriplets(coeffs.begin(), coeffs.end());
181 return mapping;
182 }
183 } // namespace
184
185 void DiffCache::init(const int dimension, const int ndof, const int n_time_steps)
186 {
187 cur_size_ = 0;
188 n_time_steps_ = n_time_steps;
189
190 u_.setZero(ndof, n_time_steps + 1);
191 disp_grad_.assign(n_time_steps + 1, Eigen::MatrixXd::Zero(dimension, dimension));
192 if (n_time_steps_ > 0)
193 {
194 bdf_order_.setZero(n_time_steps + 1);
195 v_.setZero(ndof, n_time_steps + 1);
196 acc_.setZero(ndof, n_time_steps + 1);
197 // gradu_h_prev_.resize(n_time_steps + 1);
198 }
199 gradu_h_.resize(n_time_steps + 1);
200 collision_set_.resize(n_time_steps + 1);
201 smooth_collision_set_.resize(n_time_steps + 1);
202 friction_collision_set_.resize(n_time_steps + 1);
203 normal_adhesion_collision_set_.resize(n_time_steps + 1);
204 tangential_adhesion_collision_set_.resize(n_time_steps + 1);
205 }
206
208 const Eigen::MatrixXd &u,
209 const StiffnessMatrix &gradu_h,
210 const ipc::NormalCollisions &collision_set,
211 const ipc::SmoothCollisions &smooth_collision_set,
212 const ipc::TangentialCollisions &friction_constraint_set,
213 const ipc::NormalCollisions &normal_adhesion_set,
214 const ipc::TangentialCollisions &tangential_adhesion_set,
215 const Eigen::MatrixXd &disp_grad)
216 {
217 u_ = u;
218
219 gradu_h_[0] = gradu_h;
222 friction_collision_set_[0] = friction_constraint_set;
223 normal_adhesion_collision_set_[0] = normal_adhesion_set;
224 tangential_adhesion_collision_set_[0] = tangential_adhesion_set;
226
227 cur_size_ = 1;
228 }
229
231 const int cur_step,
232 const int cur_bdf_order,
233 const Eigen::MatrixXd &u,
234 const Eigen::MatrixXd &v,
235 const Eigen::MatrixXd &acc,
236 const StiffnessMatrix &gradu_h,
237 // const StiffnessMatrix &gradu_h_prev,
238 const ipc::NormalCollisions &collision_set,
239 const ipc::SmoothCollisions &smooth_collision_set,
240 const ipc::TangentialCollisions &friction_collision_set)
241 {
242 bdf_order_(cur_step) = cur_bdf_order;
243
244 u_.col(cur_step) = u;
245 v_.col(cur_step) = v;
246 acc_.col(cur_step) = acc;
247
248 gradu_h_[cur_step] = gradu_h;
249 // gradu_h_prev_[cur_step] = gradu_h_prev;
250
251 collision_set_[cur_step] = collision_set;
254
255 cur_size_++;
256 }
257
259 const int cur_step,
260 const Eigen::MatrixXd &u,
261 const StiffnessMatrix &gradu_h,
262 const ipc::NormalCollisions &collision_set,
263 const ipc::SmoothCollisions &smooth_collision_set,
264 const ipc::NormalCollisions &normal_adhesion_set,
265 const Eigen::MatrixXd &disp_grad)
266 {
267 u_.col(cur_step) = u;
268 gradu_h_[cur_step] = gradu_h;
269 collision_set_[cur_step] = collision_set;
271 normal_adhesion_collision_set_[cur_step] = normal_adhesion_set;
272 disp_grad_[cur_step] = disp_grad;
273
274 cur_size_++;
275 }
276
277 void DiffCache::cache_adjoints(const Eigen::MatrixXd &adjoint_mat) { adjoint_mat_ = adjoint_mat; }
278
280 {
281 assert(basis_nodes_to_gbasis_nodes_.size() != 0
282 && "basis_nodes_to_gbasis_nodes is empty. Expect cache_transient(step==0) to build it first.");
283
285 }
286
288 int step,
290 const Eigen::MatrixXd &sol,
291 const Eigen::MatrixXd *pressure)
292 {
293 if (pressure)
294 {
295 log_and_throw_adjoint_error("Navier stoke problem is not supported in adjoint optimization.");
296 }
297
298 if (step == 0)
299 {
300 basis_nodes_to_gbasis_nodes_ = compute_basis_nodes_to_gbasis_nodes(varform);
301 }
302
303 const Eigen::MatrixXd disp_grad = varform.displacement_gradient();
304
305 StiffnessMatrix gradu_h(sol.size(), sol.size());
306 if (step == 0)
307 {
308 init(varform.get_mesh().dimension(), varform.primary_space().ndof(), varform.get_problem().is_time_dependent() ? varform.get_args()["time"]["time_steps"].get<int>() : 0);
309 }
310
311 ipc::NormalCollisions cur_collision_set;
312 ipc::SmoothCollisions cur_smooth_collision_set;
313 ipc::TangentialCollisions cur_friction_set;
314 ipc::NormalCollisions cur_normal_adhesion_set;
315 ipc::TangentialCollisions cur_tangential_adhesion_set;
316
317 if (!varform.get_problem().is_time_dependent() || step > 0)
318 compute_force_jacobian(varform, sol, disp_grad, gradu_h);
319
320 const auto *solve_data = varform.solve_data();
321 assert(solve_data && "Optimization varforms must expose solve data");
322 if (solve_data->contact_form)
323 {
324 if (const auto barrier_contact = dynamic_cast<const solver::BarrierContactForm *>(solve_data->contact_form.get()))
325 cur_collision_set = barrier_contact->collision_set();
326 else if (const auto smooth_contact = dynamic_cast<const solver::SmoothContactForm *>(solve_data->contact_form.get()))
327 cur_smooth_collision_set = smooth_contact->collision_set();
328 }
329 if (solve_data->friction_form)
330 cur_friction_set = solve_data->friction_form->friction_collision_set();
331 if (solve_data->normal_adhesion_form)
332 cur_normal_adhesion_set = solve_data->normal_adhesion_form->collision_set();
333 if (solve_data->tangential_adhesion_form)
334 cur_tangential_adhesion_set = solve_data->tangential_adhesion_form->tangential_collision_set();
335
336 if (varform.get_problem().is_time_dependent())
337 {
338 if (varform.get_args()["time"]["quasistatic"].get<bool>())
339 {
340 cache_quantities_quasistatic(step, sol, gradu_h, cur_collision_set, cur_smooth_collision_set, cur_normal_adhesion_set, disp_grad);
341 }
342 else
343 {
344 Eigen::MatrixXd vel, acc;
345 if (step == 0)
346 {
347 if (dynamic_cast<time_integrator::BDF *>(solve_data->time_integrator.get()))
348 {
349 const auto bdf_integrator = dynamic_cast<time_integrator::BDF *>(solve_data->time_integrator.get());
350 vel = bdf_integrator->weighted_sum_v_prevs();
351 }
352 else if (dynamic_cast<time_integrator::ImplicitEuler *>(solve_data->time_integrator.get()))
353 {
354 const auto euler_integrator = dynamic_cast<time_integrator::ImplicitEuler *>(solve_data->time_integrator.get());
355 vel = euler_integrator->v_prev();
356 }
357 else
358 log_and_throw_error("Differentiable code doesn't support this time integrator!");
359
360 acc.setZero(varform.primary_space().ndof(), 1);
361 }
362 else
363 {
364 vel = solve_data->time_integrator->compute_velocity(sol);
365 acc = solve_data->time_integrator->compute_acceleration(vel);
366 }
367
368 cache_quantities_transient(step, solve_data->time_integrator->steps(), sol, vel, acc, gradu_h, cur_collision_set, cur_smooth_collision_set, cur_friction_set);
369 }
370 }
371 else
372 {
373 cache_quantities_static(sol, gradu_h, cur_collision_set, cur_smooth_collision_set, cur_friction_set, cur_normal_adhesion_set, cur_tangential_adhesion_set, disp_grad);
374 }
375 }
376
377} // namespace polyfem
ElementAssemblyValues vals
Definition Assembler.cpp:26
Eigen::MatrixXd v_
std::vector< StiffnessMatrix > gradu_h_
std::vector< ipc::NormalCollisions > normal_adhesion_collision_set_
Eigen::MatrixXd acc_
std::vector< ipc::TangentialCollisions > friction_collision_set_
const ipc::NormalCollisions & collision_set(int step) const
Definition DiffCache.hpp:94
Eigen::MatrixXd disp_grad(int step=0) const
Definition DiffCache.hpp:55
Eigen::MatrixXd adjoint_mat_
Eigen::VectorXd v(int step) const
Definition DiffCache.hpp:70
StiffnessMatrix basis_nodes_to_gbasis_nodes_
std::vector< Eigen::MatrixXd > disp_grad_
const ipc::TangentialCollisions & friction_collision_set(int step) const
const Eigen::MatrixXd & adjoint_mat() const
Definition DiffCache.hpp:42
void cache_quantities_static(const Eigen::MatrixXd &u, const StiffnessMatrix &gradu_h, const ipc::NormalCollisions &collision_set, const ipc::SmoothCollisions &smooth_collision_set, const ipc::TangentialCollisions &friction_constraint_set, const ipc::NormalCollisions &normal_adhesion_set, const ipc::TangentialCollisions &tangential_adhesion_set, const Eigen::MatrixXd &disp_grad)
Eigen::VectorXd acc(int step) const
Definition DiffCache.hpp:77
void cache_transient(int step, varform::DifferentiableVarForm &varform, const Eigen::MatrixXd &sol, const Eigen::MatrixXd *pressure)
Cache time-dependent adjoint optimization data.
std::vector< ipc::SmoothCollisions > smooth_collision_set_
std::vector< ipc::TangentialCollisions > tangential_adhesion_collision_set_
const StiffnessMatrix & basis_nodes_to_gbasis_nodes() const
Eigen::VectorXi bdf_order_
void cache_quantities_quasistatic(const int cur_step, const Eigen::MatrixXd &u, const StiffnessMatrix &gradu_h, const ipc::NormalCollisions &collision_set, const ipc::SmoothCollisions &smooth_collision_set, const ipc::NormalCollisions &normal_adhesion_set, const Eigen::MatrixXd &disp_grad)
std::vector< ipc::NormalCollisions > collision_set_
const ipc::SmoothCollisions & smooth_collision_set(int step) const
Eigen::VectorXd u(int step) const
Definition DiffCache.hpp:63
void cache_adjoints(const Eigen::MatrixXd &adjoint_mat)
const StiffnessMatrix & gradu_h(int step) const
Definition DiffCache.hpp:85
void init(const int dimension, const int ndof, const int n_time_steps=0)
Eigen::MatrixXd u_
void cache_quantities_transient(const int cur_step, const int cur_bdf_order, const Eigen::MatrixXd &u, const Eigen::MatrixXd &v, const Eigen::MatrixXd &acc, const StiffnessMatrix &gradu_h, const ipc::NormalCollisions &collision_set, const ipc::SmoothCollisions &smooth_collision_set, const ipc::TangentialCollisions &friction_collision_set)
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,...
virtual bool is_time_dependent() const
Definition Problem.hpp:62
int dimension() const
utily for dimension
Definition Mesh.hpp:164
Backward Differential Formulas.
Definition BDF.hpp:14
Eigen::VectorXd weighted_sum_v_prevs() const
Compute the weighted sum of the previous velocities.
Definition BDF.cpp:63
Implicit Euler time integrator of a second order ODE (equivently a system of coupled first order ODEs...
const Eigen::VectorXd & v_prev() const
Get the most recent previous velocity value.
Optimization-facing interface implemented by differentiated VarForm adapters.
virtual Eigen::MatrixXd displacement_gradient() const
virtual const mesh::Mesh & get_mesh() const =0
virtual solver::SolveData * solve_data()=0
virtual assembler::Problem & get_problem()=0
virtual const FESpace & primary_space() const =0
void q_nodes_2d(const int q, Eigen::MatrixXd &val)
void p_nodes_2d(const int p, Eigen::MatrixXd &val)
void p_nodes_3d(const int p, Eigen::MatrixXd &val)
void q_nodes_3d(const int q, Eigen::MatrixXd &val)
void log_and_throw_adjoint_error(const std::string &msg)
Definition Logger.cpp:79
void log_and_throw_error(const std::string &msg)
Definition Logger.cpp:73
Eigen::SparseMatrix< double, Eigen::ColMajor > StiffnessMatrix
Definition Types.hpp:24