|
Peano
|
ExaHyPE 2 is built as a layer on top of Peano 4 and the Peano 4 Technical Architecture.
This C++ ExaHyPE 2 layer is built as a set of Peano 4 C++ utility files compiled into one shared library plus a Python API. It is relatively straightforward to understand by browsing through the C++ files, but it provides limited structure: You find most of the compute ingredients of an ExaHyPE code in there, but the actual logic are not encoded in the C++.
For this, ExaHyPE 2 provides a Python API that allows users to describe their solver and its behaviour in a more abstract way.
At the heart of ExaHyPE 2 are the solver classes and its aggregate. They model what is solved, i.e.~encode the physics. Any implementation details how things are solved - either from a numerics point of view or from a performance point of view - are omitted from this description. This is the layer users interact with.
Each solver is tied to generators which determine which numerical scheme is employed. They determine how the solver is mapped onto mesh entities, which compute kernels are generated, and which solver steps make up one time step. These generators map the solver description (see above) onto a task graph of activities.
The task graph is then mapped onto Peano 4's action sets and traversals. This part is already an element of the Peano core architecture. and is not specific to ExaHyPE 2.
This layer is what most users will consider to be ExaHyPE 2. It is a thin Python package which allows a user to model a hyperbolic PDE solver. By plugging many different objects together, users describe what their solver will look like. In short, most ExaHyPE applications only create an instance of exahype2.api.Project, and then they add instances of exahype2.api.Solver to it.
Once the structure of the solvers is in place, users attach generators to their static solver description. Generators can be used to tailor all kinds of behaviour, but, most importantly, the type of generator picked for a solver implies what numerical scheme you want to apply on a solver description.
The generators take the specification objects and they lower them into implementation objects. This is where, for example, a Runge-Kutta scheme tells the implementation that each time step consists of four substeps, which compute kernels we need to generate, and so forth.
Once we have constructed this implementation representation, there's a second layer of generators tied to the implementation: They take the implementation representation and lower it into a Peano 4 representation. On this level, idnividual solver steps are now for example mapped onto action sets or traversals.
At the heart of ExaHyPE2 are the solver classes and its aggregate. Each solver class and each aggregate are tied to a generator class. The generator classes take the solver description and either lower them into a Peano 4 class or a plain C++ file tied to the present project. Here, the same pattern repeats, i.e. Peano Python classes again hold generators which then ultimately lower the code in to plain C++.
The aim of our architecture is to decouple implementation details (how) from mathematical modelling (what) that inform the solver's numerical behaviour. For example, whether to use a GPU and whether to use task fusion fall under implementation details and should be handled by a generator not the description. How many variables to use, which PDE terms to enable and the patch size should be used however is a property of the model itself.
For general design patterns and idioms that recur across Peano and its extensions, see the developer guidelines and tips page.