libMesh
solid_system.C
Go to the documentation of this file.
1 // The libMesh Finite Element Library.
2 // Copyright (C) 2002-2025 Benjamin S. Kirk, John W. Peterson, Roy H. Stogner
3 
4 // This library is free software; you can redistribute it and/or
5 // modify it under the terms of the GNU Lesser General Public
6 // License as published by the Free Software Foundation; either
7 // version 2.1 of the License, or (at your option) any later version.
8 
9 // This library is distributed in the hope that it will be useful,
10 // but WITHOUT ANY WARRANTY; without even the implied warranty of
11 // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
12 // Lesser General Public License for more details.
13 
14 // You should have received a copy of the GNU Lesser General Public
15 // License along with this library; if not, write to the Free Software
16 // Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
17 
18 
19 
20 // \author Robert Weidlich
21 // \date Copyright 2012
22 
23 #include "libmesh/boundary_info.h"
24 #include "libmesh/diff_solver.h"
25 #include "libmesh/dof_map.h"
26 #include "libmesh/equation_systems.h"
27 #include "libmesh/fe_base.h"
28 #include "libmesh/fem_context.h"
29 #include "libmesh/getpot.h"
30 #include "libmesh/mesh.h"
31 #include "libmesh/newton_solver.h"
32 #include "libmesh/numeric_vector.h"
33 #include "libmesh/quadrature.h"
34 #include "libmesh/sparse_matrix.h"
35 #include "libmesh/steady_solver.h"
36 #include "libmesh/transient_system.h"
37 #include "libmesh/node.h"
38 #include "libmesh/elem.h"
39 
40 #include "nonlinear_neohooke_cc.h"
41 #include "solid_system.h"
42 
43 #include <memory>
44 
45 // Bring in everything from the libMesh namespace
46 using namespace libMesh;
47 
49  const std::string & name_in,
50  const unsigned int number_in) :
51  FEMSystem(es, name_in, number_in)
52 {
53 
54  // Add a time solver. We are just looking at a steady state problem here.
55  this->time_solver = std::make_unique<SteadySolver>(*this);
56 }
57 
59 {
60  System & aux_sys = this->get_equation_systems().get_system("auxiliary");
61 
62  const unsigned int dim = this->get_mesh().mesh_dimension();
63 
64  // Loop over all nodes and copy the location from the current system to
65  // the auxiliary system.
66  for (const auto & node : this->get_mesh().local_node_ptr_range())
67  for (unsigned int d = 0; d < dim; ++d)
68  {
69  unsigned int source_dof = node->dof_number(this->number(), var[d], 0);
70  unsigned int dest_dof = node->dof_number(aux_sys.number(), undefo_var[d], 0);
71  Number value = this->current_local_solution->el(source_dof);
72  aux_sys.current_local_solution->set(dest_dof, value);
73  }
74 }
75 
77 {
78  const unsigned int dim = this->get_mesh().mesh_dimension();
79 
80  // Get the default order of the used elements. Assumption:
81  // Just one type of elements in the mesh.
82  Order order = (*(this->get_mesh().elements_begin()))->default_order();
83 
84  // Add the node positions as primary variables.
85  var[0] = this->add_variable("x", order);
86  var[1] = this->add_variable("y", order);
87  if (dim == 3)
88  var[2] = this->add_variable("z", order);
89  else
90  var[2] = var[1];
91 
92  // Add variables for storing the initial mesh to an auxiliary system.
93  System & aux_sys = this->get_equation_systems().get_system("auxiliary");
94  undefo_var[0] = aux_sys.add_variable("undefo_x", order);
95  undefo_var[1] = aux_sys.add_variable("undefo_y", order);
96  undefo_var[2] = aux_sys.add_variable("undefo_z", order);
97 
98  // Set the time stepping options
99  this->deltat = args("schedule/dt", 0.2);
100 
101  // Do the parent's initialization after variables are defined
102  FEMSystem::init_data();
103 
106  //this->time_evolving(var[0]);
107  //this->time_evolving(var[1]);
108  //if (dim == 3)
109  //this->time_evolving(var[2]);
110 
111  // Tell the system which variables are containing the node positions
112  set_mesh_system(this);
113 
114  this->set_mesh_x_var(var[0]);
115  this->set_mesh_y_var(var[1]);
116  if (dim == 3)
117  this->set_mesh_z_var(var[2]);
118 
119  // Fill the variables with the position of the nodes
120  this->mesh_position_get();
121 
122  System::reinit();
123 
124  // Set some options for the DiffSolver
125  DiffSolver & solver = *(this->time_solver->diff_solver().get());
126  solver.quiet = args("solver/quiet", false);
127  solver.max_nonlinear_iterations = args("solver/nonlinear/max_nonlinear_iterations", 100);
128  solver.relative_step_tolerance = args("solver/nonlinear/relative_step_tolerance", 1.e-3);
129  solver.relative_residual_tolerance = args("solver/nonlinear/relative_residual_tolerance", 1.e-8);
130  solver.absolute_residual_tolerance = args("solver/nonlinear/absolute_residual_tolerance", 1.e-8);
131  solver.verbose = !args("solver/quiet", false);
132 
133  ((NewtonSolver &) solver).require_residual_reduction = args("solver/nonlinear/require_reduction", false);
134 
135  // And the linear solver options
136  solver.max_linear_iterations = args("max_linear_iterations", 50000);
137  solver.initial_linear_tolerance = args("initial_linear_tolerance", 1.e-3);
138 }
139 
141 {
142  System::update();
143  this->mesh_position_set();
144 }
145 
147 {
148  FEMContext & c = cast_ref<FEMContext &>(context);
149 
150  // Pre-request all the data needed
151  FEBase * elem_fe = nullptr;
152  c.get_element_fe(0, elem_fe);
153 
154  elem_fe->get_JxW();
155  elem_fe->get_phi();
156  elem_fe->get_dphi();
157  elem_fe->get_xyz();
158 
159  FEBase * side_fe = nullptr;
160  c.get_side_fe(0, side_fe);
161 
162  side_fe->get_JxW();
163  side_fe->get_phi();
164  side_fe->get_xyz();
165 }
166 
171 bool SolidSystem::element_time_derivative(bool request_jacobian,
172  DiffContext & context)
173 {
174  FEMContext & c = cast_ref<FEMContext &>(context);
175 
176  // First we get some references to cell-specific data that
177  // will be used to assemble the linear system.
178  FEBase * elem_fe = nullptr;
179  c.get_element_fe(0, elem_fe);
180 
181  // Element Jacobian * quadrature weights for interior integration
182  const std::vector<Real> & JxW = elem_fe->get_JxW();
183 
184  // Element basis functions
185  const std::vector<std::vector<RealGradient>> & dphi = elem_fe->get_dphi();
186 
187  // Dimension of the mesh
188  const unsigned int dim = this->get_mesh().mesh_dimension();
189 
190  // The number of local degrees of freedom in each variable
191  const unsigned int n_u_dofs = c.n_dof_indices(var[0]);
192  libmesh_assert(n_u_dofs == c.n_dof_indices(var[1]));
193  if (dim == 3)
194  libmesh_assert(n_u_dofs == c.n_dof_indices(var[2]));
195 
196  unsigned int n_qpoints = c.get_element_qrule().n_points();
197 
198  // Some matrices and vectors for storing the results of the constitutive
199  // law
200  DenseMatrix<Real> stiff;
201  DenseVector<Real> res;
202  VectorValue<Gradient> grad_u;
203 
204  // Instantiate the constitutive law
205  // Just calculate jacobian contribution when we need to
206  NonlinearNeoHookeCurrentConfig material(dphi, args, request_jacobian);
207 
208  // Get a reference to the auxiliary system
210  TransientExplicitSystem>("auxiliary");
211  std::vector<dof_id_type> undefo_index;
212 
213  // Assume symmetry of local stiffness matrices
214  bool use_symmetry = args("assembly/use_symmetry", false);
215 
216  // Now we will build the element Jacobian and residual.
217  // This must be calculated at each quadrature point by
218  // summing the solution degree-of-freedom values by
219  // the appropriate weight functions.
220  // This class just takes care of the assembly. The matrix of
221  // the jacobian and the residual vector are provided by the
222  // constitutive formulation.
223 
224  for (unsigned int qp = 0; qp != n_qpoints; qp++)
225  {
226  // Compute the displacement gradient
227  grad_u(0) = grad_u(1) = grad_u(2) = 0;
228  for (unsigned int d = 0; d < dim; ++d)
229  {
230  std::vector<Number> u_undefo;
231  aux_system.get_dof_map().dof_indices(&c.get_elem(), undefo_index, undefo_var[d]);
232  aux_system.current_local_solution->get(undefo_index, u_undefo);
233  for (unsigned int l = 0; l != n_u_dofs; l++)
234  grad_u(d).add_scaled(dphi[l][qp], u_undefo[l]); // u_current(l)); // -
235  }
236 
237  // initialize the constitutive formulation with the current displacement
238  // gradient
239  material.init_for_qp(grad_u, qp);
240 
241  // Acquire, scale and assemble residual and stiffness
242  for (unsigned int i = 0; i < n_u_dofs; i++)
243  {
244  res.resize(dim);
245  material.get_residual(res, i);
246  res.scale(JxW[qp]);
247  for (unsigned int ii = 0; ii < dim; ++ii)
248  (c.get_elem_residual(ii))(i) += res(ii);
249 
250  if (request_jacobian && c.elem_solution_derivative)
251  {
253  for (unsigned int j = (use_symmetry ? i : 0); j < n_u_dofs; j++)
254  {
255  material.get_linearized_stiffness(stiff, i, j);
256  stiff.scale(JxW[qp]);
257  for (unsigned int ii = 0; ii < dim; ++ii)
258  {
259  for (unsigned int jj = 0; jj < dim; ++jj)
260  {
261  (c.get_elem_jacobian(ii,jj))(i, j) += stiff(ii, jj);
262  if (use_symmetry && i != j)
263  (c.get_elem_jacobian(ii,jj))(j, i) += stiff(jj, ii);
264  }
265  }
266  }
267  }
268  }
269  } // end of the quadrature point qp-loop
270 
271  return request_jacobian;
272 }
273 
274 bool SolidSystem::side_time_derivative(bool request_jacobian,
275  DiffContext & context)
276 {
277  FEMContext & c = cast_ref<FEMContext &>(context);
278 
279  // Apply displacement boundary conditions with penalty method
280 
281  // Get the current load step
282  Real ratio = this->get_equation_systems().parameters.get<Real>("progress") + 0.001;
283 
284  // The BC are stored in the simulation parameters as array containing sequences of
285  // four numbers: Id of the side for the displacements and three values describing the
286  // displacement. E.g.: bc/displacement = '5 nan nan -1.0'. This will move all nodes of
287  // side 5 about 1.0 units down the z-axis while leaving all other directions unrestricted
288 
289  // Get number of BCs to enforce
290  boundary_id_type num_bc =
291  cast_int<boundary_id_type>(args.vector_variable_size("bc/displacement"));
292 
293  libmesh_error_msg_if(num_bc % 4 != 0,
294  "ERROR, Odd number of values in displacement boundary condition.");
295 
296  num_bc /= 4;
297 
298  // Loop over all BCs
299  for (boundary_id_type nbc = 0; nbc < num_bc; nbc++)
300  {
301  // Get IDs of the side for this BC
302  boundary_id_type positive_boundary_id =
303  cast_int<boundary_id_type>(args("bc/displacement", 1, nbc * 4));
304 
305  // The current side may not be on the boundary to be restricted
307  (&c.get_elem(),c.get_side(),positive_boundary_id))
308  continue;
309 
310  // Read values from configuration file
311  Point diff_value;
312  for (unsigned int d = 0; d < c.get_dim(); ++d)
313  diff_value(d) = args("bc/displacement", NAN, nbc * 4 + 1 + d);
314 
315  // Scale according to current load step
316  diff_value *= ratio;
317 
318  Real penalty_number = args("bc/displacement_penalty", 1e7);
319 
320  FEBase * fe = nullptr;
321  c.get_side_fe(0, fe);
322 
323  const std::vector<std::vector<Real>> & phi = fe->get_phi();
324  const std::vector<Real> & JxW = fe->get_JxW();
325  const std::vector<Point> & coords = fe->get_xyz();
326 
327  const unsigned int n_x_dofs = c.n_dof_indices(this->var[0]);
328 
329  // get mappings for dofs for auxiliary system for original mesh positions
330  const System & auxsys = this->get_equation_systems().get_system("auxiliary");
331  const DofMap & auxmap = auxsys.get_dof_map();
332  std::vector<dof_id_type> undefo_dofs[3];
333  for (unsigned int d = 0; d < c.get_dim(); ++d)
334  auxmap.dof_indices(&c.get_elem(), undefo_dofs[d], undefo_var[d]);
335 
336  for (unsigned int qp = 0; qp < c.get_side_qrule().n_points(); ++qp)
337  {
338  // calculate coordinates of qp on undeformed mesh
339  Point orig_point;
340  for (unsigned int i = 0; i < n_x_dofs; ++i)
341  {
342  for (unsigned int d = 0; d < c.get_dim(); ++d)
343  {
344  Number orig_val = auxsys.current_solution(undefo_dofs[d][i]);
345 
346 #if LIBMESH_USE_COMPLEX_NUMBERS
347  orig_point(d) += phi[i][qp] * orig_val.real();
348 #else
349  orig_point(d) += phi[i][qp] * orig_val;
350 #endif
351  }
352  }
353 
354  // Calculate displacement to be enforced.
355  Point diff = coords[qp] - orig_point - diff_value;
356 
357  // Assemble
358  for (unsigned int i = 0; i < n_x_dofs; ++i)
359  {
360  for (unsigned int d1 = 0; d1 < c.get_dim(); ++d1)
361  {
362  if (libmesh_isnan(diff(d1)))
363  continue;
364  Real val = JxW[qp] * phi[i][qp] * diff(d1) * penalty_number;
365  (c.get_elem_residual(var[d1]))(i) += val;
366  }
367  if (request_jacobian)
368  {
369  for (unsigned int j = 0; j < n_x_dofs; ++j)
370  {
371  for (unsigned int d1 = 0; d1 < c.get_dim(); ++d1)
372  {
373  if (libmesh_isnan(diff(d1)))
374  continue;
375  Real val = JxW[qp] * phi[i][qp] * phi[j][qp] * penalty_number;
376  (c.get_elem_jacobian(var[d1],var[d1]))(i, j) += val;
377  }
378  }
379  }
380  }
381  }
382  }
383 
384  return request_jacobian;
385 }
This is the EquationSystems class.
void init_for_qp(VectorValue< Gradient > &grad_u, unsigned int qp)
Initialize the class for the given displacement gradient at the specified quadrature point...
void add_scaled(const TypeVector< T2 > &, const T &)
Add a scaled value to this vector without creating a temporary.
Definition: type_vector.h:629
const DenseMatrix< Number > & get_elem_jacobian() const
Const accessor for element Jacobian.
Definition: diff_context.h:274
Order
defines an enum for polynomial orders.
Definition: enum_order.h:40
This class provides all data required for a physics package (e.g.
Definition: diff_context.h:55
void get_side_fe(unsigned int var, FEGenericBase< OutputShape > *&fe) const
Accessor for edge/face (2D/3D) finite element object for variable var for the largest dimension in th...
Definition: fem_context.h:317
bool has_boundary_id(const Node *const node, const boundary_id_type id) const
virtual bool element_time_derivative(bool request_jacobian, DiffContext &context)
Compute contribution from internal forces in elem_residual and contribution from linearized internal ...
Definition: solid_system.C:171
virtual bool side_time_derivative(bool request_jacobian, DiffContext &context)
Adds the time derivative contribution on side of elem to elem_residual.
Definition: solid_system.C:274
This class implements a constitutive formulation for an Neo-Hookean elastic solid in terms of the cur...
void dof_indices(const Elem *const elem, std::vector< dof_id_type > &di) const
Definition: dof_map.C:2164
bool quiet
The DiffSolver should not print anything to libMesh::out unless quiet is set to false; default is tru...
Definition: diff_solver.h:160
const Elem & get_elem() const
Accessor for current Elem object.
Definition: fem_context.h:908
unsigned int dim
void get_residual(DenseVector< Real > &residuum, unsigned int &i)
Return the residual vector for the current state.
unsigned int max_nonlinear_iterations
The DiffSolver should exit in failure if max_nonlinear_iterations is exceeded and continue_after_max_...
Definition: diff_solver.h:154
void resize(const unsigned int n)
Resize the vector.
Definition: dense_vector.h:396
Real absolute_residual_tolerance
The DiffSolver should exit after the residual is reduced to either less than absolute_residual_tolera...
Definition: diff_solver.h:189
unsigned int n_dof_indices() const
Total number of dof indices on the element.
Definition: diff_context.h:395
const EquationSystems & get_equation_systems() const
Definition: system.h:721
std::unique_ptr< TimeSolver > time_solver
A pointer to the solver object we&#39;re going to use.
Definition: diff_system.h:253
unsigned int var[3]
Definition: solid_system.h:73
Manages storage and variables for transient systems.
This class defines a vector in LIBMESH_DIM dimensional Real or Complex space.
The libMesh namespace provides an interface to certain functionality in the library.
void scale(const T factor)
Multiplies every element in the vector by factor.
Definition: dense_vector.h:453
const BoundaryInfo & get_boundary_info() const
The information about boundary ids on the mesh.
Definition: mesh_base.h:165
const T_sys & get_system(std::string_view name) const
bool libmesh_isnan(T x)
unsigned char get_side() const
Accessor for current side of Elem object.
Definition: fem_context.h:922
virtual void init_context(DiffContext &context)
Definition: solid_system.C:146
const MeshBase & get_mesh() const
Definition: system.h:2358
This class provides a specific system class.
Definition: fem_system.h:53
This class defines a solver which uses the default libMesh linear solver in a quasiNewton method to h...
Definition: newton_solver.h:46
virtual void set_mesh_x_var(unsigned int var)
Tells the DifferentiablePhysics that variable var from the mesh system should be used to update the x...
Definition: diff_physics.h:589
unsigned char get_dim() const
Accessor for cached mesh dimension.
Definition: fem_context.h:936
Number current_solution(const dof_id_type global_dof_number) const
Definition: system.C:165
virtual void init_data()
Initializes the member data fields associated with the system, so that, e.g., assemble() may be used...
Definition: solid_system.C:76
This is a generic class that defines a solver to handle ImplicitSystem classes, including NonlinearIm...
Definition: diff_solver.h:68
This class handles the numbering of degrees of freedom on a mesh.
Definition: dof_map.h:179
GetPot args
Definition: solid_system.h:58
unsigned int number() const
Definition: system.h:2350
const T & get(std::string_view) const
Definition: parameters.h:426
int8_t boundary_id_type
Definition: id_types.h:51
void get_linearized_stiffness(DenseMatrix< Real > &stiffness, unsigned int &i, unsigned int &j)
Return the stiffness matrix for the current state.
virtual void set_mesh_y_var(unsigned int var)
Tells the DifferentiablePhysics that variable var from the mesh system should be used to update the y...
Definition: diff_physics.h:597
virtual void update()
Update the local values to reflect the solution on neighboring processors.
Definition: solid_system.C:140
Real deltat
For time-dependent problems, this is the amount delta t to advance the solution in time...
Definition: diff_system.h:280
unsigned int max_linear_iterations
Each linear solver step should exit after max_linear_iterations is exceeded.
Definition: diff_solver.h:146
Manages consistently variables, degrees of freedom, and coefficient vectors.
Definition: system.h:96
Real elem_solution_derivative
The derivative of elem_solution with respect to the current nonlinear solution.
Definition: diff_context.h:496
libmesh_assert(ctx)
virtual_for_inffe const std::vector< Real > & get_JxW() const
Definition: fe_abstract.h:303
This class provides all data required for a physics package (e.g.
Definition: fem_context.h:62
unsigned int add_variable(std::string_view var, const FEType &type, const std::set< subdomain_id_type > *const active_subdomains=nullptr)
Adds the variable var to the list of variables for this system.
Definition: system.C:1357
unsigned int n_points() const
Definition: quadrature.h:131
SolidSystem(EquationSystems &es, const std::string &name, const unsigned int number)
Definition: solid_system.C:48
virtual_for_inffe const std::vector< Point > & get_xyz() const
Definition: fe_abstract.h:280
unsigned int undefo_var[3]
Definition: solid_system.h:77
void scale(const T factor)
Multiplies every element in the matrix by factor.
Definition: dense_matrix.h:986
bool verbose
The DiffSolver may print a lot more to libMesh::out if verbose is set to true; default is false...
Definition: diff_solver.h:166
const DenseVector< Number > & get_elem_residual() const
Const accessor for element residual.
Definition: diff_context.h:242
DIE A HORRIBLE DEATH HERE typedef LIBMESH_DEFAULT_SCALAR_TYPE Real
virtual void set_mesh_z_var(unsigned int var)
Tells the DifferentiablePhysics that variable var from the mesh system should be used to update the z...
Definition: diff_physics.h:605
void mesh_position_set()
Tells the FEMSystem to set the mesh nodal coordinates which should correspond to degree of freedom co...
Definition: fem_system.C:1087
static const bool value
Definition: xdr_io.C:54
void save_initial_mesh()
Definition: solid_system.C:58
unsigned int mesh_dimension() const
Definition: mesh_base.C:372
Parameters parameters
Data structure holding arbitrary parameters.
std::unique_ptr< NumericVector< Number > > current_local_solution
All the values I need to compute my contribution to the simulation at hand.
Definition: system.h:1605
void get_element_fe(unsigned int var, FEGenericBase< OutputShape > *&fe) const
Accessor for interior finite element object for variable var for the largest dimension in the mesh...
Definition: fem_context.h:277
Defines a dense vector for use in Finite Element-type computations.
Definition: dof_map.h:74
void mesh_position_get()
Tells the FEMSystem to set the degree of freedom coefficients which should correspond to mesh nodal c...
Definition: fem_system.C:1423
virtual void set_mesh_system(System *sys)
Tells the DifferentiablePhysics that system sys contains the isoparametric Lagrangian variables which...
Definition: diff_physics.h:569
double initial_linear_tolerance
Any required linear solves will at first be done with this tolerance; the DiffSolver may tighten the ...
Definition: diff_solver.h:208
const DofMap & get_dof_map() const
Definition: system.h:2374
A Point defines a location in LIBMESH_DIM dimensional Real space.
Definition: point.h:39
This class forms the foundation from which generic finite elements may be derived.
const QBase & get_element_qrule() const
Accessor for element interior quadrature rule for the dimension of the current _elem.
Definition: fem_context.h:802
Real relative_residual_tolerance
Definition: diff_solver.h:190
const QBase & get_side_qrule() const
Accessor for element side quadrature rule for the dimension of the current _elem. ...
Definition: fem_context.h:809
const std::vector< std::vector< OutputShape > > & get_phi() const
Definition: fe_base.h:207