Boundary and initial conditions with codeStream in OpenFOAM
Hello everybody!
For new OpenFOAM users, I’d like to talk here about one of the simple ways of customizing boundary conditions and initial conditions. Let’s have a look at this! 🙂
BC & IC in OpenFOAM : usual way of proceeding
Basically, in OpenFOAM, boundary and initial conditions are defined in the field files within the 0/ folder :
- The internalField section allows to initialize the field in the domain;
- The boundaryField section requires a choice of boundary condition for each mesh patch.
Of course, a wide range of boundary conditions are natively available, which is already sufficient for lots of applications. Concerning initial conditions, there is also the possibility to use the utility setFields in order to define non-uniform fields. But sometimes, we have to model situations requiring a more customized approach.
There are several ways of doing this, including :
- Using OpenFOAM utilities, like codeStream;
- Using an external library (the best known being swak4foam);
- Using high level programing.
Most of the time, codeStream is the simplest way to implement user boundary or initial conditions :
- It’s part of OpenFOAM;
- It’s easier than using high level programming, which requires more knowledge about OpenFOAM and C++.
The following section provides an overview of how this utility works. It should be noted than the used syntax is based on the ESI version v2312. A few minor differences can occur using other OpenFOAM variants (foundation or foam-extend version).
Using codeStream
General information
CodeStream is an utility allowing us to program directly in the input dictionaries. More generally, OpenFOAM includes the capability to compile, load and execute C++ code at run-time, and codeStream is one of the directive supporting this capability.
So #codeStream can be used in any input file for run-time compilation. The directive reads some entries to create a dynamic code which is automatically generated and copied in the directory dynamicCode, at run-time.
It should be noted that this utility can theoretically be used in any input file. However, in this article, we will focus on how to use it for coding intial and boundary conditions in the field files localized in the 0/ directory.
Implementing initial conditions with codeStream
To initialize a field, we have to complete the internalField section of the dictionary file related to this field. Let’s take an example with a pressure field, which we want to initialize as P(z) = P_0 – \rho g z , where P0 is reference pressure. The section we are interested in will look like this :
internalField #codeStream /* Use of codeStream to initialize p field */
{
codeInclude /* Headers for compilation */
#{
#include "fvCFD.H"
#};
codeOptions /* Compilation options */
#{
-I$(FOAM_SRC)/finiteVolume/lnInclude \
-I$(FOAM_SRC)/meshTools/lnInclude
#};
codeLibs /* Libraries for compilation */
#{
-lmeshTools \
-lfiniteVolume
#};
code /* User code */
#{
/* Access to internal mesh information */
const IOdictionary& d = static_cast<const IOdictionary&>(dict);
const fvMesh& mesh = refCast<const fvMesh>(d.db());
scalarField p(mesh.nCells(), 0.); /* initialization */
/* User variables initialization */
const scalar rho = 1.2;
const scalar gz = 9.81;
const scalar z0 = 0.0;
const scalar p0 = 101325;
forAll(p, i) /* Loop on elements */
{
const scalar z = mesh.C()[i][2]; /* Access to z component of cell centers coordinates */
p[i] = p0-rho*gz*(z-z0); /* Pressure assignment for all elements */
}
p.writeEntry("", os); /* Write output in the dictionary */
#};
};
To clarify some information :
- The first three sections only concern compilation. Depending on requirements, it’s obviously possible to add other files, libraries or options. But most of the time, this part can be kept as it is;
- The code section is the one to complete with the desired modelling.
Here is an overview of the obtained result in a given cubic domain :

Implementing boundary conditions with codeStream
Concerning boundary conditions, we have to define a boundary type for each mesh patch in the boundaryField section of the dictionary file, for each considered field. Let’s take an example with the velocity field, for which we want to impose a logarithmic profile at the inlet patch :
U(z) = \cfrac{U_{*}}{\kappa} ln \Big(\cfrac{z+z_0}{z_0}\Big)
where U* is the friction velocity, κ is Von Karman’s constant and z0 is the surface roughness length parameter. The inlet patch assignment will look like this :
boundaryField
{
inlet
{
type fixedValue;
value #codeStream
{
codeInclude /* Headers for compilation */
#{
#include "fvCFD.H"
#};
codeOptions */ Compilation options */
#{
-I$(FOAM_SRC)/finiteVolume/lnInclude \
-I$(FOAM_SRC)/meshTools/lnInclude
#};
codeLibs /* Libraries for compilation */
#{
-lmeshTools \
-lfiniteVolume
#};
code /* User code */
#{
*/ Access to internal mesh information */
const IOdictionary& d = static_cast<const IOdictionary&>
(
dict.parent().parent()
);
const fvMesh& mesh = refCast<const fvMesh>(d.db());
const label id = mesh.boundary().findPatchID("inlet");
const fvPatch& patch = mesh.boundary()[id];
vectorField U(patch.size(), vector(0, 0, 0)); /* initialization */
/* User variables initialization */
const scalar U_ref = -19.6; /* Reference velocity */
const scalar z_ref = 3.0; /* Reference height */
const scalar vonKarman = 0.41; /* Von Karman constant */
const scalar z_0 = 1e-3; /* Aerodynamic roughness lenght */
const scalar u_star = (U_ref*vonKarman)/log((z_ref+z_0)/z_0); /* Friction velocity */
forAll(U, i) /* Loop on elements */
{
const scalar z = patch.Cf()[i][2]; /* Access to cell centers coordinates */
U[i] = vector((u_star/vonKarman)*log((z+z_0)/z_0), 0., 0.); /* Velocity assignment */
}
U.writeEntry("", os); /* Write output in the dictionary */
#};
};
}
}
Syntax is very similar to the previous section. In this case, only access to internal mesh information differs (we have to access to boundary information of a vector field rather than cell information of a scalar field).
Conclusion
codeStream is a powerful utility, allowing to customize boundary conditions and initial conditions, while avoiding high level programming. In addition, it should be noted that concerning boundary conditions, some of existing types are derived from codeStream and work in a similar way :
- codedFixedValue;
- codedMixed;
These boundary types proposes some additional features, like an access to more information of the simulation database (e.g. time). More information can be found in references [4] and [5].
Thank you for reading this article, and for visiting this website!
About OpenFOAM
OpenFOAM (Open-source Field Operation And Manipulation) is an open-source CFD software licensed under the GNU General Public License Version 3, with a very large range of features concerning pre-processing, numerical and physics solvers, and post-processing. Three OpenFOAM variants currently coexist:
- OpenFOAM, released by OpenCFD Ltd.[1]
- OpenFOAM, released by OpenFOAM Foundation.[2]
- FOAM-Extend, released by Wikki Ltd.[3]
This post is based on the OpenFOAM variant released by OpenCFD, but the feature also exists in other forks.
