Skip to content

Latest commit

 

History

History
831 lines (609 loc) · 23 KB

developer_guide.rst

File metadata and controls

831 lines (609 loc) · 23 KB

Python

Developer Guide

A Brief Overview of the PyFR Framework

Where to Start

The symbolic link pyfr.scripts.pyfr points to the script pyfr.scripts.main, which is where it all starts! Specifically, the function process_run calls the function _process_common, which in turn calls the function get_solver, returning an Integrator -- a composite of a Controller and a Stepper. The Integrator has a method named run, which is then called to run the simulation.

Controller

A Controller acts to advance the simulation in time. Specifically, a Controller has a method named advance_to which advances a System to a specified time. There are three types of physical-time Controller available in PyFR :

pyfr.integrators.std.controllers.StdNoneController

pyfr.integrators.std.controllers.StdPIController

pyfr.integrators.dual.phys.controllers.DualNoneController

Types of physical-time Controller are related via the following inheritance diagram:

pyfr.integrators.std.controllers pyfr.integrators.dual.phys.controllers

There are two types of pseudo-time Controller available in PyFR :

pyfr.integrators.dual.pseudo.pseudocontrollers.DualNonePseudoController

pyfr.integrators.dual.pseudo.pseudocontrollers.DualPIPseudoController

Types of pseudo-time Controller are related via the following inheritance diagram:

pyfr.integrators.dual.pseudo.pseudocontrollers

Stepper

A Stepper acts to advance the simulation by a single time-step. Specifically, a Stepper has a method named step which advances a System by a single time-step. There are eight types of Stepper available in PyFR :

pyfr.integrators.std.steppers.StdEulerStepper

pyfr.integrators.std.steppers.StdRK4Stepper

pyfr.integrators.std.steppers.StdRK34Stepper

pyfr.integrators.std.steppers.StdRK45Stepper

pyfr.integrators.std.steppers.StdTVDRK3Stepper

pyfr.integrators.dual.phys.steppers.DualBackwardEulerStepper

pyfr.integrators.dual.phys.steppers.SDIRK33Stepper

pyfr.integrators.dual.phys.steppers.SDIRK43Stepper

Types of Stepper are related via the following inheritance diagram:

pyfr.integrators.std.steppers pyfr.integrators.dual.phys.steppers

PseudoStepper

A PseudoStepper acts to advance the simulation by a single pseudo-time-step. They are used to converge implicit Stepper time-steps via a dual time-stepping formulation. There are six types of PseudoStepper available in PyFR :

pyfr.integrators.dual.pseudo.pseudosteppers.DualDenseRKPseudoStepper

pyfr.integrators.dual.pseudo.pseudosteppers.DualRK4PseudoStepper

pyfr.integrators.dual.pseudo.pseudosteppers.DualTVDRK3PseudoStepper

pyfr.integrators.dual.pseudo.pseudosteppers.DualEulerPseudoStepper

pyfr.integrators.dual.pseudo.pseudosteppers.DualRK34PseudoStepper

pyfr.integrators.dual.pseudo.pseudosteppers.DualRK45PseudoStepper

Note that DualDenseRKPseudoStepper includes families of PseudoStepper whose coefficients are read from .txt files named thus:

{scheme name}-s{stage count}-p{temporal order}-sp{optimal spatial polynomial order}.txt

Types of PseudoStepper are related via the following inheritance diagram:

pyfr.integrators.dual.pseudo.pseudosteppers

System

A System holds information/data for the system, including Elements, Interfaces, and the Backend with which the simulation is to run. A System has a method named rhs, which obtains the divergence of the flux (the 'right-hand-side') at each solution point. The method rhs invokes various kernels which have been pre-generated and loaded into queues. A System also has a method named _gen_kernels which acts to generate all the kernels required by a particular System. A kernel is an instance of a 'one-off' class with a method named run that implements the required kernel functionality. Individual kernels are produced by a kernel provider. PyFR has various types of kernel provider. A Pointwise Kernel Provider produces point-wise kernels such as Riemann solvers and flux functions etc. These point-wise kernels are specified using an in-built platform-independent templating language derived from Mako, henceforth referred to as PyFR-Mako. There are four types of System available in PyFR :

pyfr.solvers.aceuler.system.ACEulerSystem

