PolyFEM
Loading...
Searching...
No Matches
ElasticityUtils.cpp
Go to the documentation of this file.
1#include "ElasticityUtils.hpp"
3
4#include <tinyexpr.h>
5
6namespace polyfem
7{
8 using namespace assembler;
9 using namespace basis;
10 using namespace utils;
11
12 double convert_to_lambda(const bool is_volume, const double E, const double nu)
13 {
14 if (is_volume)
15 return (E * nu) / ((1.0 + nu) * (1.0 - 2.0 * nu));
16
17 return (nu * E) / (1.0 - nu * nu);
18 }
19
20 double convert_to_mu(const double E, const double nu)
21 {
22 return E / (2.0 * (1.0 + nu));
23 }
24
25 Eigen::Matrix2d d_lambda_mu_d_E_nu(const bool is_volume, const double E, const double nu)
26 {
27 Eigen::Matrix2d A;
28 if (is_volume)
29 {
30 A(0, 0) = nu / ((1.0 + nu) * (1.0 - 2.0 * nu));
31 A(0, 1) = (E * (0.5 * nu * nu + 0.25)) / (pow(nu + 1., 2) * pow(0.5 - nu, 2));
32 }
33 else
34 {
35 A(0, 0) = nu / (1.0 - nu * nu);
36 A(0, 1) = (E * (1. + nu * nu)) / pow(-1. + nu * nu, 2);
37 }
38 A(1, 0) = 1 / (2 * (1 + nu));
39 A(1, 1) = -E / 2 * pow(1 + nu, -2);
40
41 return A;
42 }
43
44 Eigen::Matrix2d d_E_nu_d_lambda_mu(const bool is_volume, const double lambda, const double mu)
45 {
46 Eigen::Matrix2d A;
47 if (is_volume)
48 {
49 A(0, 0) = pow(mu / (lambda + mu), 2);
50 A(0, 1) = (3 * lambda * lambda + 4 * lambda * mu + 2 * mu * mu) / pow(lambda + mu, 2);
51 A(1, 0) = mu / 2 / pow(lambda + mu, 2);
52 A(1, 1) = -lambda / 2 / pow(lambda + mu, 2);
53 }
54 else
55 {
56 A(0, 0) = pow(2 * mu / (lambda + 2 * mu), 2);
57 A(0, 1) = (4 * lambda * lambda + 8 * lambda * mu + 8 * mu * mu) / pow(lambda + 2 * mu, 2);
58 A(1, 0) = mu * 2 / pow(lambda + 2 * mu, 2);
59 A(1, 1) = -lambda * 2 / pow(lambda + 2 * mu, 2);
60 }
61
62 return A;
63 }
64
65 double convert_to_E(const bool is_volume, const double lambda, const double mu)
66 {
67 if (is_volume)
68 return mu * (3.0 * lambda + 2.0 * mu) / (lambda + mu);
69
70 return 2 * mu * (2.0 * lambda + 2.0 * mu) / (lambda + 2.0 * mu);
71 }
72
73 double convert_to_nu(const bool is_volume, const double lambda, const double mu)
74 {
75 if (is_volume)
76 return lambda / (2.0 * (lambda + mu));
77
78 return lambda / (lambda + 2.0 * mu);
79 }
80
81 Eigen::VectorXd gradient_from_energy(const int size, const int n_bases, const assembler::NonLinearAssemblerData &data,
82 const std::function<DScalar1<double, Eigen::Matrix<double, 6, 1>>(const assembler::NonLinearAssemblerData &)> &fun6,
83 const std::function<DScalar1<double, Eigen::Matrix<double, 8, 1>>(const assembler::NonLinearAssemblerData &)> &fun8,
84 const std::function<DScalar1<double, Eigen::Matrix<double, 12, 1>>(const assembler::NonLinearAssemblerData &)> &fun12,
85 const std::function<DScalar1<double, Eigen::Matrix<double, 18, 1>>(const assembler::NonLinearAssemblerData &)> &fun18,
86 const std::function<DScalar1<double, Eigen::Matrix<double, 24, 1>>(const assembler::NonLinearAssemblerData &)> &fun24,
87 const std::function<DScalar1<double, Eigen::Matrix<double, 30, 1>>(const assembler::NonLinearAssemblerData &)> &fun30,
88 const std::function<DScalar1<double, Eigen::Matrix<double, 60, 1>>(const assembler::NonLinearAssemblerData &)> &fun60,
89 const std::function<DScalar1<double, Eigen::Matrix<double, 81, 1>>(const assembler::NonLinearAssemblerData &)> &fun81,
90 const std::function<DScalar1<double, Eigen::Matrix<double, Eigen::Dynamic, 1, 0, SMALL_N, 1>>(const assembler::NonLinearAssemblerData &)> &funN,
91 const std::function<DScalar1<double, Eigen::Matrix<double, Eigen::Dynamic, 1, 0, BIG_N, 1>>(const assembler::NonLinearAssemblerData &)> &funBigN,
93 {
94 Eigen::VectorXd grad;
95
96 switch (size * n_bases)
97 {
98 case 6:
99 {
100 auto auto_diff_energy = fun6(data);
101 grad = auto_diff_energy.getGradient();
102 break;
103 }
104 case 8:
105 {
106 auto auto_diff_energy = fun8(data);
107 grad = auto_diff_energy.getGradient();
108 break;
109 }
110 case 12:
111 {
112 auto auto_diff_energy = fun12(data);
113 grad = auto_diff_energy.getGradient();
114 break;
115 }
116 case 18:
117 {
118 auto auto_diff_energy = fun18(data);
119 grad = auto_diff_energy.getGradient();
120 break;
121 }
122 case 24:
123 {
124 auto auto_diff_energy = fun24(data);
125 grad = auto_diff_energy.getGradient();
126 break;
127 }
128 case 30:
129 {
130 auto auto_diff_energy = fun30(data);
131 grad = auto_diff_energy.getGradient();
132 break;
133 }
134 case 60:
135 {
136 auto auto_diff_energy = fun60(data);
137 grad = auto_diff_energy.getGradient();
138 break;
139 }
140 case 81:
141 {
142 auto auto_diff_energy = fun81(data);
143 grad = auto_diff_energy.getGradient();
144 break;
145 }
146 default: // default handled after with grad size
147 break;
148 }
149
150 if (grad.size() <= 0)
151 {
152 if (n_bases * size <= SMALL_N)
153 {
154 auto auto_diff_energy = funN(data);
155 grad = auto_diff_energy.getGradient();
156 }
157 else if (n_bases * size <= BIG_N)
158 {
159 auto auto_diff_energy = funBigN(data);
160 grad = auto_diff_energy.getGradient();
161 }
162 else
163 {
164 static bool show_message = true;
165
166 if (show_message)
167 {
168 logger().debug("[Warning] grad {}^{} not using static sizes", n_bases, size);
169 show_message = false;
170 }
171
172 auto auto_diff_energy = funn(data);
173 grad = auto_diff_energy.getGradient();
174 }
175 }
176
177 return grad;
178 }
179
180 Eigen::MatrixXd hessian_from_energy(const int size, const int n_bases, const assembler::NonLinearAssemblerData &data,
181 const std::function<DScalar2<double, Eigen::Matrix<double, 6, 1>, Eigen::Matrix<double, 6, 6>>(const assembler::NonLinearAssemblerData &)> &fun6,
182 const std::function<DScalar2<double, Eigen::Matrix<double, 8, 1>, Eigen::Matrix<double, 8, 8>>(const assembler::NonLinearAssemblerData &)> &fun8,
183 const std::function<DScalar2<double, Eigen::Matrix<double, 12, 1>, Eigen::Matrix<double, 12, 12>>(const assembler::NonLinearAssemblerData &)> &fun12,
184 const std::function<DScalar2<double, Eigen::Matrix<double, 18, 1>, Eigen::Matrix<double, 18, 18>>(const assembler::NonLinearAssemblerData &)> &fun18,
185 const std::function<DScalar2<double, Eigen::Matrix<double, 24, 1>, Eigen::Matrix<double, 24, 24>>(const assembler::NonLinearAssemblerData &)> &fun24,
186 const std::function<DScalar2<double, Eigen::Matrix<double, 30, 1>, Eigen::Matrix<double, 30, 30>>(const assembler::NonLinearAssemblerData &)> &fun30,
187 const std::function<DScalar2<double, Eigen::Matrix<double, 60, 1>, Eigen::Matrix<double, 60, 60>>(const assembler::NonLinearAssemblerData &)> &fun60,
188 const std::function<DScalar2<double, Eigen::Matrix<double, 81, 1>, Eigen::Matrix<double, 81, 81>>(const assembler::NonLinearAssemblerData &)> &fun81,
189 const std::function<DScalar2<double, Eigen::Matrix<double, Eigen::Dynamic, 1, 0, SMALL_N, 1>, Eigen::Matrix<double, Eigen::Dynamic, Eigen::Dynamic, 0, SMALL_N, SMALL_N>>(const assembler::NonLinearAssemblerData &)> &funN,
191 {
192 Eigen::MatrixXd hessian;
193#ifdef WIN32
194 (void)fun60;
195 (void)fun81;
196 (void)funN;
197#endif
198
199 switch (size * n_bases)
200 {
201 case 6:
202 {
203 auto auto_diff_energy = fun6(data);
204 hessian = auto_diff_energy.getHessian();
205 break;
206 }
207 case 8:
208 {
209 auto auto_diff_energy = fun8(data);
210 hessian = auto_diff_energy.getHessian();
211 break;
212 }
213 case 12:
214 {
215 auto auto_diff_energy = fun12(data);
216 hessian = auto_diff_energy.getHessian();
217 break;
218 }
219 case 18:
220 {
221 auto auto_diff_energy = fun18(data);
222 hessian = auto_diff_energy.getHessian();
223 break;
224 }
225 case 24:
226 {
227 auto auto_diff_energy = fun24(data);
228 hessian = auto_diff_energy.getHessian();
229 break;
230 }
231 case 30:
232 {
233 auto auto_diff_energy = fun30(data);
234 hessian = auto_diff_energy.getHessian();
235 break;
236 }
237#ifndef WIN32
238 case 60:
239 {
240 auto auto_diff_energy = fun60(data);
241 hessian = auto_diff_energy.getHessian();
242 break;
243 }
244 case 81:
245 {
246 auto auto_diff_energy = fun81(data);
247 hessian = auto_diff_energy.getHessian();
248 break;
249 }
250#endif
251 default: // default handled after with hessian size
252 break;
253 }
254
255 if (hessian.size() <= 0)
256 {
257#ifndef WIN32
258 if (n_bases * size <= SMALL_N)
259 {
260 auto auto_diff_energy = funN(data);
261 hessian = auto_diff_energy.getHessian();
262 }
263 else
264#endif
265 {
266 // On Windows/MSVC, the stack-backed dynamic Hessian path can overflow
267 // the stack for modest element sizes. Use the fully dynamic path there.
268 static bool show_message = true;
269
270 if (show_message)
271 {
272 logger().debug("[Warning] hessian {}*{} not using static sizes", n_bases, size);
273 show_message = false;
274 }
275
276 auto auto_diff_energy = funn(data);
277 hessian = auto_diff_energy.getHessian();
278 }
279 }
280
281 return hessian;
282 }
283
284 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)
285 {
286 assert(displacement.cols() == 1);
287
288 displacement_grad.setZero();
289
290 for (std::size_t j = 0; j < vals.basis_values.size(); ++j)
291 {
292 const auto &loc_val = vals.basis_values[j];
293
294 assert(loc_val.grad.rows() == local_pts.rows());
295 assert(loc_val.grad.cols() == size);
296
297 for (int d = 0; d < size; ++d)
298 {
299 for (std::size_t ii = 0; ii < loc_val.global.size(); ++ii)
300 {
301 displacement_grad.row(d) += loc_val.global[ii].val * loc_val.grad.row(p) * displacement(loc_val.global[ii].index * size + d);
302 }
303 }
304 }
305
306 displacement_grad = (displacement_grad * vals.jac_it[p]).eval();
307 }
308
309 void compute_diplacement_grad(const int size, const ElementBases &bs, const ElementAssemblyValues &vals, const Eigen::MatrixXd &local_pts, const int p, const Eigen::MatrixXd &displacement, Eigen::MatrixXd &displacement_grad)
310 {
311 assert(displacement.cols() == 1);
312
313 displacement_grad.setZero();
314
315 for (std::size_t j = 0; j < bs.bases.size(); ++j)
316 {
317 const Basis &b = bs.bases[j];
318 const auto &loc_val = vals.basis_values[j];
319
320 assert(bs.bases.size() == vals.basis_values.size());
321 assert(loc_val.grad.rows() == local_pts.rows());
322 assert(loc_val.grad.cols() == size);
323
324 for (int d = 0; d < size; ++d)
325 {
326 for (std::size_t ii = 0; ii < b.global().size(); ++ii)
327 {
328 displacement_grad.row(d) += b.global()[ii].val * loc_val.grad.row(p) * displacement(b.global()[ii].index * size + d);
329 }
330 }
331 }
332
333 displacement_grad = (displacement_grad * vals.jac_it[p]).eval();
334 }
335
336 double von_mises_stress_for_stress_tensor(const Eigen::MatrixXd &stress)
337 {
338 double von_mises_stress;
339
340 if (stress.rows() == 3)
341 {
342 von_mises_stress = 0.5 * (stress(0, 0) - stress(1, 1)) * (stress(0, 0) - stress(1, 1)) + 3.0 * stress(0, 1) * stress(1, 0);
343 von_mises_stress += 0.5 * (stress(2, 2) - stress(1, 1)) * (stress(2, 2) - stress(1, 1)) + 3.0 * stress(2, 1) * stress(2, 1);
344 von_mises_stress += 0.5 * (stress(2, 2) - stress(0, 0)) * (stress(2, 2) - stress(0, 0)) + 3.0 * stress(2, 0) * stress(2, 0);
345 }
346 else
347 {
348 // von_mises_stress = ( stress(0, 0) - stress(1, 1) ) * ( stress(0, 0) - stress(1, 1) ) + 3.0 * stress(0, 1) * stress(1, 0);
349 von_mises_stress = stress(0, 0) * stress(0, 0) - stress(0, 0) * stress(1, 1) + stress(1, 1) * stress(1, 1) + 3.0 * stress(0, 1) * stress(1, 0);
350 }
351
352 von_mises_stress = sqrt(fabs(von_mises_stress));
353
354 return von_mises_stress;
355 }
356
357 Eigen::MatrixXd pk1_from_cauchy(const Eigen::MatrixXd &stress, const Eigen::MatrixXd &F)
358 {
359 bool fnan = !(F.array() == F.array()).all();
360 bool stressnan = !(stress.array() == stress.array()).all();
361
362 if (fnan || stressnan)
363 return F;
364
365 return F.determinant() * stress * F.inverse().transpose();
366 }
367
368 Eigen::MatrixXd pk2_from_cauchy(const Eigen::MatrixXd &stress, const Eigen::MatrixXd &F)
369 {
370 bool fnan = !(F.array() == F.array()).all();
371 bool stressnan = !(stress.array() == stress.array()).all();
372
373 if (fnan || stressnan)
374 return F;
375
376 return F.determinant() * F.inverse() * stress * F.inverse().transpose();
377 }
378} // namespace polyfem
ElementAssemblyValues vals
Definition Assembler.cpp:25
stores per element basis values at given quadrature points and geometric mapping
std::vector< Eigen::Matrix< double, Eigen::Dynamic, Eigen::Dynamic, 0, 3, 3 > > jac_it
Represents one basis function and its gradient.
Definition Basis.hpp:44
Stores the basis functions for a given element in a mesh (facet in 2d, cell in 3d).
std::vector< Basis > bases
one basis function per node in the element
spdlog::logger & logger()
Retrieves the current logger.
Definition Logger.cpp:44
constexpr int SMALL_N
Eigen::MatrixXd pk2_from_cauchy(const Eigen::MatrixXd &stress, const Eigen::MatrixXd &F)
Eigen::MatrixXd hessian_from_energy(const int size, const int n_bases, const assembler::NonLinearAssemblerData &data, const std::function< DScalar2< double, Eigen::Matrix< double, 6, 1 >, Eigen::Matrix< double, 6, 6 > >(const assembler::NonLinearAssemblerData &)> &fun6, const std::function< DScalar2< double, Eigen::Matrix< double, 8, 1 >, Eigen::Matrix< double, 8, 8 > >(const assembler::NonLinearAssemblerData &)> &fun8, const std::function< DScalar2< double, Eigen::Matrix< double, 12, 1 >, Eigen::Matrix< double, 12, 12 > >(const assembler::NonLinearAssemblerData &)> &fun12, const std::function< DScalar2< double, Eigen::Matrix< double, 18, 1 >, Eigen::Matrix< double, 18, 18 > >(const assembler::NonLinearAssemblerData &)> &fun18, const std::function< DScalar2< double, Eigen::Matrix< double, 24, 1 >, Eigen::Matrix< double, 24, 24 > >(const assembler::NonLinearAssemblerData &)> &fun24, const std::function< DScalar2< double, Eigen::Matrix< double, 30, 1 >, Eigen::Matrix< double, 30, 30 > >(const assembler::NonLinearAssemblerData &)> &fun30, const std::function< DScalar2< double, Eigen::Matrix< double, 60, 1 >, Eigen::Matrix< double, 60, 60 > >(const assembler::NonLinearAssemblerData &)> &fun60, const std::function< DScalar2< double, Eigen::Matrix< double, 81, 1 >, Eigen::Matrix< double, 81, 81 > >(const assembler::NonLinearAssemblerData &)> &fun81, const std::function< DScalar2< double, Eigen::Matrix< double, Eigen::Dynamic, 1, 0, SMALL_N, 1 >, Eigen::Matrix< double, Eigen::Dynamic, Eigen::Dynamic, 0, SMALL_N, SMALL_N > >(const assembler::NonLinearAssemblerData &)> &funN, const std::function< DScalar2< double, Eigen::VectorXd, Eigen::MatrixXd >(const assembler::NonLinearAssemblerData &)> &funn)
double convert_to_E(const bool is_volume, const double lambda, const double mu)
constexpr int BIG_N
double convert_to_mu(const double E, const double nu)
double von_mises_stress_for_stress_tensor(const Eigen::MatrixXd &stress)
double convert_to_nu(const bool is_volume, const double lambda, const double mu)
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)
Eigen::MatrixXd pk1_from_cauchy(const Eigen::MatrixXd &stress, const Eigen::MatrixXd &F)
Eigen::VectorXd gradient_from_energy(const int size, const int n_bases, const assembler::NonLinearAssemblerData &data, const std::function< DScalar1< double, Eigen::Matrix< double, 6, 1 > >(const assembler::NonLinearAssemblerData &)> &fun6, const std::function< DScalar1< double, Eigen::Matrix< double, 8, 1 > >(const assembler::NonLinearAssemblerData &)> &fun8, const std::function< DScalar1< double, Eigen::Matrix< double, 12, 1 > >(const assembler::NonLinearAssemblerData &)> &fun12, const std::function< DScalar1< double, Eigen::Matrix< double, 18, 1 > >(const assembler::NonLinearAssemblerData &)> &fun18, const std::function< DScalar1< double, Eigen::Matrix< double, 24, 1 > >(const assembler::NonLinearAssemblerData &)> &fun24, const std::function< DScalar1< double, Eigen::Matrix< double, 30, 1 > >(const assembler::NonLinearAssemblerData &)> &fun30, const std::function< DScalar1< double, Eigen::Matrix< double, 60, 1 > >(const assembler::NonLinearAssemblerData &)> &fun60, const std::function< DScalar1< double, Eigen::Matrix< double, 81, 1 > >(const assembler::NonLinearAssemblerData &)> &fun81, const std::function< DScalar1< double, Eigen::Matrix< double, Eigen::Dynamic, 1, 0, SMALL_N, 1 > >(const assembler::NonLinearAssemblerData &)> &funN, const std::function< DScalar1< double, Eigen::Matrix< double, Eigen::Dynamic, 1, 0, BIG_N, 1 > >(const assembler::NonLinearAssemblerData &)> &funBigN, const std::function< DScalar1< double, Eigen::VectorXd >(const assembler::NonLinearAssemblerData &)> &funn)
double convert_to_lambda(const bool is_volume, const double E, const double nu)
Eigen::Matrix2d d_E_nu_d_lambda_mu(const bool is_volume, const double lambda, const double mu)
Eigen::Matrix2d d_lambda_mu_d_E_nu(const bool is_volume, const double E, const double nu)
Automatic differentiation scalar with first-order derivatives.
Definition autodiff.h:112
Automatic differentiation scalar with first- and second-order derivatives.
Definition autodiff.h:493