- unstructured grid, maybe read from a file. This relates to the grid I/O tutorial and uses other grid managers than `YaspGrid`.
- using higher-order finite elements, e.g. `Q2` or `P2`, with additional DoFs on edges (or even in the element interior). This requires a mapper, as introduced in the corresponding grid data tutorial.
- non-homogeneous boundary conditions, e.g. a subset of the boundary with Dirichlet conditions and the rest Neumann, possibly using boundary intersection normal vectors.
- build a local element matrix and local element vector before scattering into the global matrix.
We use first-order conforming Lagrange elements (`Q1` on a structured square grid, one DoF per vertex).
We use first-order conforming Lagrange elements (`Q1` on a structured square grid, one DoF per vertex) for the discretization of the function space $H^1$ and incorporate the Dirichlet boundary condition by a modification of the algebraic system.
## Three-step path
1.[Grid and linear algebra setup](../poisson/setup.md)
2.[Assembly and boundary conditions](../poisson/assembly-bc.md)
3.[Solve and VTK output](../poisson/solve-vtk.md)
## Summary and next steps
You now have the Poisson overview and implementation roadmap.
Continue with [Step 1: Grid and linear algebra setup](../poisson/setup.md).
This step creates the grid, global DoF numbering, and sparse matrix layout.
This step creates the computational grid, global DoF numbering, and sparse matrix layout.
!!! abstract "Learning goals"
After this page, you should be able to:
- create a unit-square `YaspGrid` with concise constructor syntax,
- define one global DoF per vertex using `indexSet`,
- initialize `BCRSMatrix<double>` and `BlockVector<double>`.
- create a unit-square `YaspGrid`,
- define one global DoF per vertex using an index set,
- initialize `BCRSMatrix` and `BlockVector`.
## Grid setup
@@ -23,13 +23,13 @@ For a different domain shape, number of elements, element types, or even local r
## Vertex DoF numbering
For first-order conforming elements, one DoF is attached to each vertex. Thus, we get as total number of degrees of freedom the number of vertices in the grid:
First-order conforming elements have one DoF attached to each vertex. Thus, we get as total number of degrees of freedom the number of vertices in the grid:
```cpp
constautonumDofs=gv.indexSet().size(2);
```
In each element of the grid, the local corner vertices are associated to a global vertex index. This can be retrieved from the grid's index set, by collecting the vertex subindices for each element. For performance reasons, it is good to collect this index mapping of local to global vertex indices:
In each element of the grid, the local corner vertices are associated to a global vertex index. This can be retrieved from the grid's index set, by collecting the vertex sub-indices for each element. For performance reasons, it is good to collect this index mapping of local to global vertex indices into a container,
```cpp
template<classGridView,classElement>
@@ -57,19 +57,20 @@ What this does:
!!! note
If the number of corners or the number of DoFs per element is a statically known constant, one could store this mapping in a `std::array`, instead of a dynamic `std::vector`. This requires to know the element type of the grid and its dimension.
For example, a 2d `YaspGrid` allows only square elements, and a first order Lagrange local finite-element has one degree of freedom per vertex. This makes $4=2^{\text{dim}}$ DoFs per Element.
## Sparse matrix pattern
```c++
constexpr int numElementDofs = 1<<dim;
std::array<std::size_t,numElementDofs> dofs;
for (int localVertex = 0; localVertex < numElementDofs; ++localVertex)
Before assembly, we collect all nonzero couplings with `MatrixIndexSet`:
```cpp
Dune::MatrixIndexSetpattern(numDofs,numDofs);
Dune::BCRSMatrix<double>A;
pattern.exportIdx(A);
A=0.0;
```
### Algorithm sketch: setup matrix pattern
## Sparse matrix pattern
Before assembly, we collect all nonzero couplings with `MatrixIndexSet`:
```cpp
Dune::MatrixIndexSetpattern(numDofs,numDofs);
@@ -89,7 +90,7 @@ A = 0.0;
This pattern contains all row/column pairs that can receive element contributions.
For a vertex-based first-order method, all local vertex DoFs on one element couple with each other, so we insert the full local `nCorners x nCorners` block.
The rhs uses scalar blocks too:
The rhs will be assembled into a vector with `numDofs` entries,