GetFEM  5.4.3
nonlinear_elastostatic.cc
Go to the documentation of this file.
1 /*===========================================================================
2 
3  Copyright (C) 2002-2020 Yves Renard, Julien Pommier.
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, write to the Free Software Foundation,
18  Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA.
19 
20 ===========================================================================*/
21 
22 /**
23  @file nonlinear_elastostatic.cc
24  @brief Nonlinear Elastostatic problem (large strain).
25 
26  A rubber bar is submitted to a large torsion.
27 
28  This program is used to check that getfem++ is working. This is also
29  a good example of use of GetFEM.
30 */
31 
32 #include "getfem/getfem_export.h"
36 #include "gmm/gmm.h"
37 
38 using std::endl; using std::cout; using std::cerr;
39 using std::ends; using std::cin;
40 
41 /* some GetFEM types that we will be using */
42 using bgeot::base_small_vector; /* special class for small (dim<16) vectors */
43 using bgeot::base_node; /* geometrical nodes(derived from base_small_vector)*/
44 using bgeot::base_vector;
45 using bgeot::scalar_type; /* = double */
46 using bgeot::size_type; /* = unsigned long */
47 using bgeot::dim_type;
48 using bgeot::base_matrix; /* small dense matrix. */
49 
50 /* definition of some matrix/vector types. These ones are built
51  * using the predefined types in Gmm++
52  */
54 typedef getfem::modeling_standard_sparse_matrix sparse_matrix;
55 typedef getfem::modeling_standard_plain_vector plain_vector;
56 
57 /*
58  structure for the elastostatic problem
59 */
60 struct elastostatic_problem {
61 
62  enum { DIRICHLET_BOUNDARY_NUM = 0, NEUMANN_BOUNDARY_NUM = 1};
63  getfem::mesh mesh; /* the mesh */
64  getfem::mesh_im mim; /* the integration methods */
65  getfem::mesh_fem mf_u; /* main mesh_fem, for the elastostatic solution */
66  getfem::mesh_fem mf_p; /* mesh_fem for the pressure. */
67  getfem::mesh_fem mf_rhs; /* mesh_fem for the right hand side (f(x),..) */
68  getfem::mesh_fem mf_coef; /* mesh_fem used to represent pde coefficients */
69  scalar_type p1, p2, p3; /* elastic coefficients. */
70 
71  scalar_type residual; /* max residual for the iterative solvers */
72 
73  std::string datafilename;
74  bgeot::md_param PARAM;
75 
76  bool solve(plain_vector &U);
77  void init(void);
78  elastostatic_problem(void) : mim(mesh), mf_u(mesh), mf_p(mesh), mf_rhs(mesh),
79  mf_coef(mesh) {}
80 };
81 
82 
83 /* Read parameters from the .param file, build the mesh, set finite element
84  and integration methods and selects the boundaries.
85 
86  (this is boilerplate code, not very interesting)
87  */
88 void elastostatic_problem::init(void) {
89  std::string MESH_TYPE = PARAM.string_value("MESH_TYPE","Mesh type ");
90  std::string FEM_TYPE = PARAM.string_value("FEM_TYPE","FEM name");
91  std::string FEM_TYPE_P= PARAM.string_value("FEM_TYPE_P",
92  "FEM name for the pressure");
93  std::string INTEGRATION = PARAM.string_value("INTEGRATION",
94  "Name of integration method");
95  cout << "MESH_TYPE=" << MESH_TYPE << "\n";
96  cout << "FEM_TYPE=" << FEM_TYPE << "\n";
97  cout << "INTEGRATION=" << INTEGRATION << "\n";
98 
99  /* First step : build the mesh */
102  size_type N = pgt->dim();
103  std::vector<size_type> nsubdiv(N);
104  std::fill(nsubdiv.begin(),nsubdiv.end(),
105  PARAM.int_value("NX", "Nomber of space steps "));
106  nsubdiv[1] = PARAM.int_value("NY") ? PARAM.int_value("NY") : nsubdiv[0];
107  if (N>2)
108  nsubdiv[2] = PARAM.int_value("NZ") ? PARAM.int_value("NZ") : nsubdiv[0];
109  getfem::regular_unit_mesh(mesh, nsubdiv, pgt,
110  PARAM.int_value("MESH_NOISED") != 0);
111 
112  bgeot::base_matrix M(N,N);
113  for (size_type i=0; i < N; ++i) {
114  static const char *t[] = {"LX","LY","LZ"};
115  M(i,i) = (i<3) ? PARAM.real_value(t[i],t[i]) : 1.0;
116  }
117  if (N>1) { M(0,1) = PARAM.real_value("INCLINE") * PARAM.real_value("LY"); }
118 
119  /* scale the unit mesh to [LX,LY,..] and incline it */
120  mesh.transformation(M);
121 
122  datafilename = PARAM.string_value("ROOTFILENAME","Base name of data files.");
123  residual = PARAM.real_value("RESIDUAL"); if (residual == 0.) residual = 1e-10;
124 
125  p1 = PARAM.real_value("P1", "First Elastic coefficient");
126  p2 = PARAM.real_value("P2", "Second Elastic coefficient");
127  p3 = PARAM.real_value("P3", "Third Elastic coefficient");
128 
129  mf_u.set_qdim(dim_type(N));
130 
131  /* set the finite element on the mf_u */
132  getfem::pfem pf_u =
133  getfem::fem_descriptor(FEM_TYPE);
134  getfem::pintegration_method ppi =
135  getfem::int_method_descriptor(INTEGRATION);
136 
137  mim.set_integration_method(ppi);
138  mf_u.set_finite_element(pf_u);
139 
140  mf_p.set_finite_element(getfem::fem_descriptor(FEM_TYPE_P));
141 
142  /* set the finite element on mf_rhs (same as mf_u is DATA_FEM_TYPE is
143  not used in the .param file */
144  std::string data_fem_name = PARAM.string_value("DATA_FEM_TYPE");
145  if (data_fem_name.size() == 0) {
146  GMM_ASSERT1(pf_u->is_lagrange(), "You are using a non-lagrange FEM"
147  ". In that case you need to set "
148  << "DATA_FEM_TYPE in the .param file");
149  mf_rhs.set_finite_element(mesh.convex_index(), pf_u);
150  } else {
151  mf_rhs.set_finite_element(mesh.convex_index(),
152  getfem::fem_descriptor(data_fem_name));
153  }
154 
155  /* set the finite element on mf_coef. Here we use a very simple element
156  * since the only function that need to be interpolated on the mesh_fem
157  * is f(x)=1 ... */
158  mf_coef.set_finite_element(mesh.convex_index(),
159  getfem::classical_fem(pgt,0));
160 
161  /* set boundary conditions
162  * (Neuman on the upper face, Dirichlet elsewhere) */
163  cout << "Selecting Neumann and Dirichlet boundaries\n";
164  getfem::mesh_region border_faces;
165  getfem::outer_faces_of_mesh(mesh, border_faces);
166  for (getfem::mr_visitor it(border_faces); !it.finished(); ++it) {
167  assert(it.is_face());
168  base_node un = mesh.normal_of_face_of_convex(it.cv(), it.f());
169  un /= gmm::vect_norm2(un);
170  if (gmm::abs(un[N-1] - 1.0) < 1.0E-7) {
171  mesh.region(DIRICHLET_BOUNDARY_NUM).add(it.cv(),it.f());
172  } else if (gmm::abs(un[N-1] + 1.0) < 1.0E-7) {
173  mesh.region(DIRICHLET_BOUNDARY_NUM).add(it.cv(),it.f());
174  }
175  }
176 }
177 
178 /**************************************************************************/
179 /* Model. */
180 /**************************************************************************/
181 
182 bool elastostatic_problem::solve(plain_vector &U) {
183  size_type nb_dof_rhs = mf_rhs.nb_dof();
184  size_type N = mesh.dim();
185  size_type law_num = PARAM.int_value("LAW");
186  // Linearized elasticity brick.
187  base_vector p(3); p[0] = p1; p[1] = p2; p[2] = p3;
188 
189  /* choose the material law */
190  std::string lawname;
191  switch (law_num) {
192  case 0:
193  case 1: lawname = "Saint_Venant_Kirchhoff"; p.resize(2); break;
194  case 2: lawname = "Ciarlet_Geymonat"; p.resize(3); break;
195  case 3: lawname = "Incompressible_Mooney_Rivlin"; p.resize(2); break;
196  default: GMM_ASSERT1(false, "no such law");
197  }
198 
199  if (N == 2) {
200  cout << "2D plane strain hyper-elasticity\n";
201  lawname = "Plane_Strain_"+lawname;
202  }
203 
204  getfem::model model;
205 
206  // Main unknown of the problem (displacement).
207  model.add_fem_variable("u", mf_u);
208 
209  // Nonlinear elasticity brick
210  model.add_initialized_fixed_size_data("params", p);
211  getfem::add_finite_strain_elasticity_brick(model, mim, lawname, "u","params");
212 
213  // Incompressibility
214  if (law_num == 1 || law_num == 3) {
215  model.add_fem_variable("p", mf_p);
217  }
218 
219  // Defining the volumic source term.
220  base_vector f(N);
221  f[0] = PARAM.real_value("FORCEX","Amplitude of the gravity");
222  f[1] = PARAM.real_value("FORCEY","Amplitude of the gravity");
223  if (N>2)
224  f[2] = PARAM.real_value("FORCEZ","Amplitude of the gravity");
225  plain_vector F(nb_dof_rhs * N);
226  for (size_type i = 0; i < nb_dof_rhs; ++i) {
227  gmm::copy(f, gmm::sub_vector(F, gmm::sub_interval(i*N, N)));
228  }
229  // Volumic source term brick.
230  model.add_initialized_fem_data("VolumicData", mf_rhs, F);
231  getfem::add_source_term_brick(model, mim, "u", "VolumicData");
232 
233  // Dirichlet condition
234  plain_vector F2(nb_dof_rhs * N);
235  model.add_initialized_fem_data("DirichletData", mf_rhs, F2);
236  if (PARAM.int_value("DIRICHLET_VERSION") == 0)
238  (model, mim, "u", mf_u, DIRICHLET_BOUNDARY_NUM, "DirichletData");
239  else
241  (model, mim, "u", 1E15, DIRICHLET_BOUNDARY_NUM, "DirichletData");
242 
243 
244  gmm::iteration iter;
245  gmm::set_traces_level(1); // To avoid some trace messages
246 
247 
248  /* prepare the export routine for OpenDX (all time steps will be exported)
249  (can be viewed with "dx -edit nonlinear_elastostatic.net")
250  */
251  getfem::dx_export exp(datafilename + ".dx",
252  PARAM.int_value("VTK_EXPORT")==1);
254  sl.build(mesh, getfem::slicer_boundary(mesh),8);
255  exp.exporting(sl,true); exp.exporting_mesh_edges();
256  //exp.begin_series("deformationsteps");
257  exp.write_point_data(mf_u, U, "stepinit");
258  exp.serie_add_object("deformationsteps");
259 
260  GMM_ASSERT1(!mf_rhs.is_reduced(), "To be adapted for reduced mesh_fems");
261 
262  int nb_step = int(PARAM.int_value("NBSTEP"));
263  size_type maxit = PARAM.int_value("MAXITER");
264 
265  for (int step = 0; step < nb_step; ++step) {
266  plain_vector DF(F);
267 
268  gmm::copy(gmm::scaled(F, (step+1.)/(scalar_type)nb_step), DF);
269  gmm::copy(DF, model.set_real_variable("VolumicData"));
270 
271  if (N>2) {
272  /* Apply the gradual torsion/extension */
273  scalar_type torsion = PARAM.real_value("TORSION",
274  "Amplitude of the torsion");
275  torsion *= (step+1)/scalar_type(nb_step);
276  scalar_type extension = PARAM.real_value("EXTENSION",
277  "Amplitude of the extension");
278  extension *= (step+1)/scalar_type(nb_step);
279  base_node G(N); G[0] = G[1] = 0.5;
280  for (size_type i = 0; i < nb_dof_rhs; ++i) {
281  const base_node P = mf_rhs.point_of_basic_dof(i) - G;
282  scalar_type r = sqrt(P[0]*P[0]+P[1]*P[1]),
283  theta = atan2(P[1],P[0]);
284  F2[i*N+0] = r*cos(theta + (torsion*P[2])) - P[0];
285  F2[i*N+1] = r*sin(theta + (torsion*P[2])) - P[1];
286  F2[i*N+2] = extension * P[2];
287  }
288  }
289  /* update the imposed displacement */
290  gmm::copy(F2, model.set_real_variable("DirichletData"));
291 
292  cout << "step " << step << ", number of variables : "
293  << model.nb_dof() << endl;
294  iter = gmm::iteration(residual, int(PARAM.int_value("NOISY")),
295  maxit ? maxit : 40000);
296 
297  /* let the non-linear solve (Newton) do its job */
298  getfem::standard_solve(model, iter);
299 
300  gmm::copy(model.real_variable("u"), U);
301  //char s[100]; snprintf(s, 100, "step%d", step+1);
302 
303  /* append the new displacement to the exported opendx file */
304  exp.write_point_data(mf_u, U); //, s);
305  exp.serie_add_object("deformationsteps");
306  }
307 
308  // Solution extraction
309  gmm::copy(model.real_variable("u"), U);
310 
311  return (iter.converged());
312 }
313 
314 /**************************************************************************/
315 /* main program. */
316 /**************************************************************************/
317 
318 int main(int argc, char *argv[]) {
319 
320  GETFEM_MPI_INIT(argc, argv);
321  GMM_SET_EXCEPTION_DEBUG; // Exceptions make a memory fault, to debug.
322  FE_ENABLE_EXCEPT; // Enable floating point exception for Nan.
323 
324  try {
325  elastostatic_problem p;
326  p.PARAM.read_command_line(argc, argv);
327  p.init();
328  p.mesh.write_to_file(p.datafilename + ".mesh");
329  p.mf_u.write_to_file(p.datafilename + ".mf", true);
330  p.mf_rhs.write_to_file(p.datafilename + ".mfd", true);
331  plain_vector U(p.mf_u.nb_dof());
332  GMM_ASSERT1(p.solve(U), "Solve has failed");
333  if (p.PARAM.int_value("VTK_EXPORT")) {
334  gmm::vecsave(p.datafilename + ".U", U);
335  cout << "export to " << p.datafilename + ".vtk" << "..\n";
336  getfem::vtk_export exp(p.datafilename + ".vtk",
337  p.PARAM.int_value("VTK_EXPORT")==1);
338  exp.exporting(p.mf_u);
339  exp.write_point_data(p.mf_u, U, "elastostatic_displacement");
340  cout << "export done, you can view the data file with (for example)\n"
341  "mayavi2 -d " << p.datafilename << ".vtk -f ExtractVectorNorm -f "
342  "WarpVector -m Surface -m Outline\n";
343  }
344  }
345  GMM_STANDARD_CATCH_ERROR;
346 
347  GETFEM_MPI_FINALIZE;
348 
349  return 0;
350 }
A (quite large) class for exportation of data to IBM OpenDX.
Describe a finite element method linked to a mesh.
Describe an integration method linked to a mesh.
"iterator" class for regions.
structure used to hold a set of convexes and/or convex faces.
Describe a mesh (collection of convexes (elements) and points).
Definition: getfem_mesh.h:99
`‘Model’' variables store the variables, the data and the description of a model.
size_type nb_dof(bool with_internal=false) const
Total number of degrees of freedom in the model.
void add_fem_variable(const std::string &name, const mesh_fem &mf, size_type niter=1)
Add a variable being the dofs of a finite element method to the model.
void add_initialized_fixed_size_data(const std::string &name, const VECT &v)
Add a fixed size data (assumed to be a vector) to the model and initialized with v.
void add_initialized_fem_data(const std::string &name, const mesh_fem &mf, const VECT &v)
Add an initialized fixed size data to the model, assumed to be a vector field if the size of the vect...
model_real_plain_vector & set_real_variable(const std::string &name, size_type niter) const
Gives the write access to the vector value of a variable.
const model_real_plain_vector & real_variable(const std::string &name, size_type niter) const
Gives the access to the vector value of a variable.
Extraction of the boundary of a slice.
The output of a getfem::mesh_slicer which has been recorded.
void build(const getfem::mesh &m, const slicer_action &a, size_type nrefine=1)
Build the slice, by applying a slicer_action operation.
VTK/VTU export.
Definition: getfem_export.h:68
The Iteration object calculates whether the solution has reached the desired accuracy,...
Definition: gmm_iter.h:53
sparse vector built upon std::vector.
Definition: gmm_vector.h:963
Export solutions to various formats.
Standard solvers for model bricks.
Non-linear elasticty and incompressibility bricks.
Build regular meshes.
Include common gmm files.
void copy(const L1 &l1, L2 &l2)
*‍/
Definition: gmm_blas.h:978
number_traits< typename linalg_traits< V >::value_type >::magnitude_type vect_norm2(const V &v)
Euclidean norm of a vector.
Definition: gmm_blas.h:558
void APIDECL outer_faces_of_mesh(const mesh &m, const dal::bit_vector &cvlst, convex_face_ct &flist)
returns a list of "exterior" faces of a mesh (i.e.
Definition: getfem_mesh.cc:822
std::shared_ptr< const getfem::virtual_fem > pfem
type of pointer on a fem description
Definition: getfem_fem.h:244
pfem fem_descriptor(const std::string &name)
get a fem descriptor from its string name.
Definition: getfem_fem.cc:4660
pfem classical_fem(bgeot::pgeometric_trans pgt, short_type k, bool complete=false)
Give a pointer on the structures describing the classical polynomial fem of degree k on a given conve...
Definition: getfem_fem.cc:4567
pgeometric_trans geometric_trans_descriptor(std::string name)
Get the geometric transformation from its string name.
size_t size_type
used as the common size type in the library
Definition: bgeot_poly.h:49
std::shared_ptr< const bgeot::geometric_trans > pgeometric_trans
pointer type for a geometric transformation
size_type APIDECL add_Dirichlet_condition_with_multipliers(model &md, const mesh_im &mim, const std::string &varname, const std::string &multname, size_type region, const std::string &dataname=std::string())
Add a Dirichlet condition on the variable varname and the mesh region region.
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...
void regular_unit_mesh(mesh &m, std::vector< size_type > nsubdiv, bgeot::pgeometric_trans pgt, bool noised=false)
Build a regular mesh of the unit square/cube/, etc.
pintegration_method int_method_descriptor(std::string name, bool throw_if_not_found=true)
Get an integration method from its name .
size_type APIDECL add_Dirichlet_condition_with_penalization(model &md, const mesh_im &mim, const std::string &varname, scalar_type penalization_coeff, size_type region, const std::string &dataname=std::string(), const mesh_fem *mf_mult=0)
Add a Dirichlet condition on the variable varname and the mesh region region.
size_type APIDECL add_source_term_brick(model &md, const mesh_im &mim, const std::string &varname, const std::string &dataexpr, size_type region=size_type(-1), const std::string &directdataname=std::string())
Add a source term on the variable varname.
void standard_solve(model &md, gmm::iteration &iter, rmodel_plsolver_type lsolver, abstract_newton_line_search &ls)
A default solver for the model brick system.