libMesh
Loading...
Searching...
No Matches
Functions
finite_volume_ex1.C File Reference

Go to the source code of this file.

Functions

void assemble_advection_diffusion (EquationSystems &es, const std::string &system_name)
 
Real centroid_l2_error (const System &system)
 
int main (int argc, char **argv)
 

Function Documentation

◆ assemble_advection_diffusion()

void assemble_advection_diffusion ( EquationSystems &  es,
const std::string &  system_name 
)

Definition at line 231 of file finite_volume_ex1.C.

232{
233 const MeshBase & mesh = es.get_mesh();
234 auto & system = es.get_system<LinearImplicitSystem>(system_name);
235 const unsigned int sys_num = system.number();
236
237 const Real diffusivity = es.parameters.get<Real>("diffusivity");
238 const RealVectorValue velocity = es.parameters.get<RealVectorValue>("velocity");
239
240 for (const Elem * elem : mesh.active_local_element_ptr_range())
241 {
242 const dof_id_type elem_dof = elem->dof_number(sys_num, 0, 0);
243 const Point x_elem = elem->true_centroid();
244 const GradientStencil grad_elem = gradient_stencil(*elem, sys_num);
245
246 // The net outward flux through the cell boundary
247 ScalarStencil net_flux;
248
249 for (const auto s : elem->side_index_range())
250 {
251 const FaceGeometry face = face_geometry(*elem, s);
252 const Elem * neighbor = elem->neighbor_ptr(s);
253
254 // On interior faces, the neighbor centroid and gradient; on
255 // boundary faces, the face centroid, where the Dirichlet
256 // value is known, and the gradient of this cell.
257 const Point x_across = neighbor ? neighbor->true_centroid() : face.centroid;
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;
261
262 // Diffusion: with d the offset from x_elem to x_across,
263 // n.grad(u) ~= (u_across - u_elem) / (d.n) + (n - d / (d.n)).grad(u)_face,
264 // which is exact for linear u. The second term vanishes when d
265 // is parallel to n.
266 const RealVectorValue d = x_across - x_elem;
267 const Real d_dot_n = d * face.normal;
268 const Real diffusive_scale = -diffusivity * face.area;
269
270 net_flux.coefficients[elem_dof] -= diffusive_scale / d_dot_n;
271 if (neighbor)
272 net_flux.coefficients[neighbor->dof_number(sys_num, 0, 0)] += diffusive_scale / d_dot_n;
273 else
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);
276
277 // Advection: the upwind cell value, extrapolated to the face
278 // centroid with that cell's gradient. Inflow boundary faces
279 // take the Dirichlet value.
280 const Real mass_flux = (velocity * face.normal) * face.area;
281 if (mass_flux >= 0)
282 {
283 net_flux.coefficients[elem_dof] += mass_flux;
284 add_dot(net_flux, grad_elem, face.centroid - x_elem, mass_flux);
285 }
286 else if (neighbor)
287 {
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);
290 }
291 else
292 net_flux.constant += mass_flux * exact_solution(face.centroid);
293 }
294
295 std::vector<dof_id_type> row_dofs = {elem_dof};
296 std::vector<dof_id_type> column_dofs;
297 DenseMatrix<Number> Ke(1, net_flux.coefficients.size());
298 for (const auto & [dof, coef] : net_flux.coefficients)
299 {
300 Ke(0, column_dofs.size()) = coef;
301 column_dofs.push_back(dof);
302 }
303
305 Fe(0) = forcing(x_elem, diffusivity, velocity) * elem->volume() - net_flux.constant;
306
307 system.matrix->add_matrix(Ke, row_dofs, column_dofs);
308 system.rhs->add_vector(Fe, row_dofs);
309 }
310}
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
This is the base class from which all geometric element types are derived.
Definition elem.h:96
virtual Point true_centroid() const
Definition elem.C:515
const Elem * neighbor_ptr(unsigned int i) const
Definition elem.h:2736
const MeshBase & get_mesh() const
Parameters parameters
Data structure holding arbitrary parameters.
const T_sys & get_system(std::string_view name) const
Manages consistently variables, degrees of freedom, coefficient vectors, matrices and linear solvers ...
This is the MeshBase class.
Definition mesh_base.h:81
const T & get(std::string_view) const
Definition parameters.h:451
A Point defines a location in LIBMESH_DIM dimensional Real space.
Definition point.h:41
unsigned int number() const
Definition system.h:2393
Number forcing(const Point &p)
MeshBase & mesh
uint8_t dof_id_type
Definition id_types.h:67
DIE A HORRIBLE DEATH HERE typedef LIBMESH_DEFAULT_SCALAR_TYPE Real

References libMesh::DofObject::dof_number(), exact_solution, forcing(), libMesh::Parameters::get(), libMesh::EquationSystems::get_mesh(), libMesh::EquationSystems::get_system(), mesh, libMesh::Elem::neighbor_ptr(), libMesh::System::number(), libMesh::EquationSystems::parameters, libMesh::Real, libMesh::Elem::side_index_range(), libMesh::Elem::true_centroid(), and libMesh::Elem::volume().

Referenced by main().

◆ centroid_l2_error()

Real centroid_l2_error ( const System &  system)

Definition at line 315 of file finite_volume_ex1.C.

316{
317 const unsigned int sys_num = system.number();
318
319 Real error_sq = 0;
320 for (const Elem * elem : system.get_mesh().active_local_element_ptr_range())
321 {
322 const Real u_h = libmesh_real(system.current_solution(elem->dof_number(sys_num, 0, 0)));
323 const Real diff = u_h - exact_solution(elem->true_centroid());
324 error_sq += elem->volume() * diff * diff;
325 }
326 system.comm().sum(error_sq);
327
328 return std::sqrt(error_sq);
329}
const Parallel::Communicator & comm() const
Number current_solution(const dof_id_type global_dof_number) const
Definition system.C:162
LIBMESH_DEVICE_INLINE T libmesh_real(T a)

