PolyFEM
Loading...
Searching...
No Matches
ViscousDamping.cpp
Go to the documentation of this file.
1#include "ViscousDamping.hpp"
2
3namespace polyfem::assembler
4{
5 void ViscousDamping::compute_stress_aux(const Eigen::MatrixXd &F, const Eigen::MatrixXd &dFdt, Eigen::MatrixXd &dRdF, Eigen::MatrixXd &dRdFdot) const
6 {
7 const int size = F.rows();
8
9 Eigen::MatrixXd dEdt = 0.5 * (dFdt.transpose() * F + F.transpose() * dFdt);
10
11 Eigen::MatrixXd tmp = 2 * damping_params_[0] * dEdt + damping_params_[1] * dEdt.trace() * Eigen::MatrixXd::Identity(size, size);
12 dRdF = dFdt * tmp;
13 dRdFdot = F * tmp; // Fdot is dFdt
14 }
15
16 void ViscousDamping::compute_stress_grad_aux(const Eigen::MatrixXd &F, const Eigen::MatrixXd &dFdt, Eigen::MatrixXd &d2RdF2, Eigen::MatrixXd &d2RdFdFdot, Eigen::MatrixXd &d2RdFdot2) const
17 {
18 const int size = F.rows();
19
20 Eigen::MatrixXd dEdt = 0.5 * (dFdt.transpose() * F + F.transpose() * dFdt);
21
22 Eigen::MatrixXd dEdotdF, dEdotdFdot;
23 dEdotdF.setZero(size * size, size * size);
24 dEdotdFdot.setZero(size * size, size * size);
25 for (size_t i = 0; i < size; ++i)
26 {
27 for (size_t j = 0; j < size; ++j)
28 {
29 for (size_t p = 0; p < size; ++p)
30 {
31 dEdotdF(i * size + j, p * size + j) += dFdt(p, i) / 2.;
32 dEdotdFdot(i * size + j, p * size + j) += F(p, i) / 2.;
33 dEdotdF(i * size + j, p * size + i) += dFdt(p, j) / 2.;
34 dEdotdFdot(i * size + j, p * size + i) += F(p, j) / 2.;
35 }
36 }
37 }
38
39 d2RdF2.setZero(size * size, size * size);
40 d2RdFdFdot.setZero(size * size, size * size);
41 d2RdFdot2.setZero(size * size, size * size);
42 for (size_t i = 0; i < size; ++i)
43 {
44 for (size_t j = 0; j < size; ++j)
45 {
46 const int idx = i * size + j;
47 for (size_t k = 0; k < size; ++k)
48 {
49 d2RdF2.row(idx) += (2 * damping_params_[0]) * dFdt(i, k) * dEdotdF.row(k * size + j) + damping_params_[1] * dFdt(i, j) * dEdotdF.row(k * size + k);
50
51 d2RdFdot2.row(idx) += (2 * damping_params_[0]) * F(i, k) * dEdotdFdot.row(k * size + j) + damping_params_[1] * F(i, j) * dEdotdFdot.row(k * size + k);
52
53 d2RdFdFdot(idx, i * size + k) += 2 * damping_params_[0] * dEdt(k, j);
54 d2RdFdFdot.row(idx) += (2 * damping_params_[0]) * (dFdt(i, k) * dEdotdFdot.row(k * size + j)) + damping_params_[1] * (dEdotdFdot.row(k * size + k) * dFdt(i, j));
55 d2RdFdFdot(idx, idx) += damping_params_[1] * dEdt(k, k);
56 }
57 }
58 }
59 }
60
61 void ViscousDamping::add_multimaterial(const int index, const json &params, const Units &units)
62 {
63 // TODO add units
64 assert(size() == 2 || size() == 3);
65
66 if (params.contains("psi"))
67 damping_params_[0] = params["psi"];
68 if (params.contains("phi"))
69 damping_params_[1] = params["phi"];
70 }
71
72 // E := 0.5(F^T F - I), Compute \int F * (2\psi dE/dt + \phi Tr(dE/dt) I) : gradv du
73 Eigen::VectorXd
75 {
76 if (data.x_prev.size() != data.x.size())
77 return Eigen::VectorXd::Zero(data.vals.basis_values.size() * size());
78 Eigen::MatrixXd local_disp;
79 local_disp.setZero(data.vals.basis_values.size(), size());
80 Eigen::MatrixXd local_prev_disp = local_disp;
81 for (size_t i = 0; i < data.vals.basis_values.size(); ++i)
82 {
83 const auto &bs = data.vals.basis_values[i];
84 for (size_t ii = 0; ii < bs.global.size(); ++ii)
85 {
86 for (int d = 0; d < size(); ++d)
87 {
88 local_disp(i, d) += bs.global[ii].val * data.x(bs.global[ii].index * size() + d);
89 local_prev_disp(i, d) += bs.global[ii].val * data.x_prev(bs.global[ii].index * size() + d);
90 }
91 }
92 }
93
94 Eigen::MatrixXd G;
95 G.setZero(data.vals.basis_values.size(), size());
96
97 const int n_pts = data.da.size();
98
99 Eigen::MatrixXd def_grad(size(), size()), prev_def_grad(size(), size());
100 for (long p = 0; p < n_pts; ++p)
101 {
102 def_grad.setZero();
103 prev_def_grad.setZero();
104
105 Eigen::MatrixXd grad(data.vals.basis_values.size(), size());
106
107 for (size_t i = 0; i < data.vals.basis_values.size(); ++i)
108 {
109 grad.row(i) = data.vals.basis_values[i].grad.row(p);
110 }
111
112 Eigen::MatrixXd jac_it = data.vals.jac_it[p];
113
114 def_grad = local_disp.transpose() * grad * jac_it + Eigen::MatrixXd::Identity(size(), size());
115 prev_def_grad = local_prev_disp.transpose() * grad * jac_it + Eigen::MatrixXd::Identity(size(), size());
116
117 Eigen::MatrixXd delF_delU = grad * jac_it;
118
119 Eigen::MatrixXd dRdF, dRdFdot;
120 compute_stress_aux(def_grad, (def_grad - prev_def_grad) / data.dt, dRdF, dRdFdot);
121
122 G += delF_delU * (dRdFdot / (-data.dt)) * data.da(p);
123 }
124
125 Eigen::MatrixXd G_T = G.transpose();
126
127 Eigen::VectorXd temp(Eigen::Map<Eigen::VectorXd>(G_T.data(), G_T.size()));
128
129 return temp;
130 }
131
132 // E := 0.5(F^T F - I), Compute Stress = \int dF/dt * (2\psi dE/dt + \phi Tr(dE/dt) I) : gradv du
133 Eigen::VectorXd
135 {
136 if (data.x_prev.size() != data.x.size())
137 return Eigen::VectorXd::Zero(data.vals.basis_values.size() * size());
138 Eigen::MatrixXd local_disp;
139 local_disp.setZero(data.vals.basis_values.size(), size());
140 Eigen::MatrixXd local_prev_disp = local_disp;
141 for (size_t i = 0; i < data.vals.basis_values.size(); ++i)
142 {
143 const auto &bs = data.vals.basis_values[i];
144 for (size_t ii = 0; ii < bs.global.size(); ++ii)
145 {
146 for (int d = 0; d < size(); ++d)
147 {
148 local_disp(i, d) += bs.global[ii].val * data.x(bs.global[ii].index * size() + d);
149 local_prev_disp(i, d) += bs.global[ii].val * data.x_prev(bs.global[ii].index * size() + d);
150 }
151 }
152 }
153
154 Eigen::MatrixXd G;
155 G.setZero(data.vals.basis_values.size(), size());
156
157 const int n_pts = data.da.size();
158
159 Eigen::MatrixXd def_grad(size(), size()), prev_def_grad(size(), size());
160 for (long p = 0; p < n_pts; ++p)
161 {
162 def_grad.setZero();
163 prev_def_grad.setZero();
164
165 Eigen::MatrixXd grad(data.vals.basis_values.size(), size());
166
167 for (size_t i = 0; i < data.vals.basis_values.size(); ++i)
168 {
169 grad.row(i) = data.vals.basis_values[i].grad.row(p);
170 }
171
172 Eigen::MatrixXd jac_it = data.vals.jac_it[p];
173
174 def_grad = local_disp.transpose() * grad * jac_it + Eigen::MatrixXd::Identity(size(), size());
175 prev_def_grad = local_prev_disp.transpose() * grad * jac_it + Eigen::MatrixXd::Identity(size(), size());
176
177 Eigen::MatrixXd delF_delU = grad * jac_it;
178 auto dFdt = (def_grad - prev_def_grad) / data.dt;
179
180 Eigen::MatrixXd dRdF, dRdFdot;
181 Eigen::MatrixXd dEdt = 0.5 * (dFdt.transpose() * def_grad + def_grad.transpose() * dFdt);
182 Eigen::MatrixXd tmp = 2 * damping_params_[0] * dEdt + damping_params_[1] * dEdt.trace() * Eigen::MatrixXd::Identity(size(), size());
183
184 G += delF_delU * ((dFdt + def_grad / data.dt) * tmp).transpose() * data.da(p);
185 }
186
187 Eigen::MatrixXd G_T = G.transpose();
188
189 Eigen::VectorXd temp(Eigen::Map<Eigen::VectorXd>(G_T.data(), G_T.size()));
190
191 return temp;
192 }
193
194 // Compute \int grad phi_i : dStress / dF^n : grad phi_j dx
195 Eigen::MatrixXd
197 {
198 Eigen::MatrixXd hessian;
199 hessian.setZero(data.vals.basis_values.size() * size(), data.vals.basis_values.size() * size());
200 if (data.x_prev.size() != data.x.size())
201 return hessian;
202 Eigen::MatrixXd local_disp;
203 local_disp.setZero(data.vals.basis_values.size(), size());
204 Eigen::MatrixXd local_prev_disp = local_disp;
205 for (size_t i = 0; i < data.vals.basis_values.size(); ++i)
206 {
207 const auto &bs = data.vals.basis_values[i];
208 for (size_t ii = 0; ii < bs.global.size(); ++ii)
209 {
210 for (int d = 0; d < size(); ++d)
211 {
212 local_disp(i, d) += bs.global[ii].val * data.x(bs.global[ii].index * size() + d);
213 local_prev_disp(i, d) += bs.global[ii].val * data.x_prev(bs.global[ii].index * size() + d);
214 }
215 }
216 }
217
218 const int n_pts = data.da.size();
219
220 Eigen::MatrixXd def_grad(size(), size()), prev_def_grad(size(), size());
221 Eigen::MatrixXd d2RdF2, d2RdFdFdot, d2RdFdot2;
222 Eigen::MatrixXd hessian_temp, hessian_temp2;
223 for (long p = 0; p < n_pts; ++p)
224 {
225 Eigen::MatrixXd grad(data.vals.basis_values.size(), size());
226
227 for (size_t i = 0; i < data.vals.basis_values.size(); ++i)
228 {
229 grad.row(i) = data.vals.basis_values[i].grad.row(p);
230 }
231
232 Eigen::MatrixXd jac_it = data.vals.jac_it[p];
233
234 def_grad = local_disp.transpose() * grad * jac_it + Eigen::MatrixXd::Identity(size(), size());
235 prev_def_grad = local_prev_disp.transpose() * grad * jac_it + Eigen::MatrixXd::Identity(size(), size());
236
237 Eigen::MatrixXd dFdt = (def_grad - prev_def_grad) / data.dt;
238 compute_stress_grad_aux(def_grad, dFdt, d2RdF2, d2RdFdFdot, d2RdFdot2);
239
240 hessian_temp = d2RdF2 + (1. / data.dt) * (d2RdFdFdot + d2RdFdFdot.transpose()) + (1. / data.dt / data.dt) * d2RdFdot2;
241 hessian_temp2 = hessian_temp;
242 for (int i = 0; i < size(); i++)
243 for (int j = 0; j < size(); j++)
244 for (int k = 0; k < size(); k++)
245 for (int l = 0; l < size(); l++)
246 hessian_temp(i + j * size(), k + l * size()) = hessian_temp2(i * size() + j, k * size() + l);
247
248 Eigen::MatrixXd delF_delU_tensor(jac_it.size(), grad.size());
249
250 for (size_t i = 0; i < local_disp.rows(); ++i)
251 {
252 for (size_t j = 0; j < local_disp.cols(); ++j)
253 {
254 Eigen::MatrixXd temp;
255 temp.setZero(size(), size());
256 temp.row(j) = grad.row(i);
257 temp = temp * jac_it;
258 Eigen::VectorXd temp_flattened(Eigen::Map<Eigen::VectorXd>(temp.data(), temp.size()));
259 delF_delU_tensor.col(i * size() + j) = temp_flattened;
260 }
261 }
262
263 hessian += delF_delU_tensor.transpose() * hessian_temp * delF_delU_tensor * data.da(p);
264 }
265
266 return hessian;
267 }
268
269 // Compute \int grad phi_i : dStress / dF^{n-1} : grad phi_j dx
270 Eigen::MatrixXd
272 {
273 Eigen::MatrixXd stress_grad_Ut;
274 stress_grad_Ut.setZero(data.vals.basis_values.size() * size(), data.vals.basis_values.size() * size());
275 if (data.x_prev.size() != data.x.size())
276 return stress_grad_Ut;
277 Eigen::MatrixXd local_disp;
278 local_disp.setZero(data.vals.basis_values.size(), size());
279 Eigen::MatrixXd local_prev_disp = local_disp;
280 for (size_t i = 0; i < data.vals.basis_values.size(); ++i)
281 {
282 const auto &bs = data.vals.basis_values[i];
283 for (size_t ii = 0; ii < bs.global.size(); ++ii)
284 {
285 for (int d = 0; d < size(); ++d)
286 {
287 local_disp(i, d) += bs.global[ii].val * data.x(bs.global[ii].index * size() + d);
288 local_prev_disp(i, d) += bs.global[ii].val * data.x_prev(bs.global[ii].index * size() + d);
289 }
290 }
291 }
292
293 const int n_pts = data.da.size();
294
295 Eigen::MatrixXd def_grad(size(), size()), prev_def_grad(size(), size());
296 for (long p = 0; p < n_pts; ++p)
297 {
298 def_grad.setZero();
299 prev_def_grad.setZero();
300
301 Eigen::MatrixXd grad(data.vals.basis_values.size(), size());
302
303 for (size_t i = 0; i < data.vals.basis_values.size(); ++i)
304 {
305 grad.row(i) = data.vals.basis_values[i].grad.row(p);
306 }
307
308 Eigen::MatrixXd jac_it = data.vals.jac_it[p];
309
310 def_grad = local_disp.transpose() * grad * jac_it + Eigen::MatrixXd::Identity(size(), size());
311 prev_def_grad = local_prev_disp.transpose() * grad * jac_it + Eigen::MatrixXd::Identity(size(), size());
312
313 Eigen::MatrixXd d2RdF2, d2RdFdFdot, d2RdFdot2;
314 Eigen::MatrixXd dFdt = (def_grad - prev_def_grad) / data.dt;
315 compute_stress_grad_aux(def_grad, dFdt, d2RdF2, d2RdFdFdot, d2RdFdot2);
316
317 Eigen::MatrixXd stress_grad_Ut_temp = -(1. / data.dt) * d2RdFdFdot - (1. / data.dt / data.dt) * d2RdFdot2;
318 Eigen::MatrixXd stress_grad_Ut_temp2 = stress_grad_Ut_temp;
319 for (int i = 0; i < size(); i++)
320 for (int j = 0; j < size(); j++)
321 for (int k = 0; k < size(); k++)
322 for (int l = 0; l < size(); l++)
323 stress_grad_Ut_temp(i + j * size(), k + l * size()) = stress_grad_Ut_temp2(i * size() + j, k * size() + l);
324
325 Eigen::MatrixXd delF_delU_tensor(jac_it.size(), grad.size());
326
327 for (size_t i = 0; i < local_disp.rows(); ++i)
328 {
329 for (size_t j = 0; j < local_disp.cols(); ++j)
330 {
331 Eigen::MatrixXd temp;
332 temp.setZero(size(), size());
333 temp.row(j) = grad.row(i);
334 temp = temp * jac_it;
335 Eigen::VectorXd temp_flattened(Eigen::Map<Eigen::VectorXd>(temp.data(), temp.size()));
336 delF_delU_tensor.col(i * size() + j) = temp_flattened;
337 }
338 }
339
340 stress_grad_Ut += delF_delU_tensor.transpose() * stress_grad_Ut_temp * delF_delU_tensor * data.da(p);
341 }
342
343 return stress_grad_Ut;
344 }
345
346 // E := 0.5(F^T F - I), Compute Energy = \int \psi \| \frac{\partial E}{\partial t} \|^2 + 0.5 \phi (Tr(\frac{\partial E}{\partial t}))^2 du
348 {
349 Eigen::MatrixXd local_disp;
350 local_disp.setZero(data.vals.basis_values.size(), size());
351 if (data.x_prev.size() != data.x.size())
352 return 0;
353 Eigen::MatrixXd local_prev_disp = local_disp;
354 for (size_t i = 0; i < data.vals.basis_values.size(); ++i)
355 {
356 const auto &bs = data.vals.basis_values[i];
357 for (size_t ii = 0; ii < bs.global.size(); ++ii)
358 {
359 for (int d = 0; d < size(); ++d)
360 {
361 local_disp(i, d) += bs.global[ii].val * data.x(bs.global[ii].index * size() + d);
362 local_prev_disp(i, d) += bs.global[ii].val * data.x_prev(bs.global[ii].index * size() + d);
363 }
364 }
365 }
366
367 double energy = 0;
368 const int n_pts = data.da.size();
369
370 Eigen::MatrixXd def_grad(size(), size()), prev_def_grad(size(), size());
371 for (long p = 0; p < n_pts; ++p)
372 {
373 def_grad.setZero();
374 prev_def_grad.setZero();
375
376 for (size_t i = 0; i < data.vals.basis_values.size(); ++i)
377 {
378 const auto &bs = data.vals.basis_values[i];
379
380 for (int d = 0; d < size(); ++d)
381 {
382 for (int c = 0; c < size(); ++c)
383 {
384 def_grad(d, c) += bs.grad(p, c) * local_disp(i, d);
385 prev_def_grad(d, c) += bs.grad(p, c) * local_prev_disp(i, d);
386 }
387 }
388 }
389
390 Eigen::MatrixXd jac_it(size(), size());
391 for (long k = 0; k < jac_it.size(); ++k)
392 jac_it(k) = data.vals.jac_it[p](k);
393
394 def_grad = def_grad * jac_it + Eigen::MatrixXd::Identity(size(), size());
395 prev_def_grad = prev_def_grad * jac_it + Eigen::MatrixXd::Identity(size(), size());
396
397 Eigen::MatrixXd dFdt = (def_grad - prev_def_grad) / data.dt;
398 Eigen::MatrixXd dEdt = 0.5 * (dFdt.transpose() * def_grad + def_grad.transpose() * dFdt);
399
400 double val = damping_params_[0] * dEdt.squaredNorm() + 0.5 * damping_params_[1] * pow(dEdt.trace(), 2);
401
402 energy += val * data.da(p);
403 }
404
405 return energy;
406 }
407
409 const OptAssemblerData &data,
410 const Eigen::MatrixXd &prev_grad_u_i,
411 Eigen::MatrixXd &stress,
412 Eigen::MatrixXd &result) const
413 {
414 const double dt = data.dt;
415 const Eigen::MatrixXd &grad_u_i = data.grad_u_i;
416
417 Eigen::MatrixXd F = Eigen::MatrixXd::Identity(size(), size()) + grad_u_i;
418 Eigen::MatrixXd Fdot = (grad_u_i - prev_grad_u_i) / dt;
419 Eigen::MatrixXd dRdF, dRdFdot, d2RdF2, d2RdFdFdot, d2RdFdot2;
420
421 // compute_stress_aux(F, Fdot, dRdF, dRdFdot);
422 Eigen::MatrixXd dEdt = 0.5 * (Fdot.transpose() * F + F.transpose() * Fdot);
423 Eigen::MatrixXd tmp = 2 * damping_params_[0] * dEdt + damping_params_[1] * dEdt.trace() * Eigen::MatrixXd::Identity(size(), size());
424 stress = (Fdot + (1. / dt) * F) * tmp;
425
426 compute_stress_grad_aux(F, Fdot, d2RdF2, d2RdFdFdot, d2RdFdot2);
427 result = d2RdF2 + (1. / dt) * (d2RdFdFdot + d2RdFdFdot.transpose()) + (1. / dt / dt) * d2RdFdot2;
428 }
429
431 const OptAssemblerData &data,
432 const Eigen::MatrixXd &prev_grad_u_i,
433 Eigen::MatrixXd &result) const
434 {
435 const double dt = data.dt;
436 const Eigen::MatrixXd &grad_u_i = data.grad_u_i;
437
438 Eigen::MatrixXd def_grad = Eigen::MatrixXd::Identity(grad_u_i.rows(), grad_u_i.cols()) + grad_u_i;
439 Eigen::MatrixXd def_grad_fd = (grad_u_i - prev_grad_u_i) / dt;
440 Eigen::MatrixXd d2RdF2, d2RdFdFdot, d2RdFdot2;
441
442 compute_stress_grad_aux(def_grad, def_grad_fd, d2RdF2, d2RdFdFdot, d2RdFdot2);
443 result = -(1. / dt) * d2RdFdFdot - (1. / dt / dt) * d2RdFdot2;
444 }
445
447 const OptAssemblerData &data,
448 const Eigen::MatrixXd &prev_grad_u_i,
449 Eigen::MatrixXd &dstress_dpsi,
450 Eigen::MatrixXd &dstress_dphi)
451 {
452 const double dt = data.dt;
453 const Eigen::MatrixXd &grad_u_i = data.grad_u_i;
454
455 Eigen::MatrixXd F = Eigen::MatrixXd::Identity(grad_u_i.rows(), grad_u_i.cols()) + grad_u_i;
456 Eigen::MatrixXd prev_F = Eigen::MatrixXd::Identity(prev_grad_u_i.rows(), prev_grad_u_i.cols()) + prev_grad_u_i;
457
458 Eigen::MatrixXd dFdt = (F - prev_F) / dt;
459 Eigen::MatrixXd dEdt = 0.5 * (dFdt.transpose() * F + F.transpose() * dFdt);
460
461 dstress_dpsi = 2 * (dFdt + F / dt) * dEdt;
462 dstress_dphi = dEdt.trace() * (dFdt + F / dt);
463 }
464} // namespace polyfem::assembler
double val
Definition Assembler.cpp:86
std::vector< Eigen::Matrix< double, Eigen::Dynamic, Eigen::Dynamic, 0, 3, 3 > > jac_it
virtual Eigen::VectorXd assemble_gradient(const NonLinearAssemblerData &data) const override
void compute_stress_aux(const Eigen::MatrixXd &F, const Eigen::MatrixXd &dFdt, Eigen::MatrixXd &dRdF, Eigen::MatrixXd &dRdFdot) const
double compute_energy(const NonLinearAssemblerData &data) const override
static void compute_dstress_dpsi_dphi(const OptAssemblerData &data, const Eigen::MatrixXd &prev_grad_u_i, Eigen::MatrixXd &dstress_dpsi, Eigen::MatrixXd &dstress_dphi)
void compute_stress_grad_aux(const Eigen::MatrixXd &F, const Eigen::MatrixXd &dFdt, Eigen::MatrixXd &d2RdF2, Eigen::MatrixXd &d2RdFdFdot, Eigen::MatrixXd &d2RdFdot2) const
virtual Eigen::MatrixXd assemble_hessian(const NonLinearAssemblerData &data) const override
void add_multimaterial(const int index, const json &params, const Units &units) override
void compute_stress_grad(const OptAssemblerData &data, const Eigen::MatrixXd &prev_grad_u_i, Eigen::MatrixXd &stress, Eigen::MatrixXd &result) const override
void compute_stress_prev_grad(const OptAssemblerData &data, const Eigen::MatrixXd &prev_grad_u_i, Eigen::MatrixXd &result) const override
Eigen::VectorXd assemble_gradient(const NonLinearAssemblerData &data) const override
Eigen::MatrixXd assemble_hessian(const NonLinearAssemblerData &data) const override
Used for test only.
nlohmann::json json
Definition Common.hpp:9