|
Peano
|
See page DSL Syntax for details on writing the timestep function for a new kernel.
This page details how to use this function in a solver. The implementation of the Rusanov kernel is used as an example throughout.
Each category of solver uses a python script to generate any required code, usually a file called kernels.py. For the Rusanov kernel this file is python/exahype2/solvers/fv/rusanov/kernels.py. Create a function in this file which is used to generate the C++ files from the DSL. Since the timestep function must be specified for each dimension, generating a base header file which checks the dimension is useful.
The create_kernel_definitions_2d() and create_kernel_definitions_3d() should usually be very similar, so only one with unspecified dimension is described here.
The create_kernel_definitions() function has three main parts: setting template and function arguments, generating strings containing the C++ code, and writing to files.
The template parameters and function parameters are passed as individual lists to the parsing function. Each element of the list is of type SyntaxTree.Argument. The parameters used for the Rusanov kernels are
A Python string is generated using Parser().parse(timestepFunction, template_parameters, functor_arguments, namespaces, is_stateless, use_accelerator) Its parameters are:
Calling this function returns the root node to an abstract syntax tree representing the kernel. The C++ code can then be generated by calling its print methods. The options currently are print_cpp(), print_omp() and print_tree(), which does not produce valid code and is for debugging only. The FunctionDefinition node, which is the root node, also has functions for generating declarations for code organisation (print_declaration()). It also can generate functions with a timer for benchmarking (print_declaration_with_timer(), print_definition_with_timer()).
From here the process is standard Python. For consistency the generated files should be within a kernels folder. It is also recommended to use separate header files for declarations, and separate files for different dimensions. Certain include files are also required as seen in the following example.
The solver also needs to know how to call the new kernels, which should also be defined in kernels.py. A function is defined which returns a Python string containing the C++ code used to call the timestep function. It checks which version of the function is required, such as whether its stateless or uses an accelerator and returns the relevant call.
If the code isn't stateless there are usually functor parameters which have to be passed in. There are also template parameters which need to be determined which specify whether certain parts of the kernel are required. This is best seen by example in create_compute_Riemann_kernel_for_Rusanov_dsl() in kernels.py.