References libMesh::ParallelObject::comm(), libMesh::System::current_solution(), libMesh::DofObject::dof_number(), exact_solution, libMesh::System::get_mesh(), libMesh::libmesh_real(), libMesh::System::number(), libMesh::Real, libMesh::Parallel::Communicator::sum(), libMesh::Elem::true_centroid(), and libMesh::Elem::volume().

Referenced by main().

◆ main()

int main ( int  argc,
char **  argv 
)

Definition at line 332 of file finite_volume_ex1.C.

333{
334 // Initialize libMesh.
335 LibMeshInit init(argc, argv);
336
337 // This example requires a linear solver package.
338 libmesh_example_requires(libMesh::default_solver_package() != INVALID_SOLVER_PACKAGE,
339 "--enable-petsc, --enable-trilinos, or --enable-eigen");
340
341 // The mesh is two-dimensional.
342 libmesh_example_requires(2 <= LIBMESH_DIM, "2D support");
343
344 // Parse the input file, allowing the command line to override it.
345 GetPot infile("finite_volume_ex1.in");
346 infile.parse_command_line(argc, argv);
347
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));
352
353 // The scheme is second order, and a measured rate within this
354 // distance of 2 is taken as confirmation of that order. The bound is
355 // loose enough to absorb the pre-asymptotic behavior of the error on
356 // the coarsest grids and the round-off of any supported Real
357 // precision, and tight enough to catch a loss of second-order
358 // accuracy. Dropping the advection reconstruction reduces the scheme
359 // to first order, and dropping the non-orthogonal diffusion
360 // correction stops the error from converging at all.
361 const Real expected_rate = 2;
362 const Real rate_tolerance = 0.1;
363
364 std::vector<Real> errors;
365 bool converged = false;
366 for (const auto level : make_range(max_refinements + 1))
367 {
368 const unsigned int grid_size = coarse_grid_size << level;
369
370 Mesh mesh(init.comm());
371 EquationSystems equation_systems(mesh);
372 auto & system = equation_systems.add_system<LinearImplicitSystem>("AdvectionDiffusion");
373 system.add_variable("u", CONSTANT, MONOMIAL);
374 system.attach_assemble_function(assemble_advection_diffusion);
375
376 // Couple each cell to two layers of side neighbors. The DofMap
377 // registers its coupling functor with the mesh, so building the
378 // mesh after this call also retains the corresponding ghost
379 // elements on a distributed mesh.
380 system.get_dof_map().default_coupling().set_n_levels(2);
381
382 MeshTools::Generation::build_square(mesh, grid_size, grid_size, 0., 1., 0., 1., C0POLYGON);
383
384 equation_systems.parameters.set<Real>("diffusivity") = diffusivity;
385 equation_systems.parameters.set<RealVectorValue>("velocity") = velocity;
386 equation_systems.init();
387
388 system.solve();
389
390 const Real error = centroid_l2_error(system);
391 errors.push_back(error);
392 libMesh::out << "Grid size " << grid_size << ": " << mesh.n_active_elem()
393 << " cells, centroid L2 error " << error;
394 if (level)
395 libMesh::out << ", convergence rate " << std::log2(errors[level - 1] / error);
396
397 // Fit a line to log2(error) against log2(h) over the last three
398 // grids. The grid spacing h halves at each level, so the sample
399 // points are equally spaced and the least-squares slope reduces
400 // to the difference between the first and last points divided by
401 // their separation of two levels.
402 if (level >= 2)
403 {
404 const Real fit_rate = std::log2(errors[level - 2] / error) / 2;
405 libMesh::out << ", three-grid fit rate " << fit_rate;
406 converged = std::abs(fit_rate - expected_rate) < rate_tolerance;
407 }
408 libMesh::out << std::endl;
409
410 if (converged)
411 {
412#ifdef LIBMESH_HAVE_EXODUS_API
413 ExodusII_IO(mesh).write_equation_systems("out.e", equation_systems);
414#endif
415 break;
416 }
417 }
418
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");
423
424 return 0;
425}
This is the EquationSystems class.
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.
The LibMeshInit class, when constructed, initializes the dependent libraries (e.g.
Definition libmesh.h:92
virtual dof_id_type n_active_elem() const =0
The Mesh class is a thin wrapper, around the ReplicatedMesh class by default.
Definition mesh.h:51
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
Real centroid_l2_error(const System &system)
void assemble_advection_diffusion(EquationSystems &es, const std::string &system_name)
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 init(triangulateio &t)
Initializes the fields of t to nullptr/0 as necessary.
SolverPackage default_solver_package()
Definition libmesh.C:1064
OStreamProxy out
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...
Definition int_range.h:176

References libMesh::EquationSystems::add_system(), libMesh::System::add_variable(), assemble_advection_diffusion(), libMesh::MeshTools::Generation::build_square(), libMesh::C0POLYGON, centroid_l2_error(), libMesh::CONSTANT, libMesh::default_solver_package(), libMesh::EquationSystems::init(), libMesh::INVALID_SOLVER_PACKAGE, main(), libMesh::make_range(), mesh, libMesh::MONOMIAL, libMesh::MeshBase::n_active_elem(), libMesh::out, libMesh::EquationSystems::parameters, libMesh::Real, libMesh::Parameters::set(), and libMesh::ExodusII_IO::write_equation_systems().