libMesh
Loading...
Searching...
No Matches
solid_system.C
Go to the documentation of this file.
1// The libMesh Finite Element Library.
2// Copyright (C) 2002-2026 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
41#include "solid_system.h"
42
43#include <memory>
44
45// Bring in everything from the libMesh namespace
46using 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
171bool 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;
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
274bool 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
306 if (!this->get_mesh().get_boundary_info().has_boundary_id
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}
unsigned int dim
This class implements a constitutive formulation for an Neo-Hookean elastic solid in terms of the cur...
void get_linearized_stiffness(DenseMatrix< Real > &stiffness, unsigned int &i, unsigned int &j)
Return the stiffness matrix for the current state.
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 get_residual(DenseVector< Real > &residuum, unsigned int &i)
Return the residual vector for the current state.
void save_initial_mesh()
virtual void init_context(DiffContext &context)
virtual void update()
Update the local values to reflect the solution on neighboring processors.
virtual bool side_time_derivative(bool request_jacobian, DiffContext &context)
Adds the time derivative contribution on side of elem to elem_residual.
SolidSystem(EquationSystems &es, const std::string &name, const unsigned int number)
virtual bool element_time_derivative(bool request_jacobian, DiffContext &context)
Compute contribution from internal forces in elem_residual and contribution from linearized internal ...
unsigned int undefo_var[3]
unsigned int var[3]
virtual void init_data()
Initializes the member data fields associated with the system, so that, e.g., assemble() may be used.
Defines a dense matrix for use in Finite Element-type computations.
void scale(const T factor)
Multiplies every element in the matrix by factor.
Defines a dense vector for use in Finite Element-type computations.
void resize(const unsigned int n)
Resize the vector.
void scale(const T factor)
Multiplies every element in the vector by factor.
This class provides all data required for a physics package (e.g.
Real elem_solution_derivative
The derivative of elem_solution with respect to the current nonlinear solution.
unsigned int n_dof_indices() const
Total number of dof indices on the element.
const DenseVector< Number > & get_elem_residual() const
Const accessor for element residual.
const DenseMatrix< Number > & get_elem_jacobian() const
Const accessor for element Jacobian.
This is a generic class that defines a solver to handle ImplicitSystem classes, including NonlinearIm...
Definition diff_solver.h:70
Real absolute_residual_tolerance
The DiffSolver should exit after the residual is reduced to either less than absolute_residual_tolera...
unsigned int max_linear_iterations
Each linear solver step should exit after max_linear_iterations is exceeded.
double initial_linear_tolerance
Any required linear solves will at first be done with this tolerance; the DiffSolver may tighten the ...
bool verbose
The DiffSolver may print a lot more to libMesh::out if verbose is set to true; default is false.
unsigned int max_nonlinear_iterations
The DiffSolver should exit in failure if max_nonlinear_iterations is exceeded and continue_after_max_...
bool quiet
The DiffSolver should not print anything to libMesh::out unless quiet is set to false; default is tru...
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...
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...
virtual void set_mesh_system(System *sys)
Tells the DifferentiablePhysics that system sys contains the isoparametric Lagrangian variables which...
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...
Real deltat
For time-dependent problems, this is the amount delta t to advance the solution in time.
std::unique_ptr< TimeSolver > time_solver
A pointer to the solver object we're going to use.
This class handles the numbering of degrees of freedom on a mesh.
Definition dof_map.h:181
void dof_indices(const Elem *const elem, std::vector< dof_id_type > &di) const
Definition dof_map.C:2201
This is the EquationSystems class.
Parameters parameters
Data structure holding arbitrary parameters.
const T_sys & get_system(std::string_view name) const
virtual_for_inffe const std::vector< Real > & get_JxW() const
virtual_for_inffe const std::vector< Point > & get_xyz() const
This class forms the foundation from which generic finite elements may be derived.
Definition fe_base.h:86
const std::vector< std::vector< OutputShape > > & get_phi() const
Definition fe_base.h:207
const std::vector< std::vector< OutputGradient > > & get_dphi() const
Definition fe_base.h:230
This class provides all data required for a physics package (e.g.
Definition fem_context.h:63
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...
const QBase & get_element_qrule() const
Accessor for element interior quadrature rule for the dimension of the current _elem.
unsigned char get_dim() const
Accessor for cached mesh dimension.
const Elem & get_elem() const
Accessor for current Elem object.
unsigned char get_side() const
Accessor for current side of Elem object.
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.
const QBase & get_side_qrule() const
Accessor for element side quadrature rule for the dimension of the current _elem.
This class provides a specific system class.
Definition fem_system.h:55
void mesh_position_get()
Tells the FEMSystem to set the degree of freedom coefficients which should correspond to mesh nodal c...
void mesh_position_set()
Tells the FEMSystem to set the mesh nodal coordinates which should correspond to degree of freedom co...
unsigned int mesh_dimension() const
Definition mesh_base.C:430
This class defines a solver which uses the default libMesh linear solver in a quasiNewton method to h...
const T & get(std::string_view) const
Definition parameters.h:451
A Point defines a location in LIBMESH_DIM dimensional Real space.
Definition point.h:40
unsigned int n_points() const
Definition quadrature.h:131
Manages consistently variables, degrees of freedom, and coefficient vectors.
Definition system.h:100
Number current_solution(const dof_id_type global_dof_number) const
Definition system.C:162
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:1667
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:1344
const DofMap & get_dof_map() const
Definition system.h:2417
unsigned int number() const
Definition system.h:2393
const EquationSystems & get_equation_systems() const
Definition system.h:767
const MeshBase & get_mesh() const
Definition system.h:2401
Manages storage and variables for transient systems.
void add_scaled(const TypeVector< T2 > &, const T &)
Add a scaled value to this vector without creating a temporary.
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.
int8_t boundary_id_type
Definition id_types.h:51
libmesh_assert(ctx)
bool libmesh_isnan(T x)
DIE A HORRIBLE DEATH HERE typedef LIBMESH_DEFAULT_SCALAR_TYPE Real
static const bool value
Definition xdr_io.C:55