libMesh
fem_system_ex3.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 // <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  // We're all done adding to the boundary_info; let's make sure its
177  // caches know about it.
179 
180  // Create an equation systems object.
181  EquationSystems equation_systems (mesh);
182 
183  // Declare the system and its variables.
184  ElasticitySystem & system =
185  equation_systems.add_system<ElasticitySystem> ("Linear Elasticity");
186 
187  // Solve this as a time-dependent or steady system
188  const std::string time_solver = infile("time_solver","DIE!");
189 
190  ExplicitSystem * v_system = nullptr;
191  ExplicitSystem * a_system = nullptr;
192 
193  if (time_solver == "newmark")
194  {
195  // Create ExplicitSystem to help output velocity
196  v_system = &equation_systems.add_system<ExplicitSystem> ("Velocity");
197  v_system->add_variable("u_vel", FIRST, LAGRANGE);
198  v_system->add_variable("v_vel", FIRST, LAGRANGE);
199  v_system->add_variable("w_vel", FIRST, LAGRANGE);
200 
201  // Create ExplicitSystem to help output acceleration
202  a_system = &equation_systems.add_system<ExplicitSystem> ("Acceleration");
203  a_system->add_variable("u_accel", FIRST, LAGRANGE);
204  a_system->add_variable("v_accel", FIRST, LAGRANGE);
205  a_system->add_variable("w_accel", FIRST, LAGRANGE);
206 
207  system.time_solver = std::make_unique<NewmarkSolver>(system);
208  }
209 
210  else if (time_solver == "euler")
211  {
212  system.time_solver = std::make_unique<EulerSolver>(system);
213  EulerSolver & euler_solver = cast_ref<EulerSolver &>(*(system.time_solver.get()));
214  euler_solver.theta = infile("theta", 1.0);
215  }
216 
217  else if (time_solver == "euler2")
218  {
219  system.time_solver = std::make_unique<Euler2Solver>(system);
220  Euler2Solver & euler_solver = cast_ref<Euler2Solver &>(*(system.time_solver.get()));
221  euler_solver.theta = infile("theta", 1.0);
222  }
223 
224  else if (time_solver == "steady")
225  {
226  system.time_solver = std::make_unique<SteadySolver>(system);
227  libmesh_assert_equal_to (n_timesteps, 1);
228  }
229  else
230  libmesh_error_msg(std::string("ERROR: invalid time_solver ")+time_solver);
231 
232  // Initialize the system
233  equation_systems.init ();
234 
235  // Set the time stepping options
236  system.deltat = deltat;
237 
238  // And the nonlinear solver options
239  DiffSolver & solver = *(system.time_solver->diff_solver().get());
240  solver.quiet = infile("solver_quiet", true);
241  solver.verbose = !solver.quiet;
242  solver.max_nonlinear_iterations = infile("max_nonlinear_iterations", 15);
243  solver.relative_step_tolerance = infile("relative_step_tolerance", 1.e-3);
244  solver.relative_residual_tolerance = infile("relative_residual_tolerance", 0.0);
245  solver.absolute_residual_tolerance = infile("absolute_residual_tolerance", 0.0);
246 
247  // And the linear solver options
248  solver.max_linear_iterations = infile("max_linear_iterations", 50000);
249  solver.initial_linear_tolerance = infile("initial_linear_tolerance", 1.e-3);
250 
251  // Print information about the system to the screen.
252  equation_systems.print_info();
253 
254  // If we're using EulerSolver or Euler2Solver, and we're using EigenSparseLinearSolver,
255  // then we need to reset the EigenSparseLinearSolver to use SPARSELU because BICGSTAB
256  // chokes on the Jacobian matrix we give it and Eigen's GMRES currently doesn't work.
257  NewtonSolver * newton_solver = dynamic_cast<NewtonSolver *>( &solver );
258  if (newton_solver &&
259  (time_solver == "euler" || time_solver == "euler2"))
260  {
261 #ifdef LIBMESH_HAVE_EIGEN_SPARSE
262  LinearSolver<Number> & linear_solver = newton_solver->get_linear_solver();
263  EigenSparseLinearSolver<Number> * eigen_linear_solver =
264  dynamic_cast<EigenSparseLinearSolver<Number> *>(&linear_solver);
265 
266  if (eigen_linear_solver)
267  eigen_linear_solver->set_solver_type(SPARSELU);
268 #endif
269  }
270 
271  if (time_solver == "newmark")
272  {
273  NewmarkSolver * newmark = cast_ptr<NewmarkSolver*>(system.time_solver.get());
274  newmark->compute_initial_accel();
275 
276  // Copy over initial velocity and acceleration for output.
277  // Note we can do this because of the matching variables/FE spaces
278  *(v_system->solution) = system.get_vector("_old_solution_rate");
279  *(a_system->solution) = system.get_vector("_old_solution_accel");
280  }
281 
282 #ifdef LIBMESH_HAVE_EXODUS_API
283  // Output initial state
284  {
285  std::ostringstream file_name;
286 
287  // We write the file in the ExodusII format.
288  file_name << std::string("out.")+time_solver+std::string(".e-s.")
289  << std::setw(3)
290  << std::setfill('0')
291  << std::right
292  << 0;
293 
294  ExodusII_IO(mesh).write_timestep(file_name.str(),
295  equation_systems,
296  1, // This number indicates how many time steps
297  // are being written to the file
298  system.time);
299  }
300 #endif // #ifdef LIBMESH_HAVE_EXODUS_API
301 
302  // Now we begin the timestep loop to compute the time-accurate
303  // solution of the equations.
304  for (unsigned int t_step=0; t_step != n_timesteps; ++t_step)
305  {
306  // A pretty update message
307  libMesh::out << "\n\nSolving time step "
308  << t_step
309  << ", time = "
310  << system.time
311  << std::endl;
312 
313  system.solve();
314 
315  // Advance to the next timestep in a transient problem
316  system.time_solver->advance_timestep();
317 
318  // Copy over updated velocity and acceleration for output.
319  // Note we can do this because of the matching variables/FE spaces
320  if (time_solver == "newmark")
321  {
322  *(v_system->solution) = system.get_vector("_old_solution_rate");
323  *(a_system->solution) = system.get_vector("_old_solution_accel");
324  }
325 
326 #ifdef LIBMESH_HAVE_EXODUS_API
327  // Write out this timestep if we're requested to
328  if ((t_step+1)%write_interval == 0)
329  {
330  std::ostringstream file_name;
331 
332  // We write the file in the ExodusII format.
333  file_name << std::string("out.")+time_solver+std::string(".e-s.")
334  << std::setw(3)
335  << std::setfill('0')
336  << std::right
337  << t_step+1;
338 
339  ExodusII_IO(mesh).write_timestep(file_name.str(),
340  equation_systems,
341  1, // This number indicates how many time steps
342  // are being written to the file
343  system.time);
344  }
345 #endif // #ifdef LIBMESH_HAVE_EXODUS_API
346  }
347 
348  // All done.
349  return 0;
350 }
Real time
For time-dependent problems, this is the time t at the beginning of the current timestep.
Definition: system.h:1677
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:50
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:245
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:91
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:170
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:1064
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:272
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:1748
std::unique_ptr< NumericVector< Number > > solution
Data structure to hold solution values.
Definition: system.h:1655
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:1344
void set_solver_type(const SolverType st)
Sets the type of solver to use.
void regenerate_id_sets()
Clears and regenerates the cached sets of ids.
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:2034
OStreamProxy out
virtual void solve() override
Invokes the solver associated with the system.
Definition: fem_system.C:1070
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:931
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...