libMesh
Loading...
Searching...
No Matches
fem_system_ex4.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 4 - Mixed-dimension heat transfer equation
21// with FEMSystem</h1>
22// \author Roy Stogner
23// \date 2015
24//
25// This example shows how elements of multiple dimensions can be
26// linked and computed upon simultaneously within the
27// DifferentiableSystem class framework
28
29// C++ includes
30#include <iomanip>
31#include <memory>
32
33// Basic include files
34#include "libmesh/elem.h"
35#include "libmesh/equation_systems.h"
36#include "libmesh/error_vector.h"
37#include "libmesh/exact_solution.h"
38#include "libmesh/getpot.h"
39#include "libmesh/gmv_io.h"
40#include "libmesh/exodusII_io.h"
41#include "libmesh/kelly_error_estimator.h"
42#include "libmesh/mesh.h"
43#include "libmesh/mesh_generation.h"
44#include "libmesh/mesh_refinement.h"
45#include "libmesh/parsed_function.h"
46#include "libmesh/uniform_refinement_estimator.h"
47#include "libmesh/enum_solver_package.h"
48#include "libmesh/enum_norm_type.h"
49
50// The systems and solvers we may use
51#include "heatsystem.h"
52#include "libmesh/diff_solver.h"
53#include "libmesh/euler_solver.h"
54#include "libmesh/steady_solver.h"
55
56// Bring in everything from the libMesh namespace
57using namespace libMesh;
58
59// The main program.
60int main (int argc, char ** argv)
61{
62 // Initialize libMesh.
63 LibMeshInit init (argc, argv);
64
65 // This example requires a linear solver package.
66 libmesh_example_requires(libMesh::default_solver_package() != INVALID_SOLVER_PACKAGE,
67 "--enable-petsc, --enable-trilinos, or --enable-eigen");
68
69#ifndef LIBMESH_ENABLE_AMR
70 libmesh_example_requires(false, "--enable-amr");
71#else
72
73 // We use Dirichlet boundary conditions here
74#ifndef LIBMESH_ENABLE_DIRICHLET
75 libmesh_example_requires(false, "--enable-dirichlet");
76#endif
77
78 // This doesn't converge without at least double precision
79 libmesh_example_requires(sizeof(Real) > 4, "--disable-singleprecision");
80
81 // Parse the input file
82 GetPot infile("fem_system_ex4.in");
83
84 // But allow the command line to override it.
85 infile.parse_command_line(argc, argv);
86
87 // Read in parameters from the input file
88 const Real global_tolerance = infile("global_tolerance", 0.);
89 const unsigned int nelem_target = infile("n_elements", 400);
90 const Real deltat = infile("deltat", 0.005);
91 const unsigned int coarsegridsize = infile("coarsegridsize", 20);
92 const unsigned int coarserefinements = infile("coarserefinements", 0);
93 const unsigned int max_adaptivesteps = infile("max_adaptivesteps", 10);
94 const unsigned int dim = infile("dimension", 2);
95
96 // Skip higher-dimensional examples on a lower-dimensional libMesh build
97 libmesh_example_requires(dim <= LIBMESH_DIM, "2D/3D support");
98
99 // We have only defined 2 and 3 dimensional problems
100 libmesh_assert (dim == 2 || dim == 3);
101
102 // Create a mesh, with dimension to be overridden later, distributed
103 // across the default MPI communicator.
104 Mesh mesh(init.comm());
105
106 // And an object to refine it
107 MeshRefinement mesh_refinement(mesh);
108 mesh_refinement.coarsen_by_parents() = true;
109 mesh_refinement.absolute_global_tolerance() = global_tolerance;
110 mesh_refinement.nelem_target() = nelem_target;
111 mesh_refinement.refine_fraction() = 0.3;
112 mesh_refinement.coarsen_fraction() = 0.3;
113 mesh_refinement.coarsen_threshold() = 0.1;
114
115 // Use the MeshTools::Generation mesh generator to create a uniform
116 // grid on the square or cube. We crop the domain at y=2/3 to allow
117 // for a homogeneous Neumann BC in our benchmark there.
118 boundary_id_type bcid = 3; // +y in 3D
119 if (dim == 2)
120 {
122 (mesh,
123 coarsegridsize,
124 coarsegridsize*2/3, // int arithmetic best we can do here
125 0., 1.,
126 0., 2./3.,
127 QUAD9);
128 bcid = 2; // +y in 2D
129 }
130 else if (dim == 3)
131 {
133 (mesh,
134 coarsegridsize,
135 coarsegridsize*2/3,
136 coarsegridsize,
137 0., 1.,
138 0., 2./3.,
139 0., 1.,
140 HEX27);
141 }
142
143 {
144 // Add boundary elements corresponding to the +y boundary of our
145 // volume mesh
146 std::set<boundary_id_type> bcids;
147 bcids.insert(bcid);
150 }
151
152 // To work around ExodusII file format limitations, we need elements
153 // of different dimensionality to belong to different subdomains.
154 // Our interior elements defaulted to subdomain id 0, so we'll set
155 // boundary elements to subdomain 1.
156 for (auto & elem : mesh.element_ptr_range())
157 if (elem->dim() < dim)
158 elem->subdomain_id() = 1;
159
160 // Make sure the mesh knows we added new subdomains.
162
163 mesh_refinement.uniformly_refine(coarserefinements);
164
165 // Print information about the mesh to the screen.
167
168 // Create an equation systems object.
169 EquationSystems equation_systems (mesh);
170
171 // Declare the system "Heat" and its variables.
172 HeatSystem & system =
173 equation_systems.add_system<HeatSystem> ("Heat");
174
175 // Solve this as a steady system
176 system.time_solver = std::make_unique<SteadySolver>(system);
177
178 // Initialize the system
179 equation_systems.init ();
180
181 // Set the time stepping options
182 system.deltat = deltat;
183
184 // And the nonlinear solver options
185 DiffSolver & solver = *(system.time_solver->diff_solver().get());
186 solver.quiet = infile("solver_quiet", true);
187 solver.verbose = !solver.quiet;
188 solver.max_nonlinear_iterations = infile("max_nonlinear_iterations", 15);
189 solver.relative_step_tolerance = infile("relative_step_tolerance", 1.e-3);
190 solver.relative_residual_tolerance = infile("relative_residual_tolerance", 0.0);
191 solver.absolute_residual_tolerance = infile("absolute_residual_tolerance", 0.0);
192
193 // And the linear solver options
194 solver.max_linear_iterations = infile("max_linear_iterations", 50000);
195 solver.initial_linear_tolerance = infile("initial_linear_tolerance", 1.e-3);
196
197 // Print information about the system to the screen.
198 equation_systems.print_info();
199
200 // Adaptively solve the steady solution
201 unsigned int a_step = 0;
202 for (; a_step != max_adaptivesteps; ++a_step)
203 {
204 system.solve();
205
206 system.postprocess();
207
208 ErrorVector error;
209
210 std::unique_ptr<ErrorEstimator> error_estimator;
211
212 // To solve to a tolerance in this problem we
213 // need a better estimator than Kelly
214 if (global_tolerance != 0.)
215 {
216 // We can't adapt to both a tolerance and a mesh
217 // size at once
218 libmesh_assert_equal_to (nelem_target, 0);
219
220 auto u = std::make_unique<UniformRefinementEstimator>();
221
222 // The lid-driven cavity problem isn't in H1, so
223 // lets estimate L2 error
224 u->error_norm = L2;
225 error_estimator = std::move(u);
226 }
227 else
228 {
229 // If we aren't adapting to a tolerance we need a
230 // target mesh size
231 libmesh_assert_greater (nelem_target, 0);
232
233 // Kelly is a lousy estimator to use for a problem
234 // not in H1 - if we were doing more than a few
235 // timesteps we'd need to turn off or limit the
236 // maximum level of our adaptivity eventually
237 error_estimator = std::make_unique<KellyErrorEstimator>();
238 }
239
240 error_estimator->estimate_error(system, error);
241
242 // Print out status at each adaptive step.
243 Real global_error = error.l2_norm();
244 libMesh::out << "Adaptive step "
245 << a_step
246 << ": "
247 << std::endl;
248
249 if (global_tolerance != 0.)
250 libMesh::out << "Global_error = "
251 << global_error
252 << std::endl;
253
254 if (global_tolerance != 0.)
255 libMesh::out << "Worst element error = "
256 << error.maximum()
257 << ", mean = "
258 << error.mean()
259 << std::endl;
260
261 if (global_tolerance != 0.)
262 {
263 // If we've reached our desired tolerance, we
264 // don't need any more adaptive steps
265 if (global_error < global_tolerance)
266 break;
267 mesh_refinement.flag_elements_by_error_tolerance(error);
268 }
269 else
270 {
271 // If flag_elements_by_nelem_target returns true, this
272 // should be our last adaptive step.
273 if (mesh_refinement.flag_elements_by_nelem_target(error))
274 {
275 mesh_refinement.refine_and_coarsen_elements();
276 equation_systems.reinit();
277 a_step = max_adaptivesteps;
278 break;
279 }
280 }
281
282 // Carry out the adaptive mesh refinement/coarsening
283 mesh_refinement.refine_and_coarsen_elements();
284 equation_systems.reinit();
285
286 libMesh::out << "Refined mesh to "
288 << " active elements and "
289 << equation_systems.n_active_dofs()
290 << " active dofs."
291 << std::endl;
292 }
293 // Do one last solve if necessary
294 if (a_step == max_adaptivesteps)
295 {
296 system.solve();
297
298 system.postprocess();
299 }
300
301
302#ifdef LIBMESH_HAVE_EXODUS_API
304 ("out.e", equation_systems);
305#endif // #ifdef LIBMESH_HAVE_EXODUS_API
306
307#ifdef LIBMESH_HAVE_GMV
309 ("out.gmv", equation_systems);
310#endif // #ifdef LIBMESH_HAVE_GMV
311
312#ifdef LIBMESH_HAVE_FPARSER
313 // Check that we got close to the analytic solution
314 ExactSolution exact_sol(equation_systems);
315 const std::string exact_str = (dim == 2) ?
316 "sin(pi*x)*sin(pi*y)" : "sin(pi*x)*sin(pi*y)*sin(pi*z)";
317 ParsedFunction<Number> exact_func(exact_str);
318 exact_sol.attach_exact_value(0, &exact_func);
319 exact_sol.compute_error("Heat", "T");
320
321 Real err = exact_sol.l2_error("Heat", "T");
322
323 // Print out the error value
324 libMesh::out << "L2-Error is: " << err << std::endl;
325
326 libmesh_assert_less(err, 2e-3);
327
328#endif // #ifdef LIBMESH_HAVE_FPARSER
329
330#endif // #ifndef LIBMESH_ENABLE_AMR
331
332 // All done.
333 return 0;
334}
unsigned int dim
void add_elements(const std::set< boundary_id_type > &requested_boundary_ids, UnstructuredMesh &boundary_mesh, bool store_parent_side_ids=false, const std::vector< subdomain_id_type > &new_subdomain_ids={})
Generates elements along the boundary of our _mesh, which use pre-existing nodes on the boundary_mesh...
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...
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 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
This class handles the computation of the L2 and/or H1 error for the Systems in the EquationSystems o...
Real l2_error(std::string_view sys_name, std::string_view unknown_name)
void attach_exact_value(unsigned int sys_num, FunctionBase< Number > *f)
Clone and attach an arbitrary functor which computes the exact value of the system sys_num solution a...
void compute_error(std::string_view sys_name, std::string_view unknown_name)
Computes and stores the error in the solution value e = u-u_h, the gradient grad(e) = grad(u) - grad(...
The ExodusII_IO class implements reading meshes in the ExodusII file format from Sandia National Labs...
Definition exodusII_io.h:53
virtual void write_equation_systems(const std::string &fname, const EquationSystems &es, const std::set< std::string > *system_names=nullptr) override
Writes out the solution for no specific time or timestep.
virtual void solve() override
Invokes the solver associated with the system.
virtual void postprocess() override
Runs a postprocessing loop over all elements, and if postprocess_sides is true over all sides.
This class implements writing meshes in the GMV format.
Definition gmv_io.h:48
The LibMeshInit class, when constructed, initializes the dependent libraries (e.g.
Definition libmesh.h:92
const BoundaryInfo & get_boundary_info() const
The information about boundary ids on the mesh.
Definition mesh_base.h:170
void prepare_for_use(const bool skip_renumber_nodes_and_elements, const bool skip_find_neighbors)
Prepare a newly created (or read) mesh for use.
Definition mesh_base.C:824
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
virtual void write_equation_systems(const std::string &, const EquationSystems &, const std::set< std::string > *system_names=nullptr)
This method implements writing a mesh with data to a specified file where the data is taken from the ...
Definition mesh_output.C:31
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...
The Mesh class is a thin wrapper, around the ReplicatedMesh class by default.
Definition mesh.h:51
A Function generated (via FParser) by parsing a mathematical expression.
virtual T maximum() const
Definition statistics.C:62
virtual Real l2_norm() const
Definition statistics.C:37
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.
OStreamProxy err
int8_t boundary_id_type
Definition id_types.h:51
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()