This project contains a framework for finite difference multigrid methods. The header files in include
contain class templates for several multigrid components, the src
directory contains the source files, and the drivers
directory contains examples of how to use the solvers.
The folder config/
contains several makefiles that set compiler flags, preprocessor flags, and include flags. For OpenMP target offloading in clang++
, g++
, and nvc++
and flags specific to some common GPU architectures. Note that some versions of nvc++
from the NVIDIA HPC-SDK are incompatible with the project because they do not comply with the current OpenMP 5.1 standard. Scripts to install OpenMP offloading-enabled compilers can be found in compilers/
.
To compile one of the examples, you may type
export COMPILER=<g++,clang++,nvc++>
export GPU=<V100,A100>
make APP=<multigrid,minimal_fcycle,minimal_vcycle,minimal_jacobi,minimal_gauss_seidel>
and an example can for instance be executed with
./bin/minimal_fcycle -x 513 -y 257 -z 129 -l 6 -maxiter 10
To compile only the archive, type
make archive
to make the archive libpoisson.a
. To use this archive in your project, compile with -Iinlcude -Llib -lpoisson
.
One can select between three test problems if one wants to use one of the drivers. The test problems can be selected by compiling with PROBLEM=1
, PROBLEM=2
, or PROBLEM=3
.
The most important class templates in this project are probably array.h
and the derived template class devicearray.h
. They contain functions for indexing 3D arrays that abstract away the halos. Further, they contain functionality for mapping arrays to GPUs and saving arrays with or without the halos. See for instance, the following figure:
Saved With Halo | Saved Without Halo |
---|---|
The PoissonSolver
class is heavily templated. When a solver instance is created, it is given a floating-point type, a restriction type, a prolongation type, and a relaxation type, for example
#include "libpoisson.h"
Poison::PoissonSolver<
Poisson::double_t,
Poisson::Injection,
Poisson::TrilinearInterpolation,
Poisson::GaussSeidel> solver(settings);
To initialize all the arrays in the solver to zero, use
solver.init_zero();
Before solving the problem, the right-hand side and boundary conditions must be transferred to the device. This can be done with
solver.to_device();
One can either use a relaxation scheme as the solver
solver.solve("relaxation");
or a V-cycle with
solver.solve("Vcycle");
or an F-cycle, which is recommended, with
solver.solve("Fcycle");
Finally, the result can be mapped back to the host with
solver.to_host();
The framework supports different relaxation schemes and restriction and prolongation operators.
- Relaxation:
Poisson::Relaxation
- Jacobi relaxation:
Poisson::Jacobi
- Red-black Gauss-Seidel successive overrelaxation:
Poisson::GaussSeidel
- Jacobi relaxation:
- Restriction operator:
Poisson::Restriction
- Injection:
Poisson::Injection
- Full weighting:
Poisson::FullWeighting
- Injection:
- Prolongation operator:
Poisson::Prolongation
- Trilinear interpolation:
Poisson::TrilinearInterpolation
- Trilinear interpolation:
- Boundary condition:
Poisson::Boundary
- Dirichlet condition:
Poisson::Dirichlet
- Neumann condition:
Poisson::Neumann
- Dirichlet condition:
To generate some problems, we may consider some function
We may consider some trigonometric function
for which it is easy to derive the analytic Laplacian
and the Neumann boundary conditions are given by
True Solution | Numerical Solution |
---|---|
The polynomial
has the Laplacian
The Neumann boundary conditions are given by
True Solution | Numerical Solution |
---|---|
The trigonometric funtion
has the Laplacian
The Neumann boundary conditions are given by
True Solution | Numerical Solution |
---|---|
From theory, the scheme should be second-order convergent. That means halving the grid spacing should result in a four times smaller maximal absolute error. As can be seen, the multigrid algorithm has the expected order of convergence for the three test problems. The files used to generate the convergence tests are convergence.sh
and plot_convergence.m
.