pyfr.solvers.acnavstokes.system.ACNavierStokesSystem

pyfr.solvers.euler.system.EulerSystem

pyfr.solvers.navstokes.system.NavierStokesSystem

Types of System are related via the following inheritance diagram:

pyfr.solvers.navstokes.system pyfr.solvers.euler.system pyfr.solvers.acnavstokes.system pyfr.solvers.aceuler.system

Elements

An Elements holds information/data for a group of elements. There are four types of Elements available in PyFR :

pyfr.solvers.aceuler.elements.ACEulerElements

pyfr.solvers.acnavstokes.elements.ACNavierStokesElements

pyfr.solvers.euler.elements.EulerElements

pyfr.solvers.navstokes.elements.NavierStokesElements

Types of Elements are related via the following inheritance diagram:

pyfr.solvers.navstokes.elements pyfr.solvers.euler.elements pyfr.solvers.acnavstokes.elements pyfr.solvers.aceuler.elements

Interfaces

An Interfaces holds information/data for a group of interfaces. There are eight types of (non-boundary) Interfaces available in PyFR :

pyfr.solvers.aceuler.inters.ACEulerIntInters

pyfr.solvers.aceuler.inters.ACEulerMPIInters

pyfr.solvers.acnavstokes.inters.ACNavierStokesIntInters

pyfr.solvers.acnavstokes.inters.ACNavierStokesMPIInters

pyfr.solvers.euler.inters.EulerIntInters

pyfr.solvers.euler.inters.EulerMPIInters

pyfr.solvers.navstokes.inters.NavierStokesIntInters

pyfr.solvers.navstokes.inters.NavierStokesMPIInters

Types of (non-boundary) Interfaces are related via the following inheritance diagram:

pyfr.solvers.navstokes.inters.NavierStokesMPIInters pyfr.solvers.navstokes.inters.NavierStokesIntInters pyfr.solvers.euler.inters.EulerMPIInters pyfr.solvers.euler.inters.EulerIntInters pyfr.solvers.acnavstokes.inters.ACNavierStokesMPIInters pyfr.solvers.acnavstokes.inters.ACNavierStokesIntInters pyfr.solvers.aceuler.inters.ACEulerMPIInters pyfr.solvers.aceuler.inters.ACEulerIntInters

Backend

A Backend holds information/data for a backend. There are four types of Backend available in PyFR :

pyfr.backends.cuda.base.CUDABackend

pyfr.backends.hip.base.HIPBackend

pyfr.backends.opencl.base.OpenCLBackend

pyfr.backends.openmp.base.OpenMPBackend

Types of Backend are related via the following inheritance diagram:

pyfr.backends.cuda.base pyfr.backends.hip.base pyfr.backends.opencl.base pyfr.backends.openmp.base

Pointwise Kernel Provider

A Pointwise Kernel Provider produces point-wise kernels. Specifically, a Pointwise Kernel Provider has a method named register, which adds a new method to an instance of a Pointwise Kernel Provider. This new method, when called, returns a kernel. A kernel is an instance of a 'one-off' class with a method named run that implements the required kernel functionality. The kernel functionality itself is specified using PyFR-Mako. Hence, a Pointwise Kernel Provider also has a method named _render_kernel, which renders PyFR-Mako into low-level platform-specific code. The _render_kernel method first sets the context for Mako (i.e. details about the Backend etc.) and then uses Mako to begin rendering the PyFR-Mako specification. When Mako encounters a pyfr:kernel an instance of a Kernel Generator is created, which is used to render the body of the pyfr:kernel. There are four types of Pointwise Kernel Provider available in PyFR :

pyfr.backends.cuda.provider.CUDAPointwiseKernelProvider

pyfr.backends.hip.provider.HIPPointwiseKernelProvider

pyfr.backends.opencl.provider.OpenCLPointwiseKernelProvider

pyfr.backends.openmp.provider.OpenMPPointwiseKernelProvider

Types of Pointwise Kernel Provider are related via the following inheritance diagram:

pyfr.backends.openmp.provider pyfr.backends.cuda.provider pyfr.backends.hip.provider pyfr.backends.opencl.provider pyfr.backends.base.kernels.BasePointwiseKernelProvider

Kernel Generator

