PolyFEM
Loading...
Searching...
No Matches
DiffCache.cpp
Go to the documentation of this file.
2
4
5#include <polyfem/State.hpp>
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(State &state, const Eigen::MatrixXd &sol, const Eigen::MatrixXd &disp_grad, StiffnessMatrix &hessian)
66 {
67 auto &s = state;
68
69 if (s.problem->is_time_dependent())
70 {
71 StiffnessMatrix tmp_hess;
72 s.solve_data.nl_problem->set_project_to_psd(false);
73 s.solve_data.nl_problem->FullNLProblem::solution_changed(sol);
74 s.solve_data.nl_problem->FullNLProblem::hessian(sol, tmp_hess);
75 hessian.setZero();
76 replace_rows_by_identity(hessian, tmp_hess, s.boundary_nodes);
77 }
78 else // static formulation
79 {
80 if (s.assembler->is_linear() && !s.is_contact_enabled() && !s.is_homogenization())
81 {
82 hessian.setZero();
83 StiffnessMatrix stiffness;
84 s.build_stiffness_mat(stiffness);
85 replace_rows_by_identity(hessian, stiffness, s.boundary_nodes);
86 }
87 else
88 {
89 s.solve_data.nl_problem->set_project_to_psd(false);
90 if (s.is_homogenization())
91 {
92 Eigen::VectorXd reduced;
93 std::shared_ptr<solver::NLHomoProblem> homo_problem = std::dynamic_pointer_cast<solver::NLHomoProblem>(s.solve_data.nl_problem);
94 reduced = homo_problem->full_to_reduced(sol, disp_grad);
95 s.solve_data.nl_problem->solution_changed(reduced);
96 s.solve_data.nl_problem->hessian(reduced, hessian);
97 }
98 else
99 {
100 StiffnessMatrix tmp_hess;
101 s.solve_data.nl_problem->FullNLProblem::solution_changed(sol);
102 s.solve_data.nl_problem->FullNLProblem::hessian(sol, tmp_hess);
103 hessian.setZero();
104 replace_rows_by_identity(hessian, tmp_hess, s.boundary_nodes);
105 }
106 }
107 }
108 }
109
110 StiffnessMatrix compute_basis_nodes_to_gbasis_nodes(const State &state)
111 {
112 auto &gbases = state.geom_bases();
113 auto &bases = state.bases;
114
115 std::map<std::array<int, 2>, double> pairs;
116 for (int e = 0; e < gbases.size(); e++)
117 {
118 auto &gbs = gbases[e].bases;
119 auto &bs = bases[e].bases;
120 assert(!bs.empty());
121
122 Eigen::MatrixXd local_pts;
123 int order = bs.front().order();
124 if (state.mesh->is_volume())
125 {
126 if (state.mesh->is_simplex(e))
127 {
128 autogen::p_nodes_3d(order, local_pts);
129 }
130 else
131 {
132 autogen::q_nodes_3d(order, local_pts);
133 }
134 }
135 else
136 {
137 if (state.mesh->is_simplex(e))
138 {
139 autogen::p_nodes_2d(order, local_pts);
140 }
141 else
142 {
143 autogen::q_nodes_2d(order, local_pts);
144 }
145 }
146
147 assembler::ElementAssemblyValues vals;
148 vals.compute(e, state.mesh->is_volume(), local_pts, gbases[e], gbases[e]);
149
150 for (int i = 0; i < bs.size(); i++)
151 {
152 for (int j = 0; j < gbs.size(); j++)
153 {
154 if (std::abs(vals.basis_values[j].val(i)) > 1e-7)
155 {
156 std::array<int, 2> index = {{gbs[j].global()[0].index, bs[i].global()[0].index}};
157 pairs.insert({index, vals.basis_values[j].val(i)});
158 }
159 }
160 }
161 }
162
163 int dim = state.mesh->dimension();
164 std::vector<Eigen::Triplet<double>> coeffs;
165 coeffs.reserve(pairs.size() * dim);
166 for (const auto &iter : pairs)
167 {
168 for (int d = 0; d < dim; d++)
169 {
170 coeffs.emplace_back(iter.first[0] * dim + d, iter.first[1] * dim + d, iter.second);
171 }
172 }
173
174 StiffnessMatrix mapping;
175 mapping.resize(state.n_geom_bases * dim, state.n_bases * dim);
176 mapping.setFromTriplets(coeffs.begin(), coeffs.end());
177 return mapping;
178 }
179 } // namespace
180
181 void DiffCache::init(const int dimension, const int ndof, const int n_time_steps)
182 {
183 cur_size_ = 0;
184 n_time_steps_ = n_time_steps;
185
186 u_.setZero(ndof, n_time_steps + 1);
187 disp_grad_.assign(n_time_steps + 1, Eigen::MatrixXd::Zero(dimension, dimension));
188 if (n_time_steps_ > 0)
189 {
190 bdf_order_.setZero(n_time_steps + 1);
191 v_.setZero(ndof, n_time_steps + 1);
192 acc_.setZero(ndof, n_time_steps + 1);
193 // gradu_h_prev_.resize(n_time_steps + 1);
194 }
195 gradu_h_.resize(n_time_steps + 1);
196 collision_set_.resize(n_time_steps + 1);
197 smooth_collision_set_.resize(n_time_steps + 1);
198 friction_collision_set_.resize(n_time_steps + 1);
199 normal_adhesion_collision_set_.resize(n_time_steps + 1);
200 tangential_adhesion_collision_set_.resize(n_time_steps + 1);
201 }
202
204 const Eigen::MatrixXd &u,
205 const StiffnessMatrix &gradu_h,
206 const ipc::NormalCollisions &collision_set,
207 const ipc::SmoothCollisions &smooth_collision_set,
208 const ipc::TangentialCollisions &friction_constraint_set,
209 const ipc::NormalCollisions &normal_adhesion_set,
210 const ipc::TangentialCollisions &tangential_adhesion_set,
211 const Eigen::MatrixXd &disp_grad)
212 {
213 u_ = u;
214
215 gradu_h_[0] = gradu_h;
218 friction_collision_set_[0] = friction_constraint_set;
219 normal_adhesion_collision_set_[0] = normal_adhesion_set;
220 tangential_adhesion_collision_set_[0] = tangential_adhesion_set;
222
223 cur_size_ = 1;
224 }
225
227 const int cur_step,
228 const int cur_bdf_order,
229 const Eigen::MatrixXd &u,
230 const Eigen::MatrixXd &v,
231 const Eigen::MatrixXd &acc,
232 const StiffnessMatrix &gradu_h,
233 // const StiffnessMatrix &gradu_h_prev,
234 const ipc::NormalCollisions &collision_set,
235 const ipc::SmoothCollisions &smooth_collision_set,
236 const ipc::TangentialCollisions &friction_collision_set)
237 {
238 bdf_order_(cur_step) = cur_bdf_order;
239
240 u_.col(cur_step) = u;
241 v_.col(cur_step) = v;
242 acc_.col(cur_step) = acc;
243
244 gradu_h_[cur_step] = gradu_h;
245 // gradu_h_prev_[cur_step] = gradu_h_prev;
246
247 collision_set_[cur_step] = collision_set;
250
251 cur_size_++;
252 }
253
255 const int cur_step,
256 const Eigen::MatrixXd &u,
257 const StiffnessMatrix &gradu_h,
258 const ipc::NormalCollisions &collision_set,
259 const ipc::SmoothCollisions &smooth_collision_set,
260 const ipc::NormalCollisions &normal_adhesion_set,
261 const Eigen::MatrixXd &disp_grad)
262 {
263 u_.col(cur_step) = u;
264 gradu_h_[cur_step] = gradu_h;
265 collision_set_[cur_step] = collision_set;
267 normal_adhesion_collision_set_[cur_step] = normal_adhesion_set;
268 disp_grad_[cur_step] = disp_grad;
269
270 cur_size_++;
271 }
272
273 void DiffCache::cache_adjoints(const Eigen::MatrixXd &adjoint_mat) { adjoint_mat_ = adjoint_mat; }
274
276 {
277 assert(basis_nodes_to_gbasis_nodes_.size() != 0
278 && "basis_nodes_to_gbasis_nodes is empty. Expect cache_transient(step==0) to build it first.");
279
281 }
282
284 int step,
285 State &state,
286 const Eigen::MatrixXd &sol,
287 const Eigen::MatrixXd *disp_grad,
288 const Eigen::MatrixXd *pressure)
289 {
290 auto &s = state;
291 if (pressure)
292 {
293 log_and_throw_adjoint_error("Navier stoke problem is not supported in adjoint optimization.");
294 }
295
296 if (step == 0)
297 {
298 basis_nodes_to_gbasis_nodes_ = compute_basis_nodes_to_gbasis_nodes(s);
299 }
300
301 Eigen::MatrixXd disp_grad_final;
302 if (disp_grad)
303 {
304 disp_grad_final = *disp_grad;
305 }
306 else
307 {
308 int mesh_dim = s.mesh->dimension();
309 disp_grad_final = Eigen::MatrixXd::Zero(mesh_dim, mesh_dim);
310 }
311
312 StiffnessMatrix gradu_h(sol.size(), sol.size());
313 if (step == 0)
314 {
315 init(s.mesh->dimension(), s.ndof(), s.problem->is_time_dependent() ? s.args["time"]["time_steps"].get<int>() : 0);
316 }
317
318 ipc::NormalCollisions cur_collision_set;
319 ipc::SmoothCollisions cur_smooth_collision_set;
320 ipc::TangentialCollisions cur_friction_set;
321 ipc::NormalCollisions cur_normal_adhesion_set;
322 ipc::TangentialCollisions cur_tangential_adhesion_set;
323
324 if (!s.problem->is_time_dependent() || step > 0)
325 compute_force_jacobian(s, sol, disp_grad_final, gradu_h);
326
327 if (s.solve_data.contact_form)
328 {
329 if (const auto barrier_contact = dynamic_cast<const solver::BarrierContactForm *>(s.solve_data.contact_form.get()))
330 cur_collision_set = barrier_contact->collision_set();
331 else if (const auto smooth_contact = dynamic_cast<const solver::SmoothContactForm *>(s.solve_data.contact_form.get()))
332 cur_smooth_collision_set = smooth_contact->collision_set();
333 }
334 cur_friction_set = s.solve_data.friction_form ? s.solve_data.friction_form->friction_collision_set() : ipc::TangentialCollisions();
335 cur_normal_adhesion_set = s.solve_data.normal_adhesion_form ? s.solve_data.normal_adhesion_form->collision_set() : ipc::NormalCollisions();
336 cur_tangential_adhesion_set = s.solve_data.tangential_adhesion_form ? s.solve_data.tangential_adhesion_form->tangential_collision_set() : ipc::TangentialCollisions();
337
338 if (s.problem->is_time_dependent())
339 {
340 if (s.args["time"]["quasistatic"].get<bool>())
341 {
342 cache_quantities_quasistatic(step, sol, gradu_h, cur_collision_set, cur_smooth_collision_set, cur_normal_adhesion_set, disp_grad_final);
343 }
344 else
345 {
346 Eigen::MatrixXd vel, acc;
347 if (step == 0)
348 {
349 if (dynamic_cast<time_integrator::BDF *>(s.solve_data.time_integrator.get()))
350 {
351 const auto bdf_integrator = dynamic_cast<time_integrator::BDF *>(s.solve_data.time_integrator.get());
352 vel = bdf_integrator->weighted_sum_v_prevs();
353 }
354 else if (dynamic_cast<time_integrator::ImplicitEuler *>(s.solve_data.time_integrator.get()))
355 {
356 const auto euler_integrator = dynamic_cast<time_integrator::ImplicitEuler *>(s.solve_data.time_integrator.get());
357 vel = euler_integrator->v_prev();
358 }
359 else
360 log_and_throw_error("Differentiable code doesn't support this time integrator!");
361
362 acc.setZero(s.ndof(), 1);
363 }
364 else
365 {
366 vel = s.solve_data.time_integrator->compute_velocity(sol);
367 acc = s.solve_data.time_integrator->compute_acceleration(vel);
368 }
369
370 cache_quantities_transient(step, s.solve_data.time_integrator->steps(), sol, vel, acc, gradu_h, cur_collision_set, cur_smooth_collision_set, cur_friction_set);
371 }
372 }
373 else
374 {
375 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_final);
376 }
377 }
378
379} // namespace polyfem
ElementAssemblyValues vals
Definition Assembler.cpp:22
void cache_transient(int step, State &state, const Eigen::MatrixXd &sol, const Eigen::MatrixXd *disp_grad, const Eigen::MatrixXd *pressure)
Cache time-dependent adjoint optimization data.
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:95
Eigen::MatrixXd disp_grad(int step=0) const
Definition DiffCache.hpp:56
Eigen::MatrixXd adjoint_mat_
Eigen::VectorXd v(int step) const
Definition DiffCache.hpp:71
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:43
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:78
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:64
void cache_adjoints(const Eigen::MatrixXd &adjoint_mat)
const StiffnessMatrix & gradu_h(int step) const
Definition DiffCache.hpp:86
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)
main class that contains the polyfem solver and all its state
Definition State.hpp:113
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,...
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:62
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.
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