OpenFOAM Cases¶
In this chapter we will look at the file structure and organisation of OpenFOAM cases.
Normally, the name assigned to the case becomes the name of the directory in which all the case files and subdirectories are stored.
The case directories themselves can be located anywhere. But, if they are within a run subdirectory of the project directory, eg.$HOME/OpenFOAM/$[USER]-vXXXX/run, and since the $FOAM_RUN environment variable is set to this PATH by default; we can quickly move to that directory by executing a preset alias, run, at the command line.
File Structure of OpenFOAM cases¶
The most basic directory structure for an OpenFOAM case:
flowchart TD
A(case) --> B(system);
A --> C(constant);
A --> D(time directories);
B --> controlDict --> fvSchemes --> fvSolutions --> blockMeshDict;
C --> xProperties;
C --> E(polyMesh) --> boundary --> faces --> neighbour --> owner --> points;
A system directory¶
For setting parameters associated with the solution procedure itself. It contains at least the following 3 files: controlDict where run control parameters are set including start/end time, time step and parameters for data output; fvSchemes where discretisation schemes used in the solution may be selected at run-time; and, fvSolution where the equation solvers, tolerances and other algorithm controls are set for the run.
A constant directory¶
Contains a full description of the case mesh in a subdirectory polyMesh and files specifying physical properties for the application concerned, eg. transportProperties.
A time directory¶
Containing individual files of data for particular fields. The data can be: either, initial values and boundary conditions that the user must specify to define the problem; or, results written to a file by OpenFOAM. The name of each time directory is based on the simulated time at which the data is written.
The OpenFOAM fields must always be initialised, even when the solution does not strictly require it, as in steady-state problems.
It is sufficient to say now that since we usually start our simulations at time t = 0 , the initial conditions are usually stored in a directory named 0 or 0.000000e+00, depending on the name format specified. For example, in the cavity tutorial, the velocity field \(\textbf{U}\) and pressure field \(p\) are initialised from files .../0/U and .../0/p respectively.
Basic I/O file format¶
OpenFOAM needs to read a range of data structures such as strings, scalars, vectors, tensors/matricies, lists and fields. The input/output (I/O) format of files is designed to be extremely flexible to enable the modifying the I/O in OpenFOAM applications as easily as possible.
The I/O follows a simple set of rules that make the files extremely intuitive to understand.
General syntax rules¶
The format follows some of the general principles of OpenFOAM’s C++ source code.
- Files have a free form. Columns have no meaning assigned to them and continuation across lines needs no indication.
- Lines have no particular meaning, except that
//makes OpenFOAM ignore any text that follows it until the end of the line. - A comment over multiple lines is done my eclosing text between
/*and*/.
//, /* and */ are called Delimiters
Dictionaries¶
OpenFOAM uses dictionaries as the most common way of specifying data.
A Dictionary/Dict is a data structure that contains a set of data entries that can be retrieved by the I/O by specifying the keyword.
The keyword entries follow the general format:
Most entries, however, are single data entries:
Most OpenFOAM data files are dictionaries themselves. The format for a dictionary, in this case, is to specify the dictionary name followed the entries enclosed in curly braces {} as follows:
Dictionaries provide the means for organising entries into logical categories and can be specified hierarchically so that any dictionary can itself contain one or more dictionary entries.
The data file header¶
All data files read and written by OpenFOAM begin with a dictionary named FoamFile containing a standard set of keyword entries:
| Keyword | Description | Entry |
|---|---|---|
version |
I/O format version | 2.0 |
format |
Data format | ascii/binary |
location |
PATH to the file, in “…” | (optional) |
class |
OpenFOAM class constructed from the concerned data file | typicaly dictionary or a field, eg. volVectorField |
object |
Filename | eg. controlDict |
The class entry is the name of the C++ class in the OpenFOAM library that will be constructed from the data in the file. Without knowledge of the underlying code which calls the file to be read, and knowledge of the OpenFOAM classes, the user will probably be unable to surmise the class entry correctly. However, most data files with simple keyword entries are read into an internal dictionary class and therefore the class entry is dictionary in those cases.
The extract, below, from an fvSolution dictionary file, contains 2 dictionaries, solvers and PISO.
17
18solvers
19{
20 p
21 {
22 solver PCG;
23 preconditioner DIC;
24 tolerance 1e-06;
25 relTol 0.05;
26 }
27
28 pFinal
29 {
30 $p;
31 relTol 0;
32 }
33
34 U
35 {
36 solver smoothSolver;
37 smoother symGaussSeidel;
38 tolerance 1e-05;
39 relTol 0;
40 }
41}
42
43PISO
44{
45 nCorrectors 2;
46 nNonOrthogonalCorrectors 0;
47 pRefCell 0;
48 pRefValue 0;
49}
50
51
52// ************************************************************************* //
The solvers dictionary contains multiple data entries for the solver to be used and tolerances for each of the pressure and velocity equations, represented by the p and U keywords respectively. The PISO dictionary contains algorithm controls.
The PISO algorithm (Pressure Implicit with Splitting of Operators) is an efficient method to solve the Navier-Stokes equations in unsteady problems.
Lists¶
OpenFOAM applications contain lists, eg. a list of vertex coordinates for a mesh description. Lists are commonly found in I/O and have a format of their own in which the entries are contained within parentheses ( ).
There is also a choice of format preceeding the parentheses:
The keyword is followed by the number of elements <n> in the list;
The keyword is followed by a class name identifier label <type>. Where, <type> states what the list contains;
<scalar> in List<scalar> is not a generic name but the actual text that should be entered.
This example is for a list of scalar elements, for a list of vector elements use List<vector>
The simple format is a convenient way of writing a list. The other formats allow the code to read the data faster since the size of the list can be allocated to memory in advance of reading the data.
The simple format is therefore preferred for short lists, where read time is minimal, and the other formats are preferred for long lists.
Scalars, Vectors and Tensors¶
A scalar is a single number represented as suck in a data file.
A vector is a VectorSpace of rank 1 and dimension 3. A vector is written;
Since the number of elements in a vector is always fixed to 3, the simple List format is used.
A tensor is a VectorSpace of rank 2 and dimension 3, therefore data entries are always fixed to 9 real numbers. The identity tensor can be written as;
A Tensor is just a Matrix.
A VectorSpace is a set whose elements, vectors, can be added together and multiplied, scaled, by scalars. The dimension of a VectorSpace is the number of vectors in any basis for the space to be spanned, represents the ‘3’ in ‘3D’. The rank is the dimension of the column space.
Dimensional Units¶
In contiuum mechanics, properties are represented in some chosen units. Algebraic operations must be performed on these properties using consistent units of measurement; in particular, addition, subtraction and equality are only physically meaningful for properties of the same dimensional units. As a safeguard against implementing a meaningless operation, OpenFOAM attaches dimensions to field data and physical properties and performs dimension checking on any tensor operation.
The I/O format for a dimensionSet is 7 scalars delimited by square brackets;
Where each of the values in the dimensionSet correspond to the power of each of the base units of measurements;
| No. | Property | SI Unit |
|---|---|---|
| 1 | Mass | kilogram (kg) |
| 2 | Length | metre (m) |
| 3 | Time | second (s) |
| 4 | Temperature | Kelvin (K) |
| 5 | Quantity | kilogram-mole (kgmol) |
| 6 | Current | ampere (A) |
| 7 | Luminous Intensity | candela (cd) |
We can now see that [0 2 -1 0 0 0 0] corresponds to \(m^2 s^{-1}\) (kinematic viscosity, \(\nu\) ).
Dimensioned Types¶
Physical properties are typically specified with their associated dimensions. These entries have the format that the following example of a dimensionedScalar demonstrates:
nu is the keyword; the next entry is the dimensionSet; the final entry is the scalar value
Fields¶
Much of the I/O data in OpenFOAM are tensor fields that are read from and written into the time directories. OpenFOAM writes field data using keyword entries;
| Keyword | Description | Example |
|---|---|---|
dimensions |
Dimensions of field | [1 1 -2 0 0 0 0] |
internalField |
Value of internal field | uniform (1 0 0) |
boundaryField |
Boundary Field | see note below |
The boundaryField is a dictionary containing a set of entries whose names correspond to each of the names of the boundary patches listed in the boundary file in the polyMesh directory. Each patch entry is itself a dictionary containing a list of keyword entries. The compulsory entry, type, describes the patch field condition specified for the field. The remaining entries correspond to the type of patch field condition selected and can typically include field data specifying initial conditions on patch faces (covered later)
The data begins with an entry for its dimensions. Following that, is the internalField, described in one of two ways;
An example set of field dictionary entries for velocity U are below:
17dimensions [0 1 -1 0 0 0 0];
18
19internalField uniform (0 0 0);
20
21boundaryField
22{
23 movingWall
24 {
25 type fixedValue;
26 value uniform (1 0 0);
27 }
28
29 fixedWalls
30 {
31 type noSlip;
32 }
33
34 frontAndBack
35 {
36 type empty;
37 }
38}
39
40// ************************************************************************* //
Directives and Macro Substitutions¶
There is additional file syntax that offers great flexibility for the setting up of OpenFOAM case files, namely directives and macro substitutions.
Directives are commands that can be contained within case files that begin with the hash (#) symbol.
Macro substitutions begin with the dollar ($) symbol.
At present there are 4 directive commands available:
Has the following options:
Removes any included keyword entry; takes either a word or regular expression
Followed by verbatim C++ code, compiles, loads and executes the code on-the-fly to generate the entry.
The #include and #inputMode Directives¶
For example, let us say we wish to set an initial value of pressure once to be used as the internal field and initial value at a boundary. We could create a file, initialConditions, which contains the following entries:
p:
#include "initialConditions"
internalField uniform $pressure;
boundaryField
{
patch1
{
type fixedValue;
value $internalField;
}
}
This is a fairly trivial example that simply demonstrates how this functionality works. However, the functionality can be used in many, more powerful ways particularly as a means of generalising case data to suit our needs. For example, if we have a set of cases that require the same RAS turbulence model settings, a single file can be created with those settings which is simply included in the turbulenceProperties file of each case. Macro substitutions can extend well beyond a single value so that, for example, sets of boundary conditions can be predefined and called by a single macro. The extent to which such functionality can be used is almost endless.
The #codeStream Directive¶
The #codeStream directive takes C++ code which is compiled and executed to deliver the dictionary entry. The code and compilation instructions are specified through the following keywords:
-
code: specifies the code, called with argumentsOStream& osandconst dictionary& dictwhich the user can use in the code, eg. to lookup keyword entries from within the current case dictionary (file). -
codeInclude(optional): specifies additional C++#includestatements to include OpenFOAM files. -
codeOptions(optional): specifies any extra compilation flags to be added toEXE_INCin Make/options. -
codeLibs(optional): specifies any extra compilation flags to be added toLIB_LIBSin Make/options.
Code, like any string, can be written across multiple lines by enclosing it within hash-bracket delimiters,#{ … #}. Anything in between these delimiters becomes a string with all newlines, quotes, etc. preserved.
An example of #codeStream is given below. The code in the controlDict file looks up dictionary entries and does a simple calculation for the write interval: