libMesh
fem_system_ex3.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 // <h1>FEMSystem Example 3 - Unsteady Linear Elasticity with
21 // FEMSystem</h1>
22 // \author Paul Bauman
23 // \date 2015
24 //
25 // This example shows how to solve the three-dimensional transient
26 // linear elasticity equations using the DifferentiableSystem class framework.
27 // This is just Systems of Equations Example 6 recast.
28 
29 // C++ includes
30 #include <iomanip>
31 #include <memory>
32 
33 // Basic include files
34 #include "libmesh/equation_systems.h"
35 #include "libmesh/error_vector.h"
36 #include "libmesh/getpot.h"
37 #include "libmesh/exodusII_io.h"
38 #include "libmesh/kelly_error_estimator.h"
39 #include "libmesh/mesh.h"
40 #include "libmesh/mesh_generation.h"
41 #include "libmesh/enum_solver_package.h"
42 #include "libmesh/enum_solver_type.h"
43 #include "libmesh/numeric_vector.h"
44 
45 // The systems and solvers we may use
46 #include "elasticity_system.h"
47 #include "libmesh/diff_solver.h"
48 #include "libmesh/newmark_solver.h"
49 #include "libmesh/steady_solver.h"
50 #include "libmesh/euler_solver.h"
51 #include "libmesh/euler2_solver.h"
52 #include "libmesh/elem.h"
53 #include "libmesh/newton_solver.h"
54 #include "libmesh/eigen_sparse_linear_solver.h"
55 
56 #define x_scaling 1.3
57 
58 // Bring in everything from the libMesh namespace
59 using namespace libMesh;
60 
61 // The main program.
62 int main (int argc, char ** argv)
63 {
64  // Initialize libMesh.
65  LibMeshInit init (argc, argv);
66 
67  // This example requires a linear solver package.
68  libmesh_example_requires(libMesh::default_solver_package() != INVALID_SOLVER_PACKAGE,
69  "--enable-petsc, --enable-trilinos, or --enable-eigen");
70 
71  // This example requires 3D calculations
72  libmesh_example_requires(LIBMESH_DIM > 2, "3D support");
73 
74  // We use Dirichlet boundary conditions here
75 #ifndef LIBMESH_ENABLE_DIRICHLET
76  libmesh_example_requires(false, "--enable-dirichlet");
77 #endif
78 
79  // Parse the input file
80  GetPot infile("fem_system_ex3.in");
81 
82  // Override input file arguments from the command line
83  infile.parse_command_line(argc, argv);
84 
85  // Read in parameters from the input file
86  const Real deltat = infile("deltat", 0.25);
87  unsigned int n_timesteps = infile("n_timesteps", 1);
88 
89 #ifdef LIBMESH_HAVE_EXODUS_API
90  const unsigned int write_interval = infile("write_interval", 1);
91 #endif
92 
93  // Initialize the cantilever mesh
94  const unsigned int dim = 3;
95 
96  // Make sure libMesh was compiled for 3D
97  libmesh_example_requires(dim == LIBMESH_DIM, "3D support");
98 
99  const unsigned int nx = infile("nx", 32);
100  const unsigned int ny = infile("ny", 8);
101  const unsigned int nz = infile("nz", 4);
102 
103  // Create a 3D mesh distributed across the default MPI communicator.
104  Mesh mesh(init.comm(), dim);
106  nx,
107  ny,
108  nz,
109  0., 1.*x_scaling,
110  0., 0.3,
111  0., 0.1,
112  HEX8);
113 
114 
115  // Print information about the mesh to the screen.
116  mesh.print_info(libMesh::out, /* verbosity = */ 2);
117 
118  // Let's add some node and edge boundary conditions.
119  // Each processor should know about each boundary condition it can
120  // see, so we loop over all elements, not just local elements.
121  for (const auto & elem : mesh.element_ptr_range())
122  {
123  unsigned int
124  side_max_x = 0, side_min_y = 0,
125  side_max_y = 0, side_max_z = 0;
126  bool
127  found_side_max_x = false, found_side_max_y = false,
128  found_side_min_y = false, found_side_max_z = false;
129  for (auto side : elem->side_index_range())
130  {
132  {
133  side_max_x = side;
134  found_side_max_x = true;
135  }
136 
138  {
139  side_min_y = side;
140  found_side_min_y = true;
141  }
142 
144  {
145  side_max_y = side;
146  found_side_max_y = true;
147  }
148 
150  {
151  side_max_z = side;
152  found_side_max_z = true;
153  }
154  }
155 
156  // If elem has sides on boundaries
157  // BOUNDARY_ID_MAX_X, BOUNDARY_ID_MAX_Y, BOUNDARY_ID_MAX_Z
158  // then let's set a node boundary condition
159  if (found_side_max_x && found_side_max_y && found_side_max_z)
160  for (auto n : elem->node_index_range())
161  if (elem->is_node_on_side(n, side_max_x) &&
162  elem->is_node_on_side(n, side_max_y) &&
163  elem->is_node_on_side(n, side_max_z))
164  mesh.get_boundary_info().add_node(elem->node_ptr(n), node_boundary_id);
165 
166  // If elem has sides on boundaries
167  // BOUNDARY_ID_MAX_X and BOUNDARY_ID_MIN_Y
168  // then let's set an edge boundary condition
169  if (found_side_max_x && found_side_min_y)
170  for (auto e : elem->edge_index_range())
171  if (elem->is_edge_on_side(e, side_max_x) &&
172  elem->is_edge_on_side(e, side_min_y))
174  }
175 
176  // Create an equation systems object.
177  EquationSystems equation_systems (mesh);
178 
179  // Declare the system and its variables.
180  ElasticitySystem & system =
181  equation_systems.add_system<ElasticitySystem> ("Linear Elasticity");
182 
183  // Solve this as a time-dependent or steady system
184  const std::string time_solver = infile("time_solver","DIE!");
185 
186  ExplicitSystem * v_system = nullptr;
187  ExplicitSystem * a_system = nullptr;
188 
189  if (time_solver == "newmark")
190  {
191  // Create ExplicitSystem to help output velocity
192  v_system = &equation_systems.add_system<ExplicitSystem> ("Velocity");
193  v_system->add_variable("u_vel", FIRST, LAGRANGE);
194  v_system->add_variable("v_vel", FIRST, LAGRANGE);
195  v_system->add_variable("w_vel", FIRST, LAGRANGE);
196 
197  // Create ExplicitSystem to help output acceleration
198  a_system = &equation_systems.add_system<ExplicitSystem> ("Acceleration");
199  a_system->add_variable("u_accel", FIRST, LAGRANGE);
200  a_system->add_variable("v_accel", FIRST, LAGRANGE);
201  a_system->add_variable("w_accel", FIRST, LAGRANGE);
202 
203  system.time_solver = std::make_unique<NewmarkSolver>(system);
204  }
205 
206  else if (time_solver == "euler")
207  {
208  system.time_solver = std::make_unique<EulerSolver>(system);
209  EulerSolver & euler_solver = cast_ref<EulerSolver &>(*(system.time_solver.get()));
210  euler_solver.theta = infile("theta", 1.0);
211  }
212 
213  else if (time_solver == "euler2")
214  {
215  system.time_solver = std::make_unique<Euler2Solver>(system);
216  Euler2Solver & euler_solver = cast_ref<Euler2Solver &>(*(system.time_solver.get()));
217  euler_solver.theta = infile("theta", 1.0);
218  }
219 
220  else if (time_solver == "steady")
221  {
222  system.time_solver = std::make_unique<SteadySolver>(system);
223  libmesh_assert_equal_to (n_timesteps, 1);
224  }
225  else
226  libmesh_error_msg(std::string("ERROR: invalid time_solver ")+time_solver);
227 
228  // Initialize the system
229  equation_systems.init ();
230 
231  // Set the time stepping options
232  system.deltat = deltat;
233 
234  // And the nonlinear solver options
235  DiffSolver & solver = *(system.time_solver->diff_solver().get());
236  solver.quiet = infile("solver_quiet", true);
237  solver.verbose = !solver.quiet;
238  solver.max_nonlinear_iterations = infile("max_nonlinear_iterations", 15);
239  solver.relative_step_tolerance = infile("relative_step_tolerance", 1.e-3);
240  solver.relative_residual_tolerance = infile("relative_residual_tolerance", 0.0);
241  solver.absolute_residual_tolerance = infile("absolute_residual_tolerance", 0.0);
242 
243  // And the linear solver options
244  solver.max_linear_iterations = infile("max_linear_iterations", 50000);
245  solver.initial_linear_tolerance = infile("initial_linear_tolerance", 1.e-3);
246 
247  // Print information about the system to the screen.
248  equation_systems.print_info();
249 
250  // If we're using EulerSolver or Euler2Solver, and we're using EigenSparseLinearSolver,
251  // then we need to reset the EigenSparseLinearSolver to use SPARSELU because BICGSTAB
252  // chokes on the Jacobian matrix we give it and Eigen's GMRES currently doesn't work.
253  NewtonSolver * newton_solver = dynamic_cast<NewtonSolver *>( &solver );
254  if (newton_solver &&
255  (time_solver == "euler" || time_solver == "euler2"))
256  {
257 #ifdef LIBMESH_HAVE_EIGEN_SPARSE
258  LinearSolver<Number> & linear_solver = newton_solver->get_linear_solver();
259  EigenSparseLinearSolver<Number> * eigen_linear_solver =
260  dynamic_cast<EigenSparseLinearSolver<Number> *>(&linear_solver);
261 
262  if (eigen_linear_solver)
263  eigen_linear_solver->set_solver_type(SPARSELU);
264 #endif
265  }
266 
267  if (time_solver == "newmark")
268  {
269  NewmarkSolver * newmark = cast_ptr<NewmarkSolver*>(system.time_solver.get());
270  newmark->compute_initial_accel();
271 
272  // Copy over initial velocity and acceleration for output.
273  // Note we can do this because of the matching variables/FE spaces
274  *(v_system->solution) = system.get_vector("_old_solution_rate");
275  *(a_system->solution) = system.get_vector("_old_solution_accel");
276  }
277 
278 #ifdef LIBMESH_HAVE_EXODUS_API
279  // Output initial state
280  {
281  std::ostringstream file_name;
282 
283  // We write the file in the ExodusII format.
284  file_name << std::string("out.")+time_solver+std::string(".e-s.")
285  << std::setw(3)
286  << std::setfill('0')
287  << std::right
288  << 0;
289 
290  ExodusII_IO(mesh).write_timestep(file_name.str(),
291  equation_systems,
292  1, // This number indicates how many time steps
293  // are being written to the file
294  system.time);
295  }
296 #endif // #ifdef LIBMESH_HAVE_EXODUS_API
297 
298  // Now we begin the timestep loop to compute the time-accurate
299  // solution of the equations.
300  for (unsigned int t_step=0; t_step != n_timesteps; ++t_step)
301  {
302  // A pretty update message
303  libMesh::out << "\n\nSolving time step "
304  << t_step
305  << ", time = "
306  << system.time
307  << std::endl;
308 
309  system.solve();
310 
311  // Advance to the next timestep in a transient problem
312  system.time_solver->advance_timestep();
313 
314  // Copy over updated velocity and acceleration for output.
315  // Note we can do this because of the matching variables/FE spaces
316  if (time_solver == "newmark")
317  {
318  *(v_system->solution) = system.get_vector("_old_solution_rate");
319  *(a_system->solution) = system.get_vector("_old_solution_accel");
320  }
321 
322 #ifdef LIBMESH_HAVE_EXODUS_API
323  // Write out this timestep if we're requested to
324  if ((t_step+1)%write_interval == 0)
325  {
326  std::ostringstream file_name;
327 
328  // We write the file in the ExodusII format.
329  file_name << std::string("out.")+time_solver+std::string(".e-s.")
330  << std::setw(3)
331  << std::setfill('0')
332  << std::right
333  << t_step+1;
334 
335  ExodusII_IO(mesh).write_timestep(file_name.str(),
336  equation_systems,
337  1, // This number indicates how many time steps
338  // are being written to the file
339  system.time);
340  }
341 #endif // #ifdef LIBMESH_HAVE_EXODUS_API
342  }
343 
344  // All done.
345  return 0;
346 }
Real time
For time-dependent problems, this is the time t at the beginning of the current timestep.
Definition: system.h:1615
LinearSolver< Number > & get_linear_solver()
Definition: newton_solver.h:81
This is the EquationSystems class.
const boundary_id_type edge_boundary_id
bool has_boundary_id(const Node *const node, const boundary_id_type id) const
int main(int argc, char **argv)
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
unsigned int dim
The ExodusII_IO class implements reading meshes in the ExodusII file format from Sandia National Labs...
Definition: exodusII_io.h:52
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
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
std::unique_ptr< TimeSolver > time_solver
A pointer to the solver object we&#39;re going to use.
Definition: diff_system.h:253
void print_info(std::ostream &os=libMesh::out) const
Prints information about the equation systems, by default to libMesh::out.
MeshBase & mesh
This class provides an interface to Eigen iterative solvers that is compatible with the libMesh Linea...
This class defines a Newmark time integrator for second order (in time) DifferentiableSystems.
The LibMeshInit class, when constructed, initializes the dependent libraries (e.g.
Definition: libmesh.h:90
The libMesh namespace provides an interface to certain functionality in the library.
const BoundaryInfo & get_boundary_info() const
The information about boundary ids on the mesh.
Definition: mesh_base.h:165
boundary_id_type boundary_id_max_x
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 compute_initial_accel()
This method uses the specified initial displacement and velocity to compute the initial acceleration ...
SolverPackage default_solver_package()
Definition: libmesh.C:1117
This is a generic class that defines a solver to handle ImplicitSystem classes, including NonlinearIm...
Definition: diff_solver.h:68
void add_node(const Node *node, const boundary_id_type id)
Add Node node with boundary id id to the boundary information data structures.
This class defines a theta-method (defaulting to Backward Euler with theta = 1.0) solver to handle ti...
Definition: euler2_solver.h:48
boundary_id_type boundary_id_max_z
const boundary_id_type node_boundary_id
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
void print_info(std::ostream &os=libMesh::out, const unsigned int verbosity=0, const bool global=true) const
Prints relevant information about the mesh.
Definition: mesh_base.C:1562
std::unique_ptr< NumericVector< Number > > solution
Data structure to hold solution values.
Definition: system.h:1593
void init(triangulateio &t)
Initializes the fields of t to nullptr/0 as necessary.
boundary_id_type boundary_id_max_y
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
void set_solver_type(const SolverType st)
Sets the type of solver to use.
This class defines a theta-method Euler (defaulting to Backward Euler with theta = 1...
Definition: euler_solver.h:43
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
DIE A HORRIBLE DEATH HERE typedef LIBMESH_DEFAULT_SCALAR_TYPE Real
void write_timestep(const std::string &fname, const EquationSystems &es, const int timestep, const Real time, const std::set< std::string > *system_names=nullptr)
Writes out the solution at a specific timestep.
Definition: exodusII_io.C:2017
OStreamProxy out
virtual void solve() override
Invokes the solver associated with the system.
Definition: fem_system.C:1076
virtual void init()
Initialize all the systems.
virtual System & add_system(std::string_view system_type, std::string_view name)
Add the system of type system_type named name to the systems array.
The Mesh class is a thin wrapper, around the ReplicatedMesh class by default.
Definition: mesh.h:50
boundary_id_type boundary_id_min_y
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
void build_cube(UnstructuredMesh &mesh, const unsigned int nx=0, const unsigned int ny=0, const unsigned int nz=0, const Real xmin=0., const Real xmax=1., const Real ymin=0., const Real ymax=1., const Real zmin=0., const Real zmax=1., const ElemType type=INVALID_ELEM, const bool gauss_lobatto_grid=false)
Builds a (elements) cube.
Manages consistently variables, degrees of freedom, and coefficient vectors for explicit systems...
Real relative_residual_tolerance
Definition: diff_solver.h:190
const NumericVector< Number > & get_vector(std::string_view vec_name) const
Definition: system.C:943
void add_edge(const dof_id_type elem, const unsigned short int edge, const boundary_id_type id)
Add edge edge of element number elem with boundary id id to the boundary information data structure...