PolyFEM
Loading...
Searching...
No Matches
FixedCorotational.cpp
Go to the documentation of this file.
2
5
6namespace polyfem::assembler
7{
8 namespace
9 {
10 bool delta(int i, int j)
11 {
12 return (i == j) ? true : false;
13 }
14
15 template <int dim>
16 Eigen::Matrix<double, dim, dim> hat(const Eigen::Matrix<double, dim, 1> &x)
17 {
18
19 Eigen::Matrix<double, dim, dim> prod;
20 prod.setZero();
21
22 prod(0, 1) = -x(2);
23 prod(0, 2) = x(1);
24 prod(1, 0) = x(2);
25 prod(1, 2) = -x(0);
26 prod(2, 0) = -x(1);
27 prod(2, 1) = x(0);
28
29 return prod;
30 }
31
32 template <int dim>
33 Eigen::Matrix<double, dim, 1> cross(const Eigen::Matrix<double, dim, 1> &x, const Eigen::Matrix<double, dim, 1> &y)
34 {
35
36 Eigen::Matrix<double, dim, 1> z;
37 z.setZero();
38
39 z(0) = x(1) * y(2) - x(2) * y(1);
40 z(1) = x(2) * y(0) - x(0) * y(2);
41 z(2) = x(0) * y(1) - x(1) * y(0);
42
43 return z;
44 }
45
46 template <int dim>
47 Eigen::Matrix<double, dim, dim> computeCofactorMtr(Eigen::Matrix<double, dim, dim>& F)
48 {
49 Eigen::Matrix<double, dim, dim> A;
50 A.setZero();
51 if constexpr (dim == 2)
52 {
53 A(0, 0) = F(1, 1);
54 A(0, 1) = -F(1, 0);
55 A(1, 0) = -F(0, 1);
56 A(1, 1) = F(0, 0);
57 }
58 else if constexpr (dim == 3)
59 {
60 A(0, 0) = F(1, 1) * F(2, 2) - F(1, 2) * F(2, 1);
61 A(0, 1) = F(1, 2) * F(2, 0) - F(1, 0) * F(2, 2);
62 A(0, 2) = F(1, 0) * F(2, 1) - F(1, 1) * F(2, 0);
63 A(1, 0) = F(0, 2) * F(2, 1) - F(0, 1) * F(2, 2);
64 A(1, 1) = F(0, 0) * F(2, 2) - F(0, 2) * F(2, 0);
65 A(1, 2) = F(0, 1) * F(2, 0) - F(0, 0) * F(2, 1);
66 A(2, 0) = F(0, 1) * F(1, 2) - F(0, 2) * F(1, 1);
67 A(2, 1) = F(0, 2) * F(1, 0) - F(0, 0) * F(1, 2);
68 A(2, 2) = F(0, 0) * F(1, 1) - F(0, 1) * F(1, 0);
69 }
70 return A;
71 }
72
73 } // namespace
74
78
79 void FixedCorotational::add_multimaterial(const int index, const json &params, const Units &units)
80 {
81 assert(size() == 2 || size() == 3);
82
83 params_.add_multimaterial(index, params, size() == 3, units.stress());
84 }
85
86 Eigen::VectorXd
88 {
89 Eigen::Matrix<double, Eigen::Dynamic, 1> gradient;
90
91 if (size() == 2)
92 {
93 switch (data.vals.basis_values.size())
94 {
95 case 3:
96 {
97 gradient.resize(6);
98 compute_energy_aux_gradient_fast<3, 2>(data, gradient);
99 break;
100 }
101 case 6:
102 {
103 gradient.resize(12);
104 compute_energy_aux_gradient_fast<6, 2>(data, gradient);
105 break;
106 }
107 case 10:
108 {
109 gradient.resize(20);
110 compute_energy_aux_gradient_fast<10, 2>(data, gradient);
111 break;
112 }
113 default:
114 {
115 gradient.resize(data.vals.basis_values.size() * 2);
116 compute_energy_aux_gradient_fast<Eigen::Dynamic, 2>(data, gradient);
117 break;
118 }
119 }
120 }
121 else // if (size() == 3)
122 {
123 assert(size() == 3);
124 switch (data.vals.basis_values.size())
125 {
126 case 4:
127 {
128 gradient.resize(12);
129 compute_energy_aux_gradient_fast<4, 3>(data, gradient);
130 break;
131 }
132 case 10:
133 {
134 gradient.resize(30);
135 compute_energy_aux_gradient_fast<10, 3>(data, gradient);
136 break;
137 }
138 case 20:
139 {
140 gradient.resize(60);
141 compute_energy_aux_gradient_fast<20, 3>(data, gradient);
142 break;
143 }
144 default:
145 {
146 gradient.resize(data.vals.basis_values.size() * 3);
147 compute_energy_aux_gradient_fast<Eigen::Dynamic, 3>(data, gradient);
148 break;
149 }
150 }
151 }
152
153 return gradient;
154 }
155
156 Eigen::MatrixXd
158 {
159 Eigen::MatrixXd hessian;
160
161 if (size() == 2)
162 {
163 switch (data.vals.basis_values.size())
164 {
165 case 3:
166 {
167 hessian.resize(6, 6);
168 hessian.setZero();
169 compute_energy_hessian_aux_fast<3, 2>(data, hessian);
170 break;
171 }
172 case 6:
173 {
174 hessian.resize(12, 12);
175 hessian.setZero();
176 compute_energy_hessian_aux_fast<6, 2>(data, hessian);
177 break;
178 }
179 case 10:
180 {
181 hessian.resize(20, 20);
182 hessian.setZero();
183 compute_energy_hessian_aux_fast<10, 2>(data, hessian);
184 break;
185 }
186 default:
187 {
188 hessian.resize(data.vals.basis_values.size() * 2, data.vals.basis_values.size() * 2);
189 hessian.setZero();
190 compute_energy_hessian_aux_fast<Eigen::Dynamic, 2>(data, hessian);
191 break;
192 }
193 }
194 }
195 else // if (size() == 3)
196 {
197 assert(size() == 3);
198 switch (data.vals.basis_values.size())
199 {
200 case 4:
201 {
202 hessian.resize(12, 12);
203 hessian.setZero();
204 compute_energy_hessian_aux_fast<4, 3>(data, hessian);
205 break;
206 }
207 case 10:
208 {
209 hessian.resize(30, 30);
210 hessian.setZero();
211 compute_energy_hessian_aux_fast<10, 3>(data, hessian);
212 break;
213 }
214 case 20:
215 {
216 hessian.resize(60, 60);
217 hessian.setZero();
218 compute_energy_hessian_aux_fast<20, 3>(data, hessian);
219 break;
220 }
221 default:
222 {
223 hessian.resize(data.vals.basis_values.size() * 3, data.vals.basis_values.size() * 3);
224 hessian.setZero();
225 compute_energy_hessian_aux_fast<Eigen::Dynamic, 3>(data, hessian);
226 break;
227 }
228 }
229 }
230
231 return hessian;
232 }
233
235 const int all_size,
236 const ElasticityTensorType &type,
237 Eigen::MatrixXd &all,
238 const std::function<Eigen::MatrixXd(const Eigen::MatrixXd &)> &fun) const
239 {
240 const auto &displacement = data.fun;
241 const auto &local_pts = data.local_pts;
242 const auto &bs = data.bs;
243 const auto &gbs = data.gbs;
244 const auto el_id = data.el_id;
245 const auto t = data.t;
246
247 Eigen::MatrixXd displacement_grad(size(), size());
248
249 assert(displacement.cols() == 1);
250
251 all.resize(local_pts.rows(), all_size);
252
254 vals.compute(el_id, size() == 3, local_pts, bs, gbs);
255 const auto I = Eigen::MatrixXd::Identity(size(), size());
256
257 for (long p = 0; p < local_pts.rows(); ++p)
258 {
259 compute_diplacement_grad(size(), bs, vals, local_pts, p, displacement, displacement_grad);
260
261 const Eigen::MatrixXd def_grad = I + displacement_grad;
262 if (type == ElasticityTensorType::F)
263 {
264 all.row(p) = fun(def_grad);
265 continue;
266 }
267
268 double lambda, mu;
269 params_.lambda_mu(local_pts.row(p), vals.val.row(p), t, vals.element_id, lambda, mu);
270
271 Eigen::MatrixXd stress_tensor;
272 if (size() == 2)
273 stress_tensor = compute_stress_from_def_grad<2>(def_grad, lambda, mu) * def_grad.transpose() / def_grad.determinant();
274 else
275 stress_tensor = compute_stress_from_def_grad<3>(def_grad, lambda, mu) * def_grad.transpose() / def_grad.determinant();
276 if (type == ElasticityTensorType::PK1)
277 stress_tensor = pk1_from_cauchy(stress_tensor, def_grad);
278 else if (type == ElasticityTensorType::PK2)
279 stress_tensor = pk2_from_cauchy(stress_tensor, def_grad);
280
281 all.row(p) = fun(stress_tensor);
282 }
283 }
284
286 {
287 if (size() == 2)
288 return compute_energy_aux<2>(data);
289 else
290 return compute_energy_aux<3>(data);
291 }
292
293 template <int dim>
295 {
296 Eigen::VectorXd local_disp;
297 get_local_disp(data, dim, local_disp);
298
299 Eigen::Matrix<double, dim, dim> def_grad;
300
301 double energy = 0.0;
302
303 const int n_pts = data.da.size();
304 for (long p = 0; p < n_pts; ++p)
305 {
306 compute_disp_grad_at_quad(data, local_disp, p, dim, def_grad);
307
308 // Id + grad d
309 def_grad.diagonal().array() += 1.0;
310
311 double lambda, mu;
312 params_.lambda_mu(data.vals.quadrature.points.row(p), data.vals.val.row(p), data.t, data.vals.element_id, lambda, mu);
313
314 const double val = compute_energy_from_def_grad(def_grad, lambda, mu);
315
316 energy += val * data.da(p);
317 }
318 return energy;
319 }
320
321 template <int n_basis, int dim>
322 void FixedCorotational::compute_energy_aux_gradient_fast(const NonLinearAssemblerData &data, Eigen::Matrix<double, Eigen::Dynamic, 1> &G_flattened) const
323 {
324 assert(data.x.cols() == 1);
325
326 const int n_pts = data.da.size();
327
328 Eigen::Matrix<double, n_basis, dim> local_disp(data.vals.basis_values.size(), size());
329 local_disp.setZero();
330 for (size_t i = 0; i < data.vals.basis_values.size(); ++i)
331 {
332 const auto &bs = data.vals.basis_values[i];
333 for (size_t ii = 0; ii < bs.global.size(); ++ii)
334 {
335 for (int d = 0; d < size(); ++d)
336 {
337 local_disp(i, d) += bs.global[ii].val * data.x(bs.global[ii].index * size() + d);
338 }
339 }
340 }
341
342 Eigen::Matrix<double, dim, dim> def_grad(size(), size());
343
344 Eigen::Matrix<double, n_basis, dim> G(data.vals.basis_values.size(), size());
345 G.setZero();
346
347 for (long p = 0; p < n_pts; ++p)
348 {
349 Eigen::Matrix<double, n_basis, dim> grad(data.vals.basis_values.size(), size());
350
351 for (size_t i = 0; i < data.vals.basis_values.size(); ++i)
352 {
353 grad.row(i) = data.vals.basis_values[i].grad.row(p);
354 }
355
356 const Eigen::Matrix<double, dim, dim> jac_it = data.vals.jac_it[p];
357
358 const Eigen::Matrix<double, n_basis, dim> delF_delU = grad * jac_it;
359
360 // Id + grad d
361 def_grad = local_disp.transpose() * delF_delU + Eigen::Matrix<double, dim, dim>::Identity(size(), size());
362
363 double lambda, mu;
364 params_.lambda_mu(data.vals.quadrature.points.row(p), data.vals.val.row(p), data.t, data.vals.element_id, lambda, mu);
365
366 Eigen::Matrix<double, dim, dim> gradient_temp = compute_stress_from_def_grad(def_grad, lambda, mu);
367
368 Eigen::Matrix<double, n_basis, dim> gradient = delF_delU * gradient_temp.transpose();
369
370 G.noalias() += gradient * data.da(p);
371 }
372
373 Eigen::Matrix<double, dim, n_basis> G_T = G.transpose();
374
375 constexpr int N = (n_basis == Eigen::Dynamic) ? Eigen::Dynamic : n_basis * dim;
376 Eigen::Matrix<double, N, 1> temp(Eigen::Map<Eigen::Matrix<double, N, 1>>(G_T.data(), G_T.size()));
377 G_flattened = temp;
378 }
379
380 template <int n_basis, int dim>
382 {
383 assert(data.x.cols() == 1);
384
385 constexpr int N = (n_basis == Eigen::Dynamic) ? Eigen::Dynamic : n_basis * dim;
386 const int n_pts = data.da.size();
387
388 Eigen::Matrix<double, n_basis, dim> local_disp(data.vals.basis_values.size(), size());
389 local_disp.setZero();
390 for (size_t i = 0; i < data.vals.basis_values.size(); ++i)
391 {
392 const auto &bs = data.vals.basis_values[i];
393 for (size_t ii = 0; ii < bs.global.size(); ++ii)
394 {
395 for (int d = 0; d < size(); ++d)
396 {
397 local_disp(i, d) += bs.global[ii].val * data.x(bs.global[ii].index * size() + d);
398 }
399 }
400 }
401
402 Eigen::Matrix<double, dim, dim> def_grad(size(), size());
403
404 for (long p = 0; p < n_pts; ++p)
405 {
406 Eigen::Matrix<double, n_basis, dim> grad(data.vals.basis_values.size(), size());
407
408 for (size_t i = 0; i < data.vals.basis_values.size(); ++i)
409 {
410 grad.row(i) = data.vals.basis_values[i].grad.row(p);
411 }
412
413 Eigen::Matrix<double, dim, dim> jac_it = data.vals.jac_it[p];
414
415 // Id + grad d
416 def_grad = local_disp.transpose() * grad * jac_it + Eigen::Matrix<double, dim, dim>::Identity(size(), size());
417
418 double lambda, mu;
419 params_.lambda_mu(data.vals.quadrature.points.row(p), data.vals.val.row(p), data.t, data.vals.element_id, lambda, mu);
420
421 Eigen::Matrix<double, dim * dim, dim * dim> hessian_temp = compute_stiffness_from_def_grad(def_grad, lambda, mu);
422
423 Eigen::Matrix<double, dim * dim, N> delF_delU_tensor(jac_it.size(), grad.size());
424
425 for (size_t i = 0; i < local_disp.rows(); ++i)
426 {
427 for (size_t j = 0; j < local_disp.cols(); ++j)
428 {
429 Eigen::Matrix<double, dim, dim> temp(size(), size());
430 temp.setZero();
431 temp.row(j) = grad.row(i);
432 temp = temp * jac_it;
433 Eigen::Matrix<double, dim * dim, 1> temp_flattened(Eigen::Map<Eigen::Matrix<double, dim * dim, 1>>(temp.data(), temp.size()));
434 delF_delU_tensor.col(i * size() + j) = temp_flattened;
435 }
436 }
437
438 Eigen::Matrix<double, N, N> hessian = delF_delU_tensor.transpose() * hessian_temp * delF_delU_tensor;
439
440 H += hessian * data.da(p);
441 }
442 }
443
445 const OptAssemblerData &data,
446 const Eigen::MatrixXd &mat,
447 Eigen::MatrixXd &stress,
448 Eigen::MatrixXd &result) const
449 {
450 const double t = data.t;
451 const int el_id = data.el_id;
452 const Eigen::MatrixXd &local_pts = data.local_pts;
453 const Eigen::MatrixXd &global_pts = data.global_pts;
454 const Eigen::MatrixXd &grad_u_i = data.grad_u_i;
455
456 double lambda, mu;
457 params_.lambda_mu(local_pts, global_pts, t, el_id, lambda, mu);
458
459 const Eigen::MatrixXd def_grad = Eigen::MatrixXd::Identity(grad_u_i.rows(), grad_u_i.cols()) + grad_u_i;
460 if (size() == 2)
461 {
462 stress = compute_stress_from_def_grad<2>(def_grad, lambda, mu);
463 result = (compute_stiffness_from_def_grad<2>(def_grad, lambda, mu) * mat.reshaped(size() * size(), 1)).reshaped(size(), size());
464 }
465 else
466 {
467 stress = compute_stress_from_def_grad<3>(def_grad, lambda, mu);
468 result = (compute_stiffness_from_def_grad<3>(def_grad, lambda, mu) * mat.reshaped(size() * size(), 1)).reshaped(size(), size());
469 }
470 }
471
473 const OptAssemblerData &data,
474 Eigen::MatrixXd &stress,
475 Eigen::MatrixXd &result) const
476 {
477 const double t = data.t;
478 const int el_id = data.el_id;
479 const Eigen::MatrixXd &local_pts = data.local_pts;
480 const Eigen::MatrixXd &global_pts = data.global_pts;
481 const Eigen::MatrixXd &grad_u_i = data.grad_u_i;
482
483 double lambda, mu;
484 params_.lambda_mu(local_pts, global_pts, t, el_id, lambda, mu);
485
486 Eigen::MatrixXd def_grad = Eigen::MatrixXd::Identity(grad_u_i.rows(), grad_u_i.cols()) + grad_u_i;
487 if (size() == 2)
488 {
489 stress = compute_stress_from_def_grad<2>(def_grad, lambda, mu);
490 result = (compute_stiffness_from_def_grad<2>(def_grad, lambda, mu) * stress.reshaped(size() * size(), 1)).reshaped(size(), size());
491 }
492 else
493 {
494 stress = compute_stress_from_def_grad<3>(def_grad, lambda, mu);
495 result = (compute_stiffness_from_def_grad<3>(def_grad, lambda, mu) * stress.reshaped(size() * size(), 1)).reshaped(size(), size());
496 }
497 }
498
500 const OptAssemblerData &data,
501 Eigen::MatrixXd &dstress_dmu,
502 Eigen::MatrixXd &dstress_dlambda) const
503 {
504 const double t = data.t;
505 const int el_id = data.el_id;
506 const Eigen::MatrixXd &local_pts = data.local_pts;
507 const Eigen::MatrixXd &global_pts = data.global_pts;
508 const Eigen::MatrixXd &grad_u_i = data.grad_u_i;
509
510 const Eigen::MatrixXd def_grad = Eigen::MatrixXd::Identity(size(), size()) + grad_u_i;
511
512 Eigen::MatrixXd UVT;
513 Eigen::VectorXd sigmas;
514 {
515 if (size() == 2)
516 {
517 utils::AutoFlipSVD<Eigen::Matrix<double, 2, 2>> svd(def_grad, Eigen::ComputeFullU | Eigen::ComputeFullV);
518 sigmas = svd.singularValues();
519 UVT = svd.matrixU() * svd.matrixV().transpose();
520 }
521 else
522 {
523 utils::AutoFlipSVD<Eigen::Matrix<double, 3, 3>> svd(def_grad, Eigen::ComputeFullU | Eigen::ComputeFullV);
524 sigmas = svd.singularValues();
525 UVT = svd.matrixU() * svd.matrixV().transpose();
526 }
527 }
528
529 Eigen::MatrixXd delJ_delF(size(), size());
530 delJ_delF.setZero();
531
532 if (size() == 2)
533 {
534 delJ_delF(0, 0) = def_grad(1, 1);
535 delJ_delF(0, 1) = -def_grad(1, 0);
536 delJ_delF(1, 0) = -def_grad(0, 1);
537 delJ_delF(1, 1) = def_grad(0, 0);
538 }
539 else if (size() == 3)
540 {
541 const Eigen::Matrix<double, 3, 1> u = def_grad.col(0);
542 const Eigen::Matrix<double, 3, 1> v = def_grad.col(1);
543 const Eigen::Matrix<double, 3, 1> w = def_grad.col(2);
544
545 delJ_delF.col(0) = cross<3>(v, w);
546 delJ_delF.col(1) = cross<3>(w, u);
547 delJ_delF.col(2) = cross<3>(u, v);
548 }
549
550 dstress_dmu = 2 * (def_grad - UVT);
551 dstress_dlambda = (sigmas.prod() - 1) * delJ_delF;
552 }
553
554 std::map<std::string, Assembler::ParamFunc> FixedCorotational::parameters() const
555 {
556 std::map<std::string, ParamFunc> res;
557 const auto &params = params_;
558 const int size = this->size();
559
560 res["lambda"] = [&params](const RowVectorNd &uv, const RowVectorNd &p, double t, int e) {
561 double lambda, mu;
562
563 params.lambda_mu(uv, p, t, e, lambda, mu);
564 return lambda;
565 };
566
567 res["mu"] = [&params](const RowVectorNd &uv, const RowVectorNd &p, double t, int e) {
568 double lambda, mu;
569
570 params.lambda_mu(uv, p, t, e, lambda, mu);
571 return mu;
572 };
573
574 res["E"] = [&params, size](const RowVectorNd &uv, const RowVectorNd &p, double t, int e) {
575 double lambda, mu;
576 params.lambda_mu(uv, p, t, e, lambda, mu);
577
578 if (size == 3)
579 return mu * (3.0 * lambda + 2.0 * mu) / (lambda + mu);
580 else
581 return 2 * mu * (2.0 * lambda + 2.0 * mu) / (lambda + 2.0 * mu);
582 };
583
584 res["nu"] = [&params, size](const RowVectorNd &uv, const RowVectorNd &p, double t, int e) {
585 double lambda, mu;
586
587 params.lambda_mu(uv, p, t, e, lambda, mu);
588
589 if (size == 3)
590 return lambda / (2.0 * (lambda + mu));
591 else
592 return lambda / (lambda + 2.0 * mu);
593 };
594
595 return res;
596 }
597
598 template <int dim>
599 double FixedCorotational::compute_energy_from_singular_values(const Eigen::Vector<double, dim> &sigmas, const double lambda, const double mu)
600 {
601 const double sigmam12Sum = (sigmas - Eigen::Matrix<double, dim, 1>::Ones()).squaredNorm();
602 const double sigmaProdm1 = sigmas.prod() - 1.0;
603
604 return mu * sigmam12Sum + lambda / 2.0 * sigmaProdm1 * sigmaProdm1;
605 }
606
607 template <int dim>
608 Eigen::Vector<double, dim> FixedCorotational::compute_stress_from_singular_values(const Eigen::Vector<double, dim> &sigmas, const double lambda, const double mu)
609 {
610 const double sigmaProdm1lambda = lambda * (sigmas.prod() - 1.0);
611 Eigen::Matrix<double, dim, 1> sigmaProd_noI;
612 if constexpr (dim == 2) {
613 sigmaProd_noI[0] = sigmas[1];
614 sigmaProd_noI[1] = sigmas[0];
615 }
616 else {
617 sigmaProd_noI[0] = sigmas[1] * sigmas[2];
618 sigmaProd_noI[1] = sigmas[2] * sigmas[0];
619 sigmaProd_noI[2] = sigmas[0] * sigmas[1];
620 }
621
622 const double _2mu = mu * 2;
623 Eigen::Vector<double, dim> dE_div_dsigma;
624 dE_div_dsigma.setZero();
625 dE_div_dsigma[0] = (_2mu * (sigmas[0] - 1.0) + sigmaProd_noI[0] * sigmaProdm1lambda);
626 dE_div_dsigma[1] = (_2mu * (sigmas[1] - 1.0) + sigmaProd_noI[1] * sigmaProdm1lambda);
627 if constexpr (dim == 3) {
628 dE_div_dsigma[2] = (_2mu * (sigmas[2] - 1.0) + sigmaProd_noI[2] * sigmaProdm1lambda);
629 }
630 return dE_div_dsigma;
631 }
632
633 template <int dim>
634 Eigen::Matrix<double, dim, dim> FixedCorotational::compute_stiffness_from_singular_values(const Eigen::Vector<double, dim> &sigmas, const double lambda, const double mu)
635 {
636 const double sigmaProd = sigmas.prod();
637 Eigen::Matrix<double, dim, 1> sigmaProd_noI;
638 if constexpr (dim == 2) {
639 sigmaProd_noI[0] = sigmas[1];
640 sigmaProd_noI[1] = sigmas[0];
641 }
642 else {
643 sigmaProd_noI[0] = sigmas[1] * sigmas[2];
644 sigmaProd_noI[1] = sigmas[2] * sigmas[0];
645 sigmaProd_noI[2] = sigmas[0] * sigmas[1];
646 }
647
648 double _2mu = mu * 2;
649 Eigen::Matrix<double, dim, dim> d2E_div_dsigma2;
650 d2E_div_dsigma2.setZero();
651 d2E_div_dsigma2(0, 0) = _2mu + lambda * sigmaProd_noI[0] * sigmaProd_noI[0];
652 d2E_div_dsigma2(1, 1) = _2mu + lambda * sigmaProd_noI[1] * sigmaProd_noI[1];
653 if constexpr (dim == 3) {
654 d2E_div_dsigma2(2, 2) = _2mu + lambda * sigmaProd_noI[2] * sigmaProd_noI[2];
655 }
656
657 if constexpr (dim == 2) {
658 d2E_div_dsigma2(0, 1) = d2E_div_dsigma2(1, 0) = lambda * ((sigmaProd - 1.0) + sigmaProd_noI[0] * sigmaProd_noI[1]);
659 }
660 else {
661 d2E_div_dsigma2(0, 1) = d2E_div_dsigma2(1, 0) = lambda * (sigmas[2] * (sigmaProd - 1.0) + sigmaProd_noI[0] * sigmaProd_noI[1]);
662 d2E_div_dsigma2(0, 2) = d2E_div_dsigma2(2, 0) = lambda * (sigmas[1] * (sigmaProd - 1.0) + sigmaProd_noI[0] * sigmaProd_noI[2]);
663 d2E_div_dsigma2(2, 1) = d2E_div_dsigma2(1, 2) = lambda * (sigmas[0] * (sigmaProd - 1.0) + sigmaProd_noI[2] * sigmaProd_noI[1]);
664 }
665
666 return d2E_div_dsigma2;
667 }
668
669 template <int dim>
670 double FixedCorotational::compute_energy_from_def_grad(const Eigen::Matrix<double, dim, dim> &F, const double lambda, const double mu)
671 {
672 const Eigen::Vector<double, dim> sigmas = utils::singular_values<dim>(F);
673 return compute_energy_from_singular_values(sigmas, lambda, mu);
674 }
675
676 template <int dim>
677 Eigen::Matrix<double, dim, dim> FixedCorotational::compute_stress_from_def_grad(const Eigen::Matrix<double, dim, dim> &F, const double lambda, const double mu)
678 {
679 utils::AutoFlipSVD<Eigen::Matrix<double, dim, dim>> svd(F, Eigen::ComputeFullU | Eigen::ComputeFullV);
680 const Eigen::Vector<double, dim> sigmas = svd.singularValues();
681
682 Eigen::Matrix<double, dim, dim> delJ_delF(dim, dim);
683 delJ_delF.setZero();
684
685 if (dim == 2)
686 {
687 delJ_delF(0, 0) = F(1, 1);
688 delJ_delF(0, 1) = -F(1, 0);
689 delJ_delF(1, 0) = -F(0, 1);
690 delJ_delF(1, 1) = F(0, 0);
691 }
692 else if (dim == 3)
693 {
694 const Eigen::Matrix<double, dim, 1> u = F.col(0);
695 const Eigen::Matrix<double, dim, 1> v = F.col(1);
696 const Eigen::Matrix<double, dim, 1> w = F.col(2);
697
698 delJ_delF.col(0) = cross<dim>(v, w);
699 delJ_delF.col(1) = cross<dim>(w, u);
700 delJ_delF.col(2) = cross<dim>(u, v);
701 }
702
703 return lambda * (sigmas.prod() - 1) * delJ_delF + mu * 2 * (F - svd.matrixU() * svd.matrixV().transpose());
704 }
705
706 template <int dim>
707 Eigen::Matrix<double, dim*dim, dim*dim> FixedCorotational::compute_stiffness_from_def_grad(const Eigen::Matrix<double, dim, dim> &F, const double lambda, const double mu)
708 {
709 utils::AutoFlipSVD<Eigen::Matrix<double, dim, dim>> svd(F, Eigen::ComputeFullU | Eigen::ComputeFullV);
710 const Eigen::Vector<double, dim> sigmas = svd.singularValues();
711 Eigen::Matrix<double, dim, 1> dE_div_dsigma = compute_stress_from_singular_values(sigmas, lambda, mu);
712 Eigen::Matrix<double, dim, dim> d2E_div_dsigma2 = compute_stiffness_from_singular_values(sigmas, lambda, mu);
713
714 constexpr int Cdim2 = dim * (dim - 1) / 2;
715 Eigen::Matrix<double, Cdim2, 1> BLeftCoef;
716 BLeftCoef.setZero();
717 {
718 const double tmp = lambda / 2.0 * (sigmas.prod() - 1);
719 if constexpr (dim == 2) {
720 BLeftCoef[0] = mu - tmp;
721 }
722 else {
723 BLeftCoef[0] = mu - tmp * sigmas[2];
724 BLeftCoef[1] = mu - tmp * sigmas[0];
725 BLeftCoef[2] = mu - tmp * sigmas[1];
726 }
727 }
728 Eigen::Matrix2d B[Cdim2];
729 for (int cI = 0; cI < Cdim2; cI++) {
730 B[cI].setZero();
731 int cI_post = (cI + 1) % dim;
732
733 double rightCoef = dE_div_dsigma[cI] + dE_div_dsigma[cI_post];
734 double sum_sigma = sigmas[cI] + sigmas[cI_post];
735 rightCoef /= 2.0 * std::max(sum_sigma, 1.0e-12);
736
737 const double& leftCoef = BLeftCoef[cI];
738 B[cI](0, 0) = B[cI](1, 1) = leftCoef + rightCoef;
739 B[cI](0, 1) = B[cI](1, 0) = leftCoef - rightCoef;
740 }
741
742 // compute M using A(d2E_div_dsigma2) and B
743 Eigen::Matrix<double, dim * dim, dim * dim> M;
744 M.setZero();
745 if constexpr (dim == 2) {
746 M(0, 0) = d2E_div_dsigma2(0, 0);
747 M(0, 3) = d2E_div_dsigma2(0, 1);
748 M.block(1, 1, 2, 2) = B[0];
749 M(3, 0) = d2E_div_dsigma2(1, 0);
750 M(3, 3) = d2E_div_dsigma2(1, 1);
751 }
752 else {
753 // A
754 M(0, 0) = d2E_div_dsigma2(0, 0);
755 M(0, 4) = d2E_div_dsigma2(0, 1);
756 M(0, 8) = d2E_div_dsigma2(0, 2);
757 M(4, 0) = d2E_div_dsigma2(1, 0);
758 M(4, 4) = d2E_div_dsigma2(1, 1);
759 M(4, 8) = d2E_div_dsigma2(1, 2);
760 M(8, 0) = d2E_div_dsigma2(2, 0);
761 M(8, 4) = d2E_div_dsigma2(2, 1);
762 M(8, 8) = d2E_div_dsigma2(2, 2);
763 // B01
764 M(1, 1) = B[0](0, 0);
765 M(1, 3) = B[0](0, 1);
766 M(3, 1) = B[0](1, 0);
767 M(3, 3) = B[0](1, 1);
768 // B12
769 M(5, 5) = B[1](0, 0);
770 M(5, 7) = B[1](0, 1);
771 M(7, 5) = B[1](1, 0);
772 M(7, 7) = B[1](1, 1);
773 // B20
774 M(2, 2) = B[2](1, 1);
775 M(2, 6) = B[2](1, 0);
776 M(6, 2) = B[2](0, 1);
777 M(6, 6) = B[2](0, 0);
778 }
779
780 // compute hessian
781 Eigen::Matrix<double, dim*dim, dim*dim> hessian;
782 hessian.setZero();
783 const Eigen::Matrix<double, dim, dim>& U = svd.matrixU();
784 const Eigen::Matrix<double, dim, dim>& V = svd.matrixV();
785 for (int i = 0; i < dim; i++) {
786 // int _dim_i = i * dim;
787 for (int j = 0; j < dim; j++) {
788 int ij = i + j * dim;
789 for (int r = 0; r < dim; r++) {
790 // int _dim_r = r * dim;
791 for (int s = 0; s < dim; s++) {
792 int rs = r + s * dim;
793 if (ij > rs) {
794 // bottom left, same as upper right
795 continue;
796 }
797
798 if constexpr (dim == 2) {
799 hessian(ij, rs) = M(0, 0) * U(i, 0) * V(j, 0) * U(r, 0) * V(s, 0) + M(0, 3) * U(i, 0) * V(j, 0) * U(r, 1) * V(s, 1) + M(1, 1) * U(i, 0) * V(j, 1) * U(r, 0) * V(s, 1) + M(1, 2) * U(i, 0) * V(j, 1) * U(r, 1) * V(s, 0) + M(2, 1) * U(i, 1) * V(j, 0) * U(r, 0) * V(s, 1) + M(2, 2) * U(i, 1) * V(j, 0) * U(r, 1) * V(s, 0) + M(3, 0) * U(i, 1) * V(j, 1) * U(r, 0) * V(s, 0) + M(3, 3) * U(i, 1) * V(j, 1) * U(r, 1) * V(s, 1);
800 }
801 else {
802 hessian(ij, rs) = M(0, 0) * U(i, 0) * V(j, 0) * U(r, 0) * V(s, 0) + M(0, 4) * U(i, 0) * V(j, 0) * U(r, 1) * V(s, 1) + M(0, 8) * U(i, 0) * V(j, 0) * U(r, 2) * V(s, 2) + M(4, 0) * U(i, 1) * V(j, 1) * U(r, 0) * V(s, 0) + M(4, 4) * U(i, 1) * V(j, 1) * U(r, 1) * V(s, 1) + M(4, 8) * U(i, 1) * V(j, 1) * U(r, 2) * V(s, 2) + M(8, 0) * U(i, 2) * V(j, 2) * U(r, 0) * V(s, 0) + M(8, 4) * U(i, 2) * V(j, 2) * U(r, 1) * V(s, 1) + M(8, 8) * U(i, 2) * V(j, 2) * U(r, 2) * V(s, 2) + M(1, 1) * U(i, 0) * V(j, 1) * U(r, 0) * V(s, 1) + M(1, 3) * U(i, 0) * V(j, 1) * U(r, 1) * V(s, 0) + M(3, 1) * U(i, 1) * V(j, 0) * U(r, 0) * V(s, 1) + M(3, 3) * U(i, 1) * V(j, 0) * U(r, 1) * V(s, 0) + M(5, 5) * U(i, 1) * V(j, 2) * U(r, 1) * V(s, 2) + M(5, 7) * U(i, 1) * V(j, 2) * U(r, 2) * V(s, 1) + M(7, 5) * U(i, 2) * V(j, 1) * U(r, 1) * V(s, 2) + M(7, 7) * U(i, 2) * V(j, 1) * U(r, 2) * V(s, 1) + M(2, 2) * U(i, 0) * V(j, 2) * U(r, 0) * V(s, 2) + M(2, 6) * U(i, 0) * V(j, 2) * U(r, 2) * V(s, 0) + M(6, 2) * U(i, 2) * V(j, 0) * U(r, 0) * V(s, 2) + M(6, 6) * U(i, 2) * V(j, 0) * U(r, 2) * V(s, 0);
803 }
804
805 if (ij < rs)
806 hessian(rs, ij) = hessian(ij, rs);
807 }
808 }
809 }
810 }
811
812 return hessian;
813 }
814} // namespace polyfem::assembler
int V
double val
Definition Assembler.cpp:86
ElementAssemblyValues vals
Definition Assembler.cpp:22
int y
int z
int x
std::string stress() const
Definition Units.hpp:25
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,...
std::vector< Eigen::Matrix< double, Eigen::Dynamic, Eigen::Dynamic, 0, 3, 3 > > jac_it
static double compute_energy_from_def_grad(const Eigen::Matrix< double, dim, dim > &F, const double lambda, const double mu)
static Eigen::Matrix< double, dim, dim > compute_stress_from_def_grad(const Eigen::Matrix< double, dim, dim > &F, const double lambda, const double mu)
void compute_energy_aux_gradient_fast(const NonLinearAssemblerData &data, Eigen::VectorXd &G_flattened) const
Eigen::MatrixXd assemble_hessian(const NonLinearAssemblerData &data) const override
static Eigen::Vector< double, dim > compute_stress_from_singular_values(const Eigen::Vector< double, dim > &sigmas, const double lambda, const double mu)
static double compute_energy_from_singular_values(const Eigen::Vector< double, dim > &sigmas, const double lambda, const double mu)
void add_multimaterial(const int index, const json &params, const Units &units) override
static Eigen::Matrix< double, dim *dim, dim *dim > compute_stiffness_from_def_grad(const Eigen::Matrix< double, dim, dim > &F, const double lambda, const double mu)
double compute_energy_aux(const NonLinearAssemblerData &data) const
double compute_energy(const NonLinearAssemblerData &data) const override
static Eigen::Matrix< double, dim, dim > compute_stiffness_from_singular_values(const Eigen::Vector< double, dim > &sigmas, const double lambda, const double mu)
std::map< std::string, ParamFunc > parameters() const override
void assign_stress_tensor(const OutputData &data, const int all_size, const ElasticityTensorType &type, Eigen::MatrixXd &all, const std::function< Eigen::MatrixXd(const Eigen::MatrixXd &)> &fun) const override
void compute_stress_grad_multiply_mat(const OptAssemblerData &data, const Eigen::MatrixXd &mat, Eigen::MatrixXd &stress, Eigen::MatrixXd &result) const override
void compute_energy_hessian_aux_fast(const NonLinearAssemblerData &data, Eigen::MatrixXd &H) const
Eigen::VectorXd assemble_gradient(const NonLinearAssemblerData &data) const override
void compute_stress_grad_multiply_stress(const OptAssemblerData &data, Eigen::MatrixXd &stress, Eigen::MatrixXd &result) const override
void compute_dstress_dmu_dlambda(const OptAssemblerData &data, Eigen::MatrixXd &dstress_dmu, Eigen::MatrixXd &dstress_dlambda) const override
void lambda_mu(double px, double py, double pz, double x, double y, double z, double t, int el_id, double &lambda, double &mu) const
void add_multimaterial(const int index, const json &params, const bool is_volume, const std::string &stress_unit)
const basis::ElementBases & bs
const Eigen::MatrixXd & fun
const Eigen::MatrixXd & local_pts
const basis::ElementBases & gbs
const Eigen::JacobiSVD< MatrixType >::SingularValuesType & singularValues(void) const
Definition svd.hpp:317
const MatrixType & matrixV(void) const
Definition svd.hpp:335
const MatrixType & matrixU(void) const
Definition svd.hpp:326
Used for test only.
Eigen::Matrix< double, dim, dim > hat(const Eigen::Matrix< double, dim, 1 > &x)
Eigen::Matrix< double, dim, 1 > cross(const Eigen::Matrix< double, dim, 1 > &x, const Eigen::Matrix< double, dim, 1 > &y)
Eigen::MatrixXd pk2_from_cauchy(const Eigen::MatrixXd &stress, const Eigen::MatrixXd &F)
void compute_disp_grad_at_quad(const assembler::NonLinearAssemblerData &data, const AutoDiffVect &local_disp, const int p, const int size, AutoDiffGradMat &def_grad)
nlohmann::json json
Definition Common.hpp:9
void compute_diplacement_grad(const int size, const ElementAssemblyValues &vals, const Eigen::MatrixXd &local_pts, const int p, const Eigen::MatrixXd &displacement, Eigen::MatrixXd &displacement_grad)
void get_local_disp(const assembler::NonLinearAssemblerData &data, const int size, AutoDiffVect &local_disp)
Eigen::MatrixXd pk1_from_cauchy(const Eigen::MatrixXd &stress, const Eigen::MatrixXd &F)
Eigen::Matrix< double, 1, Eigen::Dynamic, Eigen::RowMajor, 1, 3 > RowVectorNd
Definition Types.hpp:13