GetFEM  5.5
getfem_nonlinear_elasticity.cc
1 /*===========================================================================
2 
3  Copyright (C) 2000-2026 Yves Renard
4 
5  This file is a part of GetFEM
6 
7  GetFEM is free software; you can redistribute it and/or modify it
8  under the terms of the GNU Lesser General Public License as published
9  by the Free Software Foundation; either version 3 of the License, or
10  (at your option) any later version along with the GCC Runtime Library
11  Exception either version 3.1 or (at your option) any later version.
12  This program is distributed in the hope that it will be useful, but
13  WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
14  or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public
15  License and GCC Runtime Library Exception for more details.
16  You should have received a copy of the GNU Lesser General Public License
17  along with this program. If not, see https://www.gnu.org/licenses/.
18 
19 ===========================================================================*/
20 
21 
22 #include "getfem/getfem_models.h"
25 
26 namespace getfem {
27 
28 
29  /* Useful functions to compute the invariants and their derivatives
30  Note that the second derivative is symmetrized (see the user
31  documentation for more details). The matrix E is assumed to be symmetric.
32  */
33 
34 
35  static scalar_type frobenius_product_trans(const base_matrix &A,
36  const base_matrix &B) {
37  size_type N = gmm::mat_nrows(A);
38  scalar_type res = scalar_type(0);
39  for (size_type i = 0; i < N; ++i)
40  for (size_type j = 0; j < N; ++j)
41  res += A(i, j) * B(j, i);
42  return res;
43  }
44 
45  struct compute_invariants {
46 
47  const base_matrix &E;
48  base_matrix Einv;
49  size_type N;
50  scalar_type i1_, i2_, i3_, j1_, j2_;
51  bool i1_c, i2_c, i3_c, j1_c, j2_c;
52 
53  base_matrix di1, di2, di3, dj1, dj2;
54  bool di1_c, di2_c, di3_c, dj1_c, dj2_c;
55 
56  base_tensor ddi1, ddi2, ddi3, ddj1, ddj2;
57  bool ddi1_c, ddi2_c, ddi3_c, ddj1_c, ddj2_c;
58 
59 
60  /* First invariant tr(E) */
61  void compute_i1() {
62  i1_ = gmm::mat_trace(E);
63  i1_c = true;
64  }
65 
66  void compute_di1() {
67  gmm::resize(di1, N, N);
68  gmm::copy(gmm::identity_matrix(), di1);
69  di1_c = true;
70  }
71 
72  void compute_ddi1() { // not very useful, null tensor
73  ddi1 = base_tensor(N, N, N, N);
74  ddi1_c = true;
75  }
76 
77  inline scalar_type i1()
78  { if (!i1_c) compute_i1(); return i1_; }
79 
80  inline const base_matrix &grad_i1()
81  { if (!di1_c) compute_di1(); return di1; }
82 
83  inline const base_tensor &sym_grad_grad_i1()
84  { if (!ddi1_c) compute_ddi1(); return ddi1; }
85 
86 
87  /* Second invariant (tr(E)^2 - tr(E^2))/2 */
88  void compute_i2() {
89  i2_ = (gmm::sqr(gmm::mat_trace(E))
90  - frobenius_product_trans(E, E)) / scalar_type(2);
91  i2_c = true;
92  }
93 
94  void compute_di2() {
95  gmm::resize(di2, N, N);
96  gmm::copy(gmm::identity_matrix(), di2);
97  gmm::scale(di2, i1());
98  // gmm::add(gmm::scale(gmm::transposed(E), -scalar_type(1)), di2);
99  gmm::add(gmm::scaled(E, -scalar_type(1)), di2);
100  di2_c = true;
101  }
102 
103  void compute_ddi2() {
104  ddi2 = base_tensor(N, N, N, N);
105  for (size_type i = 0; i < N; ++i)
106  for (size_type k = 0; k < N; ++k)
107  ddi2(i,i,k,k) += scalar_type(1);
108  for (size_type i = 0; i < N; ++i)
109  for (size_type j = 0; j < N; ++j) {
110  ddi2(i,j,j,i) -= scalar_type(1)/scalar_type(2);
111  ddi2(j,i,j,i) -= scalar_type(1)/scalar_type(2);
112  }
113  ddi2_c = true;
114  }
115 
116  inline scalar_type i2()
117  { if (!i2_c) compute_i2(); return i2_; }
118 
119  inline const base_matrix &grad_i2()
120  { if (!di2_c) compute_di2(); return di2; }
121 
122  inline const base_tensor &sym_grad_grad_i2()
123  { if (!ddi2_c) compute_ddi2(); return ddi2; }
124 
125  /* Third invariant det(E) */
126  void compute_i3() {
127  Einv = E;
128  i3_ = bgeot::lu_inverse(&(*(Einv.begin())), gmm::mat_nrows(Einv));
129  i3_c = true;
130  }
131 
132  void compute_di3() {
133  scalar_type det = i3();
134  // gmm::resize(di3, N, N);
135  // gmm::copy(gmm::transposed(E), di3);
136  di3 = Einv;
137  // gmm::lu_inverse(di3);
138  gmm::scale(di3, det);
139  di3_c = true;
140  }
141 
142  void compute_ddi3() {
143  ddi3 = base_tensor(N, N, N, N);
144  scalar_type det = i3() / scalar_type(2); // computes also E inverse.
145  for (size_type i = 0; i < N; ++i)
146  for (size_type j = 0; j < N; ++j)
147  for (size_type k = 0; k < N; ++k)
148  for (size_type l = 0; l < N; ++l)
149  ddi3(i,j,k,l) = det*(Einv(j,i)*Einv(l,k) - Einv(j,k)*Einv(l,i)
150  + Einv(i,j)*Einv(l,k) - Einv(i,k)*Einv(l,j));
151  ddi3_c = true;
152  }
153 
154  inline scalar_type i3()
155  { if (!i3_c) compute_i3(); return i3_; }
156 
157  inline const base_matrix &grad_i3()
158  { if (!di3_c) compute_di3(); return di3; }
159 
160  inline const base_tensor &sym_grad_grad_i3()
161  { if (!ddi3_c) compute_ddi3(); return ddi3; }
162 
163  /* Invariant j1(E) = i1(E)*i3(E)^(-1/3) */
164  void compute_j1() {
165  j1_ = i1() * ::pow(gmm::abs(i3()), -scalar_type(1) / scalar_type(3));
166  j1_c = true;
167  }
168 
169  void compute_dj1() {
170  dj1 = grad_i1();
171  gmm::add(gmm::scaled(grad_i3(), -i1() / (scalar_type(3) * i3())), dj1);
172  gmm::scale(dj1, ::pow(gmm::abs(i3()), -scalar_type(1) / scalar_type(3)));
173  dj1_c = true;
174  }
175 
176  void compute_ddj1() {
177  const base_matrix &di1_ = grad_i1();
178  const base_matrix &di3_ = grad_i3();
179  scalar_type coeff1 = scalar_type(1) / (scalar_type(3)*i3());
180  scalar_type coeff2 = scalar_type(4) * coeff1 * coeff1 * i1();
181  ddj1 = sym_grad_grad_i3();
182  gmm::scale(ddj1.as_vector(), -i1() * coeff1);
183 
184  for (size_type i = 0; i < N; ++i)
185  for (size_type j = 0; j < N; ++j)
186  for (size_type k = 0; k < N; ++k)
187  for (size_type l = 0; l < N; ++l)
188  ddj1(i,j,k,l) +=
189  (di3_(i, j) * di3_(k, l)) * coeff2
190  - (di1_(i, j) * di3_(k, l) + di1_(k, l) * di3_(i, j)) * coeff1;
191 
192  gmm::scale(ddj1.as_vector(),
193  ::pow(gmm::abs(i3()), -scalar_type(1)/scalar_type(3)));
194  ddj1_c = true;
195  }
196 
197  inline scalar_type j1()
198  { if (!j1_c) compute_j1(); return j1_; }
199 
200  inline const base_matrix &grad_j1()
201  { if (!dj1_c) compute_dj1(); return dj1; }
202 
203  inline const base_tensor &sym_grad_grad_j1()
204  { if (!ddj1_c) compute_ddj1(); return ddj1; }
205 
206  /* Invariant j2(E) = i2(E)*i3(E)^(-2/3) */
207  void compute_j2() {
208  j2_ = i2() * ::pow(gmm::abs(i3()), -scalar_type(2) / scalar_type(3));
209  j2_c = true;
210  }
211 
212  void compute_dj2() {
213  dj2 = grad_i2();
214  gmm::add(gmm::scaled(grad_i3(), -scalar_type(2) * i2() / (scalar_type(3) * i3())), dj2);
215  gmm::scale(dj2, ::pow(gmm::abs(i3()), -scalar_type(2) / scalar_type(3)));
216  dj2_c = true;
217  }
218 
219  void compute_ddj2() {
220  const base_matrix &di2_ = grad_i2();
221  const base_matrix &di3_ = grad_i3();
222  scalar_type coeff1 = scalar_type(2) / (scalar_type(3)*i3());
223  scalar_type coeff2 = scalar_type(5)*coeff1*coeff1*i2() / scalar_type(2);
224  ddj2 = sym_grad_grad_i2();
225  gmm::add(gmm::scaled(sym_grad_grad_i3().as_vector(), -i2() * coeff1),
226  ddj2.as_vector());
227 
228  for (size_type i = 0; i < N; ++i)
229  for (size_type j = 0; j < N; ++j)
230  for (size_type k = 0; k < N; ++k)
231  for (size_type l = 0; l < N; ++l)
232  ddj2(i,j,k,l) +=
233  (di3_(i, j) * di3_(k, l)) * coeff2
234  - (di2_(i, j) * di3_(k, l) + di2_(k, l) * di3_(i, j)) * coeff1;
235 
236  gmm::scale(ddj2.as_vector(),
237  ::pow(gmm::abs(i3()), -scalar_type(2)/scalar_type(3)));
238  ddj2_c = true;
239  }
240 
241 
242  inline scalar_type j2()
243  { if (!j2_c) compute_j2(); return j2_; }
244 
245  inline const base_matrix &grad_j2()
246  { if (!dj2_c) compute_dj2(); return dj2; }
247 
248  inline const base_tensor &sym_grad_grad_j2()
249  { if (!ddj2_c) compute_ddj2(); return ddj2; }
250 
251 
252  compute_invariants(const base_matrix &EE)
253  : E(EE), i1_c(false), i2_c(false), i3_c(false),
254  j1_c(false), j2_c(false), di1_c(false), di2_c(false), di3_c(false),
255  dj1_c(false), dj2_c(false), ddi1_c(false), ddi2_c(false),
256  ddi3_c(false), ddj1_c(false), ddj2_c(false)
257  {
258  N = gmm::mat_nrows(E);
259  i1_=i2_=i3_=j1_=j2_=0.;
260  }
261 
262  };
263 
264 
265 
266 
267 
268  /* Symmetry check */
269 
270  int check_symmetry(const base_tensor &t) {
271  int flags = 7; size_type N = 3;
272  for (size_type n = 0; n < N; ++n)
273  for (size_type m = 0; m < N; ++m)
274  for (size_type l = 0; l < N; ++l)
275  for (size_type k = 0; k < N; ++k) {
276  if (gmm::abs(t(n,m,l,k) - t(l,k,n,m))>1e-5) flags &= (~1);
277  if (gmm::abs(t(n,m,l,k) - t(m,n,l,k))>1e-5) flags &= (~2);
278  if (gmm::abs(t(n,m,l,k) - t(n,m,k,l))>1e-5) flags &= (~4);
279  }
280  return flags;
281  }
282 
283  /* Member functions of hyperelastic laws */
284 
285  void abstract_hyperelastic_law::random_E(base_matrix &E) {
286  size_type N = gmm::mat_nrows(E);
287  base_matrix Phi(N,N);
288  scalar_type d;
289  do {
290  gmm::fill_random(Phi);
291  d = bgeot::lu_det(&(*(Phi.begin())), N);
292  } while (d < scalar_type(0.01));
293  gmm::mult(gmm::transposed(Phi),Phi,E);
294  gmm::scale(E,-1.); gmm::add(gmm::identity_matrix(),E);
295  gmm::scale(E,-0.5);
296  }
297 
298  void abstract_hyperelastic_law::test_derivatives
299  (size_type N, scalar_type h, const base_vector& param) const {
300  base_matrix E(N,N), E2(N,N), DE(N,N);
301  bool ok = true;
302 
303  for (size_type count = 0; count < 100; ++count) {
304  random_E(E); random_E(DE);
305  gmm::scale(DE, h);
306  gmm::add(E, DE, E2);
307 
308  base_matrix sigma1(N,N), sigma2(N,N);
309  getfem::base_tensor tdsigma(N,N,N,N);
310  base_matrix dsigma(N,N);
311  gmm::copy(E, E2); gmm::add(DE, E2);
312  sigma(E, sigma1, param, scalar_type(1));
313  sigma(E2, sigma2, param, scalar_type(1));
314 
315  scalar_type d = strain_energy(E2, param, scalar_type(1))
316  - strain_energy(E, param, scalar_type(1));
317  scalar_type d2 = 0;
318  for (size_type i=0; i < N; ++i)
319  for (size_type j=0; j < N; ++j) d2 += sigma1(i,j)*DE(i,j);
320  if (gmm::abs(d-d2)/(gmm::abs(d)+1e-40) > 1e-4) {
321  cout << "Test " << count << " wrong derivative of strain_energy, d="
322  << d/h << ", d2=" << d2/h << endl;
323  ok = false;
324  }
325 
326  grad_sigma(E,tdsigma,param, scalar_type(1));
327  for (size_type i=0; i < N; ++i) {
328  for (size_type j=0; j < N; ++j) {
329  dsigma(i,j) = 0;
330  for (size_type k=0; k < N; ++k) {
331  for (size_type m=0; m < N; ++m) {
332  dsigma(i,j) += tdsigma(i,j,k,m)*DE(k,m);
333  }
334  }
335  sigma2(i,j) -= sigma1(i,j);
336  if (gmm::abs(dsigma(i,j) - sigma2(i,j))
337  /(gmm::abs(dsigma(i,j)) + 1e-40) > 1.5e-4) {
338  cout << "Test " << count << " wrong derivative of sigma, i="
339  << i << ", j=" << j << ", dsigma=" << dsigma(i,j)/h
340  << ", var sigma = " << sigma2(i,j)/h << endl;
341  ok = false;
342  }
343  }
344  }
345  }
346  GMM_ASSERT1(ok, "Derivative test has failed");
347  }
348 
350  (const base_matrix& F, const base_matrix &E,
351  base_matrix &cauchy_stress, const base_vector &params,
352  scalar_type det_trans) const
353  {
354  size_type N = E.ncols();
355  base_matrix PK2(N,N);
356  sigma(E,PK2,params,det_trans);//second Piola-Kirchhoff stress
357  base_matrix aux(N,N);
358  gmm::mult(F,PK2,aux);
359  gmm::mult(aux,gmm::transposed(F),cauchy_stress);
360  gmm::scale(cauchy_stress,scalar_type(1.0/det_trans)); //cauchy = 1/J*F*PK2*F^T
361  }
362 
363 
365  (const base_matrix& F, const base_matrix& E,
366  const base_vector &params, scalar_type det_trans,
367  base_tensor &grad_sigma_ul) const
368  {
369  size_type N = E.ncols();
370  base_tensor Cse(N,N,N,N);
371  grad_sigma(E,Cse,params,det_trans);
372  scalar_type mult = 1.0/det_trans;
373  // this is a general transformation for an anisotropic material, very non-efficient;
374  // more effiecient calculations can be overloaded for every specific material
375  for(size_type i = 0; i < N; ++i)
376  for(size_type j = 0; j < N; ++j)
377  for(size_type k = 0; k < N; ++k)
378  for(size_type l = 0; l < N; ++l)
379  {
380  grad_sigma_ul(i,j,k,l) = 0.0;
381  for(size_type m = 0; m < N; ++m)
382  { for(size_type n = 0; n < N; ++n)
383  for(size_type p = 0; p < N; ++p)
384  for(size_type q = 0; q < N; ++q)
385  grad_sigma_ul(i,j,k,l)+=
386  F(i,m)*F(j,n)*F(k,p)*F(l,q)*Cse(m,n,p,q);
387  }
388  grad_sigma_ul(i,j,k,l) *= mult;
389  }
390  }
391 
392  scalar_type SaintVenant_Kirchhoff_hyperelastic_law::strain_energy
393  (const base_matrix &E, const base_vector &params, scalar_type det_trans) const {
394  // should be optimized, maybe deriving sigma from strain energy
395  if (det_trans <= scalar_type(0))
396  { return 1e200; }
397 
398  return gmm::sqr(gmm::mat_trace(E)) * params[0] / scalar_type(2)
399  + gmm::mat_euclidean_norm_sqr(E) * params[1];
400  }
401 
402  void SaintVenant_Kirchhoff_hyperelastic_law::sigma
403  (const base_matrix &E, base_matrix &result,const base_vector &params, scalar_type det_trans) const {
404  gmm::copy(gmm::identity_matrix(), result);
405  gmm::scale(result, params[0] * gmm::mat_trace(E));
406  gmm::add(gmm::scaled(E, 2 * params[1]), result);
407  if (det_trans <= scalar_type(0)) {
408  gmm::add(gmm::scaled(E, 1e200), result);
409  }
410  }
411  void SaintVenant_Kirchhoff_hyperelastic_law::grad_sigma
412  (const base_matrix &E, base_tensor &result,const base_vector &params, scalar_type) const {
413  std::fill(result.begin(), result.end(), scalar_type(0));
414  size_type N = gmm::mat_nrows(E);
415  for (size_type i = 0; i < N; ++i)
416  for (size_type l = 0; l < N; ++l) {
417  result(i, i, l, l) += params[0];
418  result(i, l, i, l) += params[1]/scalar_type(2);
419  result(i, l, l, i) += params[1]/scalar_type(2);
420  result(l, i, i, l) += params[1]/scalar_type(2);
421  result(l, i, l, i) += params[1]/scalar_type(2);
422  }
423  }
424 
426  const base_matrix& E,
427  const base_vector &params,
428  scalar_type det_trans,
429  base_tensor &grad_sigma_ul)const
430  {
431  size_type N = E.ncols();
432  base_tensor Cse(N,N,N,N);
433  grad_sigma(E,Cse,params,det_trans);
434  base_matrix Cinv(N,N); // left Cauchy-Green deform. tens.
435  gmm::mult(F,gmm::transposed(F),Cinv);
436  scalar_type mult=1.0/det_trans;
437  for(size_type i = 0; i < N; ++i)
438  for(size_type j = 0; j < N; ++j)
439  for(size_type k = 0; k < N; ++k)
440  for(size_type l = 0; l < N; ++l)
441  grad_sigma_ul(i, j, k, l)= (Cinv(i,j)*Cinv(k,l)*params[0] +
442  params[1]*(Cinv(i,k)*Cinv(j,l) + Cinv(i,l)*Cinv(j,k)))*mult;
443  }
444 
445  SaintVenant_Kirchhoff_hyperelastic_law::SaintVenant_Kirchhoff_hyperelastic_law() {
446  nb_params_ = 2;
447  }
448 
449  scalar_type membrane_elastic_law::strain_energy
450  (const base_matrix & /* E */, const base_vector & /* params */, scalar_type) const {
451  // to be done if needed
452  GMM_ASSERT1(false, "To be done");
453  return 0;
454  }
455 
456  void membrane_elastic_law::sigma
457  (const base_matrix &E, base_matrix &result,const base_vector &params, scalar_type det_trans) const {
458  // should be optimized, maybe deriving sigma from strain energy
459  base_tensor tt(2,2,2,2);
460  size_type N = (gmm::mat_nrows(E) > 2)? 2 : gmm::mat_nrows(E);
461  grad_sigma(E,tt,params, det_trans);
462  for (size_type i = 0; i < N; ++i)
463  for (size_type j = 0; j < N; ++j) {
464  result(i,j)=0.0;
465  for (size_type k = 0; k < N; ++k)
466  for (size_type l = 0; l < N; ++l)
467  result(i,j)+=tt(i,j,k,l)*E(k,l);
468  }
469  // add pretension in X' direction
470  if(params[4]!=0) result(0,0)+=params[4];
471  // add pretension in Y' direction
472  if(params[5]!=0) result(1,1)+=params[5];
473  // cout<<"sigma="<<result<<endl;
474  }
475 
476  void membrane_elastic_law::grad_sigma
477  (const base_matrix & /* E */, base_tensor &result,
478  const base_vector &params, scalar_type) const {
479  // to be optimized!!
480  std::fill(result.begin(), result.end(), scalar_type(0));
481  scalar_type poisonXY=params[0]*params[1]/params[2]; //Ex*vYX=Ey*vXY
482  //if no G entered, compute G=E/(2*(1+v))
483  scalar_type G=( params[3] == 0) ? params[0]/(2*(1+params[1])) : params[3];
484  std::fill(result.begin(), result.end(), scalar_type(0));
485  result(0,0,0,0) = params[0]/(1-params[1]*poisonXY);
486  // result(0,0,0,1) = 0;
487  // result(0,0,1,0) = 0;
488  result(0,0,1,1) = params[1]*params[0]/(1-params[1]*poisonXY);
489  result(1,1,0,0) = params[1]*params[0]/(1-params[1]*poisonXY);
490  // result(1,1,0,1) = 0;
491  // result(1,1,1,0) = 0;
492  result(1,1,1,1) = params[2]/(1-params[1]*poisonXY);
493  // result(0,1,0,0) = 0;
494  result(0,1,0,1) = G;
495  result(0,1,1,0) = G;
496  // result(0,1,1,1) = 0;
497  // result(1,0,0,0) = 0;
498  result(1,0,0,1) = G;
499  result(1,0,1,0) = G;
500  // result(1,0,1,1) = 0;
501  }
502 
503  scalar_type Mooney_Rivlin_hyperelastic_law::strain_energy
504  (const base_matrix &E, const base_vector &params
505  ,scalar_type det_trans) const {
506  //shouldn't negative det_trans be handled here???
507  if (compressible && det_trans <= scalar_type(0)) return 1e200;
508  size_type N = gmm::mat_nrows(E);
509  GMM_ASSERT1(N == 3, "Mooney Rivlin hyperelastic law only defined "
510  "on dimension 3, sorry");
511  base_matrix C = E;
512  gmm::scale(C, scalar_type(2));
513  gmm::add(gmm::identity_matrix(), C);
514  compute_invariants ci(C);
515  size_type i=0;
516  scalar_type C1 = params[i++]; // C10
517  scalar_type W = C1 * (ci.j1() - scalar_type(3));
518  if (!neohookean) {
519  scalar_type C2 = params[i++]; // C01
520  W += C2 * (ci.j2() - scalar_type(3));
521  }
522  if (compressible) {
523  scalar_type D1 = params[i++];
524  W += D1 * gmm::sqr(sqrt(gmm::abs(ci.i3())) - scalar_type(1));
525  }
526  return W;
527  }
528 
529  void Mooney_Rivlin_hyperelastic_law::sigma
530  (const base_matrix &E, base_matrix &result,
531  const base_vector &params, scalar_type det_trans) const {
532  size_type N = gmm::mat_nrows(E);
533  GMM_ASSERT1(N == 3, "Mooney Rivlin hyperelastic law only defined "
534  "on dimension 3, sorry");
535  base_matrix C = E;
536  gmm::scale(C, scalar_type(2));
537  gmm::add(gmm::identity_matrix(), C);
538  compute_invariants ci(C);
539 
540  size_type i=0;
541  scalar_type C1 = params[i++]; // C10
542  gmm::copy(gmm::scaled(ci.grad_j1(), scalar_type(2) * C1), result);
543  if (!neohookean) {
544  scalar_type C2 = params[i++]; // C01
545  gmm::add(gmm::scaled(ci.grad_j2(), scalar_type(2) * C2), result);
546  }
547  if (compressible) {
548  scalar_type D1 = params[i++];
549  scalar_type di3 = D1 - D1 / sqrt(gmm::abs(ci.i3()));
550  gmm::add(gmm::scaled(ci.grad_i3(), scalar_type(2) * di3), result);
551 
552 // shouldn't negative det_trans be handled here???
553  if (det_trans <= scalar_type(0))
554  gmm::add(gmm::scaled(C, 1e200), result);
555  }
556  }
557 
558  void Mooney_Rivlin_hyperelastic_law::grad_sigma
559  (const base_matrix &E, base_tensor &result,
560  const base_vector &params, scalar_type) const {
561  size_type N = gmm::mat_nrows(E);
562  GMM_ASSERT1(N == 3, "Mooney Rivlin hyperelastic law only defined "
563  "on dimension 3, sorry");
564  base_matrix C = E;
565  gmm::scale(C, scalar_type(2));
566  gmm::add(gmm::identity_matrix(), C);
567  compute_invariants ci(C);
568 
569  size_type i=0;
570  scalar_type C1 = params[i++]; // C10
571  gmm::copy(gmm::scaled(ci.sym_grad_grad_j1().as_vector(),
572  scalar_type(4)*C1), result.as_vector());
573  if (!neohookean) {
574  scalar_type C2 = params[i++]; // C01
575  gmm::add(gmm::scaled(ci.sym_grad_grad_j2().as_vector(),
576  scalar_type(4)*C2), result.as_vector());
577  }
578  if (compressible) {
579  scalar_type D1 = params[i++];
580  scalar_type di3 = D1 - D1 / sqrt(gmm::abs(ci.i3()));
581  gmm::add(gmm::scaled(ci.sym_grad_grad_i3().as_vector(),
582  scalar_type(4)*di3), result.as_vector());
583 
584  // second derivatives of W with respect to the third invariant
585  scalar_type A22 = D1 / (scalar_type(2) * pow(gmm::abs(ci.i3()), 1.5));
586  const base_matrix &di = ci.grad_i3();
587  for (size_type l1 = 0; l1 < N; ++l1)
588  for (size_type l2 = 0; l2 < N; ++l2)
589  for (size_type l3 = 0; l3 < N; ++l3)
590  for (size_type l4 = 0; l4 < N; ++l4)
591  result(l1, l2, l3, l4) +=
592  scalar_type(4) * A22 * di(l1, l2) * di(l3, l4);
593  }
594 
595 // GMM_ASSERT1(check_symmetry(result) == 7,
596 // "Fourth order tensor not symmetric : " << result);
597  }
598 
599  Mooney_Rivlin_hyperelastic_law::Mooney_Rivlin_hyperelastic_law
600  (bool compressible_, bool neohookean_)
601  : compressible(compressible_), neohookean(neohookean_)
602  {
603  nb_params_ = 2;
604  if (compressible) ++nb_params_; // D1 != 0
605  if (neohookean) --nb_params_; // C2 == 0
606 
607  }
608 
609 
610 
611 
612  scalar_type Neo_Hookean_hyperelastic_law::strain_energy
613  (const base_matrix &E, const base_vector &params, scalar_type det_trans) const {
614  if (det_trans <= scalar_type(0)) return 1e200;
615  size_type N = gmm::mat_nrows(E);
616  GMM_ASSERT1(N == 3, "Neo Hookean hyperelastic law only defined "
617  "on dimension 3, sorry");
618  base_matrix C = E;
619  gmm::scale(C, scalar_type(2));
620  gmm::add(gmm::identity_matrix(), C);
621  compute_invariants ci(C);
622 
623  scalar_type lambda = params[0];
624  scalar_type mu = params[1];
625  scalar_type logi3 = log(ci.i3());
626  scalar_type W = mu/2 * (ci.i1() - scalar_type(3) - logi3);
627  if (bonet)
628  W += lambda/8 * gmm::sqr(logi3);
629  else // Wriggers
630  W += lambda/4 * (ci.i3() - scalar_type(1) - logi3);
631 
632  return W;
633  }
634 
635  void Neo_Hookean_hyperelastic_law::sigma
636  (const base_matrix &E, base_matrix &result,
637  const base_vector &params , scalar_type det_trans) const {
638  size_type N = gmm::mat_nrows(E);
639  GMM_ASSERT1(N == 3, "Neo Hookean hyperelastic law only defined "
640  "on dimension 3, sorry");
641  base_matrix C = E;
642  gmm::scale(C, scalar_type(2));
643  gmm::add(gmm::identity_matrix(), C);
644  compute_invariants ci(C);
645 
646  scalar_type lambda = params[0];
647  scalar_type mu = params[1];
648  gmm::copy(gmm::scaled(ci.grad_i1(), mu), result);
649  if (bonet)
650  gmm::add(gmm::scaled(ci.grad_i3(),
651  (lambda/2 * log(ci.i3()) - mu) / ci.i3()), result);
652  else
653  gmm::add(gmm::scaled(ci.grad_i3(),
654  lambda/2 - lambda/(2*ci.i3()) - mu / ci.i3()), result);
655  if (det_trans <= scalar_type(0))
656  gmm::add(gmm::scaled(C, 1e200), result);
657  }
658 
659  void Neo_Hookean_hyperelastic_law::grad_sigma
660  (const base_matrix &E, base_tensor &result,
661  const base_vector &params, scalar_type) const {
662  size_type N = gmm::mat_nrows(E);
663  GMM_ASSERT1(N == 3, "Neo Hookean hyperelastic law only defined "
664  "on dimension 3, sorry");
665  base_matrix C = E;
666  gmm::scale(C, scalar_type(2));
667  gmm::add(gmm::identity_matrix(), C);
668  compute_invariants ci(C);
669 
670  scalar_type lambda = params[0];
671  scalar_type mu = params[1];
672 
673  scalar_type coeff;
674  if (bonet) {
675  scalar_type logi3 = log(ci.i3());
676  gmm::copy(gmm::scaled(ci.sym_grad_grad_i3().as_vector(),
677  (lambda * logi3 - 2*mu) / ci.i3()),
678  result.as_vector());
679  coeff = (lambda + 2 * mu - lambda * logi3) / gmm::sqr(ci.i3());
680  } else {
681  gmm::copy(gmm::scaled(ci.sym_grad_grad_i3().as_vector(),
682  lambda - (lambda + 2 * mu) / ci.i3()),
683  result.as_vector());
684  coeff = (lambda + 2 * mu) / gmm::sqr(ci.i3());
685  }
686 
687  const base_matrix &di = ci.grad_i3();
688  for (size_type l1 = 0; l1 < N; ++l1)
689  for (size_type l2 = 0; l2 < N; ++l2)
690  for (size_type l3 = 0; l3 < N; ++l3)
691  for (size_type l4 = 0; l4 < N; ++l4)
692  result(l1, l2, l3, l4) += coeff * di(l1, l2) * di(l3, l4);
693 
694 // GMM_ASSERT1(check_symmetry(result) == 7,
695 // "Fourth order tensor not symmetric : " << result);
696  }
697 
698  Neo_Hookean_hyperelastic_law::Neo_Hookean_hyperelastic_law(bool bonet_)
699  : bonet(bonet_)
700  {
701  nb_params_ = 2;
702  }
703 
704 
705 
706  scalar_type generalized_Blatz_Ko_hyperelastic_law::strain_energy
707  (const base_matrix &E, const base_vector &params, scalar_type det_trans) const {
708  if (det_trans <= scalar_type(0)) return 1e200;
709  scalar_type a = params[0], b = params[1], c = params[2], d = params[3];
710  scalar_type n = params[4];
711  size_type N = gmm::mat_nrows(E);
712  GMM_ASSERT1(N == 3, "Generalized Blatz Ko hyperelastic law only defined "
713  "on dimension 3, sorry");
714  base_matrix C = E;
715  gmm::scale(C, scalar_type(2));
716  gmm::add(gmm::identity_matrix(), C);
717  compute_invariants ci(C);
718 
719  return pow(a*ci.i1() + b*sqrt(gmm::abs(ci.i3()))
720  + c*ci.i2() / ci.i3() + d, n);
721  }
722 
723  void generalized_Blatz_Ko_hyperelastic_law::sigma
724  (const base_matrix &E, base_matrix &result,
725  const base_vector &params, scalar_type det_trans) const {
726  scalar_type a = params[0], b = params[1], c = params[2], d = params[3];
727  scalar_type n = params[4];
728  size_type N = gmm::mat_nrows(E);
729  GMM_ASSERT1(N == 3, "Generalized Blatz Ko hyperelastic law only defined "
730  "on dimension 3, sorry");
731  base_matrix C = E;
732  gmm::scale(C, scalar_type(2));
733  gmm::add(gmm::identity_matrix(), C);
734  compute_invariants ci(C);
735 
736  scalar_type z = a*ci.i1() + b*sqrt(gmm::abs(ci.i3()))
737  + c*ci.i2() / ci.i3() + d;
738  scalar_type nz = n * pow(z, n-1.);
739  scalar_type di1 = nz * a;
740  scalar_type di2 = nz * c / ci.i3();
741  scalar_type di3 = nz *
742  (b / (2. * sqrt(gmm::abs(ci.i3()))) - c * ci.i2() / gmm::sqr(ci.i3()));
743 
744  gmm::copy(gmm::scaled(ci.grad_i1(), di1 * 2.0), result);
745  gmm::add(gmm::scaled(ci.grad_i2(), di2 * 2.0), result);
746  gmm::add(gmm::scaled(ci.grad_i3(), di3 * 2.0), result);
747  if (det_trans <= scalar_type(0))
748  gmm::add(gmm::scaled(C, 1e200), result);
749 
750  }
751 
752  void generalized_Blatz_Ko_hyperelastic_law::grad_sigma
753  (const base_matrix &E, base_tensor &result,
754  const base_vector &params, scalar_type) const {
755  scalar_type a = params[0], b = params[1], c = params[2], d = params[3];
756  scalar_type n = params[4];
757  size_type N = gmm::mat_nrows(E);
758  GMM_ASSERT1(N == 3, "Generalized Blatz Ko hyperelastic law only defined "
759  "on dimension 3, sorry");
760  base_matrix C = E;
761  gmm::scale(C, scalar_type(2));
762  gmm::add(gmm::identity_matrix(), C);
763  compute_invariants ci(C);
764 
765 
766  scalar_type z = a*ci.i1() + b*sqrt(gmm::abs(ci.i3()))
767  + c*ci.i2() / ci.i3() + d;
768  scalar_type nz = n * pow(z, n-1.);
769  scalar_type di1 = nz * a;
770  scalar_type di2 = nz * c / ci.i3();
771  scalar_type y = (b / (2. * sqrt(gmm::abs(ci.i3()))) - c * ci.i2() / gmm::sqr(ci.i3()));
772  scalar_type di3 = nz * y;
773 
774  gmm::copy(gmm::scaled(ci.sym_grad_grad_i1().as_vector(),
775  scalar_type(4)*di1), result.as_vector());
776  gmm::add(gmm::scaled(ci.sym_grad_grad_i2().as_vector(),
777  scalar_type(4)*di2), result.as_vector());
778  gmm::add(gmm::scaled(ci.sym_grad_grad_i3().as_vector(),
779  scalar_type(4)*di3), result.as_vector());
780 
781  scalar_type nnz = n * (n-1.) * pow(z, n-2.);
782  base_matrix A(3, 3); // second derivatives of W with respect to invariants
783  A(0, 0) = nnz * a * a;
784  A(1, 0) = A(0, 1) = nnz * a * c / ci.i3();
785  A(2, 0) = A(0, 2) = nnz * a * y;
786  A(1, 1) = nnz * c * c / gmm::sqr(ci.i3());
787  A(2, 1) = A(1, 2) = nnz * y * c / ci.i3() - nz * c / gmm::sqr(ci.i3());
788  A(2, 2) = nnz * y * y + nz * (2. * c * ci.i2() / pow(ci.i3(), 3.) - b / (4. * pow(ci.i3(), 1.5)));
789 
790  typedef const base_matrix * pointer_base_matrix__;
791  pointer_base_matrix__ di[3];
792  di[0] = &(ci.grad_i1());
793  di[1] = &(ci.grad_i2());
794  di[2] = &(ci.grad_i3());
795 
796  for (size_type j = 0; j < N; ++j)
797  for (size_type k = 0; k < N; ++k) {
798  for (size_type l1 = 0; l1 < N; ++l1)
799  for (size_type l2 = 0; l2 < N; ++l2)
800  for (size_type l3 = 0; l3 < N; ++l3)
801  for (size_type l4 = 0; l4 < N; ++l4)
802  result(l1, l2, l3, l4)
803  += 4. * A(j, k) * (*di[j])(l1, l2) * (*di[k])(l3, l4);
804  }
805 
806 // GMM_ASSERT1(check_symmetry(result) == 7,
807 // "Fourth order tensor not symmetric : " << result);
808  }
809 
810  generalized_Blatz_Ko_hyperelastic_law::generalized_Blatz_Ko_hyperelastic_law() {
811  nb_params_ = 5;
812  base_vector V(5);
813  V[0] = 1.0; V[1] = 1.0, V[2] = 1.5; V[3] = -0.5; V[4] = 1.5;
814  }
815 
816 
817  scalar_type Ciarlet_Geymonat_hyperelastic_law::strain_energy
818  (const base_matrix &E, const base_vector &params, scalar_type det_trans) const {
819  if (det_trans <= scalar_type(0)) return 1e200;
820  size_type N = gmm::mat_nrows(E);
821  scalar_type a = params[2];
822  scalar_type b = params[1]/scalar_type(2) - params[2];
823  scalar_type c = params[0]/scalar_type(4) - params[1]/scalar_type(2)
824  + params[2];
825  scalar_type d = params[0]/scalar_type(2) + params[1];
826  scalar_type e = -(scalar_type(3)*(a+b) + c);
827  base_matrix C(N, N);
828  gmm::copy(gmm::scaled(E, scalar_type(2)), C);
829  gmm::add(gmm::identity_matrix(), C);
830  scalar_type det = bgeot::lu_det(&(*(C.begin())), N);
831  return a * gmm::mat_trace(C)
832  + b * (gmm::sqr(gmm::mat_trace(C)) -
833  gmm::mat_euclidean_norm_sqr(C))/scalar_type(2)
834  + c * det - d * log(det) / scalar_type(2) + e;
835  }
836 
837  void Ciarlet_Geymonat_hyperelastic_law::sigma
838  (const base_matrix &E, base_matrix &result, const base_vector &params, scalar_type det_trans) const {
839  size_type N = gmm::mat_nrows(E);
840  scalar_type a = params[2];
841  scalar_type b = params[1]/scalar_type(2) - params[2];
842  scalar_type c = params[0]/scalar_type(4) - params[1]/scalar_type(2)
843  + params[2];
844  scalar_type d = params[0]/scalar_type(2) + params[1];
845  base_matrix C(N, N);
846  if (a > params[1]/scalar_type(2)
847  || a < params[1]/scalar_type(2) - params[0]/scalar_type(4) || a < 0)
848  GMM_WARNING1("Inconsistent third parameter for Ciarlet-Geymonat "
849  "hyperelastic law");
850  gmm::copy(gmm::scaled(E, scalar_type(2)), C);
851  gmm::add(gmm::identity_matrix(), C);
852  gmm::copy(gmm::identity_matrix(), result);
853  gmm::scale(result, scalar_type(2) * (a + b * gmm::mat_trace(C)));
854  gmm::add(gmm::scaled(C, -scalar_type(2) * b), result);
855  if (det_trans <= scalar_type(0))
856  gmm::add(gmm::scaled(C, 1e200), result);
857  else {
858  scalar_type det = bgeot::lu_inverse(&(*(C.begin())), N);
859  gmm::add(gmm::scaled(C, scalar_type(2) * c * det - d), result);
860  }
861  }
862 
863  void Ciarlet_Geymonat_hyperelastic_law::grad_sigma
864  (const base_matrix &E, base_tensor &result,const base_vector &params, scalar_type) const {
865  size_type N = gmm::mat_nrows(E);
866  // scalar_type a = params[2];
867  scalar_type b2 = params[1] - params[2]*scalar_type(2); // b*2
868  scalar_type c = params[0]/scalar_type(4) - params[1]/scalar_type(2)
869  + params[2];
870  scalar_type d = params[0]/scalar_type(2) + params[1];
871  base_matrix C(N, N);
872  gmm::copy(gmm::scaled(E, scalar_type(2)), C);
873  gmm::add(gmm::identity_matrix(), C);
874  scalar_type det = bgeot::lu_inverse(&(*(C.begin())), N);
875  std::fill(result.begin(), result.end(), scalar_type(0));
876  for (size_type i = 0; i < N; ++i)
877  for (size_type j = 0; j < N; ++j) {
878  result(i, i, j, j) += 2*b2;
879  result(i, j, i, j) -= b2;
880  result(i, j, j, i) -= b2;
881  for (size_type k = 0; k < N; ++k)
882  for (size_type l = 0; l < N; ++l)
883  result(i, j, k, l) +=
884  (C(i, k)*C(l, j) + C(i, l)*C(k, j)) * (d-scalar_type(2)*det*c)
885  + (C(i, j) * C(k, l)) * det*c*scalar_type(4);
886  }
887 
888 // GMM_ASSERT1(check_symmetry(result) == 7,
889 // "Fourth order tensor not symmetric : " << result);
890  }
891 
892 
893  int levi_civita(int i, int j, int k) {
894  int ii=i+1;
895  int jj=j+1;
896  int kk=k+1; //i,j,k from 0 to 2 !
897  return static_cast<int>
898  (int(- 1)*(static_cast<int>(pow(double(ii-jj),2.))%3)
899  * (static_cast<int> (pow(double(ii-kk),double(2)))%3 )
900  * (static_cast<int> (pow(double(jj-kk),double(2)))%3)
901  * (pow(double(jj-(ii%3))-double(0.5),double(2))-double(1.25)));
902  }
903 
904 
905 
906  scalar_type plane_strain_hyperelastic_law::strain_energy
907  (const base_matrix &E, const base_vector &params, scalar_type det_trans) const {
908  GMM_ASSERT1(gmm::mat_nrows(E) == 2, "Plane strain law is for 2D only.");
909  base_matrix E3D(3,3);
910  E3D(0,0)=E(0,0); E3D(1,0)=E(1,0); E3D(0,1)=E(0,1); E3D(1,1)=E(1,1);
911  return pl->strain_energy(E3D, params, det_trans);
912  }
913 
914  void plane_strain_hyperelastic_law::sigma
915  (const base_matrix &E, base_matrix &result,const base_vector &params, scalar_type det_trans) const {
916  GMM_ASSERT1(gmm::mat_nrows(E) == 2, "Plane strain law is for 2D only.");
917  base_matrix E3D(3,3), result3D(3,3);
918  E3D(0,0)=E(0,0); E3D(1,0)=E(1,0); E3D(0,1)=E(0,1); E3D(1,1)=E(1,1);
919  pl->sigma(E3D, result3D, params, det_trans);
920  result(0,0) = result3D(0,0); result(1,0) = result3D(1,0);
921  result(0,1) = result3D(0,1); result(1,1) = result3D(1,1);
922  }
923 
924  void plane_strain_hyperelastic_law::grad_sigma
925  (const base_matrix &E, base_tensor &result,const base_vector &params, scalar_type det_trans) const {
926  GMM_ASSERT1(gmm::mat_nrows(E) == 2, "Plane strain law is for 2D only.");
927  base_matrix E3D(3,3);
928  base_tensor result3D(3,3,3,3);
929  E3D(0,0)=E(0,0); E3D(1,0)=E(1,0); E3D(0,1)=E(0,1); E3D(1,1)=E(1,1);
930  pl->grad_sigma(E3D, result3D, params, det_trans);
931  result(0,0,0,0) = result3D(0,0,0,0); result(1,0,0,0) = result3D(1,0,0,0);
932  result(0,1,0,0) = result3D(0,1,0,0); result(1,1,0,0) = result3D(1,1,0,0);
933  result(0,0,1,0) = result3D(0,0,1,0); result(1,0,1,0) = result3D(1,0,1,0);
934  result(0,1,1,0) = result3D(0,1,1,0); result(1,1,1,0) = result3D(1,1,1,0);
935  result(0,0,0,1) = result3D(0,0,0,1); result(1,0,0,1) = result3D(1,0,0,1);
936  result(0,1,0,1) = result3D(0,1,0,1); result(1,1,0,1) = result3D(1,1,0,1);
937  result(0,0,1,1) = result3D(0,0,1,1); result(1,0,1,1) = result3D(1,0,1,1);
938  result(0,1,1,1) = result3D(0,1,1,1); result(1,1,1,1) = result3D(1,1,1,1);
939  }
940 
941 
942 
943 
944 
945 
946 
947  //=========================================================================
948  //
949  // Nonlinear elasticity (old) Brick
950  //
951  //=========================================================================
952 
953  struct nonlinear_elasticity_brick : public virtual_brick {
954 
955  phyperelastic_law AHL;
956 
957  virtual void asm_real_tangent_terms(const model &md, size_type /* ib */,
958  const model::varnamelist &vl,
959  const model::varnamelist &dl,
960  const model::mimlist &mims,
961  model::real_matlist &matl,
962  model::real_veclist &vecl,
963  model::real_veclist &,
964  size_type region,
965  build_version version) const {
966  GMM_ASSERT1(mims.size() == 1,
967  "Nonlinear elasticity brick need a single mesh_im");
968  GMM_ASSERT1(vl.size() == 1,
969  "Nonlinear elasticity brick need a single variable");
970  GMM_ASSERT1(dl.size() == 1,
971  "Wrong number of data for nonlinear elasticity brick, "
972  << dl.size() << " should be 1 (vector).");
973  GMM_ASSERT1(matl.size() == 1, "Wrong number of terms for nonlinear "
974  "elasticity brick");
975 
976  const model_real_plain_vector &u = md.real_variable(vl[0]);
977  const mesh_fem &mf_u = *(md.pmesh_fem_of_variable(vl[0]));
978 
979  const mesh_fem *mf_params = md.pmesh_fem_of_variable(dl[0]);
980  const model_real_plain_vector &params = md.real_variable(dl[0]);
981  const mesh_im &mim = *mims[0];
982 
983  size_type sl = gmm::vect_size(params);
984  if (mf_params) sl = sl * mf_params->get_qdim() / mf_params->nb_dof();
985  GMM_ASSERT1(sl == AHL->nb_params(), "Wrong number of coefficients for the "
986  "nonlinear constitutive elastic law");
987 
988  mesh_region rg(region);
989  mf_u.linked_mesh().intersect_with_mpi_region(rg);
990 
991  if (version & model::BUILD_MATRIX) {
992  gmm::clear(matl[0]);
993  GMM_TRACE2("Nonlinear elasticity stiffness matrix assembly");
995  (matl[0], mim, mf_u, u, mf_params, params, *AHL, rg);
996  }
997 
998 
999  if (version & model::BUILD_RHS) {
1000  asm_nonlinear_elasticity_rhs(vecl[0], mim,
1001  mf_u, u, mf_params, params, *AHL, rg);
1002  gmm::scale(vecl[0], scalar_type(-1));
1003  }
1004 
1005  }
1006 
1007  nonlinear_elasticity_brick(const phyperelastic_law &AHL_)
1008  : AHL(AHL_) {
1009  set_flags("Nonlinear elasticity brick", false /* is linear*/,
1010  true /* is symmetric */, true /* is coercive */,
1011  true /* is real */, false /* is complex */);
1012  }
1013 
1014  };
1015 
1016  //=========================================================================
1017  // Add a nonlinear elasticity brick.
1018  //=========================================================================
1019 
1020  // Deprecated brick
1022  (model &md, const mesh_im &mim, const std::string &varname,
1023  const phyperelastic_law &AHL, const std::string &dataname,
1024  size_type region) {
1025  pbrick pbr = std::make_shared<nonlinear_elasticity_brick>(AHL);
1026 
1027  model::termlist tl;
1028  tl.push_back(model::term_description(varname, varname, true));
1029  model::varnamelist dl(1, dataname);
1030  model::varnamelist vl(1, varname);
1031  return md.add_brick(pbr, vl, dl, tl, model::mimlist(1,&mim), region);
1032  }
1033 
1034  //=========================================================================
1035  // Von Mises or Tresca stress computation.
1036  //=========================================================================
1037 
1038  void compute_Von_Mises_or_Tresca(model &md,
1039  const std::string &varname,
1040  const phyperelastic_law &AHL,
1041  const std::string &dataname,
1042  const mesh_fem &mf_vm,
1043  model_real_plain_vector &VM,
1044  bool tresca) {
1045  GMM_ASSERT1(gmm::vect_size(VM) == mf_vm.nb_dof(),
1046  "The vector has not the good size");
1047  const mesh_fem &mf_u = md.mesh_fem_of_variable(varname);
1048  const model_real_plain_vector &u = md.real_variable(varname);
1049  const mesh_fem *mf_params = md.pmesh_fem_of_variable(dataname);
1050  const model_real_plain_vector &params = md.real_variable(dataname);
1051 
1052  size_type sl = gmm::vect_size(params);
1053  if (mf_params) sl = sl * mf_params->get_qdim() / mf_params->nb_dof();
1054  GMM_ASSERT1(sl == AHL->nb_params(), "Wrong number of coefficients for "
1055  "the nonlinear constitutive elastic law");
1056 
1057  unsigned N = unsigned(mf_u.linked_mesh().dim());
1058  unsigned NP = unsigned(AHL->nb_params()), NFem = mf_u.get_qdim();
1059  model_real_plain_vector GRAD(mf_vm.nb_dof()*NFem*N);
1060  model_real_plain_vector PARAMS(mf_vm.nb_dof()*NP);
1061  if (mf_params) interpolation(*mf_params, mf_vm, params, PARAMS);
1062  compute_gradient(mf_u, mf_vm, u, GRAD);
1063  base_matrix E(N, N), gradphi(NFem,N),gradphit(N,NFem), Id(N, N),
1064  sigmahathat(N,N),aux(NFem,N), sigma(NFem,NFem),
1065  IdNFem(NFem, NFem);
1066  base_vector p(NP);
1067  if (!mf_params) gmm::copy(params, p);
1068  base_vector eig(NFem);
1069  base_vector ez(NFem); // vector normal at deformed surface, (ex X ey)
1070  double normEz(0); //norm of ez
1071  gmm::copy(gmm::identity_matrix(), Id);
1072  gmm::copy(gmm::identity_matrix(), IdNFem);
1073  for (size_type i = 0; i < mf_vm.nb_dof(); ++i) {
1074  gmm::resize(gradphi,NFem,N);
1075  std::copy(GRAD.begin()+i*NFem*N, GRAD.begin()+(i+1)*NFem*N,
1076  gradphit.begin());
1077  gmm::copy(gmm::transposed(gradphit),gradphi);
1078  for (unsigned int alpha = 0; alpha <N; ++alpha)
1079  gradphi(alpha, alpha)+=1;
1080  gmm::mult(gmm::transposed(gradphi), gradphi, E);
1081  gmm::add(gmm::scaled(Id, -scalar_type(1)), E);
1082  gmm::scale(E, scalar_type(1)/scalar_type(2));
1083  if (mf_params)
1084  gmm::copy(gmm::sub_vector(PARAMS, gmm::sub_interval(i*NP,NP)), p);
1085  AHL->sigma(E, sigmahathat, p, scalar_type(1));
1086  if (NFem == 3 && N == 2) {
1087  //jyh : compute ez, normal on deformed surface
1088  for (unsigned int l = 0; l <NFem; ++l) {
1089  ez[l]=0;
1090  for (unsigned int m = 0; m <NFem; ++m)
1091  for (unsigned int n = 0; n <NFem; ++n){
1092  ez[l]+=levi_civita(l,m,n)*gradphi(m,0)*gradphi(n,1);
1093  }
1094  normEz= gmm::vect_norm2(ez);
1095  }
1096  //jyh : end compute ez
1097  }
1098  gmm::mult(gradphi, sigmahathat, aux);
1099  gmm::mult(aux, gmm::transposed(gradphi), sigma);
1100 
1101  /* jyh : complete gradphi for virtual 3rd dim (perpendicular to
1102  deformed surface, same thickness) */
1103  if (NFem == 3 && N == 2) {
1104  gmm::resize(gradphi,NFem,NFem);
1105  for (unsigned int ll = 0; ll <NFem; ++ll)
1106  for (unsigned int ii = 0; ii <NFem; ++ii)
1107  for (unsigned int jj = 0; jj <NFem; ++jj)
1108  gradphi(ll,2)+=(levi_civita(ll,ii,jj)*gradphi(ii,0)
1109  *gradphi(jj,1))/normEz;
1110  //jyh : end complete graphi
1111  }
1112 
1113  gmm::scale(sigma, scalar_type(1) / bgeot::lu_det(&(*(gradphi.begin())), NFem));
1114 
1115  if (!tresca) {
1116  /* von mises: norm(deviator(sigma)) */
1117  gmm::add(gmm::scaled(IdNFem, -gmm::mat_trace(sigma) / NFem), sigma);
1118 
1119  //jyh : von mises stress=sqrt(3/2)* norm(sigma) ?
1120  VM[i] = sqrt(3.0/2)*gmm::mat_euclidean_norm(sigma);
1121  } else {
1122  /* else compute the tresca criterion */
1123  //jyh : to be adapted for membrane if necessary
1124  gmm::symmetric_qr_algorithm(sigma, eig);
1125  std::sort(eig.begin(), eig.end());
1126  VM[i] = eig.back() - eig.front();
1127  }
1128  }
1129  }
1130 
1131 
1132  void compute_sigmahathat(model &md,
1133  const std::string &varname,
1134  const phyperelastic_law &AHL,
1135  const std::string &dataname,
1136  const mesh_fem &mf_sigma,
1137  model_real_plain_vector &SIGMA) {
1138  const mesh_fem &mf_u = md.mesh_fem_of_variable(varname);
1139  const model_real_plain_vector &u = md.real_variable(varname);
1140  const mesh_fem *mf_params = md.pmesh_fem_of_variable(dataname);
1141  const model_real_plain_vector &params = md.real_variable(dataname);
1142 
1143  size_type sl = gmm::vect_size(params);
1144  if (mf_params) sl = sl * mf_params->get_qdim() / mf_params->nb_dof();
1145  GMM_ASSERT1(sl == AHL->nb_params(), "Wrong number of coefficients for "
1146  "the nonlinear constitutive elastic law");
1147 
1148  unsigned N = unsigned(mf_u.linked_mesh().dim());
1149  unsigned NP = unsigned(AHL->nb_params()), NFem = mf_u.get_qdim();
1150  GMM_ASSERT1(mf_sigma.nb_dof() > 0, "Bad mf_sigma");
1151  size_type qqdim = mf_sigma.get_qdim();
1152  size_type ratio = N*N / qqdim;
1153 
1154  GMM_ASSERT1(((ratio == 1) || (ratio == N*N)) &&
1155  (gmm::vect_size(SIGMA) == mf_sigma.nb_dof()*ratio),
1156  "The vector has not the good size");
1157 
1158  model_real_plain_vector GRAD(mf_sigma.nb_dof()*ratio*NFem/N);
1159  model_real_plain_vector PARAMS(mf_sigma.nb_dof()*NP);
1160 
1161 
1162  getfem::mesh_trans_inv mti(mf_sigma.linked_mesh());
1163  if (mf_params) {
1164  for (size_type i = 0; i < mf_sigma.nb_dof(); ++i)
1165  mti.add_point(mf_sigma.point_of_basic_dof(i));
1166  interpolation(*mf_params, mti, params, PARAMS);
1167  }
1168 
1169  compute_gradient(mf_u, mf_sigma, u, GRAD);
1170  base_matrix E(N, N), gradphi(NFem,N),gradphit(N,NFem), Id(N, N),
1171  sigmahathat(N,N),aux(NFem,N), sigma(NFem,NFem),
1172  IdNFem(NFem, NFem);
1173 
1174 
1175  base_vector p(NP);
1176  if (!mf_params) gmm::copy(params, p);
1177  base_vector eig(NFem);
1178  base_vector ez(NFem); // vector normal at deformed surface, (ex X ey)
1179  gmm::copy(gmm::identity_matrix(), Id);
1180  gmm::copy(gmm::identity_matrix(), IdNFem);
1181 
1182  // cout << "GRAD = " << GRAD << endl;
1183  // GMM_ASSERT1(false, "oops");
1184 
1185  for (size_type i = 0; i < mf_sigma.nb_dof()/qqdim; ++i) {
1186 // cout << "GRAD size = " << gmm::vect_size(GRAD) << endl;
1187 // cout << "i = " << i << endl;
1188 // cout << "i*NFem*N = " << i*NFem*N << endl;
1189 
1190  gmm::resize(gradphi,NFem,N);
1191  std::copy(GRAD.begin()+i*NFem*N, GRAD.begin()+(i+1)*NFem*N,
1192  gradphit.begin());
1193  // cout << "GRAD = " << gradphit << endl;
1194  gmm::copy(gmm::transposed(gradphit),gradphi);
1195  for (unsigned int alpha = 0; alpha <N; ++alpha)
1196  gradphi(alpha, alpha) += scalar_type(1);
1197  gmm::mult(gmm::transposed(gradphi), gradphi, E);
1198  gmm::add(gmm::scaled(Id, -scalar_type(1)), E);
1199  gmm::scale(E, scalar_type(1)/scalar_type(2));
1200  if (mf_params)
1201  gmm::copy(gmm::sub_vector(PARAMS, gmm::sub_interval(i*ratio*NP,NP)),p);
1202  // cout << "E = " << E << endl;
1203  AHL->sigma(E, sigmahathat, p, scalar_type(1));
1204  // cout << "ok" << endl;
1205  std::copy(sigmahathat.begin(), sigmahathat.end(), SIGMA.begin()+i*N*N);
1206  }
1207  }
1208 
1209 
1210 
1211  // ----------------------------------------------------------------------
1212  //
1213  // Nonlinear incompressibility brick
1214  //
1215  // ----------------------------------------------------------------------
1216 
1217  struct nonlinear_incompressibility_brick : public virtual_brick {
1218 
1219  virtual void asm_real_tangent_terms(const model &md, size_type,
1220  const model::varnamelist &vl,
1221  const model::varnamelist &dl,
1222  const model::mimlist &mims,
1223  model::real_matlist &matl,
1224  model::real_veclist &vecl,
1225  model::real_veclist &veclsym,
1226  size_type region,
1227  build_version version) const {
1228 
1229  GMM_ASSERT1(matl.size() == 2, "Wrong number of terms for nonlinear "
1230  "incompressibility brick");
1231  GMM_ASSERT1(dl.size() == 0, "Nonlinear incompressibility brick need no "
1232  "data");
1233  GMM_ASSERT1(mims.size() == 1, "Nonlinear incompressibility brick need a "
1234  "single mesh_im");
1235  GMM_ASSERT1(vl.size() == 2, "Wrong number of variables for nonlinear "
1236  "incompressibility brick");
1237 
1238  const mesh_fem &mf_u = md.mesh_fem_of_variable(vl[0]);
1239  const mesh_fem &mf_p = md.mesh_fem_of_variable(vl[1]);
1240  const model_real_plain_vector &u = md.real_variable(vl[0]);
1241  const model_real_plain_vector &p = md.real_variable(vl[1]);
1242  const mesh_im &mim = *mims[0];
1243  mesh_region rg(region);
1244  mim.linked_mesh().intersect_with_mpi_region(rg);
1245 
1246  if (version & model::BUILD_MATRIX) {
1247  gmm::clear(matl[0]);
1248  gmm::clear(matl[1]);
1249  asm_nonlinear_incomp_tangent_matrix(matl[0], matl[1],
1250  mim, mf_u, mf_p, u, p, rg);
1251  }
1252 
1253  if (version & model::BUILD_RHS) {
1254  asm_nonlinear_incomp_rhs(vecl[0], veclsym[1], mim, mf_u, mf_p,u,p, rg);
1255  gmm::scale(vecl[0], scalar_type(-1));
1256  gmm::scale(veclsym[1], scalar_type(-1));
1257  }
1258  }
1259 
1260 
1261  nonlinear_incompressibility_brick() {
1262  set_flags("Nonlinear incompressibility brick",
1263  false /* is linear*/,
1264  true /* is symmetric */, false /* is coercive */,
1265  true /* is real */, false /* is complex */);
1266  }
1267 
1268 
1269  };
1270 
1272  (model &md, const mesh_im &mim, const std::string &varname,
1273  const std::string &multname, size_type region) {
1274  pbrick pbr = std::make_shared<nonlinear_incompressibility_brick>();
1275  model::termlist tl;
1276  tl.push_back(model::term_description(varname, varname, true));
1277  tl.push_back(model::term_description(varname, multname, true));
1278  model::varnamelist vl(1, varname);
1279  vl.push_back(multname);
1280  model::varnamelist dl;
1281  return md.add_brick(pbr, vl, dl, tl, model::mimlist(1, &mim), region);
1282  }
1283 
1284 
1285 
1286 
1287 
1288  // ----------------------------------------------------------------------
1289  //
1290  // High-level Generic assembly operators
1291  //
1292  // ----------------------------------------------------------------------
1293 
1294 
1295  static void ga_init_scalar_(bgeot::multi_index &mi) { mi.resize(0); }
1296  static void ga_init_square_matrix_(bgeot::multi_index &mi, size_type N)
1297  { mi.resize(2); mi[0] = mi[1] = N; }
1298 
1299 
1300  // Matrix_i2 Operator (second invariant of square matrix of size >= 2)
1301  // (For 2x2 matrices, it is equivalent to det(M))
1302  struct matrix_i2_operator : public ga_nonlinear_operator {
1303  bool result_size(const arg_list &args, bgeot::multi_index &sizes) const {
1304  if (args.size() != 1 || args[0]->sizes().size() != 2
1305  || args[0]->sizes()[0] != args[0]->sizes()[1]) return false;
1306  ga_init_scalar_(sizes);
1307  return true;
1308  }
1309 
1310  // Value : (Trace(M))^2 - Trace(M^2))/2
1311  void value(const arg_list &args, base_tensor &result) const {
1312  size_type N = args[0]->sizes()[0];
1313  const base_tensor &t = *args[0];
1314  scalar_type tr = scalar_type(0);
1315  for (size_type i = 0; i < N; ++i) tr += t[i*N+i];
1316  scalar_type tr2 = scalar_type(0);
1317  for (size_type i = 0; i < N; ++i)
1318  for (size_type j = 0; j < N; ++j)
1319  tr2 += t[i+ j*N] * t[j + i*N];
1320  result[0] = (tr*tr-tr2)/scalar_type(2);
1321  }
1322 
1323  // Derivative : Trace(M)I - M^T
1324  void derivative(const arg_list &args, size_type,
1325  base_tensor &result) const {
1326  size_type N = args[0]->sizes()[0];
1327  const base_tensor &t = *args[0];
1328  scalar_type tr = scalar_type(0);
1329  for (size_type i = 0; i < N; ++i) tr += t[i*N+i];
1330  base_tensor::iterator it = result.begin();
1331  for (size_type j = 0; j < N; ++j)
1332  for (size_type i = 0; i < N; ++i, ++it)
1333  *it = ((i == j) ? tr : scalar_type(0)) - t[i*N+j];
1334  GMM_ASSERT1(it == result.end(), "Internal error");
1335  }
1336 
1337  // Second derivative : I@I - \delta_{il}\delta_{jk}
1338  void second_derivative(const arg_list &args, size_type, size_type,
1339  base_tensor &result) const {
1340  size_type N = args[0]->sizes()[0];
1341  gmm::clear(result.as_vector());
1342  for (size_type i = 0; i < N; ++i)
1343  for (size_type j = 0; j < N; ++j) {
1344  result[(N+1)*(i+N*N*j)] += scalar_type(1);
1345  result[(N+1)*N*j + i*(N*N*N + 1)] -= scalar_type(1);
1346  }
1347  }
1348  };
1349 
1350 
1351  // Matrix_j1 Operator
1352  struct matrix_j1_operator : public ga_nonlinear_operator {
1353  bool result_size(const arg_list &args, bgeot::multi_index &sizes) const {
1354  if (args.size() != 1 || args[0]->sizes().size() != 2
1355  || args[0]->sizes()[0] != args[0]->sizes()[1]) return false;
1356  ga_init_scalar_(sizes);
1357  return true;
1358  }
1359 
1360  // Value : Trace(M)/(det(M)^1/3)
1361  void value(const arg_list &args, base_tensor &result) const {
1362  size_type N = args[0]->sizes()[0];
1363  base_matrix M(N, N);
1364  gmm::copy(args[0]->as_vector(), M.as_vector());
1365  scalar_type det = bgeot::lu_det(&(*(M.begin())), N);
1366  scalar_type tr = scalar_type(0);
1367  for (size_type i = 0; i < N; ++i) tr += M(i,i);
1368  if (det > 0)
1369  result[0] = tr / pow(det, scalar_type(1)/scalar_type(3));
1370  else
1371  result[0] = 1.E200;
1372  }
1373 
1374  // Derivative : (I-Trace(M)*M^{-T}/3)/(det(M)^1/3)
1375  void derivative(const arg_list &args, size_type,
1376  base_tensor &result) const {
1377  size_type N = args[0]->sizes()[0];
1378  base_matrix M(N, N);
1379  gmm::copy(args[0]->as_vector(), M.as_vector());
1380  scalar_type tr = scalar_type(0);
1381  for (size_type i = 0; i < N; ++i) tr += M(i,i);
1382  scalar_type det = bgeot::lu_inverse(&(*(M.begin())), N);
1383  if (det > 0) {
1384  base_tensor::iterator it = result.begin();
1385  for (size_type j = 0; j < N; ++j)
1386  for (size_type i = 0; i < N; ++i, ++it)
1387  *it = (((i == j) ? scalar_type(1) : scalar_type(0))
1388  - tr*M(j,i)/scalar_type(3))
1389  / pow(det, scalar_type(1)/scalar_type(3));
1390  GMM_ASSERT1(it == result.end(), "Internal error");
1391  } else
1392  std::fill(result.begin(), result.end(), 1.E200);
1393  }
1394 
1395  // Second derivative : (-M^{-T}@I + Trace(M)*M^{-T}_{ik}M^{-T}_{lj}
1396  // -I@M^{-T} + Trace(M)*M^{-T}@M^{-T}/3)/(3det(M)^1/3)
1397  void second_derivative(const arg_list &args, size_type, size_type,
1398  base_tensor &result) const {
1399  size_type N = args[0]->sizes()[0];
1400  base_matrix M(N, N);
1401  gmm::copy(args[0]->as_vector(), M.as_vector());
1402  scalar_type tr = scalar_type(0);
1403  for (size_type i = 0; i < N; ++i) tr += M(i,i);
1404  scalar_type det = bgeot::lu_inverse(&(*(M.begin())), N);
1405  if (det > 0) {
1406  base_tensor::iterator it = result.begin();
1407  for (size_type l = 0; l < N; ++l)
1408  for (size_type k = 0; k < N; ++k)
1409  for (size_type j = 0; j < N; ++j)
1410  for (size_type i = 0; i < N; ++i, ++it)
1411  *it = (- ((k == l) ? M(j, i) : scalar_type(0))
1412  + tr*M(i,k)*M(l,j)
1413  - ((i == j) ? M(l, k) : scalar_type(0))
1414  + tr*M(j,i)*M(k,l)/ scalar_type(3))
1415  / (scalar_type(3)*pow(det, scalar_type(1)/scalar_type(3)));
1416  GMM_ASSERT1(it == result.end(), "Internal error");
1417  } else
1418  std::fill(result.begin(), result.end(), 1.E200);
1419  }
1420  };
1421 
1422 
1423  // Matrix_j2 Operator
1424  struct matrix_j2_operator : public ga_nonlinear_operator {
1425  bool result_size(const arg_list &args, bgeot::multi_index &sizes) const {
1426  if (args.size() != 1 || args[0]->sizes().size() != 2
1427  || args[0]->sizes()[0] != args[0]->sizes()[1]) return false;
1428  ga_init_scalar_(sizes);
1429  return true;
1430  }
1431 
1432  // Value : i2(M)/(det(M)^2/3)
1433  void value(const arg_list &args, base_tensor &result) const {
1434  size_type N = args[0]->sizes()[0];
1435  base_matrix M(N, N);
1436  gmm::copy(args[0]->as_vector(), M.as_vector());
1437  scalar_type tr = scalar_type(0);
1438  for (size_type i = 0; i < N; ++i) tr += M(i,i);
1439  scalar_type tr2 = scalar_type(0);
1440  for (size_type i = 0; i < N; ++i)
1441  for (size_type j = 0; j < N; ++j)
1442  tr2 += M(i,j)*M(j,i);
1443  scalar_type i2 = (tr*tr-tr2)/scalar_type(2);
1444  scalar_type det = bgeot::lu_det(&(*(M.begin())), N);
1445  if (det > 0)
1446  result[0] = i2 / pow(det, scalar_type(2)/scalar_type(3));
1447  else
1448  result[0] = 1.E200;
1449  }
1450 
1451  // Derivative : (Trace(M)*I-M^T-2i2(M)M^{-T}/3)/(det(M)^2/3)
1452  void derivative(const arg_list &args, size_type,
1453  base_tensor &result) const {
1454  size_type N = args[0]->sizes()[0];
1455  const base_tensor &t = *args[0];
1456  base_matrix M(N, N);
1457  gmm::copy(t.as_vector(), M.as_vector());
1458  scalar_type tr = scalar_type(0);
1459  for (size_type i = 0; i < N; ++i) tr += M(i,i);
1460  scalar_type tr2 = scalar_type(0);
1461  for (size_type i = 0; i < N; ++i)
1462  for (size_type j = 0; j < N; ++j)
1463  tr2 += M(i,j)*M(j,i);
1464  scalar_type i2 = (tr*tr-tr2)/scalar_type(2);
1465  scalar_type det = bgeot::lu_inverse(&(*(M.begin())), N);
1466  base_tensor::iterator it = result.begin();
1467  for (size_type j = 0; j < N; ++j)
1468  for (size_type i = 0; i < N; ++i, ++it)
1469  *it = (((i == j) ? tr : scalar_type(0)) - t[j+N*i]
1470  - scalar_type(2)*i2*M(j,i)/(scalar_type(3)))
1471  / pow(det, scalar_type(2)/scalar_type(3));
1472  GMM_ASSERT1(it == result.end(), "Internal error");
1473  }
1474 
1475  // Second derivative
1476  void second_derivative(const arg_list &args, size_type, size_type,
1477  base_tensor &result) const {
1478  size_type N = args[0]->sizes()[0];
1479  const base_tensor &t = *args[0];
1480  base_matrix M(N, N);
1481  gmm::copy(t.as_vector(), M.as_vector());
1482  scalar_type tr = scalar_type(0);
1483  for (size_type i = 0; i < N; ++i) tr += M(i,i);
1484  scalar_type tr2 = scalar_type(0);
1485  for (size_type i = 0; i < N; ++i)
1486  for (size_type j = 0; j < N; ++j)
1487  tr2 += M(i,j)*M(j,i);
1488  scalar_type i2 = (tr*tr-tr2)/scalar_type(2);
1489  scalar_type det = bgeot::lu_inverse(&(*(M.begin())), N);
1490  base_tensor::iterator it = result.begin();
1491  for (size_type l = 0; l < N; ++l)
1492  for (size_type k = 0; k < N; ++k)
1493  for (size_type j = 0; j < N; ++j)
1494  for (size_type i = 0; i < N; ++i, ++it)
1495  *it = ( + (((i==j) && (k==l)) ? 1. : 0.)
1496  - (((i==l) && (k==j)) ? 1. : 0.)
1497  + 10.*i2*M(j,i)*M(l,k)/(9.)
1498  - 2.*(M(j,i)*(tr*((k==l) ? 1.:0.)-t[l+N*k]))/(3.)
1499  - 2.*(M(l,k)*(tr*((i==j) ? 1.:0.)-t[j+N*i]))/(3.)
1500  - 2.*i2*(M(j,i)*M(l,k)-M(j,k)*M(l,i))/(3.))
1501  / pow(det, scalar_type(2)/scalar_type(3));
1502  }
1503  };
1504 
1505  // Right-Cauchy-Green operator (F^{T}F)
1506  struct Right_Cauchy_Green_operator : public ga_nonlinear_operator {
1507  bool result_size(const arg_list &args, bgeot::multi_index &sizes) const {
1508  if (args.size() != 1 || args[0]->sizes().size() != 2) return false;
1509  ga_init_square_matrix_(sizes, args[0]->sizes()[1]);
1510  return true;
1511  }
1512 
1513  // Value : F^{T}F
1514  void value(const arg_list &args, base_tensor &result) const {
1515  // to be verified
1516  size_type m = args[0]->sizes()[0], n = args[0]->sizes()[1];
1517  base_tensor::iterator it = result.begin();
1518  for (size_type j = 0; j < n; ++j)
1519  for (size_type i = 0; i < n; ++i, ++it) {
1520  *it = scalar_type(0);
1521  for (size_type k = 0; k < m; ++k)
1522  *it += (*(args[0]))[i*m+k] * (*(args[0]))[j*m+k];
1523  }
1524  }
1525 
1526  // Derivative : F{kj}delta{li}+F{ki}delta{lj}
1527  // (comes from H -> H^{T}F + F^{T}H)
1528  void derivative(const arg_list &args, size_type,
1529  base_tensor &result) const { // to be verified
1530  size_type m = args[0]->sizes()[0], n = args[0]->sizes()[1];
1531  base_tensor::iterator it = result.begin();
1532  for (size_type l = 0; l < n; ++l)
1533  for (size_type k = 0; k < m; ++k)
1534  for (size_type j = 0; j < n; ++j)
1535  for (size_type i = 0; i < n; ++i, ++it) {
1536  *it = scalar_type(0);
1537  if (l == i) *it += (*(args[0]))[j*m+k];
1538  if (l == j) *it += (*(args[0]))[i*m+k];
1539  }
1540  GMM_ASSERT1(it == result.end(), "Internal error");
1541  }
1542 
1543  // Second derivative :
1544  // A{ijklop}=delta{ok}delta{li}delta{pj} + delta{ok}delta{pi}delta{lj}
1545  // comes from (H,K) -> H^{T}K + K^{T}H
1546  void second_derivative(const arg_list &args, size_type, size_type,
1547  base_tensor &result) const { // to be verified
1548  size_type m = args[0]->sizes()[0], n = args[0]->sizes()[1];
1549  base_tensor::iterator it = result.begin();
1550  for (size_type p = 0; p < n; ++p)
1551  for (size_type o = 0; o < m; ++o)
1552  for (size_type l = 0; l < n; ++l)
1553  for (size_type k = 0; k < m; ++k)
1554  for (size_type j = 0; j < n; ++j)
1555  for (size_type i = 0; i < n; ++i, ++it) {
1556  *it = scalar_type(0);
1557  if (o == k) {
1558  if (l == i && p == j) *it += scalar_type(1);
1559  if (p == i && l == j) *it += scalar_type(1);
1560  }
1561  }
1562  GMM_ASSERT1(it == result.end(), "Internal error");
1563  }
1564  };
1565 
1566  // Left-Cauchy-Green operator (FF^{T})
1567  struct Left_Cauchy_Green_operator : public ga_nonlinear_operator {
1568  bool result_size(const arg_list &args, bgeot::multi_index &sizes) const {
1569  if (args.size() != 1 || args[0]->sizes().size() != 2) return false;
1570  ga_init_square_matrix_(sizes, args[0]->sizes()[0]);
1571  return true;
1572  }
1573 
1574  // Value : FF^{T}
1575  void value(const arg_list &args, base_tensor &result) const {
1576  // to be verified
1577  size_type m = args[0]->sizes()[0], n = args[0]->sizes()[1];
1578  base_tensor::iterator it = result.begin();
1579  for (size_type j = 0; j < m; ++j)
1580  for (size_type i = 0; i < m; ++i, ++it) {
1581  *it = scalar_type(0);
1582  for (size_type k = 0; k < n; ++k)
1583  *it += (*(args[0]))[k*m+i] * (*(args[0]))[k*m+j];
1584  }
1585  }
1586 
1587  // Derivative : F{jl}delta{ik}+F{il}delta{kj}
1588  // (comes from H -> HF^{T} + FH^{T})
1589  void derivative(const arg_list &args, size_type,
1590  base_tensor &result) const {
1591  size_type m = args[0]->sizes()[0], n = args[0]->sizes()[1];
1592  base_tensor::iterator it = result.begin();
1593  for (size_type l = 0; l < n; ++l)
1594  for (size_type k = 0; k < m; ++k)
1595  for (size_type j = 0; j < m; ++j)
1596  for (size_type i = 0; i < m; ++i, ++it) {
1597  *it = scalar_type(0);
1598  if (k == i) *it += (*(args[0]))[l*m+j];
1599  if (k == j) *it += (*(args[0]))[l*m+i];
1600  }
1601  GMM_ASSERT1(it == result.end(), "Internal error");
1602  }
1603 
1604  // Second derivative :
1605  // A{ijklop}=delta{ki}delta{lp}delta{oj} + delta{oi}delta{pl}delta{kj}
1606  // comes from (H,K) -> HK^{T} + KH^{T}
1607  void second_derivative(const arg_list &args, size_type, size_type,
1608  base_tensor &result) const {
1609  size_type m = args[0]->sizes()[0], n = args[0]->sizes()[1];
1610  base_tensor::iterator it = result.begin();
1611  for (size_type p = 0; p < n; ++p)
1612  for (size_type o = 0; o < m; ++o)
1613  for (size_type l = 0; l < n; ++l)
1614  for (size_type k = 0; k < m; ++k)
1615  for (size_type j = 0; j < m; ++j)
1616  for (size_type i = 0; i < m; ++i, ++it) {
1617  *it = scalar_type(0);
1618  if (p == l) {
1619  if (k == i && o == j) *it += scalar_type(1);
1620  if (o == i && k == j) *it += scalar_type(1);
1621  }
1622  }
1623  GMM_ASSERT1(it == result.end(), "Internal error");
1624  }
1625  };
1626 
1627 
1628  // Green-Lagrangian operator (F^{T}F-I)/2
1629  struct Green_Lagrangian_operator : public ga_nonlinear_operator {
1630  bool result_size(const arg_list &args, bgeot::multi_index &sizes) const {
1631  if (args.size() != 1 || args[0]->sizes().size() != 2) return false;
1632  ga_init_square_matrix_(sizes, args[0]->sizes()[1]);
1633  return true;
1634  }
1635 
1636  // Value : F^{T}F
1637  void value(const arg_list &args, base_tensor &result) const {
1638  // to be verified
1639  size_type m = args[0]->sizes()[0], n = args[0]->sizes()[1];
1640  base_tensor::iterator it = result.begin();
1641  for (size_type j = 0; j < n; ++j)
1642  for (size_type i = 0; i < n; ++i, ++it) {
1643  *it = scalar_type(0);
1644  for (size_type k = 0; k < m; ++k)
1645  *it += (*(args[0]))[i*m+k]*(*(args[0]))[j*m+k]*scalar_type(0.5);
1646  if (i == j) *it -= scalar_type(0.5);
1647  }
1648  }
1649 
1650  // Derivative : (F{kj}delta{li}+F{ki}delta{lj})/2
1651  // (comes from H -> (H^{T}F + F^{T}H)/2)
1652  void derivative(const arg_list &args, size_type,
1653  base_tensor &result) const { // to be verified
1654  size_type m = args[0]->sizes()[0], n = args[0]->sizes()[1];
1655  base_tensor::iterator it = result.begin();
1656  for (size_type l = 0; l < n; ++l)
1657  for (size_type k = 0; k < m; ++k)
1658  for (size_type j = 0; j < n; ++j)
1659  for (size_type i = 0; i < n; ++i, ++it) {
1660  *it = scalar_type(0);
1661  if (l == i) *it += (*(args[0]))[j*m+k]*scalar_type(0.5);
1662  if (l == j) *it += (*(args[0]))[i*m+k]*scalar_type(0.5);
1663  }
1664  GMM_ASSERT1(it == result.end(), "Internal error");
1665  }
1666 
1667  // Second derivative :
1668  // A{ijklop}=(delta{ok}delta{li}delta{pj} + delta{ok}delta{pi}delta{lj})/2
1669  // comes from (H,K) -> (H^{T}K + K^{T}H)/2
1670  void second_derivative(const arg_list &args, size_type, size_type,
1671  base_tensor &result) const { // to be verified
1672  size_type m = args[0]->sizes()[0], n = args[0]->sizes()[1];
1673  base_tensor::iterator it = result.begin();
1674  for (size_type p = 0; p < n; ++p)
1675  for (size_type o = 0; o < m; ++o)
1676  for (size_type l = 0; l < n; ++l)
1677  for (size_type k = 0; k < m; ++k)
1678  for (size_type j = 0; j < n; ++j)
1679  for (size_type i = 0; i < n; ++i, ++it) {
1680  *it = scalar_type(0);
1681  if (o == k) {
1682  if (l == i && p == j) *it += scalar_type(0.5);
1683  if (p == i && l == j) *it += scalar_type(0.5);
1684  }
1685  }
1686  GMM_ASSERT1(it == result.end(), "Internal error");
1687  }
1688  };
1689 
1690  // Cauchy stress tensor from second Piola-Kirchhoff stress tensor
1691  // (I+Grad_u)\sigma(I+Grad_u')/det(I+Grad_u)
1692  struct Cauchy_stress_from_PK2 : public ga_nonlinear_operator {
1693  bool result_size(const arg_list &args, bgeot::multi_index &sizes) const {
1694  if (args.size() != 2 || args[0]->sizes().size() != 2
1695  || args[1]->sizes().size() != 2
1696  || args[0]->sizes()[0] != args[0]->sizes()[1]
1697  || args[1]->sizes()[0] != args[0]->sizes()[1]
1698  || args[1]->sizes()[1] != args[0]->sizes()[1]) return false;
1699  ga_init_square_matrix_(sizes, args[0]->sizes()[1]);
1700  return true;
1701  }
1702 
1703  // Value : (I+Grad_u)\sigma(I+Grad_u')/det(I+Grad_u)
1704  void value(const arg_list &args, base_tensor &result) const {
1705  size_type N = args[0]->sizes()[0];
1706  base_matrix F(N, N), sigma(N,N), aux(N, N);
1707  gmm::copy(args[0]->as_vector(), sigma.as_vector());
1708  gmm::copy(args[1]->as_vector(), F.as_vector());
1709  gmm::add(gmm::identity_matrix(), F);
1710  gmm::mult(F, sigma, aux);
1711  gmm::mult(aux, gmm::transposed(F), sigma);
1712  scalar_type det = bgeot::lu_det(&(*(F.begin())), N);
1713  gmm::scale(sigma, scalar_type(1)/det);
1714  gmm::copy(sigma.as_vector(), result.as_vector());
1715  }
1716 
1717  // Derivative :
1718  void derivative(const arg_list &args, size_type nder,
1719  base_tensor &result) const { // to be verified
1720  size_type N = args[0]->sizes()[0];
1721  base_matrix F(N, N);
1722  gmm::copy(args[1]->as_vector(), F.as_vector());
1723  gmm::add(gmm::identity_matrix(), F);
1724  scalar_type det = bgeot::lu_det(&(*(F.begin())), N);
1725 
1726  base_tensor::iterator it = result.begin();
1727 
1728  switch (nder) {
1729  case 1: // Derivative with respect to sigma : F_ik F_jl / det(F)
1730  for (size_type l = 0; l < N; ++l)
1731  for (size_type k = 0; k < N; ++k)
1732  for (size_type j = 0; j < N; ++j)
1733  for (size_type i = 0; i < N; ++i, ++it)
1734  *it = F(i,k) * F(j,l) / det;
1735  break;
1736 
1737  case 2:
1738  {
1739  // Derivative with respect to Grad_u :
1740  // (delta_ik sigma_lm F_jm + F_im sigma_mk delta_lj
1741  // - F_im sigma_mn F_jn F^{-1}_lk) / det(F)
1742  base_matrix sigma(N,N), aux(N,N), aux2(N,N);
1743  gmm::copy(args[0]->as_vector(), sigma.as_vector());
1744  gmm::mult(sigma, gmm::transposed(F), aux);
1745  gmm::mult(F, aux, aux2);
1746  bgeot::lu_inverse(&(*(F.begin())), N);
1747  for (size_type l = 0; l < N; ++l)
1748  for (size_type k = 0; k < N; ++k)
1749  for (size_type j = 0; j < N; ++j)
1750  for (size_type i = 0; i < N; ++i, ++it) {
1751  *it = scalar_type(0);
1752  if (i == k) *it += aux(l, j) / det;
1753  if (l == j) *it += aux(k, i) / det;
1754  *it -= aux2(i,j) * F(l,k) / det;
1755  }
1756  }
1757  break;
1758  }
1759  GMM_ASSERT1(it == result.end(), "Internal error");
1760  }
1761 
1762  // Second derivative : to be implemented
1763  void second_derivative(const arg_list &, size_type, size_type,
1764  base_tensor &) const {
1765  GMM_ASSERT1(false, "Sorry, not implemented");
1766  }
1767  };
1768 
1769 
1770  struct AHL_wrapper_sigma : public ga_nonlinear_operator {
1771  phyperelastic_law AHL;
1772  bool result_size(const arg_list &args, bgeot::multi_index &sizes) const {
1773  if (args.size() != 2 || args[0]->sizes().size() != 2
1774  || args[1]->size() != AHL->nb_params()
1775  || args[0]->sizes()[0] != args[0]->sizes()[1]) return false;
1776  ga_init_square_matrix_(sizes, args[0]->sizes()[0]);
1777  return true;
1778  }
1779 
1780  // Value :
1781  void value(const arg_list &args, base_tensor &result) const {
1782  size_type N = args[0]->sizes()[0];
1783  base_vector params(AHL->nb_params());
1784  gmm::copy(args[1]->as_vector(), params);
1785  base_matrix Gu(N, N), E(N,N), sigma(N,N);
1786  gmm::copy(args[0]->as_vector(), Gu.as_vector());
1787  gmm::mult(gmm::transposed(Gu), Gu, E);
1788  gmm::add(Gu, E); gmm::add(gmm::transposed(Gu), E);
1789  gmm::scale(E, scalar_type(0.5));
1790  gmm::add(gmm::identity_matrix(), Gu);
1791  scalar_type det = bgeot::lu_det(&(*(Gu.begin())), N);
1792 
1793  AHL->sigma(E, sigma, params, det);
1794  gmm::copy(sigma.as_vector(), result.as_vector());
1795  }
1796 
1797  // Derivative :
1798  void derivative(const arg_list &args, size_type nder,
1799  base_tensor &result) const {
1800  size_type N = args[0]->sizes()[0];
1801  base_vector params(AHL->nb_params());
1802  gmm::copy(args[1]->as_vector(), params);
1803  base_tensor grad_sigma(N, N, N, N);
1804  base_matrix Gu(N, N), E(N,N);
1805  gmm::copy(args[0]->as_vector(), Gu.as_vector());
1806  gmm::mult(gmm::transposed(Gu), Gu, E);
1807  gmm::add(Gu, E); gmm::add(gmm::transposed(Gu), E);
1808  gmm::scale(E, scalar_type(0.5));
1809  gmm::add(gmm::identity_matrix(), Gu);
1810  scalar_type det = bgeot::lu_det(&(*(Gu.begin())), N);
1811 
1812  GMM_ASSERT1(nder == 1, "Sorry, the derivative of this hyperelastic "
1813  "law with respect to its parameters is not available.");
1814 
1815  AHL->grad_sigma(E, grad_sigma, params, det);
1816 
1817  base_tensor::iterator it = result.begin();
1818  for (size_type l = 0; l < N; ++l)
1819  for (size_type k = 0; k < N; ++k)
1820  for (size_type j = 0; j < N; ++j)
1821  for (size_type i = 0; i < N; ++i, ++it) {
1822  *it = scalar_type(0);
1823  for (size_type m = 0; m < N; ++m)
1824  *it += grad_sigma(i,j,m,l) * Gu(k, m); // to be optimized
1825  }
1826  GMM_ASSERT1(it == result.end(), "Internal error");
1827  }
1828 
1829 
1830  // Second derivative : not implemented (not necessary)
1831  void second_derivative(const arg_list &, size_type, size_type,
1832  base_tensor &) const {
1833  GMM_ASSERT1(false, "Sorry, second derivative not implemented");
1834  }
1835 
1836  AHL_wrapper_sigma(const phyperelastic_law &A) : AHL(A) {}
1837 
1838  };
1839 
1840 
1841  struct AHL_wrapper_potential : public ga_nonlinear_operator {
1842  phyperelastic_law AHL;
1843  bool result_size(const arg_list &args, bgeot::multi_index &sizes) const {
1844  if (args.size() != 2 || args[0]->sizes().size() != 2
1845  || args[1]->size() != AHL->nb_params()
1846  || args[0]->sizes()[0] != args[0]->sizes()[1]) return false;
1847  ga_init_scalar_(sizes);
1848  return true;
1849  }
1850 
1851  // Value :
1852  void value(const arg_list &args, base_tensor &result) const {
1853  size_type N = args[0]->sizes()[0];
1854  base_vector params(AHL->nb_params());
1855  gmm::copy(args[1]->as_vector(), params);
1856  base_matrix Gu(N, N), E(N,N);
1857  gmm::copy(args[0]->as_vector(), Gu.as_vector());
1858  gmm::mult(gmm::transposed(Gu), Gu, E);
1859  gmm::add(Gu, E); gmm::add(gmm::transposed(Gu), E);
1860  gmm::scale(E, scalar_type(0.5));
1861  gmm::add(gmm::identity_matrix(), Gu);
1862  scalar_type det = bgeot::lu_det(&(*(Gu.begin())), N); // not necessary here
1863 
1864  result[0] = AHL->strain_energy(E, params, det);
1865  }
1866 
1867  // Derivative :
1868  void derivative(const arg_list &args, size_type nder,
1869  base_tensor &result) const {
1870  size_type N = args[0]->sizes()[0];
1871  base_vector params(AHL->nb_params());
1872  gmm::copy(args[1]->as_vector(), params);
1873  base_matrix Gu(N, N), E(N,N), sigma(N,N);
1874  gmm::copy(args[0]->as_vector(), Gu.as_vector());
1875  gmm::mult(gmm::transposed(Gu), Gu, E);
1876  gmm::add(Gu, E); gmm::add(gmm::transposed(Gu), E);
1877  gmm::scale(E, scalar_type(0.5));
1878  gmm::add(gmm::identity_matrix(), Gu);
1879  scalar_type det = bgeot::lu_det(&(*(Gu.begin())), N); // not necessary here
1880 
1881  GMM_ASSERT1(nder == 1, "Sorry, Cannot derive the potential with "
1882  "respect to law parameters.");
1883 
1884  AHL->sigma(E, sigma, params, det);
1885  gmm::mult(Gu, sigma, E);
1886  gmm::copy(E.as_vector(), result.as_vector());
1887  }
1888 
1889 
1890  // Second derivative :
1891  void second_derivative(const arg_list &args, size_type nder1,
1892  size_type nder2, base_tensor &result) const {
1893 
1894  size_type N = args[0]->sizes()[0];
1895  base_vector params(AHL->nb_params());
1896  gmm::copy(args[1]->as_vector(), params);
1897  base_tensor grad_sigma(N, N, N, N);
1898  base_matrix Gu(N, N), E(N,N), sigma(N,N);
1899  gmm::copy(args[0]->as_vector(), Gu.as_vector());
1900  gmm::mult(gmm::transposed(Gu), Gu, E);
1901  gmm::add(Gu, E); gmm::add(gmm::transposed(Gu), E);
1902  gmm::scale(E, scalar_type(0.5));
1903  gmm::add(gmm::identity_matrix(), Gu);
1904  scalar_type det = bgeot::lu_det(&(*(Gu.begin())), N);
1905 
1906  GMM_ASSERT1(nder1 == 1 && nder2 == 1, "Sorry, Cannot derive the "
1907  "potential with respect to law parameters.");
1908 
1909  AHL->sigma(E, sigma, params, det);
1910  AHL->grad_sigma(E, grad_sigma, params, det);
1911 
1912  base_tensor::iterator it = result.begin();
1913  for (size_type l = 0; l < N; ++l)
1914  for (size_type k = 0; k < N; ++k)
1915  for (size_type j = 0; j < N; ++j)
1916  for (size_type i = 0; i < N; ++i, ++it) {
1917  *it = scalar_type(0);
1918  if (i == k) *it += sigma(l,j);
1919 
1920  for (size_type m = 0; m < N; ++m) // to be optimized
1921  for (size_type n = 0; n < N; ++n)
1922  *it += grad_sigma(n,j,m,l) * Gu(k, m) * Gu(i, n);
1923  }
1924  GMM_ASSERT1(it == result.end(), "Internal error");
1925 
1926  }
1927 
1928  AHL_wrapper_potential(const phyperelastic_law &A) : AHL(A) {}
1929 
1930  };
1931 
1932 
1933  // Saint-Venant Kirchhoff tensor:
1934  // lambda Tr(E)Id + 2*mu*E with E = (Grad_u+Grad_u'+Grad_u'Grad_u)/2
1935  struct Saint_Venant_Kirchhoff_sigma : public ga_nonlinear_operator {
1936  bool result_size(const arg_list &args, bgeot::multi_index &sizes) const {
1937  if (args.size() != 2 || args[0]->sizes().size() != 2
1938  || args[1]->size() != 2
1939  || args[0]->sizes()[0] != args[0]->sizes()[1]) return false;
1940  ga_init_square_matrix_(sizes, args[0]->sizes()[0]);
1941  return true;
1942  }
1943 
1944  // Value : Tr(E) + 2*mu*E
1945  void value(const arg_list &args, base_tensor &result) const {
1946  size_type N = args[0]->sizes()[0];
1947  scalar_type lambda = (*(args[1]))[0], mu = (*(args[1]))[1];
1948  base_matrix Gu(N, N), E(N,N);
1949  gmm::copy(args[0]->as_vector(), Gu.as_vector());
1950  gmm::mult(gmm::transposed(Gu), Gu, E);
1951  gmm::add(Gu, E); gmm::add(gmm::transposed(Gu), E);
1952  gmm::scale(E, scalar_type(0.5));
1953  scalar_type trE = gmm::mat_trace(E);
1954 
1955  base_tensor::iterator it = result.begin();
1956  for (size_type j = 0; j < N; ++j)
1957  for (size_type i = 0; i < N; ++i, ++it) {
1958  *it = 2*mu*E(i,j);
1959  if (i == j) *it += lambda*trE;
1960  }
1961  }
1962 
1963  // Derivative / u: lambda Tr(H + H'*U) Id + mu(H + H' + H'*U + U'*H)
1964  // with U = Grad_u, H = Grad_Test_u
1965  // Implementation: A{ijkl} = lambda(delta{kl}delta{ij} + U{kl}delta{ij})
1966  // + mu(delta{ik}delta{jl} + delta{il}delta{jk} + U{kj}delta{il} +
1967  // U{ki}delta{lj})
1968  void derivative(const arg_list &args, size_type nder,
1969  base_tensor &result) const {
1970  size_type N = args[0]->sizes()[0];
1971  scalar_type lambda = (*(args[1]))[0], mu = (*(args[1]))[1], trE;
1972  base_matrix Gu(N, N), E(N,N);
1973  gmm::copy(args[0]->as_vector(), Gu.as_vector());
1974  if (nder > 1) {
1975  gmm::mult(gmm::transposed(Gu), Gu, E);
1976  gmm::add(Gu, E); gmm::add(gmm::transposed(Gu), E);
1977  gmm::scale(E, scalar_type(0.5));
1978  }
1979  base_tensor::iterator it = result.begin();
1980  switch (nder) {
1981  case 1: // Derivative with respect to u
1982  for (size_type l = 0; l < N; ++l)
1983  for (size_type k = 0; k < N; ++k)
1984  for (size_type j = 0; j < N; ++j)
1985  for (size_type i = 0; i < N; ++i, ++it) {
1986  *it = scalar_type(0);
1987  if (i == j && k == l) *it += lambda;
1988  if (i == j) *it += lambda*Gu(k,l);
1989  if (i == k && j == l) *it += mu;
1990  if (i == l && j == k) *it += mu;
1991  if (i == l) *it += mu*Gu(k,j);
1992  if (l == j) *it += mu*Gu(k,i);
1993  }
1994  break;
1995  case 2:
1996  // Derivative with respect to lambda: Tr(E)Id
1997  trE = gmm::mat_trace(E);
1998  for (size_type j = 0; j < N; ++j)
1999  for (size_type i = 0; i < N; ++i, ++it) {
2000  *it = scalar_type(0); if (i == j) *it += trE;
2001  }
2002  // Derivative with respect to mu: 2E
2003  for (size_type j = 0; j < N; ++j)
2004  for (size_type i = 0; i < N; ++i, ++it) {
2005  *it += 2*E(i,j);
2006  }
2007  break;
2008  default: GMM_ASSERT1(false, "Internal error");
2009  }
2010  GMM_ASSERT1(it == result.end(), "Internal error");
2011  }
2012 
2013  // Second derivative : not implemented
2014  void second_derivative(const arg_list &, size_type, size_type,
2015  base_tensor &) const {
2016  GMM_ASSERT1(false, "Sorry, second derivative not implemented");
2017  }
2018  };
2019 
2020 
2021 
2022  static bool init_predef_operators() {
2023 
2024  ga_predef_operator_tab &PREDEF_OPERATORS
2026 
2027  PREDEF_OPERATORS.add_method
2028  ("Matrix_i2", std::make_shared<matrix_i2_operator>());
2029  PREDEF_OPERATORS.add_method
2030  ("Matrix_j1", std::make_shared<matrix_j1_operator>());
2031  PREDEF_OPERATORS.add_method
2032  ("Matrix_j2", std::make_shared<matrix_j2_operator>());
2033  PREDEF_OPERATORS.add_method
2034  ("Right_Cauchy_Green", std::make_shared<Right_Cauchy_Green_operator>());
2035  PREDEF_OPERATORS.add_method
2036  ("Left_Cauchy_Green", std::make_shared<Left_Cauchy_Green_operator>());
2037  PREDEF_OPERATORS.add_method
2038  ("Green_Lagrangian", std::make_shared<Green_Lagrangian_operator>());
2039 
2040  PREDEF_OPERATORS.add_method
2041  ("Cauchy_stress_from_PK2", std::make_shared<Cauchy_stress_from_PK2>());
2042 
2043  PREDEF_OPERATORS.add_method
2044  ("Saint_Venant_Kirchhoff_sigma",
2045  std::make_shared<Saint_Venant_Kirchhoff_sigma>());
2046  PREDEF_OPERATORS.add_method
2047  ("Saint_Venant_Kirchhoff_PK2",
2048  std::make_shared<Saint_Venant_Kirchhoff_sigma>());
2049  PREDEF_OPERATORS.add_method
2050  ("Saint_Venant_Kirchhoff_potential",
2051  std::make_shared<AHL_wrapper_potential>
2052  (std::make_shared<SaintVenant_Kirchhoff_hyperelastic_law>()));
2053  PREDEF_OPERATORS.add_method
2054  ("Plane_Strain_Saint_Venant_Kirchhoff_sigma",
2055  std::make_shared<Saint_Venant_Kirchhoff_sigma>());
2056  PREDEF_OPERATORS.add_method
2057  ("Plane_Strain_Saint_Venant_Kirchhoff_PK2",
2058  std::make_shared<Saint_Venant_Kirchhoff_sigma>());
2059  PREDEF_OPERATORS.add_method
2060  ("Plane_Strain_Saint_Venant_Kirchhoff_potential",
2061  std::make_shared<AHL_wrapper_potential>
2062  (std::make_shared<SaintVenant_Kirchhoff_hyperelastic_law>()));
2063 
2064  phyperelastic_law gbklaw
2065  = std::make_shared<generalized_Blatz_Ko_hyperelastic_law>();
2066  PREDEF_OPERATORS.add_method
2067  ("Generalized_Blatz_Ko_sigma",
2068  std::make_shared<AHL_wrapper_sigma>(gbklaw));
2069  PREDEF_OPERATORS.add_method
2070  ("Generalized_Blatz_Ko_PK2",
2071  std::make_shared<AHL_wrapper_sigma>(gbklaw));
2072  PREDEF_OPERATORS.add_method
2073  ("Generalized_Blatz_Ko_potential",
2074  std::make_shared<AHL_wrapper_potential>
2075  (std::make_shared<generalized_Blatz_Ko_hyperelastic_law>()));
2076  PREDEF_OPERATORS.add_method
2077  ("Plane_Strain_Generalized_Blatz_Ko_sigma",
2078  std::make_shared<AHL_wrapper_sigma>
2079  (std::make_shared<plane_strain_hyperelastic_law>(gbklaw)));
2080  PREDEF_OPERATORS.add_method
2081  ("Plane_Strain_Generalized_Blatz_Ko_PK2",
2082  std::make_shared<AHL_wrapper_sigma>
2083  (std::make_shared<plane_strain_hyperelastic_law>(gbklaw)));
2084  PREDEF_OPERATORS.add_method
2085  ("Plane_Strain_Generalized_Blatz_Ko_potential",
2086  std::make_shared<AHL_wrapper_potential>
2087  (std::make_shared<plane_strain_hyperelastic_law>(gbklaw)));
2088 
2089  phyperelastic_law cigelaw
2090  = std::make_shared<Ciarlet_Geymonat_hyperelastic_law>();
2091  PREDEF_OPERATORS.add_method
2092  ("Ciarlet_Geymonat_PK2", std::make_shared<AHL_wrapper_sigma>(cigelaw));
2093  PREDEF_OPERATORS.add_method
2094  ("Ciarlet_Geymonat_sigma", std::make_shared<AHL_wrapper_sigma>(cigelaw));
2095  PREDEF_OPERATORS.add_method
2096  ("Ciarlet_Geymonat_potential",
2097  std::make_shared<AHL_wrapper_potential>
2098  (std::make_shared<Ciarlet_Geymonat_hyperelastic_law>()));
2099  PREDEF_OPERATORS.add_method
2100  ("Plane_Strain_Ciarlet_Geymonat_sigma",
2101  std::make_shared<AHL_wrapper_sigma>
2102  (std::make_shared<plane_strain_hyperelastic_law>(cigelaw)));
2103  PREDEF_OPERATORS.add_method
2104  ("Plane_Strain_Ciarlet_Geymonat_PK2",
2105  std::make_shared<AHL_wrapper_sigma>
2106  (std::make_shared<plane_strain_hyperelastic_law>(cigelaw)));
2107  PREDEF_OPERATORS.add_method
2108  ("Plane_Strain_Ciarlet_Geymonat_potential",
2109  std::make_shared<AHL_wrapper_potential>
2110  (std::make_shared<plane_strain_hyperelastic_law>(cigelaw)));
2111 
2112  phyperelastic_law morilaw
2113  = std::make_shared<Mooney_Rivlin_hyperelastic_law>();
2114  PREDEF_OPERATORS.add_method
2115  ("Incompressible_Mooney_Rivlin_sigma",
2116  std::make_shared<AHL_wrapper_sigma>(morilaw));
2117  PREDEF_OPERATORS.add_method
2118  ("Incompressible_Mooney_Rivlin_PK2",
2119  std::make_shared<AHL_wrapper_sigma>(morilaw));
2120  PREDEF_OPERATORS.add_method
2121  ("Incompressible_Mooney_Rivlin_potential",
2122  std::make_shared<AHL_wrapper_potential>
2123  (std::make_shared<Mooney_Rivlin_hyperelastic_law>()));
2124  PREDEF_OPERATORS.add_method
2125  ("Plane_Strain_Incompressible_Mooney_Rivlin_PK2",
2126  std::make_shared<AHL_wrapper_sigma>
2127  (std::make_shared<plane_strain_hyperelastic_law>(morilaw)));
2128  PREDEF_OPERATORS.add_method
2129  ("Plane_Strain_Incompressible_Mooney_Rivlin_sigma",
2130  std::make_shared<AHL_wrapper_sigma>
2131  (std::make_shared<plane_strain_hyperelastic_law>(morilaw)));
2132  PREDEF_OPERATORS.add_method
2133  ("Plane_Strain_Incompressible_Mooney_Rivlin_potential",
2134  std::make_shared<AHL_wrapper_potential>
2135  (std::make_shared<plane_strain_hyperelastic_law>(morilaw)));
2136 
2137  phyperelastic_law cmorilaw
2138  = std::make_shared<Mooney_Rivlin_hyperelastic_law>(true);
2139  PREDEF_OPERATORS.add_method
2140  ("Compressible_Mooney_Rivlin_sigma",
2141  std::make_shared<AHL_wrapper_sigma>(cmorilaw));
2142  PREDEF_OPERATORS.add_method
2143  ("Compressible_Mooney_Rivlin_PK2",
2144  std::make_shared<AHL_wrapper_sigma>(cmorilaw));
2145  PREDEF_OPERATORS.add_method
2146  ("Compressible_Mooney_Rivlin_potential",
2147  std::make_shared<AHL_wrapper_potential>
2148  (std::make_shared<Mooney_Rivlin_hyperelastic_law>(true)));
2149  PREDEF_OPERATORS.add_method
2150  ("Plane_Strain_Compressible_Mooney_Rivlin_PK2",
2151  std::make_shared<AHL_wrapper_sigma>
2152  (std::make_shared<plane_strain_hyperelastic_law>(cmorilaw)));
2153  PREDEF_OPERATORS.add_method
2154  ("Plane_Strain_Compressible_Mooney_Rivlin_sigma",
2155  std::make_shared<AHL_wrapper_sigma>
2156  (std::make_shared<plane_strain_hyperelastic_law>(cmorilaw)));
2157  PREDEF_OPERATORS.add_method
2158  ("Plane_Strain_Compressible_Mooney_Rivlin_potential",
2159  std::make_shared<AHL_wrapper_potential>
2160  (std::make_shared<plane_strain_hyperelastic_law>(cmorilaw)));
2161 
2162  phyperelastic_law ineolaw
2163  = std::make_shared<Mooney_Rivlin_hyperelastic_law>(false, true);
2164  PREDEF_OPERATORS.add_method
2165  ("Incompressible_Neo_Hookean_sigma",
2166  std::make_shared<AHL_wrapper_sigma>(ineolaw));
2167  PREDEF_OPERATORS.add_method
2168  ("Incompressible_Neo_Hookean_PK2",
2169  std::make_shared<AHL_wrapper_sigma>(ineolaw));
2170  PREDEF_OPERATORS.add_method
2171  ("Incompressible_Neo_Hookean_potential",
2172  std::make_shared<AHL_wrapper_potential>
2173  (std::make_shared<Mooney_Rivlin_hyperelastic_law>(false,true)));
2174  PREDEF_OPERATORS.add_method
2175  ("Plane_Strain_Incompressible_Neo_Hookean_sigma",
2176  std::make_shared<AHL_wrapper_sigma>
2177  (std::make_shared<plane_strain_hyperelastic_law>(ineolaw)));
2178  PREDEF_OPERATORS.add_method
2179  ("Plane_Strain_Incompressible_Neo_Hookean_PK2",
2180  std::make_shared<AHL_wrapper_sigma>
2181  (std::make_shared<plane_strain_hyperelastic_law>(ineolaw)));
2182  PREDEF_OPERATORS.add_method
2183  ("Plane_Strain_Incompressible_Neo_Hookean_potential",
2184  std::make_shared<AHL_wrapper_potential>
2185  (std::make_shared<plane_strain_hyperelastic_law>(ineolaw)));
2186 
2187  phyperelastic_law cneolaw
2188  = std::make_shared<Mooney_Rivlin_hyperelastic_law>(true, true);
2189  PREDEF_OPERATORS.add_method
2190  ("Compressible_Neo_Hookean_sigma",
2191  std::make_shared<AHL_wrapper_sigma>(cneolaw));
2192  PREDEF_OPERATORS.add_method
2193  ("Compressible_Neo_Hookean_PK2",
2194  std::make_shared<AHL_wrapper_sigma>(cneolaw));
2195  PREDEF_OPERATORS.add_method
2196  ("Compressible_Neo_Hookean_potential",
2197  std::make_shared<AHL_wrapper_potential>
2198  (std::make_shared<Mooney_Rivlin_hyperelastic_law>(true,true)));
2199  PREDEF_OPERATORS.add_method
2200  ("Plane_Strain_Compressible_Neo_Hookean_sigma",
2201  std::make_shared<AHL_wrapper_sigma>
2202  (std::make_shared<plane_strain_hyperelastic_law>(cneolaw)));
2203  PREDEF_OPERATORS.add_method
2204  ("Plane_Strain_Compressible_Neo_Hookean_PK2",
2205  std::make_shared<AHL_wrapper_sigma>
2206  (std::make_shared<plane_strain_hyperelastic_law>(cneolaw)));
2207  PREDEF_OPERATORS.add_method
2208  ("Plane_Strain_Compressible_Neo_Hookean_potential",
2209  std::make_shared<AHL_wrapper_potential>
2210  (std::make_shared<plane_strain_hyperelastic_law>(cneolaw)));
2211 
2212  phyperelastic_law cneobolaw
2213  = std::make_shared<Neo_Hookean_hyperelastic_law>(true);
2214  PREDEF_OPERATORS.add_method
2215  ("Compressible_Neo_Hookean_Bonet_sigma",
2216  std::make_shared<AHL_wrapper_sigma>(cneobolaw));
2217  PREDEF_OPERATORS.add_method
2218  ("Compressible_Neo_Hookean_Bonet_PK2",
2219  std::make_shared<AHL_wrapper_sigma>(cneobolaw));
2220  PREDEF_OPERATORS.add_method
2221  ("Compressible_Neo_Hookean_Bonet_potential",
2222  std::make_shared<AHL_wrapper_potential>
2223  (std::make_shared<Neo_Hookean_hyperelastic_law>(true)));
2224  PREDEF_OPERATORS.add_method
2225  ("Plane_Strain_Compressible_Neo_Hookean_Bonet_sigma",
2226  std::make_shared<AHL_wrapper_sigma>
2227  (std::make_shared<plane_strain_hyperelastic_law>(cneobolaw)));
2228  PREDEF_OPERATORS.add_method
2229  ("Plane_Strain_Compressible_Neo_Hookean_Bonet_PK2",
2230  std::make_shared<AHL_wrapper_sigma>
2231  (std::make_shared<plane_strain_hyperelastic_law>(cneobolaw)));
2232  PREDEF_OPERATORS.add_method
2233  ("Plane_Strain_Compressible_Neo_Hookean_Bonet_potential",
2234  std::make_shared<AHL_wrapper_potential>
2235  (std::make_shared<plane_strain_hyperelastic_law>(cneobolaw)));
2236 
2237  phyperelastic_law cneocilaw
2238  = std::make_shared<Neo_Hookean_hyperelastic_law>(false);
2239  PREDEF_OPERATORS.add_method
2240  ("Compressible_Neo_Hookean_Ciarlet_sigma",
2241  std::make_shared<AHL_wrapper_sigma>(cneocilaw));
2242  PREDEF_OPERATORS.add_method
2243  ("Compressible_Neo_Hookean_Ciarlet_PK2",
2244  std::make_shared<AHL_wrapper_sigma>(cneocilaw));
2245  PREDEF_OPERATORS.add_method
2246  ("Compressible_Neo_Hookean_Ciarlet_potential",
2247  std::make_shared<AHL_wrapper_potential>
2248  (std::make_shared<Neo_Hookean_hyperelastic_law>(false)));
2249  PREDEF_OPERATORS.add_method
2250  ("Plane_Strain_Compressible_Neo_Hookean_Ciarlet_sigma",
2251  std::make_shared<AHL_wrapper_sigma>
2252  (std::make_shared<plane_strain_hyperelastic_law>(cneocilaw)));
2253  PREDEF_OPERATORS.add_method
2254  ("Plane_Strain_Compressible_Neo_Hookean_Ciarlet_PK2",
2255  std::make_shared<AHL_wrapper_sigma>
2256  (std::make_shared<plane_strain_hyperelastic_law>(cneocilaw)));
2257  PREDEF_OPERATORS.add_method
2258  ("Plane_Strain_Compressible_Neo_Hookean_Ciarlet_potential",
2259  std::make_shared<AHL_wrapper_potential>
2260  (std::make_shared<plane_strain_hyperelastic_law>(cneocilaw)));
2261 
2262  return true;
2263  }
2264 
2265  // declared in getfem_generic_assembly.cc
2266  bool predef_operators_nonlinear_elasticity_initialized
2267  = init_predef_operators();
2268 
2269 
2270  std::string adapt_law_name(const std::string &lawname, size_type N) {
2271  std::string adapted_lawname = lawname;
2272 
2273  for (size_type i = 0; i < lawname.size(); ++i)
2274  if (adapted_lawname[i] == ' ') adapted_lawname[i] = '_';
2275 
2276  if (adapted_lawname.compare("SaintVenant_Kirchhoff") == 0) {
2277  adapted_lawname = "Saint_Venant_Kirchhoff";
2278  } else if (adapted_lawname.compare("Saint_Venant_Kirchhoff") == 0) {
2279 
2280  } else if (adapted_lawname.compare("Generalized_Blatz_Ko") == 0) {
2281  if (N == 2) adapted_lawname = "Plane_Strain_" + adapted_lawname;
2282  } else if (adapted_lawname.compare("Ciarlet_Geymonat") == 0) {
2283  if (N == 2) adapted_lawname = "Plane_Strain_" + adapted_lawname;
2284  } else if (adapted_lawname.compare("Incompressible_Mooney_Rivlin") == 0) {
2285  if (N == 2) adapted_lawname = "Plane_Strain_" + adapted_lawname;
2286  } else if (adapted_lawname.compare("Compressible_Mooney_Rivlin") == 0) {
2287  if (N == 2) adapted_lawname = "Plane_Strain_" + adapted_lawname;
2288  } else if (adapted_lawname.compare("Incompressible_Neo_Hookean") == 0) {
2289  if (N == 2) adapted_lawname = "Plane_Strain_" + adapted_lawname;
2290  } else if (adapted_lawname.compare("Compressible_Neo_Hookean") == 0 ||
2291  adapted_lawname.compare("Compressible_Neo_Hookean_Bonet") == 0 ||
2292  adapted_lawname.compare("Compressible_Neo_Hookean_Ciarlet") == 0 ) {
2293  if (N == 2) adapted_lawname = "Plane_Strain_" + adapted_lawname;
2294  } else
2295  GMM_ASSERT1(false, lawname << " is not a known hyperelastic law");
2296 
2297  return adapted_lawname;
2298  }
2299 
2300 
2302  (model &md, const mesh_im &mim, const std::string &lawname,
2303  const std::string &varname, const std::string &params,
2304  size_type region) {
2305  std::string test_varname = "Test_" + sup_previous_and_dot_to_varname(varname);
2306  size_type N = mim.linked_mesh().dim();
2307  GMM_ASSERT1(N >= 2 && N <= 3,
2308  "Finite strain elasticity brick works only in 2D or 3D");
2309 
2310  const mesh_fem *mf = md.pmesh_fem_of_variable(varname);
2311  GMM_ASSERT1(mf, "Finite strain elasticity brick can only be applied on "
2312  "fem variables");
2313  size_type Q = mf->get_qdim();
2314  GMM_ASSERT1(Q == N, "Finite strain elasticity brick can only be applied "
2315  "on a fem variable having the same dimension as the mesh");
2316 
2317  std::string adapted_lawname = adapt_law_name(lawname, N);
2318 
2319  std::string expr = "((Id(meshdim)+Grad_"+varname+")*(" + adapted_lawname
2320  + "_PK2(Grad_"+varname+","+params+"))):Grad_" + test_varname;
2321 
2322  return add_nonlinear_term
2323  (md, mim, expr, region, true, false,
2324  "Finite strain elasticity brick for " + adapted_lawname + " law");
2325  }
2326 
2328  (model &md, const mesh_im &mim, const std::string &varname,
2329  const std::string &multname, size_type region) {
2330  std::string test_varname = "Test_" + sup_previous_and_dot_to_varname(varname);
2331  std::string test_multname = "Test_" + sup_previous_and_dot_to_varname(multname);
2332 
2333  std::string expr
2334  = "(" + test_multname+ ")*(1-Det(Id(meshdim)+Grad_" + varname + "))"
2335  + "-(" + multname + ")*(Det(Id(meshdim)+Grad_" + varname + ")"
2336  + "*((Inv(Id(meshdim)+Grad_" + varname + "))':Grad_"
2337  + test_varname + "))" ;
2338  return add_nonlinear_term
2339  (md, mim, expr, region, true, false,
2340  "Finite strain incompressibility brick");
2341  }
2342 
2344  (model &md, const std::string &lawname, const std::string &varname,
2345  const std::string &params, const mesh_fem &mf_vm,
2346  model_real_plain_vector &VM, const mesh_region &rg) {
2347  size_type N = mf_vm.linked_mesh().dim();
2348 
2349  std::string adapted_lawname = adapt_law_name(lawname, N);
2350 
2351  std::string expr = "sqrt(3/2)*Norm(Deviator(Cauchy_stress_from_PK2("
2352  + adapted_lawname + "_PK2(Grad_" + varname + "," + params + "),Grad_"
2353  + varname + ")))";
2354  ga_interpolation_Lagrange_fem(md, expr, mf_vm, VM, rg);
2355  }
2356 
2357 
2358 
2359 } /* end of namespace getfem. */
2360 
static T & instance()
Instance from the current thread.
virtual void grad_sigma_updated_lagrangian(const base_matrix &F, const base_matrix &E, const base_vector &params, scalar_type det_trans, base_tensor &grad_sigma_ul) const
cauchy-truesdel tangent moduli, used in updated lagrangian
virtual void cauchy_updated_lagrangian(const base_matrix &F, const base_matrix &E, base_matrix &cauchy_stress, const base_vector &params, scalar_type det_trans) const
True Cauchy stress (for Updated Lagrangian formulation)
Describe a finite element method linked to a mesh.
virtual dim_type get_qdim() const
Return the Q dimension.
const mesh & linked_mesh() const
Return a reference to the underlying mesh.
Describe an integration method linked to a mesh.
const mesh & linked_mesh() const
Give a reference to the linked mesh of type mesh.
structure used to hold a set of convexes and/or convex faces.
`‘Model’' variables store the variables, the data and the description of a model.
size_type add_brick(pbrick pbr, const varnamelist &varnames, const varnamelist &datanames, const termlist &terms, const mimlist &mims, size_type region)
Add a brick to the model.
const mesh_fem * pmesh_fem_of_variable(const std::string &name) const
Gives a pointer to the mesh_fem of a variable if any.
A language for generic assembly of pde boundary value problems.
Model representation in Getfem.
Non-linear elasticty and incompressibility bricks.
size_type nnz(const L &l)
count the number of non-zero entries of a vector or matrix.
Definition: gmm_blas.h:68
void copy(const L1 &l1, L2 &l2)
*‍/
Definition: gmm_blas.h:976
number_traits< typename linalg_traits< V >::value_type >::magnitude_type vect_norm2(const V &v)
Euclidean norm of a vector.
Definition: gmm_blas.h:556
void fill_random(L &l)
fill a vector or matrix with random value (uniform [-1,1]).
Definition: gmm_blas.h:129
linalg_traits< M >::value_type mat_trace(const M &m)
Trace of a matrix.
Definition: gmm_blas.h:527
number_traits< typename linalg_traits< M >::value_type >::magnitude_type mat_euclidean_norm(const M &m)
Euclidean norm of a matrix.
Definition: gmm_blas.h:635
void clear(L &l)
clear (fill with zeros) a vector or matrix.
Definition: gmm_blas.h:58
void resize(V &v, size_type n)
*‍/
Definition: gmm_blas.h:209
void mult(const L1 &l1, const L2 &l2, L3 &l3)
*‍/
Definition: gmm_blas.h:1663
void add(const L1 &l1, L2 &l2)
*‍/
Definition: gmm_blas.h:1275
number_traits< typename linalg_traits< M >::value_type >::magnitude_type mat_euclidean_norm_sqr(const M &m)
*‍/
Definition: gmm_blas.h:625
void asm_nonlinear_elasticity_tangent_matrix(const MAT &K_, const mesh_im &mim, const getfem::mesh_fem &mf, const VECT1 &U, const getfem::mesh_fem *mf_data, const VECT2 &PARAMS, const abstract_hyperelastic_law &AHL, const mesh_region &rg=mesh_region::all_convexes())
Tangent matrix for the non-linear elasticity.
size_t size_type
used as the common size type in the library
Definition: bgeot_poly.h:48
size_type alpha(short_type n, short_type d)
Return the value of which is the number of monomials of a polynomial of variables and degree .
Definition: bgeot_poly.cc:46
GEneric Tool for Finite Element Methods.
void compute_gradient(const mesh_fem &mf, const mesh_fem &mf_target, const VECT1 &UU, VECT2 &VV)
Compute the gradient of a field on a getfem::mesh_fem.
size_type APIDECL add_nonlinear_term(model &md, const mesh_im &mim, const std::string &expr, size_type region=size_type(-1), bool is_sym=false, bool is_coercive=false, const std::string &brickname="")
Add a nonlinear term given by the weak form language expression expr which will be assembled in regio...
size_type add_finite_strain_elasticity_brick(model &md, const mesh_im &mim, const std::string &lawname, const std::string &varname, const std::string &params, size_type region=size_type(-1))
Add a finite strain elasticity brick to the model with respect to the variable varname (the displacem...
size_type add_finite_strain_incompressibility_brick(model &md, const mesh_im &mim, const std::string &varname, const std::string &multname, size_type region=size_type(-1))
Add a finite strain incompressibility term (for large strain elasticity) to the model with respect to...
size_type add_nonlinear_elasticity_brick(model &md, const mesh_im &mim, const std::string &varname, const phyperelastic_law &AHL, const std::string &dataname, size_type region=size_type(-1))
Add a nonlinear (large strain) elasticity term to the model with respect to the variable varname (dep...
size_type add_nonlinear_incompressibility_brick(model &md, const mesh_im &mim, const std::string &varname, const std::string &multname, size_type region=size_type(-1))
Add a nonlinear incompressibility term (for large strain elasticity) to the model with respect to the...
void compute_finite_strain_elasticity_Von_Mises(model &md, const std::string &lawname, const std::string &varname, const std::string &params, const mesh_fem &mf_vm, model_real_plain_vector &VM, const mesh_region &rg=mesh_region::all_convexes())
Interpolate the Von-Mises stress of a field varname with respect to the nonlinear elasticity constitu...
void interpolation(const mesh_fem &mf_source, const mesh_fem &mf_target, const VECTU &U, VECTV &V, int extrapolation=0, double EPS=1E-10, mesh_region rg_source=mesh_region::all_convexes(), mesh_region rg_target=mesh_region::all_convexes())
interpolation/extrapolation of (mf_source, U) on mf_target.
std::shared_ptr< const virtual_brick > pbrick
type of pointer on a brick
Definition: getfem_models.h:48
virtual void grad_sigma_updated_lagrangian(const base_matrix &F, const base_matrix &E, const base_vector &params, scalar_type det_trans, base_tensor &grad_sigma_ul) const
cauchy-truesdel tangent moduli, used in updated lagrangian