Crash Course

As a quick introduction we start with analyzing the Python version of such a well known OpenFOAM solver as icoFoam. In pythonFlu it comes as icoFlux, the full version of each can be seen at corresponding page. Let's start. The first line of icoFlux

from Foam import man, ref

highlights one of the most important differency between pythonFlu and the referenced OpenFOAM C++ solver defintions. pythonFlu uses special managed layer to organize its functionality in terms of function calls (with traditional input and output parameters). In its turn, referenced OpenFOAM C++ programs are defined as a set of include directives.

To see the difference let's compare the following lines:

args = ref.setRootCase( argc, argv )
runTime = man.createTime( args )
mesh = man.createMesh( runTime )
 
transportProperties, nu, p, U, phi, pRefCell, pRefValue = createFields( runTime, mesh )
cumulativeContErr = ref.initContinuityErrs()
and
#include "setRootCase.H"
#include "createTime.H"
#include "createMesh.H"
 
#include "createFields.H"
#include "initContinuityErrs.H"

pythonFlu based solvers use ref and man as a marker to highlight what kind of OpenFOAM objects it is necessary to use. While the referenced objects can be created and die strictly inside of a function body, managed objects can be freely passed and stored outside of the local execution frame. To find more about this look at the following page.

Let's write a target solver equation - $\frac{\partial \rho \mathbf{U}}{\partial t} + \nabla \cdot\phi\mathbf{U} - \nabla \cdot\mu\nabla\mathbf{U} = - \nabla p$ in pythonFlu

UEqn = man.fvm.ddt( U ) + man.fvm.div( phi, U ) - man.fvm.laplacian( nu, U )
ref.solve( UEqn == -man.fvc.grad( p ) )
and compare it with the referenced OpenFOAM version
fvVectorMatrix UEqn( fvm::ddt( U ) + fvm::div( phi, U ) - fvm::laplacian( nu, U ) );
solve( UEqn == -fvc::grad( p ) );

As we saw, pythonFlu repeats almost every line, every symbol from the corresponding OpenFOAM definition. However, there are of course some differences. The first is Python reflection of "=" operator. Here Python and C++ use different approaches. In C++ "=" operator means "assignment", when one object is copied to another. In Python the same "=" operator means "creating a new reference" to the object. pythonFlu highlights this by introduction of special member operator - "«". Compare pythonFlu code

phi << ( ref.fvc.interpolate( U ) & mesh.Sf() ) + ref.fvc.ddtPhiCorr( rUA, U, phi )
and the corresponding OpenFOAM C++ one
phi = ( fvc::interpolate( U ) & mesh.Sf() ) + fvc::ddtPhiCorr( rUA, U, phi );

Of course, this is not a big issue, but be careful with C++ "=" operators. If, you need to change the value of an existing object use its "«" member operator.

As you can see pythonFlu coding almost coincides with the referenced OpenFOAM one. Some pythonFlu C++ differences (like usage of namespaces, includes and libraries) lead to a better structured and clearer solver code definition. The differences which come from Python, C++ and SWIG wrapping natures are explicitly highlighted by "ext_" prefix.

So, once you are familiar with OpenFOAM it would be nothing for you to start using pythonFlu. To be able to program your own solver in pythonFlu terms you need to know OpenFOAM API (the referenced documentation could be found here).