PolyFEM
Loading...
Searching...
No Matches
AMIPSEnergy.cpp
Go to the documentation of this file.
1#include "AMIPSEnergy.hpp"
2
4
6{
7 namespace {
8 template <int dim>
9 Eigen::Matrix<double, dim, dim> hat(const Eigen::Matrix<double, dim, 1> &x)
10 {
11
12 Eigen::Matrix<double, dim, dim> prod;
13 prod.setZero();
14
15 prod(0, 1) = -x(2);
16 prod(0, 2) = x(1);
17 prod(1, 0) = x(2);
18 prod(1, 2) = -x(0);
19 prod(2, 0) = -x(1);
20 prod(2, 1) = x(0);
21
22 return prod;
23 }
24
25 template <int dim>
26 Eigen::Matrix<double, dim, 1> cross(const Eigen::Matrix<double, dim, 1> &x, const Eigen::Matrix<double, dim, 1> &y)
27 {
28
29 Eigen::Matrix<double, dim, 1> z;
30 z.setZero();
31
32 z(0) = x(1) * y(2) - x(2) * y(1);
33 z(1) = x(2) * y(0) - x(0) * y(2);
34 z(2) = x(0) * y(1) - x(1) * y(0);
35
36 return z;
37 }
38 }
40 {
41 return compute_energy_aux<double>(data);
42 }
43
44 Eigen::VectorXd AMIPSEnergy::assemble_gradient(const NonLinearAssemblerData &data) const
45 {
46 Eigen::Matrix<double, Eigen::Dynamic, 1> gradient;
47
48 if (size() == 2)
49 {
50 switch (data.vals.basis_values.size())
51 {
52 case 3:
53 {
54 gradient.resize(6);
55 compute_energy_aux_gradient_fast<3, 2>(data, gradient);
56 break;
57 }
58 case 6:
59 {
60 gradient.resize(12);
61 compute_energy_aux_gradient_fast<6, 2>(data, gradient);
62 break;
63 }
64 case 10:
65 {
66 gradient.resize(20);
67 compute_energy_aux_gradient_fast<10, 2>(data, gradient);
68 break;
69 }
70 default:
71 {
72 gradient.resize(data.vals.basis_values.size() * 2);
73 compute_energy_aux_gradient_fast<Eigen::Dynamic, 2>(data, gradient);
74 break;
75 }
76 }
77 }
78 else // if (size() == 3)
79 {
80 assert(size() == 3);
81 switch (data.vals.basis_values.size())
82 {
83 case 4:
84 {
85 gradient.resize(12);
86 compute_energy_aux_gradient_fast<4, 3>(data, gradient);
87 break;
88 }
89 case 10:
90 {
91 gradient.resize(30);
92 compute_energy_aux_gradient_fast<10, 3>(data, gradient);
93 break;
94 }
95 case 20:
96 {
97 gradient.resize(60);
98 compute_energy_aux_gradient_fast<20, 3>(data, gradient);
99 break;
100 }
101 default:
102 {
103 gradient.resize(data.vals.basis_values.size() * 3);
104 compute_energy_aux_gradient_fast<Eigen::Dynamic, 3>(data, gradient);
105 break;
106 }
107 }
108 }
109
110 return gradient;
111 }
112
113 // Compute ∫ tr(FᵀF) / J^(1+2/dim) dxdydz
114 template <typename T>
116 {
117 typedef Eigen::Matrix<T, Eigen::Dynamic, 1> AutoDiffVect;
118 typedef Eigen::Matrix<T, Eigen::Dynamic, Eigen::Dynamic, 0, 3, 3> AutoDiffGradMat;
119
120 AutoDiffVect local_disp;
121 get_local_disp(data, size(), local_disp);
122
123 AutoDiffGradMat def_grad(size(), size());
124
125 T energy = T(0.0);
126
127 Eigen::MatrixXd standard(size(), size());
128 if (size() == 2)
129 standard << 1 , 0,
130 0.5, std::sqrt(3) / 2;
131 else
132 standard << 1, 0, 0,
133 0.5, std::sqrt(3) / 2., 0,
134 0.5, 0.5 / std::sqrt(3), std::sqrt(3) / 2.;
135 standard = standard.inverse().transpose().eval();
136
137 const int n_pts = data.da.size();
138 for (long p = 0; p < n_pts; ++p)
139 {
140 for (int i = 0; i < size(); ++i)
141 for (int j = 0; j < size(); ++j)
142 def_grad(i, j) = T(0);
143
144 for (size_t i = 0; i < data.vals.basis_values.size(); ++i)
145 def_grad += local_disp.segment(i * size(), size()) * data.vals.basis_values[i].grad.row(p);
146
147 AutoDiffGradMat jac_it(size(), size());
148 for (long k = 0; k < jac_it.size(); ++k)
149 jac_it(k) = T(data.vals.jac_it[p](k));
150 def_grad += jac_it.inverse();
151 def_grad = def_grad * standard;
152
153 const T powJ = pow(polyfem::utils::determinant(def_grad), size() == 2 ? 2. : 5. / 3.);
154 const T val = (def_grad.transpose() * def_grad).trace() / powJ;
155
156 energy += val * data.da(p);
157 }
158 return energy;
159 }
160
161 template <int n_basis, int dim>
162 void AMIPSEnergy::compute_energy_aux_gradient_fast(const NonLinearAssemblerData &data, Eigen::Matrix<double, Eigen::Dynamic, 1> &G_flattened) const
163 {
164 assert(data.x.cols() == 1);
165
166 const int n_pts = data.da.size();
167
168 Eigen::Matrix<double, n_basis, dim> local_disp(data.vals.basis_values.size(), size());
169 local_disp.setZero();
170 for (size_t i = 0; i < data.vals.basis_values.size(); ++i)
171 {
172 const auto &bs = data.vals.basis_values[i];
173 for (size_t ii = 0; ii < bs.global.size(); ++ii)
174 {
175 for (int d = 0; d < size(); ++d)
176 {
177 local_disp(i, d) += bs.global[ii].val * data.x(bs.global[ii].index * size() + d);
178 }
179 }
180 }
181
182 Eigen::Matrix<double, dim, dim> def_grad(size(), size());
183
184 Eigen::Matrix<double, n_basis, dim> G(data.vals.basis_values.size(), size());
185 G.setZero();
186
187 Eigen::MatrixXd standard(size(), size());
188 if (size() == 2)
189 standard << 1 , 0,
190 0.5, std::sqrt(3) / 2;
191 else
192 standard << 1, 0, 0,
193 0.5, std::sqrt(3) / 2., 0,
194 0.5, 0.5 / std::sqrt(3), std::sqrt(3) / 2.;
195 standard = standard.inverse().transpose().eval();
196
197 for (long p = 0; p < n_pts; ++p)
198 {
199 Eigen::Matrix<double, n_basis, dim> grad(data.vals.basis_values.size(), size());
200
201 for (size_t i = 0; i < data.vals.basis_values.size(); ++i)
202 {
203 grad.row(i) = data.vals.basis_values[i].grad.row(p);
204 }
205
206 Eigen::Matrix<double, dim, dim> jac_it = data.vals.jac_it[p];
207
208 // Id + grad d
209 def_grad = (local_disp.transpose() * grad + jac_it.inverse()) * standard;
210
211 double J = def_grad.determinant();
212 if (J <= 0)
213 J = std::nan("");
214
215 Eigen::Matrix<double, dim, dim> delJ_delF(size(), size());
216 delJ_delF.setZero();
217
218 if (dim == 2)
219 {
220
221 delJ_delF(0, 0) = def_grad(1, 1);
222 delJ_delF(0, 1) = -def_grad(1, 0);
223 delJ_delF(1, 0) = -def_grad(0, 1);
224 delJ_delF(1, 1) = def_grad(0, 0);
225 }
226
227 else if (dim == 3)
228 {
229 Eigen::Matrix<double, dim, 1> u(def_grad.rows());
230 Eigen::Matrix<double, dim, 1> v(def_grad.rows());
231 Eigen::Matrix<double, dim, 1> w(def_grad.rows());
232
233 u = def_grad.col(0);
234 v = def_grad.col(1);
235 w = def_grad.col(2);
236
237 delJ_delF.col(0) = cross<dim>(v, w);
238 delJ_delF.col(1) = cross<dim>(w, u);
239 delJ_delF.col(2) = cross<dim>(u, v);
240 }
241
242 const double m = (dim == 2) ? 2. : 5. / 3.;
243 const double powJ = pow(J, m);
244 Eigen::Matrix<double, dim, dim> gradient_temp = (2 * def_grad - (def_grad.squaredNorm() * m) / J * delJ_delF) / powJ;
245 Eigen::Matrix<double, n_basis, dim> gradient = grad * standard * gradient_temp.transpose();
246
247 G.noalias() += gradient * data.da(p);
248 }
249
250 Eigen::Matrix<double, dim, n_basis> G_T = G.transpose();
251
252 constexpr int N = (n_basis == Eigen::Dynamic) ? Eigen::Dynamic : n_basis * dim;
253 Eigen::Matrix<double, N, 1> temp(Eigen::Map<Eigen::Matrix<double, N, 1>>(G_T.data(), G_T.size()));
254 G_flattened = temp;
255 }
256
257 Eigen::MatrixXd AMIPSEnergy::assemble_hessian(const NonLinearAssemblerData &data) const
258 {
259 Eigen::MatrixXd hessian;
260
261 if (size() == 2)
262 {
263 switch (data.vals.basis_values.size())
264 {
265 case 3:
266 {
267 hessian.resize(6, 6);
268 hessian.setZero();
269 compute_energy_hessian_aux_fast<3, 2>(data, hessian);
270 break;
271 }
272 case 6:
273 {
274 hessian.resize(12, 12);
275 hessian.setZero();
276 compute_energy_hessian_aux_fast<6, 2>(data, hessian);
277 break;
278 }
279 case 10:
280 {
281 hessian.resize(20, 20);
282 hessian.setZero();
283 compute_energy_hessian_aux_fast<10, 2>(data, hessian);
284 break;
285 }
286 default:
287 {
288 hessian.resize(data.vals.basis_values.size() * 2, data.vals.basis_values.size() * 2);
289 hessian.setZero();
290 compute_energy_hessian_aux_fast<Eigen::Dynamic, 2>(data, hessian);
291 break;
292 }
293 }
294 }
295 else // if (size() == 3)
296 {
297 assert(size() == 3);
298 switch (data.vals.basis_values.size())
299 {
300 case 4:
301 {
302 hessian.resize(12, 12);
303 hessian.setZero();
304 compute_energy_hessian_aux_fast<4, 3>(data, hessian);
305 break;
306 }
307 case 10:
308 {
309 hessian.resize(30, 30);
310 hessian.setZero();
311 compute_energy_hessian_aux_fast<10, 3>(data, hessian);
312 break;
313 }
314 case 20:
315 {
316 hessian.resize(60, 60);
317 hessian.setZero();
318 compute_energy_hessian_aux_fast<20, 3>(data, hessian);
319 break;
320 }
321 default:
322 {
323 hessian.resize(data.vals.basis_values.size() * 3, data.vals.basis_values.size() * 3);
324 hessian.setZero();
325 compute_energy_hessian_aux_fast<Eigen::Dynamic, 3>(data, hessian);
326 break;
327 }
328 }
329 }
330
331 return hessian;
332 }
333
334 template <int n_basis, int dim>
336 {
337 assert(data.x.cols() == 1);
338
339 constexpr int N = (n_basis == Eigen::Dynamic) ? Eigen::Dynamic : n_basis * dim;
340 const int n_pts = data.da.size();
341
342 Eigen::Matrix<double, n_basis, dim> local_disp(data.vals.basis_values.size(), size());
343 local_disp.setZero();
344 for (size_t i = 0; i < data.vals.basis_values.size(); ++i)
345 {
346 const auto &bs = data.vals.basis_values[i];
347 for (size_t ii = 0; ii < bs.global.size(); ++ii)
348 {
349 for (int d = 0; d < size(); ++d)
350 {
351 local_disp(i, d) += bs.global[ii].val * data.x(bs.global[ii].index * size() + d);
352 }
353 }
354 }
355
356 Eigen::Matrix<double, dim, dim> def_grad(size(), size());
357
358 Eigen::MatrixXd standard(size(), size());
359 if (size() == 2)
360 standard << 1 , 0,
361 0.5, std::sqrt(3) / 2;
362 else
363 standard << 1, 0, 0,
364 0.5, std::sqrt(3) / 2., 0,
365 0.5, 0.5 / std::sqrt(3), std::sqrt(3) / 2.;
366 standard = standard.inverse().transpose().eval();
367
368 for (long p = 0; p < n_pts; ++p)
369 {
370 Eigen::Matrix<double, n_basis, dim> grad(data.vals.basis_values.size(), size());
371
372 for (size_t i = 0; i < data.vals.basis_values.size(); ++i)
373 {
374 grad.row(i) = data.vals.basis_values[i].grad.row(p);
375 }
376
377 Eigen::Matrix<double, dim, dim> jac_it = data.vals.jac_it[p];
378
379 // Id + grad d
380 def_grad = (local_disp.transpose() * grad + jac_it.inverse()) * standard;
381
382 Eigen::Matrix<double, dim * dim, dim * dim> hessian_temp;
383 {
384 typedef DScalar2<double, Eigen::Matrix<double, dim * dim, 1>, Eigen::Matrix<double, dim * dim, dim * dim>> Diff;
386
387 Eigen::Matrix<Diff, dim, dim> def_grad_ad(dim, dim);
388 for (int i = 0; i < def_grad.size(); i++)
389 def_grad_ad(i) = Diff(i, def_grad(i));
390
391 Diff val = pow(utils::determinant(def_grad_ad), -1. - 2. / dim) * def_grad_ad.squaredNorm();
392
393 hessian_temp = val.getHessian();
394 }
395
396 // const double J = def_grad.determinant();
397 // const double TrFFt = def_grad.squaredNorm();
398
399 // Eigen::Matrix<double, dim, dim> delJ_delF(size(), size());
400 // delJ_delF.setZero();
401 // Eigen::Matrix<double, dim * dim, dim * dim> del2J_delF2(size() * size(), size() * size());
402 // del2J_delF2.setZero();
403
404 // if (dim == 2)
405 // {
406 // delJ_delF(0, 0) = def_grad(1, 1);
407 // delJ_delF(0, 1) = -def_grad(1, 0);
408 // delJ_delF(1, 0) = -def_grad(0, 1);
409 // delJ_delF(1, 1) = def_grad(0, 0);
410
411 // del2J_delF2(0, 3) = 1;
412 // del2J_delF2(1, 2) = -1;
413 // del2J_delF2(2, 1) = -1;
414 // del2J_delF2(3, 0) = 1;
415 // }
416 // else if (size() == 3)
417 // {
418 // Eigen::Matrix<double, dim, 1> u(def_grad.rows());
419 // Eigen::Matrix<double, dim, 1> v(def_grad.rows());
420 // Eigen::Matrix<double, dim, 1> w(def_grad.rows());
421
422 // u = def_grad.col(0);
423 // v = def_grad.col(1);
424 // w = def_grad.col(2);
425
426 // delJ_delF.col(0) = cross<dim>(v, w);
427 // delJ_delF.col(1) = cross<dim>(w, u);
428 // delJ_delF.col(2) = cross<dim>(u, v);
429
430 // del2J_delF2.template block<dim, dim>(0, 6) = hat<dim>(v);
431 // del2J_delF2.template block<dim, dim>(6, 0) = -hat<dim>(v);
432 // del2J_delF2.template block<dim, dim>(0, 3) = -hat<dim>(w);
433 // del2J_delF2.template block<dim, dim>(3, 0) = hat<dim>(w);
434 // del2J_delF2.template block<dim, dim>(3, 6) = -hat<dim>(u);
435 // del2J_delF2.template block<dim, dim>(6, 3) = hat<dim>(u);
436 // }
437
438 // Eigen::Matrix<double, dim * dim, dim * dim> id = Eigen::Matrix<double, dim * dim, dim * dim>::Identity(size() * size(), size() * size());
439
440 // Eigen::Matrix<double, dim * dim, 1> g_j = Eigen::Map<const Eigen::Matrix<double, dim * dim, 1>>(delJ_delF.data(), delJ_delF.size());
441 // Eigen::Matrix<double, dim * dim, 1> F_flattened = Eigen::Map<const Eigen::Matrix<double, dim * dim, 1>>(def_grad.data(), def_grad.size());
442
443 // const double tmp = TrFFt / J / dim;
444 // const double Jpow = pow(J, 2. / dim);
445 // Eigen::Matrix<double, dim * dim, dim * dim> hessian_temp = -4. / dim / (Jpow * J) * (F_flattened - tmp * g_j) * g_j.transpose() +
446 // 2. / Jpow * (id - ((2 / dim * F_flattened - tmp * g_j) / J * g_j.transpose() + tmp * del2J_delF2));
447
448 Eigen::Matrix<double, dim * dim, N> delF_delU_tensor(jac_it.size(), grad.size());
449
450 for (size_t i = 0; i < local_disp.rows(); ++i)
451 {
452 for (size_t j = 0; j < local_disp.cols(); ++j)
453 {
454 Eigen::Matrix<double, dim, dim> temp(size(), size());
455 temp.setZero();
456 temp.row(j) = grad.row(i);
457 temp = temp * standard;
458 Eigen::Matrix<double, dim * dim, 1> temp_flattened(Eigen::Map<Eigen::Matrix<double, dim * dim, 1>>(temp.data(), temp.size()));
459 delF_delU_tensor.col(i * size() + j) = temp_flattened;
460 }
461 }
462
463 Eigen::Matrix<double, N, N> hessian = delF_delU_tensor.transpose() * hessian_temp * delF_delU_tensor;
464
465 H += hessian * data.da(p);
466 }
467 }
468
470 const int all_size,
471 const ElasticityTensorType &type,
472 Eigen::MatrixXd &all,
473 const std::function<Eigen::MatrixXd(const Eigen::MatrixXd &)> &fun) const
474 {
475 const auto &displacement = data.fun;
476 const auto &local_pts = data.local_pts;
477 const auto &bs = data.bs;
478 const auto &gbs = data.gbs;
479 const auto el_id = data.el_id;
480 const auto t = data.t;
481
482 Eigen::MatrixXd displacement_grad(size(), size());
483
484 assert(displacement.cols() == 1);
485
486 all.setZero(local_pts.rows(), all_size);
487 }
488
493
494 std::map<std::string, Assembler::ParamFunc> AMIPSEnergyAutodiff::parameters() const
495 {
496 return std::map<std::string, ParamFunc>();
497 }
498
499 void AMIPSEnergyAutodiff::add_multimaterial(const int index, const json &params, const Units &)
500 {
501 if (params.contains("canonical_transformation"))
502 {
503 canonical_transformation_.reserve(params["canonical_transformation"].size());
504 for (int i = 0; i < params["canonical_transformation"].size(); ++i)
505 {
506 Eigen::MatrixXd transform_matrix(size(), size());
507 for (int j = 0; j < size(); ++j)
508 for (int k = 0; k < size(); ++k)
509 transform_matrix(j, k) = params["canonical_transformation"][i][j][k];
510 canonical_transformation_.push_back(transform_matrix);
511 }
512 }
513 }
514
515} // namespace polyfem::assembler
double val
Definition Assembler.cpp:86
int y
int z
int x
std::map< std::string, ParamFunc > parameters() const override
std::vector< Eigen::MatrixXd > canonical_transformation_
void add_multimaterial(const int index, const json &params, const Units &units) override
double compute_energy(const NonLinearAssemblerData &data) const override
T compute_energy_aux(const NonLinearAssemblerData &data) const
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_energy_hessian_aux_fast(const NonLinearAssemblerData &data, Eigen::MatrixXd &H) const
Eigen::MatrixXd assemble_hessian(const NonLinearAssemblerData &data) const override
void compute_energy_aux_gradient_fast(const NonLinearAssemblerData &data, Eigen::VectorXd &G_flattened) const
Eigen::VectorXd assemble_gradient(const NonLinearAssemblerData &data) const override
std::vector< Eigen::Matrix< double, Eigen::Dynamic, Eigen::Dynamic, 0, 3, 3 > > jac_it
const basis::ElementBases & bs
const Eigen::MatrixXd & fun
const Eigen::MatrixXd & local_pts
const basis::ElementBases & gbs
Used for test only.
Eigen::Matrix< T, Eigen::Dynamic, Eigen::Dynamic, 0, 3, 3 > AutoDiffGradMat
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::Matrix< T, Eigen::Dynamic, 1 > AutoDiffVect
DScalar1< double, Eigen::Matrix< double, Eigen::Dynamic, 1 > > Diff
T determinant(const Eigen::Matrix< T, rows, cols, option, maxRow, maxCol > &mat)
nlohmann::json json
Definition Common.hpp:9
void get_local_disp(const assembler::NonLinearAssemblerData &data, const int size, AutoDiffVect &local_disp)
Automatic differentiation scalar with first- and second-order derivatives.
Definition autodiff.h:493
static void setVariableCount(size_t value)
Set the independent variable count used by the automatic differentiation layer.
Definition autodiff.h:54