A Kernel Generator renders the PyFR-Mako in a pyfr:kernel into low-level platform-specific code. Specifically, a Kernel Generator has a method named render, which applies Backend specific regex and adds Backend specific 'boiler plate' code to produce the low-level platform-specific source -- which is compiled, linked, and loaded. There are four types of Kernel Generator available in PyFR :

pyfr.backends.cuda.generator.CUDAKernelGenerator

pyfr.backends.hip.generator.HIPKernelGenerator

pyfr.backends.opencl.generator.OpenCLKernelGenerator

pyfr.backends.openmp.generator.OpenMPKernelGenerator

Types of Kernel Generator are related via the following inheritance diagram:

pyfr.backends.cuda.generator.CUDAKernelGenerator pyfr.backends.opencl.generator.OpenCLKernelGenerator pyfr.backends.openmp.generator.OpenMPKernelGenerator

PyFR-Mako

none

PyFR-Mako Kernels

PyFR-Mako kernels are specifications of point-wise functionality that can be invoked directly from within PyFR. They are opened with a header of the form:

<%pyfr:kernel name='kernel-name' ndim='data-dimensionality' [argument-name='argument-intent argument-attribute argument-data-type' ...]>

where

  1. kernel-name --- name of kernel

    string

  2. data-dimensionality --- dimensionality of data

    int

  3. argument-name --- name of argument

    string

  4. argument-intent --- intent of argument

    in | out | inout

  5. argument-attribute --- attribute of argument

    mpi | scalar | view

  6. argument-data-type --- data type of argument

    string

and are closed with a footer of the form:

</%pyfr:kernel>

PyFR-Mako Macros

PyFR-Mako macros are specifications of point-wise functionality that cannot be invoked directly from within PyFR, but can be embedded into PyFR-Mako kernels. PyFR-Mako macros can be viewed as building blocks for PyFR-mako kernels. They are opened with a header of the form:

<%pyfr:macro name='macro-name' params='[parameter-name, ...]'>

where

  1. macro-name --- name of macro

    string

  2. parameter-name --- name of parameter

    string

and are closed with a footer of the form:

</%pyfr:macro>

PyFR-Mako macros are embedded within a kernel using an expression of the following form:

${pyfr.expand('macro-name', ['parameter-name', ...])};

where

  1. macro-name --- name of the macro

    string

  2. parameter-name --- name of parameter

    string

Syntax

Basic Functionality

Basic functionality can be expressed using a restricted subset of the C programming language. Specifically, use of the following is allowed:

  1. +,-,*,/ --- basic arithmetic
  2. sin, cos, tan --- basic trigonometric functions
  3. exp --- exponential
  4. pow --- power
  5. fabs --- absolute value
  6. output = ( condition ? satisfied : unsatisfied ) --- ternary if
  7. min --- minimum
  8. max --- maximum

However, conditional if statements, as well as for/while loops, are not allowed.

Expression Substitution

Mako expression substitution can be used to facilitate PyFR-Mako kernel specification. A Python expression expression prescribed thus ${expression} is substituted for the result when the PyFR-Mako kernel specification is interpreted at runtime.

Example:

E = s[${ndims - 1}]

Conditionals

Mako conditionals can be used to facilitate PyFR-Mako kernel specification. Conditionals are opened with % if condition: and closed with % endif. Note that such conditionals are evaluated when the PyFR-Mako kernel specification is interpreted at runtime, they are not embedded into the low-level kernel.

Example:

% if ndims == 2:
    fout[0][1] += t_xx;     fout[1][1] += t_xy;
    fout[0][2] += t_xy;     fout[1][2] += t_yy;
    fout[0][3] += u*t_xx + v*t_xy + ${-c['mu']*c['gamma']/c['Pr']}*T_x;
    fout[1][3] += u*t_xy + v*t_yy + ${-c['mu']*c['gamma']/c['Pr']}*T_y;
% endif

Loops

Mako loops can be used to facilitate PyFR-Mako kernel specification. Loops are opened with % for condition: and closed with % endfor. Note that such loops are unrolled when the PyFR-Mako kernel specification is interpreted at runtime, they are not embedded into the low-level kernel.

Example:

% for i in range(ndims):
    rhov[${i}] = s[${i + 1}];
    v[${i}] = invrho*rhov[${i}];
% endfor