61#include "libmesh/libmesh.h"
62#include "libmesh/mesh.h"
63#include "libmesh/mesh_generation.h"
64#include "libmesh/equation_systems.h"
65#include "libmesh/linear_implicit_system.h"
66#include "libmesh/dof_map.h"
67#include "libmesh/default_coupling.h"
68#include "libmesh/elem.h"
69#include "libmesh/sparse_matrix.h"
70#include "libmesh/numeric_vector.h"
71#include "libmesh/dense_matrix.h"
72#include "libmesh/dense_vector.h"
73#include "libmesh/getpot.h"
74#include "libmesh/enum_solver_package.h"
75#include "libmesh/int_range.h"
76#include "libmesh/exodusII_io.h"
106 velocity(0) *
pi * std::cos(
pi * x) * std::cos(
pi * y) -
107 velocity(1) *
pi * std::sin(
pi * x) * std::sin(
pi * y);
117 std::map<dof_id_type, T> coefficients;
121typedef AffineStencil<Real> ScalarStencil;
122typedef AffineStencil<RealVectorValue> GradientStencil;
128 for (
const auto & [dof, coef] : g.coefficients)
129 out.coefficients[dof] +=
scale * (coef * a);
130 out.constant +=
scale * (g.constant * a);
135average(
const GradientStencil & a,
const GradientStencil &
b)
138 for (
const auto & [dof, coef] : a.coefficients)
139 avg.coefficients[dof] += 0.5 * coef;
140 for (
const auto & [dof, coef] :
b.coefficients)
141 avg.coefficients[dof] += 0.5 * coef;
142 avg.constant = 0.5 * (a.constant +
b.constant);
157face_geometry(
const Elem & elem,
const unsigned int side)
159 const std::unique_ptr<const Elem> side_elem = elem.
build_side_ptr(side);
170gradient_stencil(
const Elem & elem,
const unsigned int sys_num)
179 const unsigned int dim = elem.
dim();
182 std::vector<Sample> samples;
184 for (
const auto s : elem.side_index_range())
188 sample = {neighbor->true_centroid() - x_elem, neighbor->dof_number(sys_num, 0, 0), 0};
191 const FaceGeometry face = face_geometry(elem, s);
197 normal_matrix(i, j) += sample.offset(i) * sample.offset(j);
198 samples.push_back(sample);
205 for (
const auto & sample : samples)
209 rhs(i) = sample.offset(i);
210 normal_matrix.lu_solve(rhs, w);
216 g.coefficients[elem_dof] -=
weight;
218 g.constant += sample.value *
weight;
220 g.coefficients[sample.dof] +=
weight;
235 const unsigned int sys_num = system.
number();
240 for (
const Elem * elem :
mesh.active_local_element_ptr_range())
244 const GradientStencil grad_elem = gradient_stencil(*elem, sys_num);
247 ScalarStencil net_flux;
251 const FaceGeometry face = face_geometry(*elem, s);
258 const GradientStencil grad_neighbor =
259 neighbor ? gradient_stencil(*neighbor, sys_num) : GradientStencil();
260 const GradientStencil grad_face = neighbor ? average(grad_elem, grad_neighbor) : grad_elem;
267 const Real d_dot_n = d * face.normal;
268 const Real diffusive_scale = -diffusivity * face.area;
270 net_flux.coefficients[elem_dof] -= diffusive_scale / d_dot_n;
272 net_flux.coefficients[neighbor->
dof_number(sys_num, 0, 0)] += diffusive_scale / d_dot_n;
274 net_flux.constant += diffusive_scale / d_dot_n *
exact_solution(face.centroid);
275 add_dot(net_flux, grad_face, face.normal - d / d_dot_n, diffusive_scale);
280 const Real mass_flux = (velocity * face.normal) * face.area;
283 net_flux.coefficients[elem_dof] += mass_flux;
284 add_dot(net_flux, grad_elem, face.centroid - x_elem, mass_flux);
288 net_flux.coefficients[neighbor->
dof_number(sys_num, 0, 0)] += mass_flux;
289 add_dot(net_flux, grad_neighbor, face.centroid - x_across, mass_flux);
295 std::vector<dof_id_type> row_dofs = {elem_dof};
296 std::vector<dof_id_type> column_dofs;
298 for (
const auto & [dof, coef] : net_flux.coefficients)
300 Ke(0, column_dofs.size()) = coef;
301 column_dofs.push_back(dof);
305 Fe(0) =
forcing(x_elem, diffusivity, velocity) * elem->
volume() - net_flux.constant;
307 system.matrix->add_matrix(Ke, row_dofs, column_dofs);
308 system.rhs->add_vector(Fe, row_dofs);
317 const unsigned int sys_num = system.
number();
320 for (
const Elem * elem : system.
get_mesh().active_local_element_ptr_range())
324 error_sq += elem->
volume() * diff * diff;
328 return std::sqrt(error_sq);
339 "--enable-petsc, --enable-trilinos, or --enable-eigen");
342 libmesh_example_requires(2 <= LIBMESH_DIM,
"2D support");
345 GetPot infile(
"finite_volume_ex1.in");
346 infile.parse_command_line(argc, argv);
348 const unsigned int coarse_grid_size = infile(
"coarse_grid_size", 4);
349 const unsigned int max_refinements = infile(
"max_refinements", 6);
350 const Real diffusivity = infile(
"diffusivity", 1.);
351 const RealVectorValue velocity(infile(
"velocity_x", 1.), infile(
"velocity_y", 0.5));
361 const Real expected_rate = 2;
362 const Real rate_tolerance = 0.1;
364 std::vector<Real> errors;
365 bool converged =
false;
366 for (
const auto level :
make_range(max_refinements + 1))
368 const unsigned int grid_size = coarse_grid_size << level;
380 system.get_dof_map().default_coupling().set_n_levels(2);
386 equation_systems.
init();
391 errors.push_back(error);
393 <<
" cells, centroid L2 error " << error;
395 libMesh::out <<
", convergence rate " << std::log2(errors[level - 1] / error);
404 const Real fit_rate = std::log2(errors[level - 2] / error) / 2;
406 converged = std::abs(fit_rate - expected_rate) < rate_tolerance;
412#ifdef LIBMESH_HAVE_EXODUS_API
419 libmesh_error_msg_if(!converged,
420 "The three-grid fit of the L2 error convergence rate did not reach "
421 << expected_rate <<
" +/- " << rate_tolerance <<
" within "
422 << max_refinements <<
" refinements");
Number(* exact_solution)(const Point &p, const Parameters &, const std::string &, const std::string &)
Defines a dense matrix for use in Finite Element-type computations.
Defines a dense vector for use in Finite Element-type computations.
dof_id_type dof_number(const unsigned int s, const unsigned int var, const unsigned int comp) const
static constexpr dof_id_type invalid_id
An invalid id to distinguish an uninitialized DofObject.
This is the base class from which all geometric element types are derived.
virtual Point true_centroid() const
virtual unsigned short dim() const =0
virtual Point side_vertex_average_normal(const unsigned int s) const
virtual Real volume() const
const Elem * neighbor_ptr(unsigned int i) const
IntRange< unsigned short > side_index_range() const
virtual std::unique_ptr< Elem > build_side_ptr(const unsigned int i)=0
This is the EquationSystems class.
const MeshBase & get_mesh() const
Parameters parameters
Data structure holding arbitrary parameters.
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.
const T_sys & get_system(std::string_view name) const
The ExodusII_IO class implements reading meshes in the ExodusII file format from Sandia National Labs...
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.
The LibMeshInit class, when constructed, initializes the dependent libraries (e.g.
Manages consistently variables, degrees of freedom, coefficient vectors, matrices and linear solvers ...
This is the MeshBase class.
virtual dof_id_type n_active_elem() const =0
The Mesh class is a thin wrapper, around the ReplicatedMesh class by default.
const Parallel::Communicator & comm() const
T & set(const std::string &)
const T & get(std::string_view) const
A Point defines a location in LIBMESH_DIM dimensional Real space.
Manages consistently variables, degrees of freedom, and coefficient vectors.
Number current_solution(const dof_id_type global_dof_number) const
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.
unsigned int number() const
const MeshBase & get_mesh() const
Number forcing(const Point &p)
Real centroid_l2_error(const System &system)
void assemble_advection_diffusion(EquationSystems &es, const std::string &system_name)
The libMesh namespace provides an interface to certain functionality in the library.
SolverPackage default_solver_package()
LIBMESH_DEVICE_INLINE T libmesh_real(T a)
DIE A HORRIBLE DEATH HERE typedef LIBMESH_DEFAULT_SCALAR_TYPE Real
IntRange< T > make_range(T beg, T end)
The 2-parameter make_range() helper function returns an IntRange<T> when both input parameters are of...