Grids and Discrete Functions

A grid is a partitioning of a domain ΩRd \Omega\subset\mathbf{R}^d into simple geometric elements, like triangles or quads in 2d and tetrahedra, cubes, pyramids, or prisms in 3d. The grid data structure manages the various entities (vertices, edges, faces, and cells) that are part of the grid and its connectivity.

Several grid implementations are available for different puroses. Some are optimized for very structured domain discretizations, some are build for unstructured grids. Some grid managers are shipped with the Dune core modules, others need to be installed separately, as an extra Dune module or external library.

All grid implementations have a common interface defined in dune-grid. But each module may have some extended features not shared with other grid managers.

Some standard grid modules are

  • OneDGrid: an unstructured one-dimensional grid
  • YaspGrid: a structured 2/3 dimensional cube grid
  • UGGrid: an unstructured 2/3 dimensional grid with mixed element types (requires the dune-uggrid module)
  • AlbertaGrid: wrapper for the 1/2/3 dimensional simplex grid of the external Alberta FEM library. Allows for surface grids, i.e. dim != dow.

Grid Construction

There are several ways to create a grid. Each grid provides some construtors for individual creation. A common approach is to use a GridFactory that allows to insert vertices and element connectivity directly. For rectangular domains a StructuredGridFactory can be used that discretizes a box-partitioning of the domain into cubes or simplices. And there are some file readers that allow to read a grid description from a common file format, like GMsh, AmiraMesh, or AlbertaGrid files.

#include <dune/grid/yaspgrid.hh>
#include <dune/grid/uggrid.hh>

// direct creation of [0.0, 1.0]^2 with 4 elements in each coordinate direction
Dune::YaspGrid<2> grid1({1.0, 1.0}, {4,4});

// using a StructuredGridFactory
using Factory = Dune::StructuredGridFactory<Dune::YaspGrid<2>>;
std::array<unsigned int, 2> numCells{4,4};
std::unique_ptr<Dune::YaspGrid<2>> grid2( Factory::createCubeGrid({0.0, 0.0}, {1.0, 1.0}, numCells) );

// using a file reader
using Reader = Dune::GmshReader<Dune::UGGrid<2>>;
std::unique_ptr<Dune::UGGrid<2>> grid3( Reader::read("gridfile.msh") );

AMDiS provides a way to construct a grid by inspecting some initfile parameters. Therefore, we have implemented the MeshCreator. It expects in the constructor the base name of a parameter that defines how to construct the grid given as template type:

#include <dune/grid/albertagrid.hh>

using Grid = Dune::AlbertaGrid<2>;
std::unique_ptr<Grid> grid4( MeshCreator<Grid>("mesh").create() );

where "mesh" defines a key that can be used in the parameter file to describe the grid:

% structured rectangular grid
mesh->structured: [cube|simplex]
mesh->min corner: 0.0 0.0
mesh->max corner: 1.0 1.0
mesh->num cells: 4 4

% read grid from file
mesh->macro file name: gridfile.msh

At first, the MeshCreator looks for the parameter macro file name, if found, it tries to determine from the file extension which file format to read. GMsh files use the extension .msh, AlbertaGrid files one of .2d, .3d, or .amc and the Dune DGF files have the extension .dgf.

If no filename is given, it looks for the structured parameter to determine which elements (cubes or simplices) to use for the construction of a structured rectangular grid described by the bounding box min corner - max corner and the number of subdivisions in each coordinate direction num cells.

If no structured parameter is given, the MeshCreator tries to create the grid directly. This may allow to pass more grid specific parameters, e.g. the YaspGrid allows to specify in addition to min corner, max corner, and num cells:

  • overlap: the number of overlapping elements in a partitioned grid
  • periodic: a bitfield characterizing the periodicity of the grid

Global Basis and Function Spaces

A discrete function is described by a set of (global) basis functions and a coefficient vector. This pair is called a DOFVector in AMDiS. The global basis is thereby a class implementing the interface of the GlobalBasis in the dune-functions module.

The simplest global bases are build of a composition of local basis functions associated to grid elements. The connectivity of these basis functions, i.e. a global numbering of all the local functions, defines the set of global basis functions restricted to each grid element. Details about this interface and mathematical background can be found on dune-project and in the publication The interface for functions in the dune-functions module.

Construction of a global basis can be done using directly the factory functions of dune-functions:

#include <dune/functions/functionspacebases/lagrangebasis.hh>
#include <dune/functions/functionspacebases/powerbasis.hh>
#include <amdis/functions/GlobalBasis.hpp>

// the factory functions are defined in this namespace
using namespace Dune::Functions::BasisFactory;

// create a power basis of 3 lagrange bases with local polynomial degree 2
// on the leaf elements of the grid
GlobalBasis basis1{grid2->leafGridView(), power<3>(lagrange<2>())};

or by using some predefined wrappers:

#include <amdis/ProblemStatTraits.hpp>

// use the wrapper provided in AMDiS to create a power basis of 3 lagrange bases
// of local polynomial degree 2
using BasisCreator = LagrangeBasis<Dune::YaspGrid<2>, 2,2,2>;
auto basis2 = BasisCreator::create(grid2->leafGridView());

Note

Different to dune-functions, we have introduced a (Parallel) GlobalBasis that has a direct connection to the underlying Grid and can thus react on grid changes by grid refinement or by repartitioning. Additionally, it stores a communication object to construct global DOFMappings for distributed data structured.

This GlobalBasis can be converted from a DefaultGlobalBasis of dune-functions.

A DOFVector takes a global basis and provides the coefficient vector as data member. This defines a discrete function that can be evaluated in local and global coordinates and can be used as GridFunction in the operators, see below.

// use a generator function
auto vec1 = makeDOFVector(basis1);

// provide the type of the basis directly
DOFVector<typename BasisCreator::GlobalBasis> vec2(basis2);

// with c++17 class template argument deduction
DOFVector vec3(basis2);

Note

DOFVectors allow to specify the underlying data type, e.g. to use quad-precision coefficients or (maybe in the future) to use complex-valued data.

This coefficient type can be specified as additional template parameter to makeDOFVector<double>(...) or in the class templates DOFVector<GB, double>.