Peano
Loading...
Searching...
No Matches
Tutorial 02: Matrix-free Discontinuous Galerkin single-level solver on a regular grid
This documentation is autogenerated from ./tutorials/mghype/examples/03_matrix-free-dg.ipynb. Once you clone the Peano repository, please work against this notebook or study Peano's generic description how to generate web docu from Jupyter notebooks.

This tutorial runs through the steps that we perform to write a single-level DG solver on a regular grid. We implement the standard "benchmark" for this type of solvers, which is solving the Poisson equation on the unit square. All sources for this can be found in tests/multigrid/matrixfree/poisson/dg.py, as the solver is routinely used to do convergence measurements. While we follow some steps of this script, the test Python script has more technical flavours/details which we omit in the notebook. Therefore, it is reasonable to study the present text in combination with the actual script once you've done the notebook once.

The notebook clarifies how to construct an MGHyPE project with one solver of the type multigrid.matrixfree.solvers.api.DiscontinuousGalerkinDiscretisationPointWiseRiemannSolver (cmp multigrid/matrixfree/solvers/api/DiscontinuousGalerkinDiscretisationPointWiseRiemannSolver.py in src).

Since we solve the Poisson equation, and employ a Discontinuous Galerkin formalism with a point-wise Riemann solver, we start from

\( \mathcal{L}(u) = - \Delta u = f \)

and apply a weak formulation:

\( \begin{eqnarray} \int \left( - \Delta u, v \right) dx & = & \int (f, v) dx \\ \int _c \left( \nabla u, \nabla v \right) dx - \sum _f \int _f \left( \nabla u, n \right) v dS(x) & = & \int (f, v) dx \\ \int _c \left( \nabla u, \nabla v \right) dx - \sum _f \int _f \left( \mathcal{R}(u^-,u^+), n \right) \phi dS(x) & = & \int (f,v) dx. \end{eqnarray} \)

Todo
Alex can you add something on the numerical flux employed and fix the equations above? I think we can copy n paste from the paper draft.

Before we start, we assume that you have either set export PYTHONPATH=../../../../python:../../../../src or you invoke

import sys, os
sys.path.insert(0, os.path.abspath("../../../python/"))
sys.path.insert(0, os.path.abspath("../../../src/"))

We create an MGHyPE project (bear in mind that we basically discuss how to write the test case in the repo; we'd likely use a different namespace otherwise):

import mghype
project = mghype.matrixfree.api.Project( project_name = "DGPointwise",
namespace = [ "tests", "multigrid", "matrixfree", "poisson" ],
)
Peano 4 (C) www.peano-framework.org
VTK is not available, not loading peano4.visualisation.
ParaView is not available, not loading peano4.visualisation.
Peano 4 - Multigrid extension
project.subdirectories =  ['']

The solver construction also is a "one-liner" using the following observations:

  • We solve a scalar equation system. Consequently, we have only one unknown per cell node.
  • For our numerical flux, we'll need two unknowns per node on the face: One holds the solution and one the gradient. The face will have to hold that info from the left and right side, but MGHyPE takes care of that.
dimensions = 2
polynomial_degree = 5
mesh_size = 0.1
omega_c = 0.5
omega_f = 1.0
dimensions,
polynomial_degree,
1, # Unknowns per cell dof. Scalar PDE here
2, # We use the penalty formulation (see docu in tutorials)
2
)
assembly_matrix, assembly_matrix_scaling = matrices.get_cell_system_matrix_for_laplacian()
mass_matrix, mass_matrix_scaling = matrices.get_cell_mass_matrix()
face_from_cell_projection, \
face_from_cell_projection_scaling = matrices.get_face_from_cell_matrix()
cell_from_face_projection, \
cell_from_face_projection_scaling = matrices.get_cell_from_face_matrix()
approximate_system_matrix, \
approximate_system_matrix_scaling = matrices.get_A_tilde()
solver = mghype.matrixfree.solvers.api.DiscontinuousGalerkinDiscretisationPointWiseRiemannSolver(
name = "Poisson",
dimensions = dimensions,
poly_degree = polynomial_degree,
unknowns_per_cell_node = 1,
solutions_per_face_node = 2,
projections_per_face_node = 2,
min_h = mesh_size,
max_h = mesh_size,
assembly_matrix= assembly_matrix,
assembly_matrix_scaling = assembly_matrix_scaling,
mass_matrix = mass_matrix,
mass_matrix_scaling = mass_matrix_scaling,
face_from_cell_projection = face_from_cell_projection,
face_from_cell_projection_scaling = face_from_cell_projection_scaling,
cell_from_face_projection = cell_from_face_projection,
cell_from_face_projection_scaling = cell_from_face_projection_scaling,
riemann_matrix = matrices.get_face_face_riemann_problem_matrix(),
boundary_matrix = matrices.get_boundary_matrix(),
cell_relaxation = omega_c,
face_relaxation = omega_f,
approximate_system_matrix = approximate_system_matrix,
approximate_system_matrix_scaling = approximate_system_matrix_scaling,
solver_tolerance = 1e-8,
)
Warning: penalty parameter gamma_F is set to 2/h and does not depend on the polynomial degree!

This code block employs MGHyPE's matrix generator quite heavily. It makes sense to consult this class' documentation for furhter info. Or switch from Gauss Lobatto (GL) to Gausss Legendre.

@Alex can you add a remark how to do so?

We next add this solver to the project and set some global parameters:

