PYFR(1)
π PYFR(1) β pyfr π¦
bestie. BESTIE. you found it. this is the pyfr manual page and it is literally the entire PyFR documentation living inside a manpage like the absolute icon it is. it's long. it's gorgeous. we're doing it in parts. strap in. π
π NAME π
pyfr β PyFR Documentation
Contents: π
π HOME π
π Overview
β¨ What is PyFR?
PyFR is an open-source Python based framework for solving advection-diffusion type problems on streaming architectures, and it does it using the Flux Reconstruction approach of Huynh. the whole framework is designed to solve a range of governing systems on mixed unstructured grids that contain various element types. it's also designed to target a range of hardware platforms, and it pulls that off via an in-built domain specific language derived from the Mako templating engine. π§
the current release (PyFR 1.5.0) has the following capabilities:
- Governing Equations β Euler, Navier Stokes
- Dimensionality β 2D, 3D
- Element Types β Triangles, Quadrilaterals, Hexahedra, Prisms, Tetrahedra, Pyramids
- Platforms β CPU Clusters, Nvidia GPU Clusters, AMD GPU Clusters, Intel Xeon Phi Clusters
- Spatial Discretisation β High-Order Flux Reconstruction
- Temporal Discretisation β Explicit and Implicit (via Dual Time-Stepping)
- Precision β Single, Double
- Mesh Files Imported β Gmsh (
.msh), CGNS (.cgns) - Solution Files Exported β Unstructured VTK (
.vtu,.pvtu)
okay the range?? the versatility?? she does it all. π«Ά
π How do I Cite PyFR?
if you're gonna cite PyFR (and you should, we don't do unpaid labour here π ), please reference this paper:
- PyFR: An Open Source Framework for Solving Advection-Diffusion Type Problems on Streaming Architectures using the Flux Reconstruction Approach. F. D. Witherden, A. M. Farrington, P. E. Vincent. Computer Physics Communications, Volume 185, Pages 3028-3040, 2014.
πΈ Who is Funding PyFR?
development of PyFR is supported by the Engineering and Physical Sciences Research Council, Innovate UK, the European Commission, BAE Systems, Airbus, and the Air Force Office of Scientific Research. we are also grateful for hardware donations from Nvidia, Intel, and AMD. π the sponsors really said "we got you bestie" and honestly? iconic behaviour.
π§ THEORY π§
π Flux Reconstruction
π Overview
high-order numerical methods for unstructured grids combine the superior accuracy of high-order spectral or finite difference methods with the geometrical flexibility of low-order finite volume or finite element schemes. the Flux Reconstruction (FR) approach unifies various high-order schemes for unstructured grids inside a single framework. β¨
and here's the slay part: the FR approach exhibits a significant degree of element locality, which means it can run efficiently on modern streaming architectures, such as Graphical Processing Units (GPUs). all of that together means FR offers a promising route to performing affordable β and therefore industrially relevant β scale-resolving simulations of hitherto intractable unsteady flows (think separation, acoustics, etc.) within the vicinity of real-world engineering geometries. π€
a detailed overview of the FR approach is given in:
- A Flux Reconstruction Approach to High-Order Schemes Including Discontinuous Galerkin Methods. H. T. Huynh. AIAA Paper 2007-4079
π Linear Stability
the linear stability of an FR schemes depends on the form of the correction function. linear stability issues are discussed in:
- A New Class of High-Order Energy Stable Flux Reconstruction Schemes. P. E. Vincent, P. Castonguay, A. Jameson. Journal of Scientific Computing, Volume 47, Number 1, Pages 50-72, 2011
- Insights from von Neumann Analysis of High-Order Flux Reconstruction Schemes. P. E. Vincent, P. Castonguay, A. Jameson. Journal of Computational Physics, Volume 230, Issue 22, Pages 8134-8154, 2011
- A New Class of High-Order Energy Stable Flux Reconstruction Schemes for Triangular Elements. P. Castonguay, P. E. Vincent, A. Jameson. Journal of Scientific Computing, Volume 51, Number 1, Pages 224-256, 2012
- Energy Stable Flux Reconstruction Schemes for Advection-Diffusion Problems. P. Castonguay, D. M. Williams, P. E. Vincent, A. Jameson. Computer Methods in Applied Mechanics and Engineering, Volume 267, Pages 400-417, 2013
- Energy Stable Flux Reconstruction Schemes for Advection-Diffusion Problems on Triangles. D. M. Williams, P. Castonguay, P. E. Vincent, A. Jameson. Journal of Computational Physics, Volume 250, Pages 53-76, 2013
- Energy Stable Flux Reconstruction Schemes for Advection-Diffusion Problems on Tetrahedra. D. M. Williams, A. Jameson. Journal of Scientific Computing, Volume 59, Pages 721-759, 2014
- An Extended Range of Stable-Symmetric-Conservative Flux Reconstruction Correction Functions. P. E. Vincent, A. M. Farrington, F. D. Witherden, A. Jameson. Computer Methods in Applied Mechanics and Engineering, Volume 296, Pages 248-272, 2015
a whole reading list. bestie is BOOKED and BUSY. π
π Non-Linear Stability
the non-linear stability of an FR schemes depends on the location of the solution points. non-linear stability issues are discussed in:
- On the Non-Linear Stability of Flux Reconstruction Schemes. A. Jameson, P. E. Vincent, P. Castonguay. Journal of Scientific Computing, Volume 50, Number 2, Pages 434-445, 2012
- An Analysis of Solution Point Coordinates for Flux Reconstruction Schemes on Triangular Elements. F. D. Witherden, P. E. Vincent. Journal of Scientific Computing, Volume 61, Pages 398-423, 2014
π USER GUIDE π
π Getting Started
π₯ Downloading the Source
PyFR can be obtained here.
π§© Dependencies
π Overview
PyFR 1.5.0 has a hard dependency on Python 3.3+ and the following Python packages:
gimmik >= 2.0h5py >= 2.6mako >= 1.0.0mpi4py >= 2.0numpy >= 1.8pytools >= 2016.2.1
β οΈ note that due to a bug in numpy, PyFR is not compatible with 32-bit Python distributions. 64-bit or nothing, bestie. π
π© CUDA Backend
the CUDA backend targets NVIDIA GPUs with a compute capability of 2.0 or greater. the backend requires:
CUDA >= 4.2pycuda >= 2015.1
π¦ MIC Backend
the MIC backend targets Intel Xeon Phi co-processors. the backend requires:
ICC >= 14.0Intel MKL >= 11.1Intel MPSS >= 3.3pymic >= 0.7 (post commit 4d8a2da)
πͺ OpenCL Backend
the OpenCL backend targets a range of accelerators including GPUs from AMD and NVIDIA. the backend requires:
OpenCLpyopencl >= 2015.2.4clBLAS
π§ OpenMP Backend
the OpenMP backend targets multi-core CPUs. the backend requires:
GCC >= 4.9- A BLAS library compiled as a shared library (e.g. OpenBLAS)
π Running in Parallel
to partition meshes for running in parallel you also need one of the following partitioners installed:
metis >= 5.0scotch >= 6.0
π¦ Importing CGNS Meshes
to import CGNS meshes you need the following installed:
CGNS >= 3.3 (develop branch post commit e0faea6)
π yes, that's the develop branch, post that specific commit. read it and weep.
π Installation
before running PyFR 1.5.0 you first need to either install the software using the provided setup.py installer, or add the root PyFR directory to PYTHONPATH like this:
user@computer ~/PyFR$ export PYTHONPATH=.:$PYTHONPATH
to manage installation of Python dependencies we strongly recommend using pip and virtualenv. do it. your future self will thank you. π«Ά
π Running PyFR
π Overview
PyFR 1.5.0 uses three distinct file formats:
.ini--- configuration file.pyfrm--- mesh file.pyfrs--- solution file
the following commands are available from the pyfr program:
pyfr import--- convert a Gmsh.mshfile or CGNS.cgnsfile into a PyFR.pyfrmfile.
Example:
pyfr import mesh.msh mesh.pyfrm
pyfr partition--- partition an existing mesh and associated solution files.
Example:
pyfr partition 2 mesh.pyfrm solution.pyfrs .
pyfr run--- start a new PyFR simulation.
Example:
pyfr run mesh.pyfrm configuration.ini
pyfr restart--- restart a PyFR simulation from an existing solution file.
Example:
pyfr restart mesh.pyfrm solution.pyfrs
pyfr export--- convert a PyFR.pyfrsfile into an unstructured VTK.vtuor.pvtufile.
Example:
pyfr export mesh.pyfrm solution.pyfrs solution.vtu
five commands, five little besties, all serving. π
π Running in Parallel
pyfr can be run in parallel. to do so, prefix pyfr with mpirun -n <cores/devices>. π₯
β οΈ note that the mesh must be pre-partitioned, and the number of cores or devices must be equal to the number of partitions. no matching, no running. fr fr.
βοΈ Configuration File (.ini)
π Overview
the .ini configuration file parameterises the simulation. it's written in the INI format. parameters are grouped into sections. the roles of each section and their associated parameters are described below. β¬οΈ
π [backend]
parameterises the backend with
precisionβ number precision:single | doublerank-allocatorβ MPI rank allocator:linear | random
Example:
[backend]
precision = double
rank-allocator = linear
π© [backend-cuda]
parameterises the CUDA backend with
device-idβ method for selecting which device(s) to run on:int | round-robin | local-rankgimmik-max-nnzβ cutoff for GiMMiK in terms of the number of non-zero entires in a constant matrix:intmpi-typeβ type of MPI library that is being used:standard | cuda-awareblock-1dβ block size for one dimensional pointwise kernels:intblock-2dβ block size for two dimensional pointwise kernels:int, int
Example:
[backend-cuda]
device-id = round-robin
gimmik-max-nnz = 512
mpi-type = standard
block-1d = 64
block-2d = 128, 2
π¦ [backend-mic]
parameterises the MIC backend with
device-idβ for selecting which device(s) to run on:int | local-rankmkl-rootβ path to MKL root directory:string
πͺ [backend-opencl]
parameterises the OpenCL backend with
platform-idβ for selecting platform id:int | stringdevice-typeβ for selecting what type of device(s) to run on:all | cpu | gpu | acceleratordevice-idβ for selecting which device(s) to run on:int | string | local-rankgimmik-max-nnzβ cutoff for GiMMiK in terms of the number of non-zero entires in a constant matrix:intlocal-size-1dβ local work size for one dimensional pointwise kernels:intlocal-size-2dβ local work size for two dimensional pointwise kernels:int, int
Example:
[backend-opencl]
platform-id = 0
device-type = gpu
device-id = local-rank
gimmik-max-nnz = 512
local-size-1d = 16
local-size-2d = 128, 1
π§ [backend-openmp]
parameterises the OpenMP backend with
ccβ C compiler:stringcflagsβ additional C compiler flags:stringcblasβ path to shared C BLAS library:stringcblas-typeβ type of BLAS library:serial | parallel
Example:
πΈ and that's where part 1 dips β the [backend-openmp] example is chilling in part 2, bestie. don't go anywhere. π
[backend-openmp]
cc = gcc
cblas= example/path/libBLAS.dylib
cblas-type = parallel
πΈ [constants] πΈ
Okay bestie, this is where you drop the literal constants that your simulation runs on. You've got five, and here they are:
gammaβ ratio of specific heats:floatmuβ dynamic viscosity:floatPrβ Prandtl number:floatcpTrefβ product of specific heat at constant pressure and reference temperature for Sutherland's Law:floatcpTsβ product of specific heat at constant pressure and Sutherland temperature for Sutherland's Law:float
Example, because a vibe is nothing without a demo:
[constants]
gamma = 1.4
mu = 0.001
Pr = 0.72
β¨ [solver] β¨
This one parameterises the solver itself. Five knobs, all iconic:
systemβ governing system:euler | navier-stokesorderβ order of polynomial solution basis:intanti-aliasβ type of anti-aliasing:flux | surf-flux | div-flux | flux, surf-flux | flux, div-flux | surf-flux, div-flux | flux, surf-flux, div-fluxviscosity-correctionβ viscosity correction:none | sutherlandshock-capturingβ shock capturing scheme:none | artificial-viscosity
Example:
[solver]
system = navier-stokes
order = 3
anti-alias = flux
viscosity-correction = none
shock-capturing = artificial-viscosity
π [solver-time-integrator] π
Time to parameterise the time-integration scheme your solver is gonna use. Yes, that sentence is doing a lot, but so are you. π
formulationβ formulation:std | dual
where
std requires
schemeβ time-integration scheme:euler | rk34 | rk4 | rk45 | tvd-rk3tstartβ initial time:floattendβ final time:floatdtβ time-step:floatcontrollerβ time-step controller:none | pi
where
pi only works with rk34 and rk45 and requires
atolβ absolute error tolerance:floatrtolβ relative error tolerance:floaterrest-normβ norm to use for estimating the error:uniform | l2safety-factβ safety factor for step size adjustment (suitable range0.80-0.95):floatmin-factβ minimum factor that the time-step can change between iterations (suitable range0.1-0.5):floatmax-factβ maximum factor that the time-step can change between iterations (suitable range2.0-6.0):float
dual requires
schemeβ time-integration scheme:backward-euler | bdf2 | bdf3pseudo-schemeβ pseudo-time-integration scheme:euler | tvd-rk3 | rk4tstartβ initial time:floattendβ final time:floatdtβ time-step:floatpseudo-dtβ pseudo-time-step:floatcontrollerβ pseudo-time-step controller:none
where
none requires
pseudo-niters-maxβ minimum number of iterations:intpseudo-niters-minβ maximum number of iterations:intpseudo-aresidβ absolute residual tolerance:floatpseudo-rresidβ relative residual tolerance:float
Example:
[solver-time-integrator]
formulation = std
scheme = rk45
controller = pi
tstart = 0.0
tend = 10.0
dt = 0.001
atol = 0.00001
rtol = 0.00001
errest-norm = l2
safety-fact = 0.9
min-fact = 0.3
max-fact = 2.5
π«Ά quick heads up bestie, yes, the original really does saypseudo-niters-maxis the minimum andpseudo-niters-minis the maximum. Not a typo on my end, I'm just the messenger. Don't shoot me. π
π¦ [solver-interfaces] π¦
Parameterises the interfaces. Three things:
riemann-solverβ type of Riemann solver:rusanov | hll | hllc | roe | roemldg-betaβ beta parameter used for LDG:floatldg-tauβ tau parameter used for LDG:float
Example:
[solver-interfaces]
riemann-solver = rusanov
ldg-beta = 0.5
ldg-tau = 0.1
π [solver-interfaces-line] π
Parameterises the line interfaces, specifically:
flux-ptsβ location of the flux points on a line interface:gauss-legendre | gauss-legendre-lobattoquad-degβ degree of quadrature rule for anti-aliasing on a line interface:intquad-ptsβ name of quadrature rule for anti-aliasing on a line interface:gauss-legendre | gauss-legendre-lobatto
Example:
[solver-interfaces-line]
flux-pts = gauss-legendre
quad-deg = 10
quad-pts = gauss-legendre
π [solver-interfaces-tri] π
Parameterises the triangular interfaces:
flux-ptsβ location of the flux points on a triangular interface:williams-shunnquad-degβ degree of quadrature rule for anti-aliasing on a triangular interface:intquad-ptsβ name of quadrature rule for anti-aliasing on a triangular interface:williams-shunn | witherden-vincent
Example:
[solver-interfaces-tri]
flux-pts = williams-shunn
quad-deg = 10
quad-pts = williams-shunn
π [solver-interfaces-quad] π
Parameterises the quadrilateral interfaces:
flux-ptsβ location of the flux points on a quadrilateral interface:gauss-legendre | gauss-legendre-lobattoquad-degβ degree of quadrature rule for anti-aliasing on a quadrilateral interface:intquad-ptsβ name of quadrature rule for anti-aliasing on a quadrilateral interface:gauss-legendre | gauss-legendre-lobatto | witherden-vincent
Example:
[solver-interfaces-quad]
flux-pts = gauss-legendre
quad-deg = 10
quad-pts = gauss-legendre
π§ [solver-elements-tri] π§
Now we're on the elements, starting with the triangles:
soln-ptsβ location of the solution points in a triangular element:williams-shunnquad-degβ degree of quadrature rule for anti-aliasing in a triangular element:intquad-ptsβ name of quadrature rule for anti-aliasing in a triangular element:williams-shunn | witherden-vincent
Example:
[solver-elements-tri]
soln-pts = williams-shunn
quad-deg = 10
quad-pts = williams-shunn
πΈ [solver-elements-quad] πΈ
The quadrilateral elements:
soln-ptsβ location of the solution points in a quadrilateral element:gauss-legendre | gauss-legendre-lobattoquad-degβ degree of quadrature rule for anti-aliasing in a quadrilateral element:intquad-ptsβ name of quadrature rule for anti-aliasing in a quadrilateral element:gauss-legendre | gauss-legendre-lobatto | witherden-vincent
Example:
[solver-elements-quad]
soln-pts = gauss-legendre
quad-deg = 10
quad-pts = gauss-legendre
β [solver-elements-hex] β
Hexahedral elements, my beloved:
soln-ptsβ location of the solution points in a hexahedral element:gauss-legendre | gauss-legendre-lobattoquad-degβ degree of quadrature rule for anti-aliasing in a hexahedral element:intquad-ptsβ name of quadrature rule for anti-aliasing in a hexahedral element:gauss-legendre | gauss-legendre-lobatto | witherden-vincent
Example:
[solver-elements-hex]
soln-pts = gauss-legendre
quad-deg = 10
quad-pts = gauss-legendre
π [solver-elements-tet] π
Tetrahedral elements:
soln-ptsβ location of the solution points in a tetrahedral element:shunn-hamquad-degβ degree of quadrature rule for anti-aliasing in a tetrahedral element:intquad-ptsβ name of quadrature rule for anti-aliasing in a tetrahedral element:shunn-ham | witherden-vincent
Example:
[solver-elements-tet]
soln-pts = shunn-ham
quad-deg = 10
quad-pts = shunn-ham
π [solver-elements-pri] π
Prismatic elements β and yes, the names here get a lil compound with that tilde in the middle, so read carefully bestie:
soln-ptsβ location of the solution points in a prismatic element:williams-shunn~gauss-legendre | williams-shunn~gauss-legendre-lobattoquad-degβ degree of quadrature rule for anti-aliasing in a prismatic element:intquad-ptsβ name of quadrature rule for anti-aliasing in a prismatic element:williams-shunn~gauss-legendre | williams-shunn~gauss-legendre-lobatto | witherden-vincent
Example:
[solver-elements-pri]
soln-pts = williams-shunn~gauss-legendre
quad-deg = 10
quad-pts = williams-shunn~gauss-legendre
π¦ [solver-elements-pyr] π¦
Pyramidal elements:
soln-ptsβ location of the solution points in a pyramidal element:gauss-legendre | gauss-legendre-lobattoquad-degβ degree of quadrature rule for anti-aliasing in a pyramidal element:intquad-ptsβ name of quadrature rule for anti-aliasing in a pyramidal element:witherden-vincent
Example:
[solver-elements-pyr]
soln-pts = gauss-legendre
quad-deg = 10
quad-pts = witherden-vincent
π₯ [solver-source-terms] π₯
This section parameterises source terms that depend on the solution, on space (x, y, [z]), and on time (t). Note that z is hanging out in brackets because it's only there when you've got a third dimension, iykyk:
rhoβ density source term:stringrhouβ x-momentum source term:stringrhovβ y-momentum source term:stringrhowβ z-momentum source term:stringEβ energy source term:string
Example:
[solver-source-terms]
rho = t
rhou = x*y*sin(y)
rhov = z*rho
rhow = 1.0
E = 1.0/(1.0+x)
β¨ [solver-artificial-viscosity] β¨
Last one in this batch, and it's all about artificial viscosity for shock capturing:
max-artviscβ maximum artificial viscosity:floats0β sensor cut-off:floatkappaβ sensor range:float
Example:
[solver-artificial-viscosity]
max-artvisc = 0.01
s0 = 0.01
kappa = 5.0
[soln-filter]</p> π
Ok so this one sets up an exponential solution filter β bestie, it's literally just vibes control for your solution. You parameterise it with:
nstepsβ apply the filter everynsteps: typeintβ¨alphaβ strength of the filter: typefloatπͺorderβ order of the filter: typeintcutoffβ cutoff frequency below which no filtering is applied: typeintπ«
Example, because examples eat every time:
[soln-filter]
nsteps = 10
alpha = 36.0
order = 16
cutoff = 1
[soln-plugin-writer]</p> πΎ
Periodically write the solution to disk in the pyfrs format. It's giving "save your work, queen." Parameterised with:
dt-outβ write to disk everydt-outtime units: typefloatβ±οΈbasedirβ relative path to directory where outputs will be written: typestringπbasenameβ pattern of output names: typestringπ·οΈpost-actionβ command to execute after writing the file: typestringpost-action-modeβ how the post-action command should be executed:blocking | non-blockingπ¦
Example:
[soln-plugin-writer]
dt-out = 0.01
basedir = .
basename = files-{t:.2f}
post-action = echo "Wrote file {soln} at time {t} for mesh {mesh}."
post-action-mode = blocking
[soln-plugin-fluidforce-name]</p> π
Periodically integrates the pressure and viscous stress on the boundary labelled name and writes out the resulting force vectors to a CSV file. Yes bestie, it's doing calculus on your boundary. Parameterised with:
nstepsβ integrate everynsteps: typeintfileβ output file path; should the file already exist it will be appended to: typestringπheaderβ if to output a header row or not: typeboolean
Example:
[soln-plugin-fluidforce-wing]
nsteps = 10
file = wing-forces.csv
header = true
[soln-plugin-nancheck]</p> π
Periodically checks the solution for NaN values. It's literally the vibe check of plugins β if your sim is giving nothing but NaN, this one snitches. Parameterised with:
nstepsβ check everynsteps: typeint
Example:
[soln-plugin-nancheck]
nsteps = 10
[soln-plugin-residual]</p> π
Periodically calculates the residual and writes it out to a CSV file. Convergence watching? Obsessed. Parameterised with:
nstepsβ calculate everynsteps: typeintfileβ output file path; should the file already exist it will be appended to: typestringπheaderβ if to output a header row or not: typeboolean
Example:
[soln-plugin-residual]
nsteps = 10
file = residual.csv
header = true
[soln-plugin-dtstats]</p> β³
Write time-step statistics out to a CSV file. Parameterised with:
flushstepsβ flush to disk everyflushsteps: typeintfileβ output file path; should the file already exist it will be appended to: typestringπheaderβ if to output a header row or not: typeboolean
Example:
[soln-plugin-dtstats]
flushsteps = 100
file = dtstats.csv
header = true
[soln-plugin-sampler]</p> π
Periodically samples specific points in the volume and writes them out to a CSV file. Okay so important tea: the plugin actually samples the solution point closest to each sample point, hence a slight discrepancy in the output sampling locations is to be expected. A nearest-neighbour search is used to locate the closest solution point to the sample point. The location process automatically takes advantage of scipy.spatial.cKDTree where available. π§ Parameterised with:
nstepsβ sample everynsteps: typeintsamp-ptsβ list of points to sample:[(x, y), (x, y), ...] | [(x, y, z), (x, y, z), ...]formatβ output variable format:primitive | conservativefileβ output file path; should the file already exist it will be appended to: typestringπheaderβ if to output a header row or not: typeboolean
Example:
[soln-plugin-sampler]
nsteps = 10
samp-pts = [(1.0, 0.7, 0.0), (1.0, 0.8, 0.0)]
format = primative
file = point-data.csv
header = true
[soln-plugin-tavg]</p> π
Time average quantities. Averaging is so main character honestly. Parameterised with:
nstepsβ accumulate the average everynstepstime steps: typeintdt-outβ write to disk everydt-outtime units: typefloatβ±οΈbasedirβ relative path to directory where outputs will be written: typestringπbasenameβ pattern of output names: typestringπ·οΈavg-nameβ expression as a function of the primitive variables, time (t), and space (x,y,[z]) to time average; multiple expressions, each with their own name, may be specified: typestringβ¨
Example:
[soln-plugin-tavg]
nsteps = 10
dt-out = 2.0
basedir = .
basename = files-{t:06.2f}
avg-p = p
avg-p2 = p*p
avg-vel = sqrt(u*u + v*v)
[soln-bcs-name]</p> π§±
Parameterises constant, or if available space (x, y, [z]) and time (t) dependent, boundary condition labelled name in the .pyfrm file with:
typeβ type of boundary condition:
char-riem-inv | no-slp-adia-wall | no-slp-isot-wall |
slp-adia-wall | sub-in-frv | sub-in-ftpttang | sub-out-fp |
sup-in-fa | sup-out-fn
where... π
char-riem-invrequiresrhoβ density:float | stringuβ x-velocity:float | stringvβ y-velocity:float | stringwβ z-velocity:float | stringpβ static pressure:float | string
no-slp-isot-wallrequiresuβ x-velocity of wall:floatvβ y-velocity of wall:floatwβ z-velocity of wall:floatcpTwβ product of specific heat capacity at constant pressure and temperature of wall:float
sub-in-frvrequiresrhoβ density:float | stringuβ x-velocity:float | stringvβ y-velocity:float | stringwβ z-velocity:float | string
sub-in-ftpttangrequiresptβ total pressure:floatcpTtβ product of specific heat capacity at constant pressure and total temperature:floatthetaβ azimuth angle (in degrees) of inflow measured in the x-y plane relative to the positive x-axis:floatπphiβ inclination angle (in degrees) of inflow measured relative to the positive z-axis:floatπ
sub-out-fprequirespβ static pressure:float | string
sup-in-farequiresrhoβ density:float | stringuβ x-velocity:float | stringvβ y-velocity:float | stringwβ z-velocity:float | stringpβ static pressure:float | string
Example:
[soln-bcs-bcwallupper]
type = no-slp-isot-wall
cpTw = 10.0
u = 1.0
[soln-ics]</p> π±
Parameterises space (x, y, [z]) dependent initial conditions with:
rhoβ initial density distribution: typestringuβ initial x-velocity distribution: typestringvβ initial y-velocity distribution: typestringwβ initial z-velocity distribution: typestringpβ initial static pressure distribution: typestring
Example:
[soln-ics]
rho = 1.0
u = x*y*sin(y)
v = z
w = 1.0
p = 1.0/(1.0+x)
Example --- 2D Couette Flow π¦
Proceed with the following steps to run a serial 2D Couette flow simulation on a mixed unstructured mesh:
- Create a working directory called
couette_flow_2d/π - Copy the configuration file
PyFR/examples/couette_flow_2d/couette_flow_2d.iniintocouette_flow_2d/ - Copy the Gmsh mesh file
PyFR/examples/couette_flow_2d/couette_flow_2d.mshintocouette_flow_2d/ - Run
pyfrto covert the Gmsh mesh file into a PyFR mesh file calledcouette_flow_2d.pyfrm:
pyfr import couette_flow_2d.msh couette_flow_2d.pyfrm
- Run
pyfrto solve the Navier-Stokes equations on the mesh, generating a series of PyFR solution files calledcouette_flow_2d-*.pyfrs:
pyfr run -b cuda -p couette_flow_2d.pyfrm couette_flow_2d.ini
- Run
pyfron the solution filecouette_flow_2d-040.pyfrsconverting it into an unstructured VTK file calledcouette_flow_2d-040.vtu. Note that in order to visualise the high-order data, each high-order element is sub-divided into smaller linear elements. The level of sub-division is controlled by the integer at the end of the command:
pyfr export couette_flow_2d.pyfrm couette_flow_2d-040.pyfrs couette_flow_2d-040.vtu -d 4
- Visualise the unstructured VTK file in Paraview
[image: couette flow] [image] Colour map of steady-state density distribution. π¨
Example --- 2D Euler Vortex πͺοΈ
Proceed with the following steps to run a parallel 2D Euler vortex simulation on a structured mesh:
- Create a working directory called
euler_vortex_2d/π - Copy the configuration file
PyFR/examples/euler_vortex_2d/euler_vortex_2d.iniintoeuler_vortex_2d/ - Copy the Gmsh file
PyFR/examples/euler_vortex_2d/euler_vortex_2d.mshintoeuler_vortex_2d/ - Run
pyfrto convert the Gmsh mesh file into a PyFR mesh file calledeuler_vortex_2d.pyfrm:
pyfr import euler_vortex_2d.msh euler_vortex_2d.pyfrm
- Run
pyfrto partition the PyFR mesh file into two pieces:
pyfr partition 2 euler_vortex_2d.pyfrm .
- Run
pyfrto solve the Euler equations on the mesh, generating a series of PyFR solution files calledeuler_vortex_2d*.pyfrs:
mpirun -n 2 pyfr run -b cuda -p euler_vortex_2d.pyfrm euler_vortex_2d.ini
- Run
pyfron the solution fileeuler_vortex_2d-100.0.pyfrsconverting it into an unstructured VTK file calledeuler_vortex_2d-100.0.vtu. Note that in order to visualise the high-order data, each high-order element is sub-divided into smaller linear elements. The level of sub-division is controlled by the integer at the end of the command:
pyfr export euler_vortex_2d.pyfrm euler_vortex_2d-100.0.pyfrs euler_vortex_2d-100.0.vtu -d 4
- Visualise the unstructured VTK file in Paraview
[image: euler vortex] [image] Colour map of density distribution at 100 time units. π¨
πΈ DEVELOPER GUIDE πΈ
okay bestie, this is the part where we go behind the scenes. like, past the shiny CLI, past the theory, straight into the actual Python that makes PyFR go. it's giving "backstage pass" energy and honestly? iconic. π
β¨ A Brief Overview of the PyFR Framework β¨
π«Ά Where to Start
okay so first things first, 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. and then the Integrator has a method named run, which is then called to run the simulation. that's the whole main-character arc right there. no cap. π₯
π Controller
so 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 Controller available in PyFR 1.5.0. three. that's it. a small but mighty squad. π
class pyfr.integrators.std.controllers.StdNoneController(*args, **kwargs)
class pyfr.integrators.std.controllers.StdNoneController(*args, **kwargs)
_abc_impl = <_abc_data object>
_accept_step(dt, idxcurr, err=None)
_add(*args)
_controller_needs_errest
_get_axnpby_kerns(n, subdims=None)
_get_gndofs()
_get_kernels(name, nargs, **kwargs)
_get_plugins()
_get_reg_banks(nreg)
_prepare_reg_banks(*bidxes)
_reject_step(dt, idxold, err=None)
_stepper_has_errest
_stepper_nfevals
_stepper_nregs
_stepper_order
advance_to(t)
call_plugin_dt(dt)
cfgmeta
collect_stats(stats)
controller_name = 'none'
formulation = 'std'
nsteps
run()
soln
step(t, dt)
class pyfr.integrators.std.controllers.StdPIController(*args, **kwargs)
class pyfr.integrators.std.controllers.StdPIController(*args, **kwargs)
_abc_impl = <_abc_data object>
_accept_step(dt, idxcurr, err=None)
_add(*args)
_controller_needs_errest
_errest(x, y, z)
_get_axnpby_kerns(n, subdims=None)
_get_errest_kerns()
_get_gndofs()
_get_kernels(name, nargs, **kwargs)
_get_plugins()
_get_reg_banks(nreg)
_prepare_reg_banks(*bidxes)
_reject_step(dt, idxold, err=None)
_stepper_has_errest
_stepper_nfevals
_stepper_nregs
_stepper_order
advance_to(t)
call_plugin_dt(dt)
cfgmeta
collect_stats(stats)
controller_name = 'pi'
formulation = 'std'
nsteps
run()
soln
step(t, dt)
class pyfr.integrators.dual.controllers.DualNoneController(*args, **kwargs)
class pyfr.integrators.dual.controllers.DualNoneController(*args, **kwargs)
_abc_impl = <_abc_data object>
_accept_step(dt, idxcurr)
_add(*args)
_dual_time_source()
_get_axnpby_kerns(n, subdims=None)
_get_errest_kerns()
_get_gndofs()
_get_kernels(name, nargs, **kwargs)
_get_plugins()
_get_reg_banks(nreg)
_prepare_reg_banks(*bidxes)
_resid(x, y)
_source_regidx
_stepper_nfevals
_stepper_nregs
_stepper_order
_stepper_regidx
advance_to(t)
call_plugin_dt(dt)
cfgmeta
collect_stats(stats)
controller_name = 'none'
finalise_step(currsoln)
formulation = 'dual'
nsteps
run()
soln
step(t, dt)
and bestie, the types of Controller are related via the following inheritance diagram: π³β¨ (yes, there's a diagram, and yes, it's exactly as satisfying as it sounds)
π Stepper
okay so 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 11 types of Stepper available in PyFR 1.5.0. eleven!! the roster is stacked. π₯
class pyfr.integrators.std.steppers.StdEulerStepper(*args, **kwargs)
class pyfr.integrators.std.steppers.StdEulerStepper(*args, **kwargs)
_abc_impl = <_abc_data object>
_add(*args)
_controller_needs_errest
_get_axnpby_kerns(n, subdims=None)
_get_gndofs()
_get_kernels(name, nargs, **kwargs)
_get_plugins()
_get_reg_banks(nreg)
_prepare_reg_banks(*bidxes)
_stepper_has_errest
_stepper_nfevals
_stepper_nregs
_stepper_order
advance_to(t)
call_plugin_dt(dt)
cfgmeta
collect_stats(stats)
formulation = 'std'
nsteps
run()
soln
step(t, dt)
stepper_name = 'euler'
class pyfr.integrators.std.steppers.StdRK4Stepper(*args, **kwargs)
class pyfr.integrators.std.steppers.StdRK4Stepper(*args, **kwargs)
_abc_impl = <_abc_data object>
_add(*args)
_controller_needs_errest
_get_axnpby_kerns(n, subdims=None)
_get_gndofs()
_get_kernels(name, nargs, **kwargs)
_get_plugins()
_get_reg_banks(nreg)
_prepare_reg_banks(*bidxes)
_stepper_has_errest
_stepper_nfevals
_stepper_nregs
_stepper_order
advance_to(t)
call_plugin_dt(dt)
cfgmeta
collect_stats(stats)
formulation = 'std'
nsteps
run()
soln
step(t, dt)
stepper_name = 'rk4'
class pyfr.integrators.std.steppers.StdRK34Stepper(*args, **kwargs)
class pyfr.integrators.std.steppers.StdRK34Stepper(*args, **kwargs)
_abc_impl = <_abc_data object>
_add(*args)
_controller_needs_errest
_get_axnpby_kerns(n, subdims=None)
_get_gndofs()
_get_kernels(name, nargs, **kwargs)
_get_plugins()
_get_reg_banks(nreg)
_prepare_reg_banks(*bidxes)
_stepper_has_errest
_stepper_nfevals
_stepper_nregs
_stepper_order
a = [0.32416573882874605, 0.5570978645055429,
-0.08605491431272755]
advance_to(t)
b = [0.10407986927510238, 0.6019391368822611, 2.9750900268840206,
-2.681109033041384]
bhat = [0.3406814840808433, 0.09091523008632837,
2.866496742725443, -2.298093456892615]
call_plugin_dt(dt)
cfgmeta
collect_stats(stats)
formulation = 'std'
nsteps
run()
soln
step(t, dt)
stepper_name = 'rk34'
class pyfr.integrators.std.steppers.StdRK45Stepper(*args, **kwargs)
class pyfr.integrators.std.steppers.StdRK45Stepper(*args, **kwargs)
_abc_impl = <_abc_data object>
_add(*args)
_controller_needs_errest
_get_axnpby_kerns(n, subdims=None)
_get_gndofs()
_get_kernels(name, nargs, **kwargs)
_get_plugins()
_get_reg_banks(nreg)
_prepare_reg_banks(*bidxes)
_stepper_has_errest
_stepper_nfevals
_stepper_nregs
_stepper_order
a = [0.22502245872571303, 0.5440433129514047,
0.14456824349399464, 0.7866643421983568]
advance_to(t)
b = [0.05122930664033915, 0.3809548257264019,
-0.3733525963923833, 0.5925012850263623, 0.34866717899927996]
bhat = [0.13721732210321927, 0.19188076232938728,
-0.2292067211595315, 0.6242946765438954, 0.27581396018302956]
call_plugin_dt(dt)
cfgmeta
collect_stats(stats)
formulation = 'std'
nsteps
run()
soln
step(t, dt)
stepper_name = 'rk45'
class pyfr.integrators.std.steppers.StdTVDRK3Stepper(*args, **kwargs)
class pyfr.integrators.std.steppers.StdTVDRK3Stepper(*args, **kwargs)
_abc_impl = <_abc_data object>
_add(*args)
_controller_needs_errest
_get_axnpby_kerns(n, subdims=None)
_get_gndofs()
_get_kernels(name, nargs, **kwargs)
_get_plugins()
_get_reg_banks(nreg)
_prepare_reg_banks(*bidxes)
_stepper_has_errest
_stepper_nfevals
_stepper_nregs
_stepper_order
advance_to(t)
call_plugin_dt(dt)
cfgmeta
collect_stats(stats)
formulation = 'std'
nsteps
run()
soln
step(t, dt)
stepper_name = 'tvd-rk3'
class pyfr.integrators.dual.steppers.DualBDF2Stepper(*args, **kwargs)
class pyfr.integrators.dual.steppers.DualBDF2Stepper(*args, **kwargs)
_abc_impl = <_abc_data object>
_add(*args)
_dual_time_source
_get_axnpby_kerns(n, subdims=None)
_get_gndofs()
_get_kernels(name, nargs, **kwargs)
_get_plugins()
_get_reg_banks(nreg)
_prepare_reg_banks(*bidxes)
_source_regidx
_stepper_nfevals
_stepper_nregs
_stepper_order
_stepper_regidx
advance_to(t)
call_plugin_dt(dt)
cfgmeta
collect_stats(stats)
finalise_step(currsoln)
formulation = 'dual'
nsteps
run()
soln
step(t, dt)
stepper_name = 'bdf2'
class pyfr.integrators.dual.steppers.DualBDF3Stepper(*args, **kwargs)
class pyfr.integrators.dual.steppers.DualBDF3Stepper(*args, **kwargs)
_abc_impl = <_abc_data object>
_add(*args)
_dual_time_source
_get_axnpby_kerns(n, subdims=None)
_get_gndofs()
_get_kernels(name, nargs, **kwargs)
_get_plugins()
_get_reg_banks(nreg)
_prepare_reg_banks(*bidxes)
_source_regidx
_stepper_nfevals
_stepper_nregs
_stepper_order
_stepper_regidx
advance_to(t)
call_plugin_dt(dt)
cfgmeta
collect_stats(stats)
finalise_step(currsoln)
formulation = 'dual'
nsteps
run()
soln
step(t, dt)
stepper_name = 'bdf3'
class pyfr.integrators.dual.steppers.DualBackwardEulerStepper(*args, **kwargs)
class pyfr.integrators.dual.steppers.DualBackwardEulerStepper(*args, **kwargs)
_abc_impl = <_abc_data object>
_add(*args)
_dual_time_source
_get_axnpby_kerns(n, subdims=None)
_get_gndofs()
_get_kernels(name, nargs, **kwargs)
_get_plugins()
_get_reg_banks(nreg)
_prepare_reg_banks(*bidxes)
_source_regidx
_stepper_nfevals
_stepper_nregs
_stepper_order
_stepper_regidx
advance_to(t)
call_plugin_dt(dt)
cfgmeta
collect_stats(stats)
finalise_step(currsoln)
formulation = 'dual'
nsteps
run()
soln
step(t, dt)
stepper_name = 'backward-euler'
class pyfr.integrators.dual.pseudosteppers.DualPseudoRK4Stepper(*args, **kwargs)
class pyfr.integrators.dual.pseudosteppers.DualPseudoRK4Stepper(*args, **kwargs)
_abc_impl = <_abc_data object>
_add(*args)
_add_with_dts(*args, c)
_dual_time_source()
okay so picking up right where we left off with that stepper class, here's the rest of its members, every single one, no skips π
_get_axnpby_kerns(n, subdims=None)
_get_gndofs()
_get_kernels(name, nargs, **kwargs)
_get_plugins()
_get_reg_banks(nreg)
_prepare_reg_banks(*bidxes)
_pseudo_stepper_nregs
_pseudo_stepper_order
_source_regidx
_stepper_nfevals
_stepper_nregs
_stepper_order
_stepper_regidx
advance_to(t)
call_plugin_dt(dt)
cfgmeta
collect_stats(stats)
finalise_step(currsoln)
formulation = 'dual'
nsteps
pseudo_stepper_name = 'rk4'
run()
soln
step(t, dt, dtau)
β¨ class pyfr.integrators.dual.pseudosteppers.DualPseudoTVDRK3Stepper(*args, **kwargs) β¨
same energy, different flavour β this one's the tvd-rk3 girlie π
_abc_impl = <_abc_data object>
_add(*args)
_add_with_dts(*args, c)
_dual_time_source()
_get_axnpby_kerns(n, subdims=None)
_get_gndofs()
_get_kernels(name, nargs, **kwargs)
_get_plugins()
_get_reg_banks(nreg)
_prepare_reg_banks(*bidxes)
_pseudo_stepper_nregs
_pseudo_stepper_order
_source_regidx
_stepper_nfevals
_stepper_nregs
_stepper_order
_stepper_regidx
advance_to(t)
call_plugin_dt(dt)
cfgmeta
collect_stats(stats)
finalise_step(currsoln)
formulation = 'dual'
nsteps
pseudo_stepper_name = 'tvd-rk3'
run()
soln
step(t, dt, dtau)
β¨ class pyfr.integrators.dual.pseudosteppers.DualPseudoEulerStepper(*args, **kwargs) β¨
and the euler one, keeping it simple and iconic π¦
_abc_impl = <_abc_data object>
_add(*args)
_add_with_dts(*args, c)
_dual_time_source()
_get_axnpby_kerns(n, subdims=None)
_get_gndofs()
_get_kernels(name, nargs, **kwargs)
_get_plugins()
_get_reg_banks(nreg)
_prepare_reg_banks(*bidxes)
_pseudo_stepper_nregs
_pseudo_stepper_order
_source_regidx
_stepper_nfevals
_stepper_nregs
_stepper_order
_stepper_regidx
advance_to(t)
call_plugin_dt(dt)
cfgmeta
collect_stats(stats)
finalise_step(currsoln)
formulation = 'dual'
nsteps
pseudo_stepper_name = 'euler'
run()
soln
step(t, dt, dtau)
Types of Stepper are related via the following inheritance diagram:
π System π
A System holds information/data for the system β including Elements, Interfaces, and the Backend the simulation is gonna run on. Bestie it's basically the whole vibe holder.
A System has a method named rhs, which grabs the divergence of the flux (the 'right-hand-side') at every solution point. That rhs method then calls up a bunch of kernels that were pre-generated and already loaded into queues. A System also has a method named _gen_kernels whose whole job is generating all the kernels a particular System needs.
A kernel is an instance of a 'one-off' class with a method named run that implements whatever kernel functionality is required. Individual kernels get produced by a kernel provider. PyFR 1.5.0 has various types of kernel provider. A Pointwise Kernel Provider produces point-wise kernels like 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 two types of System available in PyFR 1.5.0:
π class pyfr.solvers.euler.system.EulerSystem(backend, rallocs, mesh, initsoln, nreg, cfg) π
_abc_impl = <_abc_data object>
_gen_kernels(eles, iint, mpiint, bcint)
_gen_queues()
_load_bc_inters(rallocs, mesh, elemap)
_load_eles(rallocs, mesh, initsoln, nreg, nonce)
_load_int_inters(rallocs, mesh, elemap)
_load_mpi_inters(rallocs, mesh, elemap)
_nonce_seq = count(0)
_nqueues = 2
bbcinterscls
alias of pyfr.solvers.euler.inters.EulerBaseBCInters
ele_scal_upts(idx)
elementscls
alias of pyfr.solvers.euler.elements.EulerElements
filt(uinoutbank)
intinterscls
alias of pyfr.solvers.euler.inters.EulerIntInters
mpiinterscls
alias of pyfr.solvers.euler.inters.EulerMPIInters
name = 'euler'
rhs(t, uinbank, foutbank)
π class pyfr.solvers.navstokes.system.NavierStokesSystem(backend, rallocs, mesh, initsoln, nreg, cfg) π
_abc_impl = <_abc_data object>
_gen_kernels(eles, iint, mpiint, bcint)
_gen_queues()
_load_bc_inters(rallocs, mesh, elemap)
_load_eles(rallocs, mesh, initsoln, nreg, nonce)
_load_int_inters(rallocs, mesh, elemap)
_load_mpi_inters(rallocs, mesh, elemap)
_nonce_seq = count(0)
_nqueues = 2
bbcinterscls
alias of
pyfr.solvers.navstokes.inters.NavierStokesBaseBCInters
ele_scal_upts(idx)
elementscls
alias of
pyfr.solvers.navstokes.elements.NavierStokesElements
filt(uinoutbank)
intinterscls
alias of
pyfr.solvers.navstokes.inters.NavierStokesIntInters
mpiinterscls
alias of
pyfr.solvers.navstokes.inters.NavierStokesMPIInters
name = 'navier-stokes'
rhs(t, uinbank, foutbank)
Types of System are related via the following inheritance diagram:
πΈ Elements πΈ
An Elements holds information/data for a group of elements. There are two types of Elements available in PyFR 1.5.0:
π¦ class pyfr.solvers.euler.elements.EulerElements(basiscls, eles, cfg) π¦
_abc_impl = <_abc_data object>
_gen_pnorm_fpts()
_mag_pnorm_fpts = None
_norm_pnorm_fpts = None
_ploc_in_src_exprs = None
_scratch_bufs
_smats_djacs_mpts = None
_soln_in_src_exprs = None
_src_exprs = None
_srtd_face_fpts = None
static con_to_pri(cons, cfg)
convarmap = {2: ['rho', 'rhou', 'rhov', 'E'], 3: ['rho', 'rhou',
'rhov', 'rhow', 'E']}
dualcoeffs = {2: ['rho', 'rhou', 'rhov', 'E'], 3: ['rho', 'rhou',
'rhov', 'rhow', 'E']}
formulations = ['std', 'dual']
get_mag_pnorms(eidx, fidx)
get_mag_pnorms_for_inter(eidx, fidx)
get_norm_pnorms(eidx, fidx)
get_norm_pnorms_for_inter(eidx, fidx)
get_ploc_for_inter(eidx, fidx)
get_scal_fpts_for_inter(eidx, fidx)
get_vect_fpts_for_inter(eidx, fidx)
opmat(expr)
ploc_at(name)
ploc_at_np(name)
plocfpts = None
static pri_to_con(pris, cfg)
privarmap = {2: ['rho', 'u', 'v', 'p'], 3: ['rho', 'u', 'v', 'w',
'p']}
rcpdjac_at(name)
rcpdjac_at_np(name)
set_backend(backend, nscalupts, nonce)
set_ics_from_cfg()
set_ics_from_soln(solnmat, solncfg)
smat_at(name)
smat_at_np(name)
visvarmap = {2: {'density': ['rho'], 'pressure': ['p'],
'velocity': ['u', 'v']}, 3: {'density': ['rho'], 'pressure':
['p'], 'velocity': ['u', 'v', 'w']}}
π¦ class pyfr.solvers.navstokes.elements.NavierStokesElements(basiscls, eles, cfg) π¦
_abc_impl = <_abc_data object>
_gen_pnorm_fpts()
_mag_pnorm_fpts = None
_norm_pnorm_fpts = None
_ploc_in_src_exprs = None
_scratch_bufs
_smats_djacs_mpts = None
_soln_in_src_exprs = None
_src_exprs = None
_srtd_face_fpts = None
static con_to_pri(cons, cfg)
convarmap = {2: ['rho', 'rhou', 'rhov', 'E'], 3: ['rho', 'rhou',
'rhov', 'rhow', 'E']}
dualcoeffs = {2: ['rho', 'rhou', 'rhov', 'E'], 3: ['rho', 'rhou',
'rhov', 'rhow', 'E']}
formulations = ['std', 'dual']
get_artvisc_fpts_for_inter(eidx, fidx)
get_mag_pnorms(eidx, fidx)
get_mag_pnorms_for_inter(eidx, fidx)
get_norm_pnorms(eidx, fidx)
get_norm_pnorms_for_inter(eidx, fidx)
get_ploc_for_inter(eidx, fidx)
get_scal_fpts_for_inter(eidx, fidx)
get_vect_fpts_for_inter(eidx, fidx)
opmat(expr)
ploc_at(name)
ploc_at_np(name)
plocfpts = None
static pri_to_con(pris, cfg)
privarmap = {2: ['rho', 'u', 'v', 'p'], 3: ['rho', 'u', 'v', 'w',
'p']}
rcpdjac_at(name)
rcpdjac_at_np(name)
set_backend(backend, nscalupts, nonce)
set_ics_from_cfg()
set_ics_from_soln(solnmat, solncfg)
shockvar = 'rho'
smat_at(name)
smat_at_np(name)
visvarmap = {2: {'density': ['rho'], 'pressure': ['p'],
'velocity': ['u', 'v']}, 3: {'density': ['rho'], 'pressure':
['p'], 'velocity': ['u', 'v', 'w']}}
Types of Elements are related via the following inheritance diagram:
π Interfaces π
An Interfaces holds information/data for a group of interfaces. There are four types of (non-boundary) Interfaces available in PyFR 1.5.0:
π class pyfr.solvers.euler.inters.EulerIntInters(*args, **kwargs) π
_const_mat(inter, meth)
_gen_perm(lhs, rhs)
_scal_view(inter, meth)
_scal_xchg_view(inter, meth)
_vect_view(inter, meth)
_vect_xchg_view(inter, meth)
_view(inter, meth, vshape=())
_xchg_view(inter, meth, vshape=())
π class pyfr.solvers.euler.inters.EulerMPIInters(*args, **kwargs) π
MPI_TAG = 2314
_const_mat(inter, meth)
_scal_view(inter, meth)
_scal_xchg_view(inter, meth)
_vect_view(inter, meth)
_vect_xchg_view(inter, meth)
_view(inter, meth, vshape=())
_xchg_view(inter, meth, vshape=())
π class pyfr.solvers.navstokes.inters.NavierStokesIntInters(be, lhs, rhs, elemap, cfg) π
_const_mat(inter, meth)
_gen_perm(lhs, rhs)
_scal_view(inter, meth)
_scal_xchg_view(inter, meth)
_vect_view(inter, meth)
_vect_xchg_view(inter, meth)
_view(inter, meth, vshape=())
_xchg_view(inter, meth, vshape=())
π class pyfr.solvers.navstokes.inters.NavierStokesMPIInters(be, lhs, rhsrank, rallocs, elemap, cfg) π
okay so the interface classes also rock these π
MPI_TAG = 2314
_const_mat(inter, meth)
_scal_view(inter, meth)
_scal_xchg_view(inter, meth)
_vect_view(inter, meth)
_vect_xchg_view(inter, meth)
_view(inter, meth, vshape=())
_xchg_view(inter, meth, vshape=())
and all the different types of (non-boundary) Interfaces are related via the following inheritance diagram β it's giving family reunion π³
π Backend π
A Backend holds information/data for a backend. that's it, that's the job. There are four types of Backend available in PyFR 1.5.0:
class pyfr.backends.cuda.base.CUDABackend(cfg)
_abc_impl = <_abc_data object>
_malloc_impl(nbytes)
alias(obj, aobj)
commit()
const_matrix(initval, extent=None, tags={})
kernel(name, *args, **kwargs)
lookup = None
malloc(obj, extent)
matrix(ioshape, initval=None, extent=None, aliases=None, tags={})
matrix_bank(mats, initbank=0, tags={})
matrix_rslice(mat, p, q)
name = 'cuda'
queue()
runall(sequence)
view(matmap, rmap, cmap, rstridemap=None, vshape=(), tags={})
xchg_matrix(ioshape, initval=None, extent=None, aliases=None, tags={})
xchg_matrix_for_view(view, tags={})
xchg_view(matmap, rmap, cmap, rstridemap=None, vshape=(), tags={})
class pyfr.backends.mic.base.MICBackend(cfg)
_abc_impl = <_abc_data object>
_malloc_impl(nbytes)
alias(obj, aobj)
commit()
const_matrix(initval, extent=None, tags={})
kernel(name, *args, **kwargs)
lookup = None
malloc(obj, extent)
matrix(ioshape, initval=None, extent=None, aliases=None, tags={})
matrix_bank(mats, initbank=0, tags={})
matrix_rslice(mat, p, q)
name = 'mic'
queue()
runall(sequence)
view(matmap, rmap, cmap, rstridemap=None, vshape=(), tags={})
xchg_matrix(ioshape, initval=None, extent=None, aliases=None, tags={})
xchg_matrix_for_view(view, tags={})
xchg_view(matmap, rmap, cmap, rstridemap=None, vshape=(), tags={})
class pyfr.backends.opencl.base.OpenCLBackend(cfg)
_abc_impl = <_abc_data object>
_malloc_impl(nbytes)
alias(obj, aobj)
commit()
const_matrix(initval, extent=None, tags={})
kernel(name, *args, **kwargs)
lookup = None
malloc(obj, extent)
matrix(ioshape, initval=None, extent=None, aliases=None, tags={})
matrix_bank(mats, initbank=0, tags={})
matrix_rslice(mat, p, q)
name = 'opencl'
queue()
runall(sequence)
view(matmap, rmap, cmap, rstridemap=None, vshape=(), tags={})
xchg_matrix(ioshape, initval=None, extent=None, aliases=None, tags={})
xchg_matrix_for_view(view, tags={})
xchg_view(matmap, rmap, cmap, rstridemap=None, vshape=(), tags={})
class pyfr.backends.openmp.base.OpenMPBackend(cfg)
_abc_impl = <_abc_data object>
_malloc_impl(nbytes)
alias(obj, aobj)
commit()
const_matrix(initval, extent=None, tags={})
kernel(name, *args, **kwargs)
lookup = None
malloc(obj, extent)
matrix(ioshape, initval=None, extent=None, aliases=None, tags={})
matrix_bank(mats, initbank=0, tags={})
matrix_rslice(mat, p, q)
name = 'openmp'
queue()
runall(sequence)
view(matmap, rmap, cmap, rstridemap=None, vshape=(), tags={})
xchg_matrix(ioshape, initval=None, extent=None, aliases=None, tags={})
xchg_matrix_for_view(view, tags={})
xchg_view(matmap, rmap, cmap, rstridemap=None, vshape=(), tags={})
Types of Backend are related via the following inheritance diagram: π
π₯ Pointwise Kernel Provider π₯
A Pointwise Kernel Provider produces point-wise kernels. bestie, listen β 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 1.5.0:
class pyfr.backends.cuda.provider.CUDAPointwiseKernelProvider(backend)
_abc_impl = <_abc_data object>
_build_arglst(dims, argn, argt, argdict)
_build_kernel(name, src, argtypes)
_instantiate_kernel(dims, fun, arglst)
_render_kernel(name, mod, tplargs)
kernel_generator_cls
alias of pyfr.backends.cuda.generator.CUDAKernelGenerator
register(mod)
class pyfr.backends.mic.provider.MICPointwiseKernelProvider(backend)
_abc_impl = <_abc_data object>
_build_arglst(dims, argn, argt, argdict)
_build_kernel(name, src, argtypes, restype=None)
_instantiate_kernel(dims, fun, arglst)
_render_kernel(name, mod, tplargs)
kernel_generator_cls
alias of pyfr.backends.mic.generator.MICKernelGenerator
register(mod)
class pyfr.backends.opencl.provider.OpenCLPointwiseKernelProvider(backend)
_abc_impl = <_abc_data object>
_build_arglst(dims, argn, argt, argdict)
_build_kernel(name, src, argtypes)
_instantiate_kernel(dims, fun, arglst)
_render_kernel(name, mod, tplargs)
kernel_generator_cls
alias of pyfr.backends.opencl.generator.OpenCLKernelGenerator
register(mod)
class pyfr.backends.openmp.provider.OpenMPPointwiseKernelProvider(backend)
_abc_impl = <_abc_data object>
_build_arglst(dims, argn, argt, argdict)
_build_kernel(name, src, argtypes, restype=None)
_instantiate_kernel(dims, fun, arglst)
_render_kernel(name, mod, tplargs)
kernel_generator_cls
alias of pyfr.backends.openmp.generator.OpenMPKernelGenerator
register(mod)
Types of Pointwise Kernel Provider are related via the following inheritance diagram: πΈ
β¨ 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. no cap, that's the whole pipeline π«Ά There are four types of Kernel Generator available in PyFR 1.5.0:
class pyfr.backends.cuda.generator.CUDAKernelGenerator(*args, **kwargs)
_abc_impl = <_abc_data object>
_deref_arg_array_1d(arg)
_deref_arg_array_2d(arg)
_deref_arg_view(arg)
_render_body(body)
_render_spec()
argspec()
needs_ldim(arg)
render()
class pyfr.backends.mic.generator.MICKernelGenerator(name, ndim, args, body, fpdtype)
_abc_impl = <_abc_data object>
_deref_arg_array_1d(arg)
_deref_arg_array_2d(arg)
_deref_arg_view(arg)
_render_body(body)
_render_spec_unpack()
argspec()
needs_ldim(arg)
render()
class pyfr.backends.opencl.generator.OpenCLKernelGenerator(*args, **kwargs)
_abc_impl = <_abc_data object>
_deref_arg_array_1d(arg)
_deref_arg_array_2d(arg)
_deref_arg_view(arg)
_render_body(body)
_render_spec()
argspec()
needs_ldim(arg)
render()
class pyfr.backends.openmp.generator.OpenMPKernelGenerator(name, ndim, args, body, fpdtype)
_abc_impl = <_abc_data object>
_deref_arg_array_1d(arg)
_deref_arg_array_2d(arg)
_deref_arg_view(arg)
_render_body(body)
_render_spec()
argspec()
needs_ldim(arg)
render()
Types of Kernel Generator are related via the following inheritance diagram: π¦
π PyFR-Mako π
πΈ 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
- kernel-name β name of kernel
string
- data-dimensionality β dimensionality of data
int
- argument-name β name of argument
string
- argument-intent β intent of argument
in | out | inout
- argument-attribute β attribute of argument
mpi | scalar | view
- 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
- macro-name β name of macro
string
- 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
- macro-name β name of the macro
string
- 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:
+,-,*,/β basic arithmeticsin,cos,tanβ basic trigonometric functionsexpβ exponentialpowβ powerfabsβ absolute valueoutput = ( condition ? satisfied : unsatisfied )β ternary ifminβ minimummaxβ maximum
However, conditionalifstatements, as well asfor/whileloops, are not allowed. Like, not even a little. π
β¨ Expression Substitution β¨
Mako expression substitution is your bestie for building PyFR-Mako kernel specs. A Python expression written like ${expression} gets substituted for the result when the PyFR-Mako kernel specification is interpreted at runtime. Itβs giving runtime magic, fr fr. πͺ
Example:
E = s[${ndims - 1}]
πΈ Conditionals πΈ
Mako conditionals can also facilitate PyFR-Mako kernel specification. You open them with % if condition: and close them with % endif. Important vibe check: these conditionals are evaluated when the PyFR-Mako kernel specification is interpreted at runtime β they are not embedded into the low-level kernel. No cap. π
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 too. You open them with % for condition: and close them with % endfor. Major key: such loops are unrolled when the PyFR-Mako kernel specification is interpreted at runtime β they are not embedded into the low-level kernel. Obsessed with runtime interpretation, honestly. β¨
Example:
% for i in range(ndims):
rhov[${i}] = s[${i + 1}];
v[${i}] = invrho*rhov[${i}];
% endfor
π INDICES AND TABLES π
genindexmodindexsearch
π AUTHOR π
Imperial College London
π COPYRIGHT π
2013-2019, Imperial College London
Okay bestie, thatβs the whole page! This iconic manual is from PyFR 1.5.0, dated Mar 05, 2019 β periodt. π
π
π¦ where this page comes from
- ubuntu jammy: pyfr 1.5.0-3 Β· BSD-3-Clause
- ubuntu noble: pyfr 1.5.0-3 Β· BSD-3-Clause
- π girlified by deepseek-ai/DeepSeek-V4.1-Flash on : a language model's rewrite of the original, under its terms