libMesh
Loading...
Searching...
No Matches
fem_system_ex1.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 1 - Unsteady Navier-Stokes Equations with
21// FEMSystem</h1>
22// \author Roy Stogner
23// \date 2006
24//
25// This example shows how the transient nonlinear problem from
26// systems_of_equations_ex2 can be solved using the
27// DifferentiableSystem class framework
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/replicated_mesh.h"
41#include "libmesh/distributed_mesh.h"
42#include "libmesh/mesh_generation.h"
43#include "libmesh/mesh_refinement.h"
44#include "libmesh/uniform_refinement_estimator.h"
45#include "libmesh/enum_solver_package.h"
46#include "libmesh/enum_norm_type.h"
47
48// The systems and solvers we may use
49#include "naviersystem.h"
50#include "libmesh/diff_solver.h"
51#include "libmesh/petsc_diff_solver.h"
52#include "libmesh/newton_solver.h"
53#include "libmesh/euler_solver.h"
54#include "libmesh/steady_solver.h"
55#include "libmesh/partitioner.h"
56
57// Bring in everything from the libMesh namespace
58using namespace libMesh;
59
60// The main program.
61int main (int argc, char ** argv)
62{
63 // Initialize libMesh.
64 LibMeshInit init (argc, argv);
65
66 // This example requires a linear solver package.
67 libmesh_example_requires(libMesh::default_solver_package() != INVALID_SOLVER_PACKAGE,
68 "--enable-petsc, --enable-trilinos, or --enable-eigen");
69
70 // This example fails without at least double precision FP
71#ifdef LIBMESH_DEFAULT_SINGLE_PRECISION
72 libmesh_example_requires(false, "--disable-singleprecision");
73#endif
74
75#ifndef LIBMESH_ENABLE_AMR
76 libmesh_example_requires(false, "--enable-amr");
77#else
78
79 // We use Dirichlet boundary conditions here
80#ifndef LIBMESH_ENABLE_DIRICHLET
81 libmesh_example_requires(false, "--enable-dirichlet");
82#endif
83
84 // Trilinos and Eigen solvers NaN by default here.
85 // We'll skip this example for now.
86 libmesh_example_requires(libMesh::default_solver_package() != TRILINOS_SOLVERS, "--enable-petsc");
87
88 // Parse the input file
89 GetPot infile("fem_system_ex1.in");
90
91 // Override input file arguments from the command line
92 infile.parse_command_line(argc, argv);
93
94 // Read in parameters from the input file
95 const Real global_tolerance = infile("global_tolerance", 0.);
96 const unsigned int nelem_target = infile("n_elements", 400);
97 const bool transient = infile("transient", true);
98 const Real deltat = infile("deltat", 0.005);
99 unsigned int n_timesteps = infile("n_timesteps", 20);
100 const unsigned int coarsegridsize = infile("coarsegridsize", 1);
101 const unsigned int coarserefinements = infile("coarserefinements", 0);
102 const unsigned int max_adaptivesteps = infile("max_adaptivesteps", 10);
103 const unsigned int dim = infile("dimension", 2);
104 const std::string slvr_type = infile("solver_type", "newton");
105 const std::string mesh_type = infile("mesh_type" , "replicated");
106 const bool constrain_in_solver = infile("constrain_in_solver", true);
107
108 // More desperate debugging options
109 const bool print_solutions = infile("print_solutions", false);
110 const bool print_residuals = infile("print_residuals", false);
111 const bool print_jacobians = infile("print_jacobians", false);
112
113#ifdef LIBMESH_HAVE_EXODUS_API
114 const unsigned int write_interval = infile("write_interval", 5);
115#endif
116
117 // Skip higher-dimensional examples on a lower-dimensional libMesh build
118 libmesh_example_requires(dim <= LIBMESH_DIM, "2D/3D support");
119
120 // We have only defined 2 and 3 dimensional problems
121 libmesh_assert (dim == 2 || dim == 3);
122
123 // Create a mesh, with dimension to be overridden later, distributed
124 // across the default MPI communicator.
125 std::shared_ptr<UnstructuredMesh> mesh;
126
127 if (mesh_type == "distributed")
128 mesh = std::make_shared<DistributedMesh>(init.comm());
129 else if (mesh_type == "replicated")
130 mesh = std::make_shared<ReplicatedMesh>(init.comm());
131 else
132 libmesh_error_msg("Error: specified mesh_type not understood");
133
134 // And an object to refine it
135 MeshRefinement mesh_refinement(*mesh);
136 mesh_refinement.coarsen_by_parents() = true;
137 mesh_refinement.absolute_global_tolerance() = global_tolerance;
138 mesh_refinement.nelem_target() = nelem_target;
139 mesh_refinement.refine_fraction() = 0.3;
140 mesh_refinement.coarsen_fraction() = 0.3;
141 mesh_refinement.coarsen_threshold() = 0.1;
142
143 // Use the MeshTools::Generation mesh generator to create a uniform
144 // grid on the square [-1,1]^D. We instruct the mesh generator
145 // to build a mesh of 8x8 Quad9 elements in 2D, or Hex27
146 // elements in 3D. Building these higher-order elements allows
147 // us to use higher-order approximation, as in example 3.
148 if (dim == 2)
150 coarsegridsize,
151 coarsegridsize,
152 0., 1.,
153 0., 1.,
154 QUAD9);
155 else if (dim == 3)
157 coarsegridsize,
158 coarsegridsize,
159 coarsegridsize,
160 0., 1.,
161 0., 1.,
162 0., 1.,
163 HEX27);
164
165 mesh_refinement.uniformly_refine(coarserefinements);
166
167 // Print information about the mesh to the screen.
168 mesh->print_info();
169
170 // Create an equation systems object.
171 EquationSystems equation_systems (*mesh);
172
173 // Declare the system "Navier-Stokes" and its variables.
174 NavierSystem & system =
175 equation_systems.add_system<NavierSystem> ("Navier-Stokes");
176
177 // Debug it if requested
178 system.print_solutions = print_solutions;
179 system.print_solution_norms = print_solutions;
180 system.print_residuals = print_residuals;
181 system.print_residual_norms = print_residuals;
182 system.print_jacobians = print_jacobians;
183 system.print_jacobian_norms = print_jacobians;
184
185 // Solve this as a time-dependent or steady system
186 if (transient)
187 system.time_solver = std::make_unique<EulerSolver>(system);
188 else
189 {
190 system.time_solver = std::make_unique<SteadySolver>(system);
191 libmesh_assert_equal_to (n_timesteps, 1);
192 }
193
194 // Initialize the system
195 equation_systems.init ();
196
197 // Set the time stepping options
198 system.deltat = deltat;
199
200 // And the nonlinear solver options
201 if (slvr_type == "newton")
202 system.time_solver->diff_solver() = std::make_unique<NewtonSolver>(system);
203 else if (slvr_type == "petscdiff")
204#if defined(LIBMESH_HAVE_PETSC) && defined(LIBMESH_HAVE_METAPHYSICL)
205 system.time_solver->diff_solver() = std::make_unique<PetscDiffSolver>(system);
206#else
207 libmesh_example_requires(false, "--enable-petsc --enable-metaphysicl-required");
208#endif
209 else
210 libmesh_error_msg("Error: specified solver_type not understood");
211
212 DiffSolver & solver = *(system.time_solver->diff_solver().get());
213 solver.init();
214
215 solver.quiet = infile("solver_quiet", true);
216 solver.verbose = !solver.quiet;
218 infile("max_nonlinear_iterations", 15);
220 infile("relative_step_tolerance", 1.e-3);
222 infile("relative_residual_tolerance", 0.0);
224 infile("absolute_residual_tolerance", 0.0);
225
226 system.set_constrain_in_solver(constrain_in_solver);
227
228 // And the linear solver options
229 solver.max_linear_iterations =
230 infile("max_linear_iterations", 50000);
232 infile("initial_linear_tolerance", 1.e-3);
233
234 // Print information about the system to the screen.
235 equation_systems.print_info();
236
237 // Now we begin the timestep loop to compute the time-accurate
238 // solution of the equations.
239 for (unsigned int t_step=0; t_step != n_timesteps; ++t_step)
240 {
241 // A pretty update message
242 libMesh::out << "\n\nSolving time step "
243 << t_step
244 << ", time = "
245 << system.time
246 << std::endl;
247
248 // Adaptively solve the timestep
249 unsigned int a_step = 0;
250 for (; a_step != max_adaptivesteps; ++a_step)
251 {
252 system.solve();
253
254 system.postprocess();
255
256 ErrorVector error;
257
258 std::unique_ptr<ErrorEstimator> error_estimator;
259
260 // To solve to a tolerance in this problem we
261 // need a better estimator than Kelly
262 if (global_tolerance != 0.)
263 {
264 // We can't adapt to both a tolerance and a mesh
265 // size at once
266 libmesh_assert_equal_to (nelem_target, 0);
267
268 error_estimator = std::make_unique<UniformRefinementEstimator>();
269
270 // The lid-driven cavity problem isn't in H1, so
271 // lets estimate L2 error
272 error_estimator->error_norm = L2;
273 }
274 else
275 {
276 // If we aren't adapting to a tolerance we need a
277 // target mesh size
278 libmesh_assert_greater (nelem_target, 0);
279
280 // Kelly is a lousy estimator to use for a problem
281 // not in H1 - if we were doing more than a few
282 // timesteps we'd need to turn off or limit the
283 // maximum level of our adaptivity eventually
284 error_estimator = std::make_unique<KellyErrorEstimator>();
285 }
286
287 // Calculate error based on u and v (and w?) but not p
288 std::vector<Real> weights(2,1.0); // u, v
289 if (dim == 3)
290 weights.push_back(1.0); // w
291 weights.push_back(0.0); // p
292 // Keep the same default norm type.
293 std::vector<FEMNormType>
294 norms(1, error_estimator->error_norm.type(0));
295 error_estimator->error_norm = SystemNorm(norms, weights);
296
297 error_estimator->estimate_error(system, error);
298
299 // Print out status at each adaptive step.
300 Real global_error = error.l2_norm();
301 libMesh::out << "Adaptive step "
302 << a_step
303 << ": "
304 << std::endl;
305
306 if (global_tolerance != 0.)
307 libMesh::out << "Global_error = "
308 << global_error
309 << std::endl;
310
311 if (global_tolerance != 0.)
312 libMesh::out << "Worst element error = "
313 << error.maximum()
314 << ", mean = "
315 << error.mean()
316 << std::endl;
317
318 if (global_tolerance != 0.)
319 {
320 // If we've reached our desired tolerance, we
321 // don't need any more adaptive steps
322 if (global_error < global_tolerance)
323 break;
324 mesh_refinement.flag_elements_by_error_tolerance(error);
325 }
326 else
327 {
328 // If flag_elements_by_nelem_target returns true, this
329 // should be our last adaptive step.
330 if (mesh_refinement.flag_elements_by_nelem_target(error))
331 {
332 mesh_refinement.refine_and_coarsen_elements();
333 equation_systems.reinit();
334 a_step = max_adaptivesteps;
335 break;
336 }
337 }
338
339 // Carry out the adaptive mesh refinement/coarsening
340 mesh_refinement.refine_and_coarsen_elements();
341 equation_systems.reinit();
342
343 libMesh::out << "Refined mesh to "
344 << mesh->n_active_elem()
345 << " active elements and "
346 << equation_systems.n_active_dofs()
347 << " active dofs."
348 << std::endl;
349 }
350 // Do one last solve if necessary
351 if (a_step == max_adaptivesteps)
352 {
353 system.solve();
354
355 system.postprocess();
356 }
357
358 // Advance to the next timestep in a transient problem
359 system.time_solver->advance_timestep();
360
361#ifdef LIBMESH_HAVE_EXODUS_API
362 // Write out this timestep if we're requested to
363 if ((t_step+1)%write_interval == 0)
364 {
365 std::ostringstream file_name;
366
367 // We write the file in the ExodusII format.
368 file_name << "out_"
369 << std::setw(3)
370 << std::setfill('0')
371 << std::right
372 << t_step+1
373 << ".e";
374
375 ExodusII_IO(*mesh).write_timestep(file_name.str(),
376 equation_systems,
377 1, // This number indicates how many time steps
378 // are being written to the file
379 system.time);
380 }
381#endif // #ifdef LIBMESH_HAVE_EXODUS_API
382 }
383#endif // #ifndef LIBMESH_ENABLE_AMR
384
385 // All done.
386 return 0;
387}
unsigned int dim
virtual void postprocess()
Runs a postprocessing loop over all elements, and if postprocess_sides is true over all sides.
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.
virtual void init()
The initialization function.
Definition diff_solver.C:72
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...
bool print_jacobians
Set print_jacobians to true to print J whenever it is assembled.
bool print_residuals
Set print_residuals to true to print F whenever it is assembled.
Real deltat
For time-dependent problems, this is the amount delta t to advance the solution in time.
virtual void set_constrain_in_solver(bool enable)
set_constrain_in_solver to false to apply constraints only via residual terms in the systems to be so...
bool print_solution_norms
Set print_residual_norms to true to print |U| whenever it is used in an assembly() call.
bool print_solutions
Set print_solutions to true to print U whenever it is used in an assembly() call.
bool print_residual_norms
Set print_residual_norms to true to print |F| whenever it is assembled.
bool print_jacobian_norms
Set print_jacobian_norms to true to print |J| whenever it is assembled.
std::unique_ptr< TimeSolver > time_solver
A pointer to the solver object we're going to use.
This is the EquationSystems class.
virtual void reinit()
Handle any mesh changes and reinitialize all the systems on the updated mesh.
void print_info(std::ostream &os=libMesh::out) const
Prints information about the equation systems, by default to libMesh::out.
std::size_t n_active_dofs() const
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 ErrorVector is a specialization of the StatisticsVector for error data computed on a finite eleme...
virtual Real mean() const override
The ExodusII_IO class implements reading meshes in the ExodusII file format from Sandia National Labs...
Definition exodusII_io.h:53
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.
virtual void solve() override
Invokes the solver associated with the system.
The LibMeshInit class, when constructed, initializes the dependent libraries (e.g.
Definition libmesh.h:92
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:1755
virtual dof_id_type n_active_elem() const =0
Implements (adaptive) mesh refinement algorithms for a MeshBase.
void flag_elements_by_error_tolerance(const ErrorVector &error_per_cell)
Flags elements for coarsening and refinement based on the computed error passed in error_per_cell.
Real & absolute_global_tolerance()
If absolute_global_tolerance is set to a nonzero value, methods like flag_elements_by_global_toleranc...
void uniformly_refine(unsigned int n=1)
Uniformly refines the mesh n times.
bool & coarsen_by_parents()
If coarsen_by_parents is true, complete groups of sibling elements (elements with the same parent) wi...
bool flag_elements_by_nelem_target(const ErrorVector &error_per_cell)
Flags elements for coarsening and refinement based on the computed error passed in error_per_cell.
Real & coarsen_threshold()
The coarsen_threshold provides hysteresis in AMR/C strategies.
dof_id_type & nelem_target()
If nelem_target is set to a nonzero value, methods like flag_elements_by_nelem_target() will attempt ...
bool refine_and_coarsen_elements()
Refines and coarsens user-requested elements.
Real & refine_fraction()
The refine_fraction sets either a desired target or a desired maximum number of elements to flag for ...
Real & coarsen_fraction()
The coarsen_fraction sets either a desired target or a desired maximum number of elements to flag for...
virtual T maximum() const
Definition statistics.C:62
virtual Real l2_norm() const
Definition statistics.C:37
This class defines a norm/seminorm to be applied to a NumericVector which contains coefficients in a ...
Definition system_norm.h:50
Real time
For time-dependent problems, this is the time t at the beginning of the current timestep.
Definition system.h:1677
MeshBase & mesh
void build_square(UnstructuredMesh &mesh, const unsigned int nx, const unsigned int ny, const Real xmin=0., const Real xmax=1., const Real ymin=0., const Real ymax=1., const ElemType type=INVALID_ELEM, const bool gauss_lobatto_grid=false)
A specialized build_cube() for 2D meshes.
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.
The libMesh namespace provides an interface to certain functionality in the library.
SolverPackage default_solver_package()
Definition libmesh.C:1064
libmesh_assert(ctx)
OStreamProxy out
DIE A HORRIBLE DEATH HERE typedef LIBMESH_DEFAULT_SCALAR_TYPE Real
int main()