import peano4
project.add_solver(solver)
build_mode = peano4.output.CompileMode.Release
cube_size = 1.0
project.set_global_simulation_parameters(
dimensions = dimensions,
offset = [ 0.0 for _ in range(dimensions) ],
domain_size = [ cube_size for _ in range(dimensions) ],
plot_each_timestep = False,
)
project.set_load_balancing( "toolbox::loadbalancing::RecursiveSubdivision", "new ::exahype2::LoadBalancingConfiguration()" )
project.set_Peano4_installation( "../../..", build_mode )

Create data for solver DGPoisson

In line with the hitchhiker's guide, we now lower this into a Peano project and make the latter dump the C++ code:

peano4_project = project.generate_Peano4_project(False)
peano4_project.output.makefile.add_cpp_file( "Scenario.cpp" )
peano4_project.generate()
parse configure outcome ../../../config.log to extract configure settings
parse configure outcome ../../../src/Makefile to extract compile settings



---------------------------------------------------------------------------

AttributeError                            Traceback (most recent call last)

Cell In[6], line 1
----> 1 peano4_project = project.generate_Peano4_project(False)
      2 peano4_project.output.makefile.add_cpp_file( "Scenario.cpp" )
      3 peano4_project.generate()


File ~/git/Peano/src/mghype/matrixfree/api/Project.py:176, in Project.generate_Peano4_project(self, verbose)
    173     self._project.solversteps.add_step(self.algorithm_step_plot)
    175     self.__configure_makefile()
--> 176     self.__generate_solver_repository()
    178     self._project.output.readme.add_package_description( """
    179 
    180 
    181 """ )
    183     return self._project


File ~/git/Peano/src/mghype/matrixfree/api/Project.py:204, in Project.__generate_solver_repository(self)
    196 templatefile_prefix = os.path.realpath(__file__).replace( ".pyc", "" ).replace( ".py", "" )
    197 template_name       = templatefile_prefix + ".SolverRepository.template"
    198 generated_repository_files = peano4.output.Jinja2TemplatedHeaderImplementationFilePair(
    199   template_name + ".h",
    200   template_name + ".cpp",
    201   "SolverRepository", 
    202   self._project.namespace, # + ["repositories"],
    203   self._project.subdirectory + "repositories", 
--> 204   self.dictionary,
    205   True,
    206   True)
    208 self._project.output.add( generated_repository_files )
    209 self._project.output.makefile.add_h_file( self._project.subdirectory + "repositories/SolverRepository.h", generated=True )


AttributeError: 'Project' object has no attribute 'dictionary'

The only "new" thing here's the line add_cpp_file() which we discuss next.

Setting the initial condition and tailoring our solver

Whenever we create a solver, MGHyPE creates two classes in our home directory. As we strictly split each class into its header and its implementation, we get four files:

!ls
01_matrix-free-cg.dox    02_matrix-free-dg.ipynb  solver-class-hierarchy.png
01_matrix-free-cg.ipynb  11_petsc-cg.dox      solver-class-hierarchy.svg
02_matrix-free-dg.dox    11_petsc-cg.ipynb

The abstract class inherits from some class with MGHyPE. It will contain all the matrices and whatever stuff we have specified in the Python script. The class Poisson.cpp is the one where we can inject our own behaviour.

Generated class hierarchy

For example, we should use it to implement our own initial guess and the right-hand side. See

void tests::multigrid::matrixfree::poisson::DGPoisson::initCell(
) {
logTraceInWith4Arguments("initCell", x, h, value, rhs);
auto bottomLeft = x - 0.5 * h;
// we only have one cell unknown, so we can reuse this macro
int counter = 0;
dfor( k, PolyDegree + 1 )
{
// convert k to double
tarch::la::Vector<Dimensions, double> kDouble = tarch::la::convertScalar<double, Dimensions, int>(k);
auto dofPosition = bottomLeft + h(0)*kDouble / (double)repositories::instanceOfDGPoisson.PolyDegree;
rhs[counter] = getPointWiseRhs(dofPosition);
value[counter] = 0;
counter++;
}
logTraceOutWith4Arguments("initCell", x, h, value, rhs);
}

for an example. We can always add additional files to the Peano project, and we've done exactly this through the add_cpp_file() above. This allows us to use the same right-hand side, i.e. the same scenario, in each and every test case.

Task 1: Set up the code

Open the generated .h and .cpp file of the implementation, compare its content to the files in the test directory, and implement your own solver.

Compile

The compilation is straightforward. We simply invoke the Makefile. Once the implementation of the solver is in place, we can rerun the Python script arbitrarily often. The actual implementation will never ever been overwritten, i.e. we can play around with different polynomial degrees, matrices, and so forth, within the Python script.

import os
os.system( "make clean" )
os.system( "make" )

Run the experiments

If the make is successful, we will obtain an executable, which we can once again call from the Jupyter notebook. Note that I pipe the output into a file, so I can easily access it later on:

!ls
!./peano > output.txt
01_matrix-free-cg.dox    02_matrix-free-dg.ipynb  solver-class-hierarchy.png
01_matrix-free-cg.ipynb  11_petsc-cg.dox      solver-class-hierarchy.svg
02_matrix-free-dg.dox    11_petsc-cg.ipynb
/bin/bash: line 1: ./peano: No such file or directory

Visualisation

MGHyPE comes along with some scripts to parse the dump of a solver and to visualise it directly via matplotlib. As we have piped the solver's output into a file output.txt, we can directly invoke the script from within the Jupyter notebook:

Obviously, visualising the convergence behaviour is only part of the game. We also want to see what the solution looks like. For this, we have to convert the output of the program. Peano provides some scripts for this. It is tricky to embed them into a Jupyter notebook, so they are best invoked on the command line:

!

From hereon, you can open Paraview or VisIt and directly visualise the outcome. You should obtain a picture similar to

Task 2: Do some convergence studies for various polynomial degrees and mesh sizes

Todo
DO we need some docu here?