openFoamUserManual PFM
openFoamUserManual PFM
A little User-Manual
Gerhard Holzinger∗ †
25th February 2022
Abstract
This document is a collection of my own experience on learning and using OpenFOAM. Herein, knowledge
and background information is assembled which may be useful to others when learning to use OpenFOAM.
WARNING:
During the assembly of this manual OpenFOAM and other tools, e.g. pyFoam, have been continuously
updated. This manual was started with OpenFOAM-2.0.x installed and over the time the author has
worked with all major point releases of OpenFOAM and the development versions. Consequently it is
possible that some parts may be outdated by the time you read this. Furthermore, functionalities may have
been extended, modified or superseded. Nevertheless, this manual is intended to cast some light on the inner
workings of OpenFOAM and explain the usage in a rather practical way.
Furthermore, this document is, and will always be, work in progress. As it is extended whenever something
interesting is encountered or learned, parts of the document will always be fragmentary. All errors and
omissions are the sole product of the author.
All information contained in this manual can be found in the internet (http://www.openfoam.org, http:
//www.cfd-online.com/Forums/openfoam/); in the source code of OpenFOAM, or it was gathered by trial
and error (What happens if ...? Why did that happen?!). All errors in this manual are the solely the
product of the author. The interested reader is invited to contact the author to point out any discovered
errors.
This offering is not approved or endorsed by ESI® Group, ESI-OpenCFD® or the OpenFOAM®
Foundation, the producer of the OpenFOAM® software and owner of the OpenFOAM® trademark.
1
Contents
1 Getting help 16
2 Lessons learned 17
2.1 Philosophy . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 17
2.2 Learning by using OpenFOAM . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 18
2.3 Learning by tinkering with OpenFOAM . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 19
I Installation 20
3 Install OpenFOAM 20
3.1 Prerequistes . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 20
3.2 Download the sources . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 20
3.3 Compile the sources . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 21
3.4 Install paraView . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 21
3.5 Remove OpenFOAM . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 21
3.6 Install several versions of OpenFOAM . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 22
This offering is not approved or endorsed by ESI® Group, ESI-OpenCFD® or the OpenFOAM®
2
Foundation, the producer of the OpenFOAM® software and owner of the OpenFOAM® trademark.
11 Controlling OpenFOAM 42
11.1 The means of exerting control . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 42
11.2 Syntax of the dictionaries . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 43
11.3 The controlDict . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 45
11.4 Run-time modifcations of dictionaries . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 50
11.5 The fvSolution dictionary . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 51
11.6 Command line arguments . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 51
12 Usage of OpenFOAM 52
12.1 Use OpenFOAM . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 52
12.2 Abort an OpenFOAM simulation . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 54
12.3 Terminate an OpenFOAM simulation . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 54
12.4 Continue a simulation . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 58
12.5 Do parallel simulations with OpenFOAM . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 58
12.6 Using tools . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 62
12.7 Using OpenFOAM on a local machine and a cluster . . . . . . . . . . . . . . . . . . . . . . . 63
12.8 Using scripts to run OpenFOAM . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 63
III Pre-processing 65
13 Mesh basics 66
13.1 Basics of the mesh . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 66
13.2 General advice on meshing and mesh/case manipulation . . . . . . . . . . . . . . . . . . . . . 67
13.3 General mesh-related topics . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 68
15 blockMesh 72
15.1 The block . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 72
15.2 The blockMeshDict . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 73
15.3 Create multiple blocks . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 84
15.4 Grading . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 85
15.5 Parametric meshes by the help of m4 and blockMesh . . . . . . . . . . . . . . . . . . . . . . . 88
15.6 Trouble-shooting . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 93
16 snappyHexMesh 95
16.1 Documentation . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 95
16.2 Work flow . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 95
16.3 Example: Bath Tub . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 95
17 foamyHexMesh 99
17.1 Crude comparison between a snappy and a foamy bath tub . . . . . . . . . . . . . . . . . . . 99
18 cfMesh 101
18.1 Usage . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 101
19 checkMesh 104
19.1 Definitions . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 104
19.2 Pitfalls . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 110
19.3 Useful output . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 114
20 extrudeMesh 116
20.1 Control . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 116
20.2 Extruding 2-D meshes . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 119
21 polyDualMesh 123
22 combinePatchFaces 126
This offering is not approved or endorsed by ESI® Group, ESI-OpenCFD® or the OpenFOAM®
3
Foundation, the producer of the OpenFOAM® software and owner of the OpenFOAM® trademark.
23 Salome 127
23.1 Export & Conversion . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 127
23.2 Combined operations: blockMesh & salome . . . . . . . . . . . . . . . . . . . . . . . . . . . . 129
23.3 Meshing tips for Salome . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 131
24 Gmsh 136
25 enGrid 137
IV Modelling 172
31 Solution dimensions 172
31.1 Basic rules for simulations with reduced solution dimensions . . . . . . . . . . . . . . . . . . . 172
32 Turbulence-Models 175
32.1 Organisation . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 175
32.2 Reynolds averaged models (RAS) . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 180
32.3 Categories . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 181
32.4 RAS-Models . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 181
32.5 LES-Models . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 183
32.6 Pitfalls . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 183
This offering is not approved or endorsed by ESI® Group, ESI-OpenCFD® or the OpenFOAM®
4
Foundation, the producer of the OpenFOAM® software and owner of the OpenFOAM® trademark.
33 Thermophysical modelling 187
33.1 The modelling framework . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 187
33.2 Model selection . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 191
33.3 transport models . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 192
33.4 thermo . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 194
33.5 equationOfState . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 196
33.6 Energy . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 197
33.7 Thermophysical properties . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 198
33.8 Mixture . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 198
33.9 Model combination . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 200
33.10Solids : Thermophysical modelling . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 200
33.11Density: modelling degrees of (in-)compressibility . . . . . . . . . . . . . . . . . . . . . . . . . 203
33.12Under pressure: setting a reference . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 204
V Solver 250
This offering is not approved or endorsed by ESI® Group, ESI-OpenCFD® or the OpenFOAM®
5
Foundation, the producer of the OpenFOAM® software and owner of the OpenFOAM® trademark.
41 Solution Algorithms 250
41.1 SIMPLE . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 250
41.2 PISO . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 252
41.3 PIMPLE . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 252
41.4 Block-coupled solution . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 252
42 pimpleFoam 253
42.1 Governing equations . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 253
42.2 The PIMPLE Algorithm – or, what’s under the hood? . . . . . . . . . . . . . . . . . . . . . . 255
43 rhoPimpleFoam 261
43.1 General remarks . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 261
43.2 Solution algorithm . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 261
43.3 Governing equations . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 261
44 twoPhaseEulerFoam 262
44.1 General remarks . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 262
44.2 Solver algorithm . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 262
44.3 Momentum exchange between the phases . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 264
44.4 Kinetic Theory . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 267
45 twoPhaseEulerFoam-2.3 268
45.1 Physics . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 268
45.2 Naming scheme . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 268
45.3 Solver capabilities . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 269
45.4 Turbulence models . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 269
45.5 Energy equation . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 276
45.6 Momentum equation . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 277
45.7 Interfacial interaction . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 278
45.8 Interfacial momentum exchange . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 282
45.9 MRF method - avoiding errors . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 288
46 reactingTwoPhaseEulerFoam 289
46.1 Solver basics . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 289
46.2 Phase modelling . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 289
46.3 Turbulence modelling . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 291
46.4 Interfacial momentum exchange . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 291
47 multiphaseEulerFoam 291
47.1 Fields . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 291
47.2 Momentum exchange . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 292
48 driftFluxFoam 293
48.1 Governing equations . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 293
48.2 incompressibleTwoPhaseInteractingMixture . . . . . . . . . . . . . . . . . . . . . . . . . . 295
48.3 Mixture viscosity models . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 295
48.4 Relative velocity models - hindered settling . . . . . . . . . . . . . . . . . . . . . . . . . . . . 297
48.5 settlingFoam . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 299
VI Postprocessing 301
49 functions 302
49.1 Stay up to date . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 302
49.2 Definition . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 302
49.3 Control . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 303
49.4 probes . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 304
49.5 fieldAverage . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 306
49.6 faceSource . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 307
49.7 cellSource . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 309
49.8 readFields . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 309
49.9 writeObjects . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 310
49.10Execute C++ code as functionObject . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 310
49.11wallHeatFlux . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 311
This offering is not approved or endorsed by ESI® Group, ESI-OpenCFD® or the OpenFOAM®
6
Foundation, the producer of the OpenFOAM® software and owner of the OpenFOAM® trademark.
49.12Execute functions after a simulation has finished . . . . . . . . . . . . . . . . . . . . . . . . . 312
50 sample 313
50.1 Usage . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 313
50.2 sampleDict . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 313
50.3 Update OpenFOAM-4 . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 316
51 ParaView 317
51.1 Reader’s choice . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 317
51.2 View the mesh . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 319
51.3 Saving animations . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 322
51.4 Case manipulation using ParaView . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 323
52 postProcess 326
52.1 Usage . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 326
54 swak4foam 336
54.1 Installation . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 336
54.2 simpleSwakFunctionObjects . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 336
55 blockMeshDG 338
55.1 Installation . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 338
55.2 Usage . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 338
55.3 Pitfalls . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 338
This offering is not approved or endorsed by ESI® Group, ESI-OpenCFD® or the OpenFOAM®
7
Foundation, the producer of the OpenFOAM® software and owner of the OpenFOAM® trademark.
57.14Math-like syntax in OpenFOAM . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 387
IX Theory 396
60 Discretization 397
60.1 Temporal discretization . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 397
60.2 Spatial discretization . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 397
60.3 Continuity error correction . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 397
X Appendix 435
67 Useful Linux commands 435
67.1 Getting help . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 435
67.2 Finding files . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 435
67.3 Find files and scan them . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 436
67.4 Scan a log file . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 436
67.5 Running in scripts . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 437
67.6 diff . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 438
This offering is not approved or endorsed by ESI® Group, ESI-OpenCFD® or the OpenFOAM®
8
Foundation, the producer of the OpenFOAM® software and owner of the OpenFOAM® trademark.
67.7 Case setup . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 439
67.8 Miscellaneous . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 439
Bibliography 443
This offering is not approved or endorsed by ESI® Group, ESI-OpenCFD® or the OpenFOAM®
9
Foundation, the producer of the OpenFOAM® software and owner of the OpenFOAM® trademark.
List of Figures
1 Initializing a new git repository. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 27
2 Pointing the new git repository to the proper remote repository. . . . . . . . . . . . . . . . . . . 28
3 Updating the new git repository by pulling from the remote repository. . . . . . . . . . . . . . . . 28
4 Updating the local files of our OpenFOAM-6 installation. . . . . . . . . . . . . . . . . . . . . . . 28
5 The top face of the generic block of Figure 8 . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 66
6 The same axi-symmetric two-dimensional viewed with three different installations of ParaView. . 69
7 The STL mesh of a circular area generated by OpenSCAD . . . . . . . . . . . . . . . . . . . . . . 71
8 The generic block . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 72
9 Creating a wedge geometry for 2D, axisymmetric domains. Reproduced after [52]. . . . . . . . . 75
10 A block with a poly-line at the left side. The red line indicates the poly-line. This figure makes
it obvious that edges defines in the blockMeshDict serve to compute the locations of the block’s
internal nodes. The block itself however, does not obey the poly-line. . . . . . . . . . . . . . . . . 78
11 The initial velocity field depending on the order of the wall and banana. Left: Setting as in
Listing 108. Right: wall and banana have changed places. . . . . . . . . . . . . . . . . . . . . . 81
12 The mesh of two merged blocks . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 83
13 The mesh of two merged blocks. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 83
14 Two connected blocks . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 84
15 Two unconnected blocks . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 85
16 The mesh of a stirred tank with a Rushton impeller, stator baffles and an aeration device. . . . . 91
17 The blocks of a parametric mesh consisting of nine blocks. . . . . . . . . . . . . . . . . . . . . . . 94
18 A bath tub. The outlet patch is marked grey at the very bottom of the drain tube. . . . . . . . . 96
19 A badly chosen featureAngle causes snappy to add incomplete boundary layers. . . . . . . . . . 96
20 The boundary layers added by snappy. On the left, layer addition went as we intended it to do; on
the right, we see the effect of the (missing) keyword slipFeatureAngle of the addLayersControls
dictionary of snappyHexMeshDict. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 97
21 A collapsing boundary layer. Maybe we did not want the mesh that way, however, we told snappy
to create it exactly that way. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 98
22 A bath tub with a background mesh enclosing the STL-surface of the bath tub. . . . . . . . . . . 99
23 SnappyBathTub . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 99
24 FoamyBathTub . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 100
25 Poor feature edge resolution caused by not providing information on feature edges. Note, the
whole geometry is bounded by a single patch. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 102
26 Resolved feature edge of the bath tub. In this case, the boundary consists of two patches: the
top surface and the rest. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 103
27 Definition of non-orthogonality for internal faces . . . . . . . . . . . . . . . . . . . . . . . . . . . 104
28 Definition of non-orthogonality for boundary faces . . . . . . . . . . . . . . . . . . . . . . . . . . 105
29 Definition of skewness of internal faces . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 106
30 Definition of skewness of boundary faces . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 108
31 Face warpage . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 109
32 A distorted mesh . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 111
33 The cells with two internal faces in an all-tet, 3D-mesh. . . . . . . . . . . . . . . . . . . . . . . . 113
34 The under-determined cells, which were found by checkMesh in the mesh of an axi-symmetric
simulation. These cells are on a far corner of the 2-D domain, and grading towards the more
interesting regions led them to have a high aspect ratio. In fact, these cells have the highest
aspect ratio of the whole mesh. The proximity to the lower wall results in these cells to be
quite fine in the y-direction. Since, these cells are furthest from the axis of symmetry, they are
relatively large in radial and tangential direction. . . . . . . . . . . . . . . . . . . . . . . . . . . . 114
35 Sets created by checkMesh in the sets directory. . . . . . . . . . . . . . . . . . . . . . . . . . . . 115
36 Extrude the wall patch from a cylinder mesh. left: constructFrom mesh. right: constructFrom
patch. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 116
37 The mesh for a 2D study generated from an STL surface. . . . . . . . . . . . . . . . . . . . . . . 117
38 A cheap 90° pipe bend. The outlet patch of the original mesh was extruded along the sector of
a circle. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 118
39 Subsequent mesh extrusions: sector, linearNormal and linearDirection. . . . . . . . . . . . . 118
40 Grow a wall! The walls patch of the pipe mesh was extruded using the linearNormal model. . . 119
This offering is not approved or endorsed by ESI® Group, ESI-OpenCFD® or the OpenFOAM®
10
Foundation, the producer of the OpenFOAM® software and owner of the OpenFOAM® trademark.
41 Snappy two-dimensional meshing. The side patch of a snappy mesh was extruded using the
linearNormal model, with the base mesh being discarded. Thus, we remain with a snappy-like
mesh for the two-dimensional flow around a cylinder. . . . . . . . . . . . . . . . . . . . . . . . . . 119
42 Extruding a slice. Left: a 1 degree sector extrusion, Right: a 5 degrees sector extrusion. . . . . 120
43 Extruding the mesh for a 2-D slice of a hollow sphere. . . . . . . . . . . . . . . . . . . . . . . . . 120
44 Creating an axi-symmetric mesh by extruding a patch (the patch front shown in blue). . . . . . . 122
45 Connecting the centers of the circumcircles produces the Voronoi diagram (in red). Source https:
//commons.wikimedia.org/wiki/File:Delaunay_Voronoi.svg. . . . . . . . . . . . . . . . . . . 123
46 The mesh of the elbow tutorial case; before and after the application of polyDualMesh. . . . . . . 124
47 The mesh of the bubble column tutorial case; before and after the application of polyDualMesh. . 124
48 The dual mesh of a single tetrahedron: the original tet-cell is outlined in blue, the face-decomposition
is outlined in black, and one of the resulting cells is shown in grey. . . . . . . . . . . . . . . . . . 125
49 The dual mesh of a single hexahedron: the original hex-cell is outlined in blue, the face-decomposition
is outlined in black, and one of the resulting cells is shown in grey. . . . . . . . . . . . . . . . . . 125
50 The dual mesh of the elbow tutorial case; before and after the application of combinePatchFaces.126
51 Mesh export issue in Salome with the UNV format. . . . . . . . . . . . . . . . . . . . . . . . . . . 127
52 A big simulation domain with a quite small geometric feature: the geometry. . . . . . . . . . . . 129
53 A big simulation domain with a quite small geometric feature: the blockMesh-only mesh. . . . . . 129
54 The mesh of the cut-out block in salome. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 130
55 Meshing of a block in salome. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 130
56 Combining blockMesh and salome: the meshed block was re-combined with the initial mesh. . . . 131
57 A complex geometry warranting a complex meshing work-flow. Two pipe coils respresent a heat-
exchanger in a box-shaped vessel. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 132
58 The geometry of a pipe, both ends of a single coil are visible. The geometry was created by
extruding a face along a path. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 132
59 Left: insufficiently guided extrusion. Right: extrusion with proper guidance. . . . . . . . . . . . . 133
60 Extrusion gone bad: the inner and outer surface of the pipe, shown in grey and red. Cells with
negative volume are shown in green. Note the vertices on the inner and the outer surfaces. . . . . 133
61 An extruded 2D mesh of quad elements created with Gmsh. . . . . . . . . . . . . . . . . . . . . . 136
62 Meshes by enGrid: left: tet-mesh with prismatic boundary layer, right: polyhedral mesh with
boundary layer. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 137
63 The entry for groups of edges in the object browser of Salome. . . . . . . . . . . . . . . . . . . . 139
64 The extruded mesh of a heat-exchanger coil . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 140
65 A faulty cell set definition. The red cells are part of the cell set. All other cells are blue. . . . . . 143
66 An example of a refined mesh. The refined region is marked in red. . . . . . . . . . . . . . . . . . 144
67 The base mesh for the wall layer refinement. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 145
68 Applying the wall layer refinement once. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 145
69 Applying the wall layer refinement a second time. . . . . . . . . . . . . . . . . . . . . . . . . . . . 145
70 Applying the wall layer refinement twice on the horizontal patch at a concave edge. . . . . . . . . 146
71 Applying the wall layer refinement twice on both patches of a convex edge. . . . . . . . . . . . . 146
72 Applying the wall layer refinement twice on one patch of a convex edge. . . . . . . . . . . . . . . 146
73 Applying the wall layer refinement successively on two patches of a convex edge. This approach
leads to a different outcome than the one shown in Figure 71. . . . . . . . . . . . . . . . . . . . . 147
74 A simple mesh with 8 cells and different cell labelling schemes. . . . . . . . . . . . . . . . . . . . 148
75 The connectivity graph of our mesh. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 148
76 The matrix structure of the connectivity graph of Figure 75 . . . . . . . . . . . . . . . . . . . . . 148
77 Scrambled cell sets caused by mesh renumbering . . . . . . . . . . . . . . . . . . . . . . . . . . . 149
78 Renumbering the solution of the cavity case: the case was run, and all time steps prior to 0.3
were deleted. Then renumberMesh -overwrite was run. As 0.3 was the first time step, the fields
in the time step 0.3 were renumbered along with the mesh. The later time steps, however, were
left untouched. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 150
79 A tet-decomposed tetrahedron: the original tet-cell is outlined in blue, the face-decomposition is
outlined in black, and one of the resulting sub-tets is shown in grey. . . . . . . . . . . . . . . . . 152
80 A tet-decomposed hexahedron: the original hex-cell is outlined in blue, the face-decomposition
is outlined in black, and one of the resulting sub-tets is shown in grey. . . . . . . . . . . . . . . . 153
This offering is not approved or endorsed by ESI® Group, ESI-OpenCFD® or the OpenFOAM®
11
Foundation, the producer of the OpenFOAM® software and owner of the OpenFOAM® trademark.
81 The cell distribution of a multi-region case, with 2 regions and 4 sub-domains for parallel pro-
cessing. The small region outlined in white is the solid region, the surrounding larger region is
the fluid region of this case. Each sub-domain (colour-coded from 0 to 3) is assigned a chunk of
each region. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 153
82 A cellSet after running mirrorMesh to mirror the mesh using the x − y plane. . . . . . . . . . . . 155
83 The mapped field . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 164
84 The unmapped fields . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 166
85 Established flow and modified boundary condition . . . . . . . . . . . . . . . . . . . . . . . . . . 168
86 The class hierarchy of the basis of the old turbulence model framework. . . . . . . . . . . . . . . 176
87 The class hierarchy of the basis of the new turbulence model framework. . . . . . . . . . . . . . . 177
88 The (templated) class hierarchy of the new turbulence model framework. . . . . . . . . . . . . . . 178
89 The class hierarchy of the elementary turbulence models of the new turbulence model framework. 179
90 The class hierarchy of a selection of turbulence models of the new turbulence model framework. . 180
91 The class hierarchy of the basis of the thermophysical modelling framework in OpenFOAM-7. . . 188
92 The class hierarchy of the templated classes of the thermophysical modelling framework in
OpenFOAM-7. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 191
93 The dynamic viscosity of nitrogen: the model coefficients were fitted to data reporded in [16],
the model is compared to values reported in [2]. . . . . . . . . . . . . . . . . . . . . . . . . . . . . 192
94 The thermal conductivity of nitrogen: the model is using a modified Eucken correlation with the
viscosity model, which was fitted to viscosity data reporded in [16], the model is compared to
values of thermal conductivity reported in [2, 16]. . . . . . . . . . . . . . . . . . . . . . . . . . . . 193
95 The viscosity of a fluid and the viscosity computed by the WLF and Andrade models fitted to
the data. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 194
96 Specific heat capacity Cp of air computed with the JANAF model compared to data from [64]. . 196
97 The thermal conductivity of nickel: data from literature [29], and the available, fitted models of
OpenFOAM. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 202
98 Two rows of warm pipes in a fluid domain. The mesh is a hybrid mesh consisting of hexahedral
and prismatic cells, which was created by extruding a mixed tet-quad mesh. . . . . . . . . . . . . 205
99 Onset of natural convection: both cases feature a quite similar velocity field. . . . . . . . . . . . . 205
100 On-going development of natural convection: the flow field on the right shows developing errors
in the flow caused by the pressure boundary condition. . . . . . . . . . . . . . . . . . . . . . . . . 206
101 Further development of natural convection: in the flow field on the right, the errors in the flow
field now outweigh the proper flow. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 206
102 The result of faceAgglomerate and viewFactorGen applied to a slightly refined cavity case.
The patches movingWall and fixedWalls have both been agglomerated, i.e. for the purposes of
computing the view factor, several faces of a patch form a coarsened face. This is evident from
the visualisation of the rays created by viewFactorGen, each bundle of rays starts from the center
of such a coarsened face. The colour of the rays is a mere ID, not the actual view factor. . . . . . 209
103 One of the aggressively agglomerated faces: On the right boundary the temperature is 300 K,
yet the radiative heat-flux computed by the mean temperature cools the solid down to 165 K,
which is very unphysical for a case that computes a heated solid interacting with a body of gas.
No cooling should occur at all. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 211
104 Modelling approach on the example of a gas-liquid two-phase system. . . . . . . . . . . . . . . . 213
105 Modelling approach on the example of a gas-liquid two-phase system. . . . . . . . . . . . . . . . 221
106 Our simulation domain. The block structure of outer domain, in blue, does not match the block
structure of the inner domain, in red. However, by keeping the two regions separate, we cen mesh
each region individually, which is fairly easy, and use AMI to essentially connect the two regions.
After meshing, we can rotate the inner domain with respect to the outer domain to change the
orientation of the triangle in the center of the inner domain. . . . . . . . . . . . . . . . . . . . . . 228
107 Varying the orientation of the investigated body. Since the body-fitting mesh of the inner domain
is in an over-all cylindrical shape, we simply can rotate the inner domain with respect to the outer
domain, to change the orientation of the investigated body with respect to the incident flow. After
creating the mesh, we can use moveMesh to rotate the inner domain. With appropriate settings
for the angular velocity and the write interval, we can get a mesh for any orientation of the
triangular prism. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 229
108 A 2D simulation of the triangular, prismatic body in laminar cross-flow using AMI to connect
the body fitted mesh of the inner region with the mesh of the outer domain. . . . . . . . . . . . . 229
This offering is not approved or endorsed by ESI® Group, ESI-OpenCFD® or the OpenFOAM®
12
Foundation, the producer of the OpenFOAM® software and owner of the OpenFOAM® trademark.
109 A simulation domain with two unconnected regions. Note that the inner region only partially
fills the void of the outer region. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 230
110 The inner domain in more detail. The block-structure of the inner domain is clearly recognizable.
The remaining void is the body under investigation, in this case a semi-cylinder. . . . . . . . . . 230
111 A 2D simulation of the semi-cylinder in laminar cross-flow using ACMI to connect the mesh of
the inner region with the mesh of the outer domain. . . . . . . . . . . . . . . . . . . . . . . . . . 231
112 A baffled stirred tank with a Rushton impeller. The stator patch is shown in grey and the rotor
patch is shown in red. The white wireframe shows the boundary of the rotor zone. For all cells
of the rotor zone the MRF method is applied. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 233
113 Half a baffled stirred tank with a Rushton impeller. The cyclic-type patches are shown as
coloured wireframes, and all other patches are shown as coloured surfaces. . . . . . . . . . . . . . 233
114 Schematic diagrams of doubly-linked lists. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 242
115 The class hierarchy needed for intrusive lists of objects of type T; . . . . . . . . . . . . . . . . . . 243
116 The class hierarchy of the class basicKinematicCloud. . . . . . . . . . . . . . . . . . . . . . . . 244
117 A simplified sequence diagram of a call to evolve() from DPMFoam. . . . . . . . . . . . . . . . . . 246
118 A set of polygons has been defined to count and remove traversing particles. In this case of a
cylinder in laminar cross-flow, particles are inserted through the inlet patch. The ParticleCollector
cloud function object was set to remove all counted particles, which is clearly visible in this snapshot.249
119 Flow chart of the SIMPLE algorithm . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 251
120 Flow chart of the PISO algorithm . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 252
121 Flow chart of the PIMPLE algorithm . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 256
122 Flow chart of the main loop of twoPhaseEulerFoam . . . . . . . . . . . . . . . . . . . . . . . . . . 263
123 Flow chart of the operations in alphaEqn.H . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 265
124 Air volume fraction of the bubble column. Initial field (left) and solution at t = 10 s (right). . . . 275
125 Linear blending: f1 over α . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 281
126 Hyperbolic blending: f1 over α . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 282
127 Velocity vectors of the gaseous phase at the inlet boundary (red vectors) in an aerated stirred
tank. That the gas inlet boundary lies within the MRF zone. On the left, we see the initial
condition and on the right we see the boundary condition after the constraints by the MRF
method have been applied. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 288
128 A part of the directory tree after the simulation ended . . . . . . . . . . . . . . . . . . . . . . . . 305
129 The content of the postProcessing folder . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 309
130 Directory tree after compilation of a coded functionObject . . . . . . . . . . . . . . . . . . . . . . 311
131 Launching ParaView with OpenFOAM’s reader for OpenFOAM cases. . . . . . . . . . . . . . . . 317
132 Launching ParaView with its native reader for OpenFOAM cases. . . . . . . . . . . . . . . . . . 318
133 Using ParaView with its native reader to read a multi-region OpenFOAM case. . . . . . . . . . . 318
134 The case directories of a decomposed, multi-region case with the initial mesh still present. This
directory tree was generated by calling the following command from the case directory: tree -L
3 -d . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 319
135 Select the proper representation to view the mesh . . . . . . . . . . . . . . . . . . . . . . . . . . . 320
136 Viewing a polyhedral mesh with ParaView’s standard settings. . . . . . . . . . . . . . . . . . . . 320
137 Viewing a polyhedral mesh with adjusted settings. . . . . . . . . . . . . . . . . . . . . . . . . . . 321
138 Viewing a polyhedral mesh with ParaView’s native OpenFOAM reader. . . . . . . . . . . . . . . 321
139 Selecting the file name for the animation. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 322
140 The Tetrahedralize filter of ParaView takes no user input. . . . . . . . . . . . . . . . . . . . . . . 323
141 Left: an extruded mesh created from an STL surface mesh. Right: the mesh after tetrahedralisation.324
142 Exporting data from ParaView using the Save Data command from the File menu. . . . . . . . . 324
143 Export data from ParaView in the Legacy VTK format. . . . . . . . . . . . . . . . . . . . . . . . 325
144 The Courant number plotted with pyFoamPlotWatcher. . . . . . . . . . . . . . . . . . . . . . . . 329
145 The Courant number based on the relative velocity plotted with pyFoamPlotWatcher . . . . . . . 330
146 The average volume fraction plotted with pyFoamPlotWatcher and a custom regular expression . 332
147 The execution time plotted over time with pyFoamPlotWatcher. . . . . . . . . . . . . . . . . . . . 332
148 Screenshot of pyFoamDisplayBlockMesh . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 334
149 Double grading problem . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 339
150 Class hierarchy of some injection models for Lagrangian particles. An intermediate base class is
used to reduce code duplication from closely related, yet different injection models. . . . . . . . . 350
151 The three arguments of Eq. (167) plotted over x . . . . . . . . . . . . . . . . . . . . . . . . . . . 362
This offering is not approved or endorsed by ESI® Group, ESI-OpenCFD® or the OpenFOAM®
13
Foundation, the producer of the OpenFOAM® software and owner of the OpenFOAM® trademark.
152 A partial view of the class hierarchy involving regIOobject; . . . . . . . . . . . . . . . . . . . . . 368
153 The base classes of the class objectRegistry; . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 369
154 Graphic representation of inheritance of the turbulence model classes. . . . . . . . . . . . . . . . 378
155 Inheritance of RAS turbulence models . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 379
156 First layer of the class hierarchy of the LES models of OpenFOAM . . . . . . . . . . . . . . . . . 411
157 Class hierarchy of the eddy viscosity models in OpenFOAM . . . . . . . . . . . . . . . . . . . . . 412
158 A screenshot of Meld . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 439
This offering is not approved or endorsed by ESI® Group, ESI-OpenCFD® or the OpenFOAM®
14
Foundation, the producer of the OpenFOAM® software and owner of the OpenFOAM® trademark.
List of Tables
1 Run-time cavity test case . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 52
2 Comparison of hard disk space consumption . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 54
3 Valid and invalid face definitions . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 67
4 The different settings for pressure in the two compared cases. Case 1 follows the settings of the
hotRoomBoussinesq tutorial, which is a natural convection case with an enclosed domain. Case
2 is based on the comfortHotRoom tutorial, which is an open domain case using the Boussinesq
equation of state. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 204
5 Overview of diameter modelling in Eulerian multiphase solvers . . . . . . . . . . . . . . . . . . . 222
6 Levels of coupling between Lagrangian particles and (Eulerian) flow . . . . . . . . . . . . . . . . 239
7 Turbulence model combinations for phase-inversion cases. . . . . . . . . . . . . . . . . . . . . . . 275
8 Comparison of the eddy viscosity models of OpenFOAM . . . . . . . . . . . . . . . . . . . . . . . 412
9 Comparison of disk space reduction . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 441
10 Comparison of disk space reduction . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 441
11 Comparing the resulting file size of the mesh archive file for various conditions/treatments. All file
or folder sizes were determined with the Linux command du -sh FILE. The mesh was compressed
using the LZMA algorithm at maximum compression: tar -cv constant/polyMesh | lzma -9
> polyMesh.tar.xz. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 442
This offering is not approved or endorsed by ESI® Group, ESI-OpenCFD® or the OpenFOAM®
15
Foundation, the producer of the OpenFOAM® software and owner of the OpenFOAM® trademark.
1 Getting help
Apart from this manual, there are lots of resources on the internet to find help on OpenFOAM.
• The OpenFOAM User Guide
http://www.openfoam.org/docs/user/
• Word of mouth
https://github.com/ParticulateFlow/OSCCAR-doc/blob/master/openFoamUserManual_PFM.pdf
This is where this manual is hosted.
This offering is not approved or endorsed by ESI® Group, ESI-OpenCFD® or the OpenFOAM®
16
Foundation, the producer of the OpenFOAM® software and owner of the OpenFOAM® trademark.
2 Lessons learned
• For production-use we strongly recommend to use the point-releases of OpenFOAM. As the development
versions of OpenFOAM continuously get updated, OpenFOAM’s behaviour might change. Thus, users are
advised to base their work entirely on point-releases of OpenFOAM. That way, once your simulation cases
run, they will run indefinitely, or as long as you are able to install the respective version of OpenFOAM
on a computer.
• Keep an eye on developments in OpenFOAM. A more recent version might provide some functionality or
feature you desperately need. Even if you added this feature yourself to e.g. your custom solver or model,
the developers of OpenFOAM might provide a cleaner or more powerful implementation of that feature.
As it is easily possible to install several versions of OpenFOAM side by side on a computer, play around
with the latest version.
• Build the source-code documentation of your local installation. It is located e.g. in $HOME/OpenFOAM/
OpenFOAM-2.3.x/doc/Doxygen if you installed OpenFOAM in your home directory. This makes you
independent of being online and the doxygen gives you e.g. a very well-structured overwiew of a classes
methods and members.
• Study the code. Even as “the documentation is in the code” does not sound helpful at all, the code in
fact tells you what is going on provided you are able to make sense of the C++ syntax. Become familiar
with basic concepts of object-oriented (OO) software design.
• The more I used and tinkered with OpenFOAM, the more I am convinced that its design is really ingenious.
However, it takes time and effort to come to this conclusion. It is also probably a matter of taste.
• Document your own work and stuff you tried. There is no need to create hundreds of pages, but paper or
dead electrons have a longer memory as mere mortal humans. Furthermore, the fact “I have already tried
X at some point in the past, and I wrote it down at Y” is more likely to be remembered than “I tried X,
and that’s how it went in all detail”.
2.1 Philosophy
OpenFOAM is largely following the general rules of the UNIX philosophy – see e.g. Eric S. Raymond [22] or
http://www.catb.org/esr/writings/taoup/html/ch01s06.html – by accident, by design or by law.
6. Rule of Parsimony: Write a big program only when it is clear by demonstration that nothing else will do.
Again, OpenFOAM is a large collection of specialized tools, rather than a big monolithic – one size fits
nobody – monster.
7. Rule of Transparency: Design for visibility to make inspection and debugging easier.
Here, we quote Eric S. Raymond1 : “A software system is transparent when you can look at it and
immediately understand what it is doing and how.” CFD is admittedly very complex, however, the close-
to-mathematical notation of OpenFOAM’s high-level code, can be seen as an example of OpenFOAM’s
obedience to the Rule of Transparency.
8. Rule of Robustness: Robustness is the child of transparency and simplicity.
1 http://www.catb.org/esr/writings/taoup/html/ch01s06.html
This offering is not approved or endorsed by ESI® Group, ESI-OpenCFD® or the OpenFOAM®
17
Foundation, the producer of the OpenFOAM® software and owner of the OpenFOAM® trademark.
9. Rule of Representation: Fold knowledge into data so program logic can be stupid and robust.
Although this rule was stated without object-orientation in mind, we can observe, that OpenFOAM’s data
structures and classes absorb much of the complexity. Thus, the top level solver source code looks quite
unspectacular.
10. Rule of Least Surprise: In interface design, always do the least surprising thing.
We see this rule in action, when we look at all the shared command line options. All tools that support
time selection offer common options, such as latestTime or noZero.
11. Rule of Silence: When a program has nothing surprising to say, it should say nothing.
This rule is obeyed by most function objects, which provide the user with the choice of deactivating
writing to the Terminal. This output may be useful during testing. As soon as the case is properly set up,
however, it is sufficient for the function object to write its output to the corresponging file in the folder
postProcessing.
12. Rule of Repair: When you must fail, fail noisily and as soon as possible.
Ever noticed the FOAM FATAL ERROR messages?
13. Rule of Economy: Programmer time is expensive; conserve it in preference to machine time.
If we allow ourselves a very broad view of this rule, we might postulate, that OpenFOAM’s mechanism to
specify default values for keywords2 is one example for following this rule from a user’s perspective, i.e.
it is the user’s time which is conserved.
14. Rule of Generation: Avoid hand-hacking; write programs to write programs when you can.
We can see the heavy use of templates as an example of OpenFOAM following the Rule of Generation.
The TurbulenceModels framework3 is an example of a modelling framework, which is coded once and
applied in several different incarnations.
However, this applies only in a wider sense, since this rule was stated not with C++’s templates in mind.
15. Rule of Optimization: Prototype before polishing. Get it working before you optimize it.
16. Rule of Diversity: Distrust all claims for “one true way”.
OpenFOAM offers the user plenty of choice such as the solvers to use, the solution algorithms, and
discretisation and interpolation schemes.
17. Rule of Extensibility: Design for the future, because it will be here sooner than you think.
OpenFOAM sometimes exhibits a different behaviour based on its version, or the format of the input files.
See Section 36.4.1 for an example on differences in the input syntax of fixedValue boundary conditions.
The important lesson in this case is to allow for evolution of the code without breaking compatibility.
• Never deactivate the unit checking of OpenFOAM. FYI: It can be done in the global controlDict in the
etc directory of your OpenFOAM installation.
• Many classes provide optional debug information. Debug flags can be controlled via a global controlDict
as well as the case’s controlDict.
• Play around! A great part of learning is trial and error. Although many of us regard themselves as
scientists or aspire to become scientists, never disregard the value of plain trail and error.
2 See Section 57.3.2
3 See Section 32.
This offering is not approved or endorsed by ESI® Group, ESI-OpenCFD® or the OpenFOAM®
18
Foundation, the producer of the OpenFOAM® software and owner of the OpenFOAM® trademark.
2.3 Learning by tinkering with OpenFOAM
2.3.1 I learned something today.
• Have a look at the test directory in the applications folder of your installation, e.g. in $HOME/OpenFOAM/
OpenFOAM-2.3.x/applications/test. There, you find examples of how to use certain data structures,
which may be exactly what you need when implementing something.
• Create your own test application, if you are about to implement something new. With a test application,
you can keep the problem nearly primitive, thus, allowing yourself more mental freedom to explore and
to learn. Later, you might be more likely to implement your solver / library with less bugs and errors.
• OpenFOAM makes heavy use of C++’s language features and other smart moves in OO software design.
Thus, make sure you understand the basics of the following concepts / language features before you try
to study / modify the code of OpenFOAM. Your life gets easier if you do.
inheritance virtually everything of OpenFOAM is described and implemented using the concept of classes.
Classes can be derived from other classes to implement an is a relationship, i.e. every cat is an animal
but not vice versa.
Note: C++ support multiple inheritance, i.e. a class can be derived from a number of classes, not just
one. Other programming languages are (slightly) different in this aspect, e.g. Java allows you to derive
only from one class, however, you can implement interfaces.
poly-morphism is a wider concept, however it applies also to inheritance and classes.
templates allow the user to write code for as-of-yet unspecified data types. Container classes are the prime
example for the use of templates (or generics as this concept is called in Java).
Examples of the excellent use of the aforementioned concepts is the turbulence modelling framework discussed
in Section 32.1.2, or the Lagrangian modelling framework discussed in Section 40.2.
This offering is not approved or endorsed by ESI® Group, ESI-OpenCFD® or the OpenFOAM®
19
Foundation, the producer of the OpenFOAM® software and owner of the OpenFOAM® trademark.
Part I
Installation
3 Install OpenFOAM
3.1 Prerequistes
OpenFOAM is easily installed by following the instructions from this website: http://www.openfoam.org/
download/git.php.
First of all, you need to make sure all required packages are installed on your system. This is easily done
via the package management software. OpenFOAM is a software made primarily for Linux systems. It can also
be installed on Mac or Windows plattforms. However, the authors uses a Ubuntu-Linux system, therefore this
manual will be based on the assumption that a Linux system is used.
If OpenFOAM is to be used by a single user, then the User Manual suggests to install OpenFOAM in the
$HOME/OpenFOAM directory.
cd $HOME
mkdir OpenFOAM
cd OpenFOAM
git clone git :// github . com / OpenFOAM / OpenFOAM -2.1. x . git
cd OpenFOAM -2.1. x
git pull
Prior to compiling the sources some environment variables have to be defined. In order to do that a line (see
Listing 3) has to added to the file $HOME/.bashrc.
When the command source $HOME/.bashrc is issued or when a new Terminal is opened this change is
effective. Now with the defined environment variables OpenFOAM can be installed on the system. Before
compiling a system check can be made by running foamSystemCheck.
This offering is not approved or endorsed by ESI® Group, ESI-OpenCFD® or the OpenFOAM®
I 20
Foundation, the producer of the OpenFOAM® software and owner of the OpenFOAM® trademark.
Continue OpenFOAM installation .
Listing 4: foamSystemCheck
export WM_NCOMPPROCS =4
./ Allwmake
For working with OpenFOAM a user directory needs to be created. The name of this directory consists of
the username and the version number of OpenFOAM. With version 2.1.x this folder needs to be named like
this: user-2.1.x
cd $ W M _ T H I R D _ P A R T Y _ D I R
./ makeParaView
4 http://www.cfd-online.com/Forums/openfoam-installation/57512-completely-remove-openfoam-start-fresh.html
5 http://www.openfoam.org/download/git.php
This offering is not approved or endorsed by ESI® Group, ESI-OpenCFD® or the OpenFOAM®
I 21
Foundation, the producer of the OpenFOAM® software and owner of the OpenFOAM® trademark.
cd ∼/ OpenFOAM
rm - rf OpenFOAM -2.0.1
rm - rf user -2.0.1
cd
rm - rf ∼/. OpenFOAM
cd ∼/ OpenFOAM
ls -1
user -2.0. x
user -2.1. x
OpenFOAM -2.0. x
OpenFOAM -2.1. x
ThirdParty -2.0. x
ThirdParty -2.1. x
Another thing to remove is the entry in the .bashrc file in the home directory. Delete the line shown in
Listing 3.
This offering is not approved or endorsed by ESI® Group, ESI-OpenCFD® or the OpenFOAM®
I 22
Foundation, the producer of the OpenFOAM® software and owner of the OpenFOAM® trademark.
4 Updating the repository release of OpenFOAM
4.1 Version management
OpenFOAM is distributed in two different ways. There is the repository release that can be downloaded using
the Git repository. The version number of the repository release is marked by the appended x, e.g. OpenFOAM
2.1.x. This release is updated regularly and is in some ways a development release. Changes and updates are
released quickly, however, there is a larger possibility of bugs in this release. Because this release is updated
frequently an OpenFOAM installation of version 2.1.x on one system may or will be different to another instal-
lation of version 2.1.x on an other system. Therefore, each installation has an additional information to mark
different builds of OpenFOAM. The version number is accompanied by a hash code to uniquely identify the
various builds of the repository release, see Listing 9. Whenever OpenFOAM is updated and compiled anew,
this hash code gets changed. Two OpenFOAM installations are on an equal level, if the build is equal.
Apart from the repository release there are also pack releases. These are upadated periodically in longer
intervals than the repository release. The version number of a pack release contains no x, e.g. OpenFOAM
2.1.1. In contrast to the repository release all installations of the same version number are equal. Due to the
longer release cycle the pack release is regarded to be less prone to software bugs.
There are several types of those releases. The are precompiled packages for widely used Linux distributions
(Ubuntu, SuSE and Fedora) and also a source pack. The source pack can be installed on any system on which
the source codes compile (usually all kinds of Linux running computers, e.g. high performance computing
clusters, or even computers running other operation systems, e.g. Mac OSX6 or even Windows7 ).
This offering is not approved or endorsed by ESI® Group, ESI-OpenCFD® or the OpenFOAM®
I 23
Foundation, the producer of the OpenFOAM® software and owner of the OpenFOAM® trademark.
Listing 11: OpenFOAM is up to date
4.4.1 Workflow
Listing 14 shows the necessary commands to update an existing OpenFOAM installation. However this applies
only for repository releases (e.g. OpenFOAM-2.1.x). The point releases (every version of OpenFOAM without
an x in the version number) are not updated in the same sense as the repository releases. For simplicity an update
of a point release (OpenFOAM-2.1.0 → OpenFOAM-2.1.1) can be treated like a complete new installation, see
Section 3.6.
The first two commands in Listing 14 change to the directory of the OpenFOAM installation. Then the
latest source files are downloaded by invoking git pull.
The statement in red can be omitted. However if the compilation ends with some errors, this command
usually does the trick, see Section 4.5.2. The last statement causes the source files to be compiled. If wclean all
was not called before, then only the files that did change are compiled. If wclean all was invoked then
everything is compiled. This may or will take much longer.
If there is enough time for the update (e.g. overnight), then wclean all should be called before compiling.
This will in most cases make sure that compilation of the updated sources succeeds.
cd $F OAM_INST _DIR
cd OpenFOAM -2.1. x
git pull
8 git pull calls git fetch to download the remote files and then calls git merge to merge the retrieved files with the local files.
This offering is not approved or endorsed by ESI® Group, ESI-OpenCFD® or the OpenFOAM®
I 24
Foundation, the producer of the OpenFOAM® software and owner of the OpenFOAM® trademark.
wclean all
./ Allwmake
4.4.2 Trouble-shooting
If compilation reports some errors it is helpful to call ./Allwmake again. This reduces the output of the
successful operations considerably and the actual error messages of the compiler are easier to find.
wclean all
The brute force variant would be, to recompile OpenFOAM as a whole, instead of recompiling a updated
library.
The command listed in Listing 16 causes git to erase all files git does not track. That means all files that
are not part of the git-repository are deleted. In this case, this is the official git-repository of OpenFOAM. git
clean removes all files that are not under version control recursively starting from the current directory. The
option -d means that also untracked folders are removed.
After the command from Listing 16 is executed, the sources have to be compiled as described in Section 3.3.
This offering is not approved or endorsed by ESI® Group, ESI-OpenCFD® or the OpenFOAM®
I 25
Foundation, the producer of the OpenFOAM® software and owner of the OpenFOAM® trademark.
Lost binary compatibility after an update of OpenFOAM leads to segmentation faults when loading a library
with lost binary compatibility. This happens because our own solvers dynamically load the required libraries of
OpenFOAM at start-up and the memory layout of certain objects of the library has changed since the update.
See the following resources for further information on this topic:
• https://community.kde.org/Policies/Binary_Compatibility_Issues_With_C%2B%2B
• https://en.wikipedia.org/wiki/Binary_code_compatibility
• https://en.wikipedia.org/wiki/Source_code_compatibility
Losing binary compatibility happens not after every update, and it also does not happen to every library.
Thus, you may encounter such problems long after the update, and after you successfully used other solvers
and libraries of your creation. Thus, the source of the issues described in this Section may not be immediately
clear to the user. Thus, if your code suddenly fails to run properly for no good reason, recomile and see what
happens.
This offering is not approved or endorsed by ESI® Group, ESI-OpenCFD® or the OpenFOAM®
I 26
Foundation, the producer of the OpenFOAM® software and owner of the OpenFOAM® trademark.
Figure 1: Initializing a new git repository.
5.2.1 Initialization
With git init, we tell git to create a new git repository. If we run this command in a directory with files
being already present, this does not change anyone of them.
After running git init, we fill find that a new folder has been created: .git. The file .gitignore has
been part of the source pack.
11 https://openfoam.org/release/6/
12 The reader may apologize the rambling babble.
13 https://github.com/OpenFOAM/OpenFOAM-6
This offering is not approved or endorsed by ESI® Group, ESI-OpenCFD® or the OpenFOAM®
I 27
Foundation, the producer of the OpenFOAM® software and owner of the OpenFOAM® trademark.
Figure 2: Pointing the new git repository to the proper remote repository.
Figure 3: Updating the new git repository by pulling from the remote repository.
The checkout command now applies all the changes that have been made to the remote master branch to
our local master branch. Now, all the local files have been updated, and we can recompile the source files.
Note, that we need to update the third-party source-code directory in the same way as we updated the
OpenFOAM source-code directory.
This offering is not approved or endorsed by ESI® Group, ESI-OpenCFD® or the OpenFOAM®
I 28
Foundation, the producer of the OpenFOAM® software and owner of the OpenFOAM® trademark.
5.3 Recompile the source pack
The last step to update any installation from source, is to recompile the sources. This can be conveniently done
by running
./ Allwmake - update
This offering is not approved or endorsed by ESI® Group, ESI-OpenCFD® or the OpenFOAM®
I 29
Foundation, the producer of the OpenFOAM® software and owner of the OpenFOAM® trademark.
6 Maintaining your OpenFOAM installation
Due to the ease of having multiple versions of OpenFOAM installed side-by-side on your system, there is the
issue of long-term maintaining of your OpenFOAM installations. Over the years OpenFOAM installations may
accumulate on your system. Furthermore, the operating system as well receives attention from its developers
in the form of updates and upgrades.
Trouble-shooting tip: reboot your machine and try again, this may actually help
OS updates can cause weird errors. Your trusted author encountered a situation in which mpirun ceased to
work, and the error message, contained a stack trace which featured words such as memory mapping and such.
This problem was most likely caused by OS updates which updated the MPI library and/or kernel updates.
However, the problems disappeared when the machine was rebooted.
Having a long uptime, i.e. is has been a very long time since the computer last rebooted, is only recommended
for computing server, which do not receive updates frequently, and are best not connected to the general internet.
A normal workstation, which is frequently updated, should be rebooted regularly. The author has experienced
multiple occasions, when the workstation after several kernel updates (these are ones that require a reboot to
take effect) with no reboot started to behave weirdly.
cd $W M_ P RO JE CT_ DI R
wclean all
./ Allwmake
Running old versions of OpenFOAM is generally not recommended, as they might or will contain bugs which
have long been fixed since. However, for checking on old simulations or re-running them to compare them with
current runs, it is quite handy to have a functional installation at hand.
This offering is not approved or endorsed by ESI® Group, ESI-OpenCFD® or the OpenFOAM®
I 30
Foundation, the producer of the OpenFOAM® software and owner of the OpenFOAM® trademark.
7 Install third-party software
The software presented in this section is optional. Without this software OpenFOAM is complete and perfectly
useable. However, the software mentioned in this section can be very useful for specific tasks.
cd OpenFOAM / AlbertoPa / d y n a m i c S m a g o r i n s k y
wmake libso
This offering is not approved or endorsed by ESI® Group, ESI-OpenCFD® or the OpenFOAM®
I 31
Foundation, the producer of the OpenFOAM® software and owner of the OpenFOAM® trademark.
8 Setting up the environment
8.1 Sourcing OpenFOAM
OpenFOAM makes use of plenty of environment variables, see Section 11.1.1 for a brief discussion. In order
to use OpenFOAM, we need to assign values to the variables. Another task enabling the convenient use of
OpenFOAM is to add the directories in which OpenFOAM executables are located to the system’s $PATH
variable.
The name of this section stems from the Linux command source, which is used in setting up the proper
environment for using OpenFOAM. Setting up the environment for using OpenFOAM can be done in two ways,
which are discussed below. Each of these variants involves editing a .bashrc file14 . This .bashrc file can be
either a systemwide one for systemwide installations, or belonging to the user who installed OpenFOAM in
his/her home directory.
Once the OpenFOAM environment has been sourced in a Terminal, OpenFOAM is ready to use as long as
the Terminal is open.
14 If you for some reason unthinkable to the author do not want to edit any .bashrc file, you can simply enter the instruction
shown in Listing 20 into the Terminal whenever you want to use OpenFOAM.
15 There is a limit on how long a single command can be. On the author’s Linux system, this is north of 2 million bytes.
16 We can, in fact, define an alias which has the same name as an existing command. In this case, the alias “shadows” the
corresponding command. This is used in Ubuntu Linux to add some eye candy, e.g. for ls, which is shadowed by alias ls=’ls
–color=auto’. In this case, the Terminal expands the alias, whenever a user types ls.
This offering is not approved or endorsed by ESI® Group, ESI-OpenCFD® or the OpenFOAM®
I 32
Foundation, the producer of the OpenFOAM® software and owner of the OpenFOAM® trademark.
8.2 Working with Environment Modules
On a personal machine/workstation we can source our OpenFOAM environment as described in Section 8.1.2,
however, on computational clusters thinks may work differently. Especially on managed clusters, i.e. computa-
tional clusters not managed by ourselves, there are more sophisticated methods of dealing with the environment,
namely Environment Modules17 .
With Environment Modules we define a modulefile containing all relevant information regarding the software
in question. A modulefile is written using Tcl (Tool Command Language)18 .
# wmake
setenv W M _ CO M PI L E R _ T Y P E " ThirdParty "
This offering is not approved or endorsed by ESI® Group, ESI-OpenCFD® or the OpenFOAM®
I 33
Foundation, the producer of the OpenFOAM® software and owner of the OpenFOAM® trademark.
setenv gmp_version " $gmp_version "
setenv mpfr_version " $mpfr_version "
setenv mpc_version " $mpc_version "
setenv gcc_version " $gcc_version "
Listing 23: Snippets of a modulefile for OpenFOAM using a custom gcc installation.
This offering is not approved or endorsed by ESI® Group, ESI-OpenCFD® or the OpenFOAM®
I 34
Foundation, the producer of the OpenFOAM® software and owner of the OpenFOAM® trademark.
Part II
General Remarks about OpenFOAM
9 Units and dimensions
This section discusses the treatment of physical units (e.g. meter, second, etc.) and dimensions (scalar, vector,
etc.) in OpenFOAM. In OpenFOAM physical units are referred to as dimensions and they are covered by the
class dimensionSet. The dimensionality (a quantity being a scalar or a vector) is treated implicitely by the
data types. The data types scalar or vector do not need any further specification of their dimensionality.
A dimension set contains the exponents of (1) that define the desired unit. With the dimension set OpenFOAM
is able to perform unit checks.
dimensions [0 1 -2 0 0 0 0];
From function checkMethod ( const fvMatrix < Type >& , const fvMatrix < Type >&)
in file / home / user / OpenFOAM / OpenFOAM -2.1. x / src / finiteVolume / lnInclude / fvMatrix . C at line
1316.
FOAM aborting
Listing 24 shows an incorrect definition of the dimension of the velocity, e.g. in the file 0/U. m/s2 has been
defined instead of m/s. OpenFOAM recognises this false definition, because mathematical operations do not
work out anymore. Listing 25 shows a corresponding error message produced by two summands having different
units. Therefore, OpenFOAM aborts and displays an error message.
This offering is not approved or endorsed by ESI® Group, ESI-OpenCFD® or the OpenFOAM®
II 35
Foundation, the producer of the OpenFOAM® software and owner of the OpenFOAM® trademark.
Eq. (2) is based on the source code of OpenFOAM, see Listing 26. Eq. (3) is based on [4, 3].
Listing 26: The definition of the order of the base units in the file dimensionSet.H
The reason for changing the order of the base units may be motivated from a CFD based point of view.
For fluid dynamics involving compressible flows as well as reactive flows and combustion the first five units of
OpenFOAM’s set of base units suffice.
phaseb
{
rho rho [ 1 -3 0 0 0 ] 1000;
nu nu [ 0 2 -1 0 0 ] 1e -06;
d d [ 0 1 0 0 0 0 0 ] 0.00048;
}
FOAM exiting
This offering is not approved or endorsed by ESI® Group, ESI-OpenCFD® or the OpenFOAM®
II 36
Foundation, the producer of the OpenFOAM® software and owner of the OpenFOAM® trademark.
Calculating dimensioned quantities
Calculated fields inherit their dimension set from the involved operations and operands. Listing 29 shows the
creation of the kinetic energy field K from the square of the velocity fields21 . The newly created field, bears
the name K, as this is passed as an argument to the constructor. The dimension set of the field K is derived
from the constructor’s second argument. Since all mathematical operations on numeric types are mirrored for
dimensions, any mathematical operation on a dimensioned type not only yields a numerical result, it also yields
a resulting dimension. In this case the resulting dimension is square metre per square second.
1 Info < < " Creating field kinetic energy K \ n " << endl ;
2 volS calarFie ld K ( " K " , 0.5* magSqr ( U ) ) ;
Always explicitely stating the dimension set with its 5 or 7 exponents would seriously bloat the code for no
benefit. Thus, there are a number of global constants of the data type dimensionSet. These constants define
the most common dimension sets and offer a very convenient short-hand notation22 as seen in Listing 31.
Since all mathematical operations performed on the numeric part of a dimensioned quantity are also per-
formed on the dimension set, the class dimensionSet implements mathematical operations. We can use these
and the global short-hands to define the dimension set of our new dimensioned quantity. In Listing 32, we
needlessly compute the dimension set for a velocity, however, this Listing demonstrates the use of mathematical
operations on dimension sets.
9.2 Dimensions
Fields in fluid mechanics can be scalars, vectors or tensors. There are in OpenFOAM different data types to
distinguish between quantities of different dimensions.
volScalarField A scalar field throughout the whole computaional domain, e.g. pressure.
volScalarField p
volVectorField A vector field throughout the whole domain, e.g. velocity.
volVectorField U
21 The kinetic energy is defined in textbooks as k = 1/2ρu2 , which involves the fluid density ρ, which the definition in Listing
29 is lacking. However, the fluid density field rho enters the scene as second argument in the terms of the energy transport
equation, as can be seen in the temporal derivative and convective terms of rhoPimpleFoam’s energy equation: fvc::ddt(rho, K)
+ fvc::div(phi, K). Thus, OpenFOAM’s kinetic energy K is in fact a specific kinetic energy.
22 You can find these definitions in $FOAM_SRC/OpenFOAM/dimensionSet/dimensionSets.C
This offering is not approved or endorsed by ESI® Group, ESI-OpenCFD® or the OpenFOAM®
II 37
Foundation, the producer of the OpenFOAM® software and owner of the OpenFOAM® trademark.
volTensorField A tensor field throughtout the whole domain, e.g. Reynolds stresses.
volTensorField Rca
surfaceScalarField A scalar field, defined on surfaces (surfaces of the finiten volumes), e.g. flux.
surfaceScalarField phi
dimensionedScalar A scalar constant throughout the whole domain (i.e. no field quantity).
dimensionedScalar nu
dimensions [ 0 0 0 0 0 0 0 ];
internalField uniform ( 0 0 0 ) ;
boundaryField
{
inlet
{
type fixedValue ;
value uniform 0;
}
file : / home / user / OpenFOAM / user -2.1. x / run / t w o P h a s e E u l e r F o a m / bed /0/ alpha :: internalField at line
19.
FOAM exiting
nu nu [ 0 2 -1 0 0 0 0 ] 0.01;
p
p̂ = (4)
ρ
For this reason the entries in the 0/p files differ depending on the solver in use. This is visible by the unit of
pressure.
This offering is not approved or endorsed by ESI® Group, ESI-OpenCFD® or the OpenFOAM®
II 38
Foundation, the producer of the OpenFOAM® software and owner of the OpenFOAM® trademark.
9.4.1 Incompressible
The unit of the pressure in an incompressible solver is defined by (4)
N m3 m kgm m m2
[p̂] = 2
· =N = 2 · = 2 (5)
m kg kg s kg s
dimensions [0 2 -2 0 0 0 0];
9.4.2 Compressible
The unit of the pressure in a compressible solver is the physical unit of pressure.
kgm
N 2 kg
[p] = = s2 = (6)
m2 m ms2
dimensions [ 1 -1 -2 0 0 0 0 ];
This offering is not approved or endorsed by ESI® Group, ESI-OpenCFD® or the OpenFOAM®
II 39
Foundation, the producer of the OpenFOAM® software and owner of the OpenFOAM® trademark.
10 Files and directories
OpenFOAM saves its data not in a single file, like Fluent does, it uses several different files. Depending on its
purpose a specific file is located in one of several folders.
0 This is the first of the time-directories. It contains the initial and boundary conditions of all variable quan-
tities. A case does not have to start at time t = 0. However, if there is no specific reason for a case to
start at another time that t = 0, a case will always begin at time t = 0. The name of a time-directory is
simply the number of elapsed seconds.
constant This folder contains all files dealing with constant quantities as well as the mesh.
polymesh This is a subdirectory of constant. In this folder all files defining the mesh reside.
system In this folder all files that control the solver or other tools are located
In the course of computing the case two kinds of folders are created. First of all, at defined times all information
is written two the harddisk. A new time-directory is created with the number of elapsed seconds in its name. In
this folder all kinds of files are saved. The number of files is equal or larger than in the 0 -directory containing
the initial conditions.
The second category of directory subsumes all kinds of folders created for all kind of reasons or by all kind
of tools, see Section 10.2 for a brief introduction to some of the more common of them.
10.2.1 processor*
If a case is solved in parallel, i.e. the case is computed using more than one processor at the time. In this case
the computational domain has to be decomposed into several parts, to divide the problem between the involved
parallel processes. The tool that is used to decompose the case created the processor*-directories. The * stands
for a consecutive number starting with 0. So, if a case is to be solved using 4 parallel processes, then the domain
has to be split into 4 parts. Therefore, the folders processor0 to processor3 are created.
Every one of the parallel*-directories contains a 0 - and also a constant-directory containing only the mesh.
The system-directory remains in the case folder. See Section 12.5 for more information about conducting parallel
calculations.
This offering is not approved or endorsed by ESI® Group, ESI-OpenCFD® or the OpenFOAM®
II 40
Foundation, the producer of the OpenFOAM® software and owner of the OpenFOAM® trademark.
10.2.2 functions
functions or functionObjects perform all kind of operations during the computation. Each function creates a
folder of the same name to save its data in. See Section 49 for more information about functions.
10.2.3 sets
If the tool sample has been used, then all data generated by sample is stored in a folder named sets. See Section
50 for more information about sample.
fvSchemes In this file the finite volume discretisation schemes are defined
fvSolution This files contains controls related to the mathematical solver, solver algorithms and tolerances.
probesDict Alternative to the use of the file probesDict, probes can also be defined in the file controlDict.
decomposeParDict Used by decomposePar. In this file the number of subdomains and the method of decom-
position are defined.
setFieldsDict Necessary for the tool setFields to initialise field quantities.
This offering is not approved or endorsed by ESI® Group, ESI-OpenCFD® or the OpenFOAM®
II 41
Foundation, the producer of the OpenFOAM® software and owner of the OpenFOAM® trademark.
11 Controlling OpenFOAM
11.1 The means of exerting control
Classical UNIX applications know several means of controlling their configuration [22]:
• System-wide run-control files
An example for these are files in /etc on Linux or UNIX systems. For OpenFOAM, such system-wide
run-control files are located in $FOAM_ETC, which might be home/user/OpenFOAM/OpenFOAM-3.0.0/etc.
There, we can find the global controlDict, controlling OpenFOAM’s behaviour installation-wide.
• System-wide environment variables
Such a system-wide variable on a Linux system is $HOSTNAME, which is the name associated to identify
the computer within a network. This name is the same for all users logged in at a certain machine, and
it can and should not be changed by a user. For OpenFOAM such system-wide environment variables are
$FOAM_ETC, $FOAM_INST_DIR or $WM_THIRD_PARTY_DIR. This variables are equal for all users of a certain
installation.
The distinction between system-wide and user-defined settings blurs, when we install OpenFOAM in our
home directory, then we are the administrator and the single user of our installation. This distinction was
made for clusters, which provide one installation to many users.
• User-defined run-control files
A perfect example of a user-defined run-controlled file is the file .bashrc in the user’s home directory.
This file contains user-specific settings. During the installation process of OpenFOAM, this file needs to
be edited to make the OpenFOAM installation available to the user.
11.1.1 Variables
Variables are the best place to store information, which is repeatedly needed. E.g. it would make no sense to
specify the installation directory of OpenFOAM in every run-control file which needs to know where OpenFOAM
is installed on the system, instead a variable $FOAM_INST_DIR is defined in one of OpenFOAM’s global run-
control files. In all other run-control files, which need to know the installation path, this variable is used. Thus,
information redundancy is avoided. Imagine the poor cluster administrators, if some information were stored
in multiple places, and this information were to change. Good luck finding and updating ALL occurances of
this data.
Variables offer the freedom to use the same name (i.e. the variable) regardless of what the actual information
is. OpenFOAM is always installed at $FOAM_INST_DIR, whether that is /home/user/OpenFOAM, /opt/OpenFOAM
or /home/user/Desktop/important_softWare.
11.1.2 Dictionaries
Dictionaries are the run-control files of OpenFOAM. Most of the controls of OpenFOAM are set in so called
dictionaries. An important dictionary is the file controlDict. Dictionaries offer a convenient way to store
structured information of arbitrary size, which would be rather impossible using variables or command line
arguments. Imagine typing all contents of controlDict every time you run a solver.
This offering is not approved or endorsed by ESI® Group, ESI-OpenCFD® or the OpenFOAM®
II 42
Foundation, the producer of the OpenFOAM® software and owner of the OpenFOAM® trademark.
The distinction between global and local dictionaries saves ourselves from messing up the OpenFOAM
installation when fiddling with a case’s set-up.
The file format follows some general principles of C++ source code.
The most basic format to enter data in a dictionary is the key-value pair. The value of a key-value pair can
be any sort of data, e.g. a number, a list or a dictionary.
Listing 39 shows the error message that is displayed when the value banana is assigned to the key startFrom
that controls at which time a simulation should start. The error message contains a note that is formated in
this way: expected X, Y or Z found ABC.
If in a dictionary several key-value pairs are erroneous, only the first one produces an error, as OpenFOAM
aborts all further operations.
This offering is not approved or endorsed by ESI® Group, ESI-OpenCFD® or the OpenFOAM®
II 43
Foundation, the producer of the OpenFOAM® software and owner of the OpenFOAM® trademark.
11.2.2 Mandatory and optional settings
Some settings are expected by the solver to be made. If they are not present, OpenFOAM will return an error
message. Other settings have a default value, which is used if the user does not specify a value. In this sense,
settings can be divided into mandatory and optional ones.
As mandatory settings causes an error if they are not set, a simulation can be run only if all mandatory
settings were made.
About errors
• There will be an error when mandatory settings were not made.
• There is no error message if an optional setting (that is necessary) was omitted. All optional controls have
a default value and will be in place.
• There is no error message if a setting was made and that setting is not needed. The solver simply ignores
it. Consequently the definition of a variable time step in controlDict does not necessarily mean, that the
simulation is performed with variable time steps, e.g. if icoFoam (a fixed time step solver) is used.
• Sometimes an error message points to the setting of a keyword that is actually not faulty. See Section
11.2.3.
See Section 57.3 for a detailed discussion – including a thorough look at some source code – about reading
keywords from dictionaries.
dimensions [0 1 -1 0 0 0 0];
internalField uniform (0 0 0) ;
boundaryField
{
inlet
{
type fixedValue ;
value uniform (0 0 0.03704) ;
}
outlet
{
type zeroGradient
}
walls
{
type fixedValue ;
value uniform (0 0 0) ;
}
}
This offering is not approved or endorsed by ESI® Group, ESI-OpenCFD® or the OpenFOAM®
II 44
Foundation, the producer of the OpenFOAM® software and owner of the OpenFOAM® trademark.
--> FOAM FATAL IO ERROR :
keyword walls is undefined in dictionary "/ home / user / OpenFOAM / user -2.1. x / run / t w o P h a s e E u l e r F o a m
/ case /0/ U1 :: boundaryField "
file : / home / user / OpenFOAM / user -2.1. x / run / t w o P h a s e E u l e r F o a m / case /0/ U1 :: boundaryField from line
25 to line 47.
FOAM exiting
11.2.4 Switches
Besides key-value pairs there are switches. These enable or disable a function or a feature. Consequently, they
only can have a logical value.
Allowed values are: on/off, true/false or yes/no. See Section 57.4.1 for a detailed discussion about valid
entries.
firstTime the simulation starts from the earliest time step from the set of time directories.
startTime the simulation starts from the time specified by the startTime keyword entry.
latestTime the simulation starts from the latest time step from the set of time directories.
startTime start time from which the simulation starts. Only relevant if startFrom startTime has been
specified. Otherwise this entry is completely ignored23 .
stopAt controls the end of the simulation. Possible values are {endTime, nextWrite, noWriteNow, writeNow}.
This offering is not approved or endorsed by ESI® Group, ESI-OpenCFD® or the OpenFOAM®
II 45
Foundation, the producer of the OpenFOAM® software and owner of the OpenFOAM® trademark.
runTimeModifiable controls whether or not OpenFOAM should read certain dictionaries (e.g. controlDict)
at the beginning of each time step. If this option is enabled, a simulation can be stopped by using setting
stopAt to one of these values {nextWrite, noWriteNow, writeNow}, see Section 12.2.
maxCo when the simulation is run with an adjustable time step, then we can specify the maximum Courant
number, which is used to impose an upper boundary on the time step size.
maxDeltaT when we run a simulation with an adjustable time step, we can provide a manual, hard upper
boundary for the maximum time step. This setting limits the time step size, regardless of other conditions
allowing for a larger time step, e.g. the Courant number criterion.
In Section 57.6 a couple of aspects regarding time step control are discussed.
runTime when this option is chosen, then every writeInterval seconds the data is written. This
option has no influence on the time step. Hence, the interval at which data is written may/does
not exactly match the entry in writeInterval, i.e. for a 1 s interval the data may be written at
t = 1.0012, 2.0005, . . . s.
adjustableRunTime this option allows the solver to adjust the time step, so that every writeInterval
seconds the data can be written. This option imposes an upper boundary upon the time step.
There must be at least 5 time steps between two instances at which data is written, i.e. ∆t ≤
0.2 ∗ writeInterval.
timeStep the data is written every writeInterval time steps. In this case, writeInterval is an integer,
not a time.
writeInterval a value that controls the interval of data writing. This value gets its meaning from the value
assigned to writeControl.
writeFormat controls how the data is written to hard disk. It is possible to write text files or binary files.
Consequently, the options are {ascii, binary}.
writePrecision controls the precision of the values written to the hard disk.
writeCompression controls whether to compress the written files or not. By default compression is disabled.
When it is activated, all written files are compressed using gzip.
timeFormat controls the format that is used to write the time step folders.
timePrecision specifies the number of digits after the decimal point. The default value is 6.
purgeWrite this setting control whether to clear out old time steps. The default value is 0, which means
that no clearing out will be conducted. For enabling clearing out old time steps, valid values are positive
integer numbers. If enabled with a non-zero value N , only the last N time steps will be retained. Once
the simulation has written N time steps to disk, for every new time step saved, the oldest one will be
deleted. The initial time step is not affected and will always remain in the case25 .
25 In the file TimeIO.C we see, that each time we reach write-time, the current time step is added to a FIFO stack. Subsequently,
the stack’s size is checked against the purgeWrite value. If the stack is larger, then one item will be removed.
This offering is not approved or endorsed by ESI® Group, ESI-OpenCFD® or the OpenFOAM®
II 46
Foundation, the producer of the OpenFOAM® software and owner of the OpenFOAM® trademark.
Pitfall: timePrecision
OpenFOAM is able to automatically increase the value of timePrecision parameter if need arises, e.g. due
to a reduction in (dynamic) time step size26 . This is typically the case when a simulation diverges and the
(dynamic) time step gets decreased by orders of magnitudes. However, simulations that do not diverge may
also create the need for an increase in time precision.
Listing 43: Exemplary solver output in the case of an automatic increase of the timePrecision value.
If a simulation that increased its time precision is to be restarted or continued from the latest time step, then
the chosen time precision may not be sufficient to represent the present time step values, i.e. a timePrecision
of 3 is not sufficient to represent the latest time step at t = 0.1023 s. OpenFOAM will apply rounding to the
reach the selected number of digits behind the comma. Consequently, OpenFOAM will fail to find files at time
t = 0.102 s.
This behaviour is hard to detect for an unaware user. The only clue for detection lies in this case in the
fourth digit behind the comma, which is present in only in the name of the time step directory but not in
the timeName that is looked up by OpenFOAM. Listing 44 shows the according error message and a directory
listing of the case directory. It is up to the reader to decide whether this is an easy to spot error. The author
took some time, which motivated him to elaborate on this issue in this little collection of errors and misbehaviour.
file : / home / user / OpenFOAM / user -2.3. x / run / icoFoam / cavity /0.102/ p at line 0.
FOAM exiting
Listing 44: Exemple of an error caused by an automatic increase of the timePrecision value in the previous
simulation run. We fail to restart the simulation as OpenFOAM is not able to find the correct time step.
precision is not sufficient to adequately represent the time step. This leads to a automatic increase of time precision after the first
time step is written to disk. I.e. if ∆t can’t be represented with timePrecision number of digits after the comma, then t1 + ∆t
also can’t be represented. Thus, t1 and t1 + ∆t would get the same time name and would consequently be indistinguishable. See
Section 57.6.3 on more implementation details on this matter.
This offering is not approved or endorsed by ESI® Group, ESI-OpenCFD® or the OpenFOAM®
II 47
Foundation, the producer of the OpenFOAM® software and owner of the OpenFOAM® trademark.
Since, we selected runTime as write-control, the writeInterval has no effect on the time step size. If
the time step controls allow for a time step larger than writeInterval, e.g. via the Courant criterion, then
OpenFOAM will oblige. In this case, after every time step OpenFOAM notices, that the time elapsed since the
last write-to-disk is larger than the writeInterval. Thus, it is time to write to disk again.
If we do not want this kind of behaviour, then we need to select adjustableRunTime as our write-control,
because then the time step will be checked against the writeInterval.
Note that the line in Listing 45 is a keyword (libs) followed by a list-type entry. Thus, the space between
the keyword and the opening parenthesis is vital, since whitespace is used to separate a keyword from its value.
11.3.4 functions
functions, or functionObjects as they are called in OpenFOAM, offer a wide variety of extra functionality, e.g.
probing values or run-time post-processing. See Section 49.
functions can be enabled or disabled at run-time.
All inclusive
In this case the probe is defined completely in controlDict.
functions
{
probes1
{
type probes ;
f u n c t i o n O bj e c t L i b s (" libsampling . so ") ;
fields
(
p
U
);
outputControl outputTime ;
outp utInterv al 0.01;
prob eLocatio ns
This offering is not approved or endorsed by ESI® Group, ESI-OpenCFD® or the OpenFOAM®
II 48
Foundation, the producer of the OpenFOAM® software and owner of the OpenFOAM® trademark.
(
(0.5 0.5 0.05)
);
}
}
Seperate probesDict
In this case the definition of the probe is done in a seperate file – the probesDict. In controlDict the name of
this dictionary is assigned to the keyword dictionary. This dictionary has be located in the system-directory of
the case. It is not possible to assign the path of this dictionary to this keyword.
functions
{
probes1
{
type probes ;
f u n c t i o n O bj e c t L i b s (" libsampling . so ") ;
dictionary probesDict ;
}
}
fields
(
p
U
);
outputControl outputTime ;
outp utInterv al 0.01;
prob eLocatio ns
(
(20.5 0.5 0.05)
);
Everything external
There is also the possibility to move the whole definition of a functionObject into a seperate file. In this case
the macro #include is used. This macro is similar to the pre-processor macro if C++.
functions
{
# include " cuttingPlane "
}
cuttingPlane
{
type surfaces ;
f u n c t i o n O b j ec t L i b s (" libsampling . so ") ;
outputControl outputTime ;
surfaceFormat raw ;
fields ( alpha1 ) ;
i n t e r p o l a t i o n S c h e m e cellPoint ;
This offering is not approved or endorsed by ESI® Group, ESI-OpenCFD® or the OpenFOAM®
II 49
Foundation, the producer of the OpenFOAM® software and owner of the OpenFOAM® trademark.
surfaces
(
yNormal
{
type cuttingPlane ;
planeType point AndNorma l ;
pointAndNormalDict
{
basePoint (0 0.1 0) ;
normalVector (0 1 0) ;
}
interpolate true ;
}
);
}
11.3.6 Pitfalls
timePrecision
If the time precision is not sufficient, then OpenFOAM issues a warning message and increases the time precision
without aborting a running simulation.
Listing 51 shows such a warning message. The simulation time exceeded 100 s and OpenFOAM figured that
the time precision was not sufficient anymore.
101. 50000000 02
101. 00000000 02
100. 50000000 02
100
99.5
99
98.5
This offering is not approved or endorsed by ESI® Group, ESI-OpenCFD® or the OpenFOAM®
II 50
Foundation, the producer of the OpenFOAM® software and owner of the OpenFOAM® trademark.
11.5 The fvSolution dictionary
The file fvSolution contains all settings controlling the solvers and the solution algorithm. This file must
contain two dictionaries. The first controls the solvers and the second controls the solution algorithm.
PIMPLE
{
n O u t e r C o r r e ct o r s 1;
nCorrectors 2;
n N o n O r t h o g o n a l C o r r e c t o r s 0;
pRefCell 0;
pRefValue 0;
}
no control dict
The help summary displayed by -help, in some cases, describes the -dict options as follows: read control dic-
tionary from specified location. However, the dictionary specified with the -dict option is not the controlDict.
Thus, all entries that go into controlDict need to go into controlDict. For some tools the description of
the -dict option seems a little ambiguous. What is meant by control dictionary in this case is the dictio-
nary controlling this specific tool, such as blockMeshDict controlls blockMesh or snappyHexMeshDict controls
snappyHexMesh.
This offering is not approved or endorsed by ESI® Group, ESI-OpenCFD® or the OpenFOAM®
II 51
Foundation, the producer of the OpenFOAM® software and owner of the OpenFOAM® trademark.
12 Usage of OpenFOAM
12.1 Use OpenFOAM
In the most simple case, Listing 55 represents a complete simulation-run.
blockMesh
checkMesh
icoFoam
paraFoam
The first command, blockMesh, creates the mesh. The geometry has to be defined in blockMeshDict. checkMesh
performs, as the name suggests, checks on the mesh. The third command is also the name of the solver. All
solvers of OpenFOAM are invoked simply by their name. The last command opens the post-processing tool
ParaView.
There are additional tasks that extend the sequence of commands shown in Listing 55. These can be
• Convert a mesh created by an other meshing tool, e.g. import a Fluent mesh
• Initialise fields
• Set up an parallel simulation; see Section 12.5
Redirecting the solver output does not only create a log file, it also save the time that is needed to print the
output to the Terminal. In some cases this can reduce simulation time drastically. However, writing to hard
disk also takes its time.
executionTime is the time the processor takes to calculate the solution of the case. clockTime is the time
that elapses between start and end of the simulation, this is the time the wall clock indicates. The value of
the clockTime is always larger than the value of the executionTime, because computing the solution is not the
only task the processor of the system performs. Consequently, the value of the ClockTime depends on external
factors, e.g. the system load.
This offering is not approved or endorsed by ESI® Group, ESI-OpenCFD® or the OpenFOAM®
II 52
Foundation, the producer of the OpenFOAM® software and owner of the OpenFOAM® trademark.
Redirect output to nowhere
If the output of a program is of no interest it can be redirected to virtually nowhere to prevent it from being
displayed on the Terminal. Listing 57 shows haw this is done. /dev/null is a special file on unix-like systems
that discards all data written to it.
12.1.2 Run OpenFOAM in the background, redirect output and read log
In Section 12.1.1 the redirection of the solver output was explained. To monitor the progress of running
calculation the end of the log can be read with the tail command.
Listing 58 shows how a simlation with icoFoam is started and the solver output is redirected. The & at
the end of the line causes the invoked command to be executed in the background. The Terminal remains
therefore available. Otherwise the Terminal would be waiting for icoFoam to finish before executing any further
commands.
The second command invoked in Listing 58 prints the last 5 lines of the log file to the Terminal. tail returns
the last lines of a text file. Without the parameter -n tail returns by default the last 10 lines.
user@host :∼/ OpenFOAM / user -2.1. x / run / icoFoam / cavity$ icoFoam > foamRun . log &
[1] 10416
user@host :∼/ OpenFOAM / user -2.1. x / run / icoFoam / cavity$ tail foamRun . log -n 5
ExecutionTime = 0.74 s ClockTime = 1 s
Time = 1.12
Listing 58: Read redirected output from log file while the solver is running
The probes1 -directory contains the data generated by the functionObject named probes1. The time-directories
contain the solution data of the whole computational domain. Listing 60 shows the contents of the 0 - and the
0.1 -directory. Typically, time-directories generated in the course of the computation contain more data than
the 0 -directory defining the initial conditions.
This offering is not approved or endorsed by ESI® Group, ESI-OpenCFD® or the OpenFOAM®
II 53
Foundation, the producer of the OpenFOAM® software and owner of the OpenFOAM® trademark.
Using binary files or compressing files
In general the time-directories use the majority of the hard disk space a completed case takes. If the time-
directories are saved in binary instead of ascii format, these use generally a little less space. Another advantage
of storing time step data in binary format, the time step data has full precision.
OpenFOAM also offers the possibility to compress all files in the time step directories. For compression
OpenFOAM uses gzip, this is indicated by the files names in the time step directories, i.e. alpha1.gz instead
alpha1.
Table 2 shows a comparison of hard disk use. The most reduction is achieved by compressing ascii data files.
However, storing the time step data in ascii has the disadvantage that the numerical precision is limited to the
number of digits stated with the writePrecision keyword in the controlDict. In this case writePrecision
was set to 6, i.e. numbers have up to 6 significant digits. Compressing the binary files shows less effect than
compressing the ascii files, which indicates that the binary files contain less redundant bytes.
This offering is not approved or endorsed by ESI® Group, ESI-OpenCFD® or the OpenFOAM®
II 54
Foundation, the producer of the OpenFOAM® software and owner of the OpenFOAM® trademark.
user@host :∼$ sleep 3
user@host :∼$
user@host :∼$ ps
PID TTY TIME CMD
13490 pts /1 00:00:00 bash
13714 pts /1 00:00:00 ps
user@host :∼$
The output of 62 is rather dull. However, there are lots of parameters telling ps what to do. The option -e
makes ps list all systemwide running processes. The output of such a call can be quite long, because ps lists all
processes started by the users as well as all system processes27 .
The option -F controls the output format of ps. In this case -F stands for extra full. This means the output
contains a lot of information. Another option to display much information is -l. This option truncates the
names of the processes to 15 characters, whereas -F displays not only the full name of the process, it also
displays the parameters with which the processes were called.
ps - eF
ps displays much information about a process. For terminating a process only the PID is necessary.
This offering is not approved or endorsed by ESI® Group, ESI-OpenCFD® or the OpenFOAM®
II 55
Foundation, the producer of the OpenFOAM® software and owner of the OpenFOAM® trademark.
Both are standard solvers of OpenFOAM. The bold part are the first 15 characters of the solver’s name. If the
option -F was omitted and both solvers were running, the results of ps would be ambiguous.
The second part of the command invoked in Listing 64 shows the call of grep. grep can be called with one or
two arguments. If only one argument is passed to grep, grep uses the standard input as input. If grep is called
with two parameters, the second argument has to specify the file from which grep has to read. As grep is called
with only one argument, it reads from the standard input.
Because it would be even more boring to type the list returned by ps we redirect the output of ps to the
standard input of grep. This is done by the pipe. The character | marks the connection of two processes in the
Terminal. The command left of the | passes its output directly to the command specified right of the |.
Now we can read and interpret Listing 64. It shows the output of the search for all running processes con-
taining the pattern Foam. In this case a parallel computation is going on. The first line of the result is mpirun.
This process controls the parallel running solvers. The next four lines are the four instances of the solver. How
parallel simulation works is explained in Section 12.5. The second last entry of the result is grep waiting for
input28 . The last line of the result is the pdf viewer which displays this document at that time. This example
shows that is important to choose the pattern wisely, the search may return unexpected results.
user@host :∼$ ps -C t w o P h a s e E u l e r F o a m
PID TTY TIME CMD
11006 pts /2 00:47:44 t wo Ph as e Eu le rF o
11007 pts /2 00:47:44 tw oP h as eE ul e rF o
11008 pts /2 00:47:44 tw oP h as eE ul e rF o
11009 pts /2 00:47:43 t wo Ph as e Eu le rF o
user@host :∼$
user@host :∼$ ps -C t w o P h a s e E u l e r F o a
PID TTY TIME CMD
12741 pts /0 00:00:34 tw oP h as eE ul e rF o
12742 pts /0 00:00:34 tw oP h as eE ul e rF o
12743 pts /0 00:00:34 tw oP h as eE ul e rF o
12744 pts /0 00:00:34 tw oP h as eE ul e rF o
28 On most Unix-like systems processes connected by a pipe are started at the same time. For this reason grep is already running
This offering is not approved or endorsed by ESI® Group, ESI-OpenCFD® or the OpenFOAM®
II 56
Foundation, the producer of the OpenFOAM® software and owner of the OpenFOAM® trademark.
user@host :∼$ ps -C t wo Ph as e Eu le rF o
PID TTY TIME CMD
12741 pts /0 00:00:36 t wo Ph as e Eu le rF o
12742 pts /0 00:00:36 t wo Ph as e Eu le rF o
12743 pts /0 00:00:36 t wo Ph as e Eu le rF o
12744 pts /0 00:00:36 t wo Ph as e Eu le rF o
user@host :∼$ ps -C twoPhase EulerF
PID TTY TIME CMD
user@host :∼$ ps -C t wP ha se E ul er Fo a
PID TTY TIME CMD
Terminate
The operating system interacts with running processes using signals. The user can also send signals to processes
using the command kill. kill sends by default the termination signal. To identify the process to which the signal
is to be sent, the PID of this process has to be passed as an argument.
Listing 67 shows how the programm sleep is executed, all running processes are listed, the running instance
of sleep is terminated and the running processes are listed again. When ps was executed the second time, a
message is displayed stating the process has been terminated29 . If the process would not have been terminated
the message at the “natural” end of the process would be like in Listing 6830 .
29 On other systems this message is displayed immediately – see Listing 69. In this case the procedure was tried on the local
computing cluster.
30 A system with English language setting the message would read Terminated if the process would have been terminated and
This offering is not approved or endorsed by ESI® Group, ESI-OpenCFD® or the OpenFOAM®
II 57
Foundation, the producer of the OpenFOAM® software and owner of the OpenFOAM® trademark.
12.4 Continue a simulation
If a simulation has ended at the end time or if it has been aborted there may be the need to continue the
simulation. The most important setting to enable a simulation to be continued has to be made in the file
controlDict. There, the keyword startFrom controls from which time the simulation will be started.
The easiest way to continue a simulation is to set the startFrom parameter to latestTime. Then, if
necessary, the value of endTime needs to be adjusted. After this changes, the simulation can be continued by
simply invoking the solver in the Terminal.
The number of processes, in this case 4, has to be equal the number of processor* folders. These folders are
created by decomposePar and their number is defined in decomposeParDict. See Section 12.5.2 for information
about domain decomposition.
If this numbers – the number of processor* folders and the number of parallel processes with which mpirun
is invoked – are not equal OpenFOAM issues an error message similar to Listing 71. In this case the domain
was decomposed into 4 subdomains and it was tried to start the parallel simulation with 2 processes. If the
parallel simulation is called with too many processes, OpenFOAM issues an error message like in Listing 72.
The first example shows, that OpenFOAM reacts differently whether the parallel job was started with loo little
or too many processes.
This offering is not approved or endorsed by ESI® Group, ESI-OpenCFD® or the OpenFOAM®
II 58
Foundation, the producer of the OpenFOAM® software and owner of the OpenFOAM® trademark.
Pitfall: -parallel
The parameter -parallel is important. If this parameter is omitted, the solver will be executed n times.
Listing 73 shows the output of the command ls when it is run with mpirun with two processes. In this case ls
is simply run twice.
If the parameter -parallel is missing, the same happens as in the case of ls. The simulation is run by n
processes at roughly the same time. Listing 74 shows the first lines of output of a situation where the -parallel
parameter was omitted. All solvers start the calculation of the whole case and write their output to the Ter-
minal. The output appears on the Terminal in the order as it is generated by the solvers – in other words, the
output on the Terminal is completely disarranged. If the -parallel parameter is missing, there is also no check
if the processor* folders are present.
user@host :∼/ OpenFOAM / user -2.1. x / run / icoFoam / cavity$ mpirun - np 4 icoFoam
/* - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -*\
| ========= | |
| \\ / F ield | OpenFOAM : The Open Source CFD Toolbox |
| \\ / O peration | Version : 2.1. x |
| \\ / A nd | Web : www . OpenFOAM . org |
| \\/ M anipulation | |
\* - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -*/
Build : 2.1. x -6 e89ba0bcd15
Exec : icoFoam
Date : Jan 29 2013
Time : 10:51:12
Host : " host "
PID : 25622
/* - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -*\
| ========= | |
| \\ / F ield | OpenFOAM : The Open Source CFD Toolbox |
| \\ / O peration | Version : 2.1. x |
| \\ / A nd | Web : www . OpenFOAM . org |
| \\/ M anipulation | |
\* - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -*/
Build : 2.1. x -6 e89ba0bcd15
Exec : icoFoam
This offering is not approved or endorsed by ESI® Group, ESI-OpenCFD® or the OpenFOAM®
II 59
Foundation, the producer of the OpenFOAM® software and owner of the OpenFOAM® trademark.
12.5.2 Domain decomposition
Before a parallel simulation can be started the domain has to be decomposed into the correct number of
subdomains – one for each parallel process. The parallel processes calculate on their own subdomain and
exchange data of the border regions at the end of each time step. This is also the reason why the parallel
processes have to be synchonous. Otherwise, processes with a lower computational load would overtake other
processes and they would exchange data from different times.
Just before starting the simulation the domain has to be decomposed. The tool decompsePar is used for
this purpose. Other operations, e.g. initialising fields using setFields have to take place before the domain
decomposition. decomposePar reads from decomposeParDict in the system directory. This file has to contain
al least the number of subdomains and the decomposition method.
decomposePar creates the processor* directories in the case directory. Inside the processor* folders a 0 and
a constant folder are created. The 0 folder contains the initial and boundary conditions of the subdomain and
the constant folder contains a polyMesh folder containing the mesh of the subdomain.
All parallel processes read from the same system directory, as the information stored there is not affected
by the domain decomposition. Also the files in the constant directory are not altered.
--> FOAM FATAL ERROR : Case is already decomposed with 2 domains , use the - force option or
manually
remove processor directories before decomposing . e . g . ,
rm - rf / home / user / OpenFOAM / user -2.1. x / run / icoFoam / cavity / processor *
This offering is not approved or endorsed by ESI® Group, ESI-OpenCFD® or the OpenFOAM®
II 60
Foundation, the producer of the OpenFOAM® software and owner of the OpenFOAM® trademark.
12.5.3 Domain reconstruction
To be able to look at the results the data has to be reassembled again. This job is done by reconstructPar. This
tool collects all data of the processor* folders and reconstructs the original domain using all the generated time
step data. After reconstructPar has finished the data of the whole domain resides in the case directory and the
data of the subdomains resides in the processor* folders.
Listing 78 shows the content of the case directory after a parallel simulation has finished. The first command
is a simple call of ls to display the contents of the case directory. This is not different from the situation before
the parallel simulation was started with the exception of the log file. However, this log file could be from a
previous run. So, listing the contents after a parallel simulation has finished carries no real information.
The second command lists the contents of the processor0 directory. In this directory – as well as in all other
processor* folders – there is time step data. The third command reconstructs the domain. After this tool has
finished, the case directory also contains time step data. The last command lists the contents of the processor0
folder again. This data has not been removed. So, a finished parallel case stores its time step data twice and
therefore uses a lot of space.
Time management
If a simulation has been startet from t = t1 the domain has to be reconstructed for times t > t1 . Calling re-
constructPar without any options regarding time, the program starts reconstructing the domain at the earliest
time. To prevent the tool from reconstructing already reconstructed time steps the -time option can be used.
Listing 79 shows how simulation results are reconstructed for t ≤ 60 s.
Another option to reconstruct only the new time steps is the command line option -newTimes. By using
this option the proper time span to reconstruct is automatically determined.
1. Set up the case and run some test simulations, e.g. for a small number of time steps, on the workstation
to ensure the simulation runs
2. Do the actual simulation on the cluster
The fact, that OpenFOAM runs on a great number of platforms enables the user to do simulations on the
workstation as well as on a big cluster with tens or hundreds of processors.
This offering is not approved or endorsed by ESI® Group, ESI-OpenCFD® or the OpenFOAM®
II 61
Foundation, the producer of the OpenFOAM® software and owner of the OpenFOAM® trademark.
Run OpenFOAM using a script
Section 67.5 explaines how to set up a script that runs multiple cases.
Listing 80: Excluding the wifi interface (named wlp3s0 in this case) form use by mpirun
Alternatively, this setting can also be made permanent via an environment variables34 .
file : / home / user / OpenFOAM / user -2.1. x / run / icoFoam / testCase / constant / polyMesh / system / controlDict
at line 0.
FOAM exiting
This offering is not approved or endorsed by ESI® Group, ESI-OpenCFD® or the OpenFOAM®
II 62
Foundation, the producer of the OpenFOAM® software and owner of the OpenFOAM® trademark.
The correct usage of the -case option is shown in Listung 82. There the correct path to the case directory
– two levels upwards – is specified using ../...36
user@host :∼/ OpenFOAM / user -2.1. x / run / icoFoam / testCase / constant / polyMesh$ f l u e n t 3 D M e s h T o F o a m -
case ../.. caseMesh . msh
12.7.2 Pitfalls
Delete dynamicCode folder
A very common workflow, when using OpenFOAM on a remote computing cluster, involves setting-up the case
on your local machine, and then pass the case to the number crunching cluster. Set-up the case, and subsequent
trouble-shooting is best done locally, since generally time on clusters is a limited resource, which is best not
wasted with trouble-shooting.
However, when tinkering with a case with dynamic code, e.g. coded boundary conditions or coded function
objects, we need to delete the dynamicCode directory from the case, before passing the case on to the cluster.
The local machine and the cluster, are most probably not completely binary compatible, causing the parts
relying on dynamic code to cause OpenFOAM to abort. By deleting the dynamicCode folder, we ensure that
the OpenFOAM installation compiles all dynamic code related parts of the case by itself.
A common nuisance related to this topic occurs when dealing with cases featuring coded boundary condi-
tions, such as codedFixedValue. Operations on the local machine, e.g. parallel decomposition, cause the local
OpenFOAM installation to compile the coded boundary condition. Later, when starting the parallel run of
the case on the remote machine, the coded boundary condition is not recognized by the remote OpenFOAM
installation, and thus (remote) OpenFOAM aborts with an error message saying that the specified boundary
condition does not exist.
change in the Terminal one directory upwards on Linux cd .. does the job and on MS-DOS or Windows cd.. is the proper
command.
Also, on Linux systems the tilda refers to the home directory of the current user.
This offering is not approved or endorsed by ESI® Group, ESI-OpenCFD® or the OpenFOAM®
II 63
Foundation, the producer of the OpenFOAM® software and owner of the OpenFOAM® trademark.
shell scripts with respect to using OpenFOAM deserves a prominent place in this section on the general use
of OpenFOAM. Section 67.5.1 of this document also discusses the use of shell script when running simulations
using OpenFOAM.
# !/ bin / bash
37 https://github.com/OpenFOAM/OpenFOAM-dev/commit/845d5b16e30d568af3eb71c69ff7f8079347522e
This offering is not approved or endorsed by ESI® Group, ESI-OpenCFD® or the OpenFOAM®
II 64
Foundation, the producer of the OpenFOAM® software and owner of the OpenFOAM® trademark.
Part III
Pre-processing
This part of the document deals with all issues related to pre-processing, i.e. all the tasks necessary to set-up a
valid simulation case. The majority of the following sections deal with the mesh. The final sections of this part
deal with general case manipulation and initialisation.
This offering is not approved or endorsed by ESI® Group, ESI-OpenCFD® or the OpenFOAM®
III 65
Foundation, the producer of the OpenFOAM® software and owner of the OpenFOAM® trademark.
13 Mesh basics
13.1 Basics of the mesh
13.1.1 Files
A mesh is defined by OpenFOAM using several files. All of these files reside in constant/polyMesh/. The
names of these files are rather self explanatory, the rest is explained in the OpenFOAM User Guide [52].
boundary contains a list of all faces forming the boundary patches. This file is always written in ASCII format.
faces contains the definition of all faces. A face is defined by the points that form the face.
neighbour contains a list of the neighbouring cells of the faces
owner contains a list of the owning cells of the faces
13.1.2 Definitions
Face
A face is defined by the vertices or points that are part of the face. The points need to be stated in an order
which is defined by the face normal vector pointing to the outside of the cell or the block. The way faces are
defined is the same for cells of the mesh or for blocks of the geometry.
n
7 6
4 5
To elaborate this further we look at the top face of the generic block of Figure 8 in Figure 5. The vertices
with the numbers 4, 5, 6 and 7 are part of the face. The face normal vector – denoted by n in Figure 5 – that
points outwards of the block is parallel to the local z axis. Therefore we need to specify the vertices defining
This offering is not approved or endorsed by ESI® Group, ESI-OpenCFD® or the OpenFOAM®
III 66
Foundation, the producer of the OpenFOAM® software and owner of the OpenFOAM® trademark.
the face in counter-clockwise circular order, when we look at the block from the top. The direction of rotation
is marked in Figure 5 with the + sign. The starting vertex is arbitrary but it must not appear twice in the list.
Correct definitions
(4 5 6 7) (7 4 5 6) (6 7 4 5) (5 6 7 4)
While the definition of the face normal of boundary faces is straight forwards, as discussed above, the face
normal of internal faces is not as obvious. Internal faces connect two adjacent cells. While internal faces are
created by OpenFOAM’s meshing utilities, and no valid use-case for manually specifying internal faces comes
to mind, the face-normal orientation of internal faces may be important when specifying sets of internal faces
for run-time post-processing. The user-guide38 states, that the orientation of the face-normal of internal faces
is such, that the face normal points from the cell with the lower cell label to the cell with the higher cell label.
As all cells are consecuitively numbered from 0 to N , with N being the number of cells, the stated rule provides
a clear rule for the face-normal direction of internal faces.
The binary format might not be compatible across various OpenFOAM variants
If we run checkMesh of foam-extend on a mesh which was written in binary format by OpenFOAM-6, then an
error as in Listing 85 occurs. Thus, make sure to pass the mesh between OpenFOAM variants in ASCII format.
See Section 27.6.4 for a discussion on how to convert mesh files from the binary to the ASCII format.
file : / home / user / foam / run -4.0/ meshTesting / constant / polyMesh / faces at line 15.
FOAM exiting
Listing 85: A possible error when reading a binary mesh with a different OpenFOAM variant.
This offering is not approved or endorsed by ESI® Group, ESI-OpenCFD® or the OpenFOAM®
III 67
Foundation, the producer of the OpenFOAM® software and owner of the OpenFOAM® trademark.
tools to create the intended mesh. The most basic of such a mesh-creation & mesh-manipulation sequence
would be to first run blockMesh and subsequently run renumberMesh.
Thus, we should aspire to organize our cases in a way to achieve a separation of separated tasks, i.e. creating
the mesh, running the case and post-processing the case. Such a separation can be translated into an actual
division of labour by creating sub-scripts for each task. Listing 86 shows a pattern for an Allrun script, which
embodies this separation of tasks. Instead of calling tools and solvers directly, we call sub-scripts which we
created for those specific tasks.
# !/ bin / sh
# this script contains all steps for mesh - creation and mesh - manipulation
./ createMesh
# now , that the mesh is in its final form , we instate the initial time step 0
cp -r 0. org 0
If we introduced our fields too early, then missing – yet to be created – patches may cause some pre-
processing tools to fail. By eliminating the fields from the mesh-creation stage, we eliminate one source of
error. Furthermore, dragging the fields through the mesh-generation process, with creation of patches, adding
or removing cells, any many other non-trivial mesh-modifications, is a useless waste of computational effort,
and a needless source of error. Thus, it is advised to follow this rough guideline:
1. Create the mesh, without involving the fields
2. Set up the fields for the final form of the mesh
Tools for three dimensions and tools for three dimensions or less
Not all tools in OpenFOAM’s arsenal allow for lesser-dimensional meshes. The two main mesh creation tools
serve as a perfect example. While blockMesh is perfectly capable to create meshes for three dimensions or less;
snappyHexMesh is a purely three-dimensional mesher39 .
39 Since there are always expections to any rule, there is also an exception for this rule. We can create a two-dimensional snappy-
like mesh by meshing a quasi two-dimensional block using snappyHexMesh, and then extrude a single-cell layer from this mesh and
discard the base mesh.
This offering is not approved or endorsed by ESI® Group, ESI-OpenCFD® or the OpenFOAM®
III 68
Foundation, the producer of the OpenFOAM® software and owner of the OpenFOAM® trademark.
13.3.2 Pitfall: combined front-and-back patch in a 2D wedge geometry
While it is perfectly normal and valid to define a combined front-and-back patch of the empty type in “normal”
two-dimensional simulations, axisymmetric 2D simulations do not allow for a combined front-and-back patch of
the type wedge.
If we defined such a combined front-and-back patch, OpenFOAM will complain about encountering a non-
planar wedge-type patch. While, the front and the back surface might be perfectly planar, a combined front-
and-back patch will inevitably cause problems. OpenFOAM’s definition for the planarity of a patch is that the
surface normal of the individual faces of a patch is parallel to the patch-average normal vector. A combined
front-and-back patch will violate this condition.
Thus, with axi-symmetric mesh must have separate front and back patches of the type wedge.
Figure 6: The same axi-symmetric two-dimensional viewed with three different installations of ParaView.
This offering is not approved or endorsed by ESI® Group, ESI-OpenCFD® or the OpenFOAM®
III 69
Foundation, the producer of the OpenFOAM® software and owner of the OpenFOAM® trademark.
14 Geometry creation & other pre-processing software
There are many ways to create a geometry. There is a great number of CAD software, there is a number of
CFD pre-processors capable of creating geometries and there is the good old blockMeshDict.
This section is about the different ways to generate the geometry for creating a finite volume mesh.
14.1 blockMesh
blockMesh is one of OpenFOAMs own pre-processing tools. It is able to create the domain geometry and the
corresponding mesh. See Section 15 for a discussion on blockMesh. For the reason of simplicity all aspects of
blockMesh – geometry creation as well as meshing – are covered in Section 15.
14.2.1 OpenSCAD
OpenSCAD [http://www.openscad.org/] is an open source CAD tool for creating solid 3D CAD models. A
CAD model is created by using primitve shapes (cubes, cylinders, etc.) or by extruding 2D paths. Models are
not created interactively like in other CAD software. The user writes an input script which is interpreted by
OpenSCAD. This makes it easy to create parametric models.
For further information on usage see the documentation http://en.wikibooks.org/wiki/OpenSCAD_User_
Manual.
40 STL is infact a surface mesh enclosing the geometry. Therefore the term STL mesh or STL surface mesh is also valid.
This offering is not approved or endorsed by ESI® Group, ESI-OpenCFD® or the OpenFOAM®
III 70
Foundation, the producer of the OpenFOAM® software and owner of the OpenFOAM® trademark.
Figure 7: The STL mesh of a circular area generated by OpenSCAD
14.3 Salome
Salome [http://www.salome-platform.org/] is a powerful open source pre-processing software developed by
EDF. Salome can be used to create a geometry interactively or by interpreting a python script41 . Salome comes
with a number of internal and external meshing utilities. Salome has also a post-processing module.
Salome is a part of a collection of open source software developed by EDF. Salome serves as the pre- and
post-processor for Code_Aster (structural analysis) and Code_Saturne (CFD).
14.3.1 Geometry
Salome can be used for geometry generation only. A common way of doing so, is to use Salome’s meshing
module to create a surface mesh of the CAD geometry, which can be exporting using the STL format. The
resulting STL file can then be used by other meshing tools, e.g. snappyHexMesh.
14.3.2 Mesh
Salome can also used to create the geometry and subsequently the mesh. This mesh needs to be exported by
Salome in the UNV format, which can be converted by the ideasUnvToFoam utility of OpenFOAM.
See http://caelinux.org/wiki/index.php/Doc:Salome for documentation and usage examples of Salome,
and Section 23 for some further points on creating the mesh with Salome.
14.4 GMSH
GMSH is a meshing tool with some pre- and post-processing capabilities [http://www.geuz.org/gmsh/]. The
meshes generated by GMSH can be converted to OpenFOAM’s format using the gmshToFoam utility.
41 Salome can be controlled completely by Python. Thus parametric geometry or mesh creation is possible.
This offering is not approved or endorsed by ESI® Group, ESI-OpenCFD® or the OpenFOAM®
III 71
Foundation, the producer of the OpenFOAM® software and owner of the OpenFOAM® trademark.
15 blockMesh
blockMesh is used to create a mesh. The geometry is defined in blockMeshDict. This file also contains all
necessary parameters needed to create the mesh, e.g. the number of cells. Therefore, blockMesh is a combined
tool to define and mesh a geometry in contrast to other meshers that use CAD files to import a geometry
created by some other software.
7 2 →
6
% %
7 6
3 → ↑
4 5 10
↑
11
↑
↑ 9
8 3 1 →
2
z
%
%
4 5
y
x 0 →
0 1
Figure 8: The generic block
42 In mathematics the positive direction of rotation is generally determined with the right-hand or cork-screw rule. Let the thumb
of your right hand point in the positive direction of the rotation axis, then the fingers of the right hand point in the positive
direction of revolution.
43 If we number all vertices in the x − y plane then the local z axis is the axis of revolution. Thus the counter-clockwise direction
This offering is not approved or endorsed by ESI® Group, ESI-OpenCFD® or the OpenFOAM®
III 72
Foundation, the producer of the OpenFOAM® software and owner of the OpenFOAM® trademark.
15.2 The blockMeshDict
The file blockMeshDict defines the geometry and controls the meshing process of blockMesh. Listing 87 shows
a reduced example of the blockMeshDict. This file was taken from the cavity tutorial case.
/* - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -* - C ++ -* - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -*\
| ========= | |
| \\ / F ield | OpenFOAM : The Open Source CFD Toolbox |
| \\ / O peration | Version : 2.1. x |
| \\ / A nd | Web : www . OpenFOAM . org |
| \\/ M anipulation | |
\* - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - */
FoamFile
{
version 2.0;
format ascii ;
class dictionary ;
object blockMeshDict ;
}
// * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * //
c on ve rt T oM et er s 0.1;
vertices
(
(0 0 0) // 0
(0 0 0.1) // 1
...
);
blocks
(
hex (0 1 2 3 4 5 6 7) (20 20 1) simpleGrading (1 1 1)
);
edges
(
);
boundary
(
movingWall
{
type wall ;
faces
(
(3 7 6 2)
);
}
...
);
m er ge Pa t ch Pa ir s
(
);
// * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * //
15.2.1 convertToMeters
convertToMeters is a scaling factor to convert the vertex coordinates of blockMeshDict into meters. If the
vertex coordinates are entered in an other unit than meters, this value has to be chosen accordingly. Listing 88
shows how to set this factor if the vertex coordinates are entered in millimeters.
c on ve rt T oM et er s 0.001;
This offering is not approved or endorsed by ESI® Group, ESI-OpenCFD® or the OpenFOAM®
III 73
Foundation, the producer of the OpenFOAM® software and owner of the OpenFOAM® trademark.
Listing 88: convertToMeters
If the keyword convertToMeters is missing in the blockMeshDict, then no scaling is used, i.e. the default
value of 1 is assumed.
To make sure if a scaling factor has been used, the output of blockMesh can be checked. Listing 89 shows
the message issued by blockMesh regarding the scaling factor defined with convertToMeters.
15.2.2 vertices
The vertices sub-dictionary contains a list of vertices. Each vertexs is defines by its coordinates in the global
coordinate system. By default OpenFOAM treats these coordinates as in metres. However, with the help of
the keyword convertToMeters, the vertices can be specified in other units.
The index of a vertex in this list is also the global number of this vertex, which is needed when constructing
blocks from the vertices. Remember, counting starts from zero. Thus the first vertex is the list of vertices can
be addressed by its index 0. A way to keep oneself aware of this fact is to add comments44 to the vertex list as
in Listing 87.
15.2.3 blocks
The only valid entry in the blocks sub-dictionary is the hex keyword. The blocks section of the blockMeshDict
contains a list of hex commands. Listing 90 shows an example of a block definition with the hex keyword.
After the word hex a list of eight numbers defining the eight vertices of the block follows. The order of the
entries in this list is the same order as the local vertex numbers of the block in Figure 8.
Then a list of three positive integer numbers follows. These numbers tell blockMesh how many cells need
to be created in the direction of the local coordinate axes. Thus, the first number is the number of cells in the
local x direction.
The next entry is a word stating the grading of the edges. This entry is in fact redundant. In OpenFOAM-
2.1.x only the last entry, the list of expansion ratio, controls the grading. The third entry could even be omitted.
However, maybe future versions of OpenFOAM make use of this entry. So the author does not advocate to
omit this parameter.
The last entry of the block definition is a list of either three or twelve positive numbers. This numbers define
the expansion ratio of the grading. In the case of three numbers, simpleGrading is applied. If twelve numbers
are stated, then edgeGrading is performed.
If the list contains only one entry, then all edges share the same expansion ratio. Any other number of
entries in this list leads to an error.
Listing 91: The hex command in blockMeshDict with a cell set definition.
44 As OpenFOAM treats its dictionaries much in the same way as C/C++ source files are treated by the C/C++ compiler.
This offering is not approved or endorsed by ESI® Group, ESI-OpenCFD® or the OpenFOAM®
III 74
Foundation, the producer of the OpenFOAM® software and owner of the OpenFOAM® trademark.
Creating a block with 6 faces
The hex instruction can also be used to create a prism with a triangular cross-section. Such blocks are needed
for simulations that make use of axi-symmetry. In such a case, an “axis-patch” is created using only two vertices,
as shown in Figure 9. This patch is constructed from the vertex list (4 5 5 4), instead of (4 5 6 7) as it
would be the case for an ordinary block.
Figure 9: Creating a wedge geometry for 2D, axisymmetric domains. Reproduced after [52].
This collapsed patch results in an empty patch, i.e. one that contains no faces. In Listing 92, we see the
summary on the patches, which is printed to the Terminal by blockMesh. Here, we can see the empty patch axis.
Patches
----------------
patch 0 ( start : 10159 size : 5) name : inletCH4
patch 1 ( start : 10164 size : 70) name : wallOutside
patch 2 ( start : 10234 size : 61) name : wallTube
patch 3 ( start : 10295 size : 5) name : inletPilot
patch 4 ( start : 10300 size : 60) name : inletAir
patch 5 ( start : 10360 size : 71) name : outlet
patch 6 ( start : 10431 size : 0) name : axis
patch 7 ( start : 10431 size : 5170) name : f r o n t A nd B a c k _ p o s
patch 8 ( start : 15601 size : 5170) name : f r o n t A n d B a c k _ ne g
Listing 92: The patch list of an axisymmetric case from the OpenFOAM tutorials.
When setting up a two-dimensional case, pay attention to velocity boundary conditions, especially those
with a user-provided flow-rate. OpenFOAM is not aware, that the inlet patch is only a fraction of the real inlet.
Thus, a flow rate at the inlet needs to be corrected by the area ratio, i.e. the ratio of the inlet patch of the
two-dimensional simulation domain and the real inlet area.
This behaviour might have been introduced sometime in the past, or it have been there from the beginning.
This offering is not approved or endorsed by ESI® Group, ESI-OpenCFD® or the OpenFOAM®
III 75
Foundation, the producer of the OpenFOAM® software and owner of the OpenFOAM® trademark.
with at least 10 digits.
Listing 94: Using at least 10 digits for writing the points file; excerpt from the file blockMesh.C of OpenFOAM-
5.0
However, some mesh manipulation tools, simply use the setting from the writePrecision setting in the
controlDict. If a too small number of digits is specified in combination with writing in ascii format, informa-
tion (geometric precision) may be lost. This lost precision may be sufficient to trigger the warning messages,
which were discussed above.
OpenFOAM is, at times, quite generous when it comes to the information provided in its error messages.
Below, the example warning message is shown again. This time, the relevant bit of information is highlighted
in red. This very small difference between the local face-normal vector and the patch-average normal-vector is
indicative of an issue regarding writing precision.
This indication could also be gleaned from a comparison of the two listed vectors, the affected local face-
normal and the patch-average normal-vector. However, the highlighted number, which is the magnitude of the
difference, is much easier to read and comprehend.
15.2.4 edges
The edges sub-dictionary contains pairs of vertices that define an edge. By default edges are straight, by
explicitely specifying the shape of the edge, curved edges can be created. This sub-dictionary can be omitted.
Listing 96 shows the message issued by blockMesh when edges is omitted.
Otherwise, blockMesh issues a message as in Listing 97 regardless whether curved edges are actually created or
only an empty edges sub-dictionary is present.
This offering is not approved or endorsed by ESI® Group, ESI-OpenCFD® or the OpenFOAM®
III 76
Foundation, the producer of the OpenFOAM® software and owner of the OpenFOAM® trademark.
Creating arcs
With the keyword arc a circular arc between two vertices can be created. Listing 98 shows the definition of a
circular arc between the vertices 0 and 3. In order to define a circular arc three points are necessary. Therefore
the third point follows the indizes of the two vertices defining the edge.
edges
(
arc 0 3 (0 0.5 0.05)
);
FOAM aborting
Listing 99: Output of blockMesh when the three points defining an arc are co-linear
Creating splines
The keyword spline defines a spline. After the two vertices defining the edge a list of interpolation points has
to follow.
edges
(
spline 0 3 ((0 0.25 0.05) (0 0.75 0.05) )
);
Creating a poly-line
Other than a spline, a poly-line connects several points with straight lines.
edges
(
polyLine 0 3 ((0 0.25 0.05) (0 0.75 0.05) )
);
edges
(
line 0 3
);
This offering is not approved or endorsed by ESI® Group, ESI-OpenCFD® or the OpenFOAM®
III 77
Foundation, the producer of the OpenFOAM® software and owner of the OpenFOAM® trademark.
Summary
Edges defined within the blockMeshDict are used to compute the locations of a block’s internal nodes. The
edge however, is approximated linearly as shown in Figure 10, i.e. the number of cells along the edge determine
the resolution of the edges.
Figure 10: A block with a poly-line at the left side. The red line indicates the poly-line. This figure makes it
obvious that edges defines in the blockMeshDict serve to compute the locations of the block’s internal nodes.
The block itself however, does not obey the poly-line.
Another feature of the edge definition is, that the two vertices defining the edge can be supplied in any
order.
Pitfalls
Edge creation of blockMesh sometimes fails silently46 . If we define an arc between two vertices not directly
connected by an edge, e.g. the vertices 0 and 2 in Figure 8, then blockMesh proceeds without any warning or
error. The faulty edge definition seems to be simply ignored. This, silence in the face of error might make it
hard for the user building his or her blockMeshDict to spot the reason why the definition of curved edges does
not result in curved edges.
15.2.5 boundary
The boundary list contains a dictionary per patch. This dictionary contains the type of the patch and the list
of faces composing the patch. Listing 103 shows an example of how a patch consisting of one face is defined.
boundary
(
inlet
{
type patch ;
faces
(
(0 3 2 1)
);
}
...
);
46 An example non blockMesh failing noisily is the definition of a co-linear interpolation point for an arc.
This offering is not approved or endorsed by ESI® Group, ESI-OpenCFD® or the OpenFOAM®
III 78
Foundation, the producer of the OpenFOAM® software and owner of the OpenFOAM® trademark.
Listing 103: The boundary list of blockMeshDict
Pitfall: defaultFaces
If faces are forgotten in the boundary definition, then blockMesh creates an additional patch named defaultFaces.
This patch has an empty boundary condition automatically assigned. Listing 104 shows a warning message is-
sued by blockMesh. In this case some faces were missing in the boundary definition. This, however, does not
cause blockMesh to abort mesh generation. If a 2D mesh is to be created, the creation of the default patch
with an empty boundary condition can be expected behaviour. However, it is not advisible to rely this kind of
default behaviour when building a case.
If faces are forgotten in the creation of a 3D mesh, this behaviour might hide the source of error. blockMesh
quietly creates the mesh with the default patch – save the warning message as in Listing 104. Running the case
with the errorneous mesh definition will not immediately crash the solver. Even the fact that none of the fields
have a boundary condition specified for the default patch does not cause the solver to abort. A patch with an
empty boundary condition does not require any further entries in the field-files (e.g. U or p). OpenFOAM knows
already all it needs to know about this specific patch and there is no reason to throw an error message. When
the case is run with a 3D mesh and one or more empty patches, the solver starts running without complaints.
At some point the solution might run into numerical trouble.
Only running checkMesh is able to give an indication to detect such kind of error. Listing 105 shows
the warning message issued by checkMesh when a 3D mesh contains one empty default patch. Although, the
warning states that there is something wrong with the mesh, in the end checkMesh reports no failed mesh checks.
Listing 105: A warning message of checkMesh caused by an incomplete boundary definition of a 3D mesh.
Patch groups
Patches can be grouped to save ourselves the hassle to prescript large numbers of identical boundary con-
ditions. Patch groups were introduced with OpenFOAM-2.2.0 see http://openfoam.org/release/2-2-0/
pre-processing-macros-patch-groups/. All boundaries of the constraint type, e.g. empty or processor,
are automatically added to patch groups of the same name. Furthermore, since OpenFOAM-2.3.047 , the patches
of the type wall are added to a group named wall. Also, with OpenFOAM-2.3.0 the order of precedence for
defining boundary conditions for fields was defined:
1. An exact match of the patch name, e.g. inlet
2. A match by a patchGroup
3. A match by regular expression, e.g. “wallPatch.*” for wallPatch0815
2
(
wall 4(0 1 2 3)
empty 1(4)
)
47 http://openfoam.org/release/2-3-0/pre-processing/
This offering is not approved or endorsed by ESI® Group, ESI-OpenCFD® or the OpenFOAM®
III 79
Foundation, the producer of the OpenFOAM® software and owner of the OpenFOAM® trademark.
Listing 106: The automatically defined patch groups of the cavity tutorial of icoFoam. The list was created
with the method groupPatchIDs() of the Foam::polyBoundaryMesh and printed to Terminal with the Info
statement.
3
(
wall 4(0 1 2 3)
banana 3(1 2 3)
empty 1(4)
)
Listing 107: The patch groups of the modified cavity tutorial of icoFoam.
boundaryField
{
movingWall
{
type fixedValue ;
value uniform (1 0 0) ;
}
wall
{
type noSlip ;
}
banana
{
type fixedValue ;
value uniform ( -1 0 0) ;
}
}
Listing 108: The velocity field boundary conditions of the modified cavity tutorial. The entry for frontAndBack
is omitted for brevity. Only movingWall is specified by exact patch name. The fixed walls are specified via
patch groups.
The resulting initial velocity field depends on the order of the entries for wall and banana.
This offering is not approved or endorsed by ESI® Group, ESI-OpenCFD® or the OpenFOAM®
III 80
Foundation, the producer of the OpenFOAM® software and owner of the OpenFOAM® trademark.
Figure 11: The initial velocity field depending on the order of the wall and banana. Left: Setting as in Listing
108. Right: wall and banana have changed places.
Thus, users are suggested to avoid situations involving multiple group membership when specifying boundary
conditions via patch groups.
Listing 109: OpenFOAM is warning about identical names of a patch and a patchGroup.
From function const Foam :: HashTable < Foam :: List < int > , Foam :: word >& Foam :: p o l y B o u n d a r y M es h ::
groupPatchIDs () const
in file meshes / polyMesh / p o l y B o un d a r y M e s h / p o l y B o u n d a r y M e s h . C at line 448.
FOAM exiting
Listing 110: Identical names for patches and patchGroups are not allowed anymore.
Pitfall: patches
In older versions of OpenFOAM, there was a patches sub-dictionary instead of the boundary sub-dictionary,
see http://www.openfoam.org/version2.0.0/meshing.php. In some tutorial cases the old patches sub-
dictionary can be found. However, it is recommended to use the boundary sub-dictionary because in some cases
the use of the patches sub-dictionary results in errors.
To find out if there are still tutorial cases present that use the patches sub-dictionary the command of
Listing 111 searches all files with the name blockMeshDict in the tutorials for the word patches.
Listing 111: Find cases that still use the patches sub-dictionary in the blockMeshDict to define the boundaries
This offering is not approved or endorsed by ESI® Group, ESI-OpenCFD® or the OpenFOAM®
III 81
Foundation, the producer of the OpenFOAM® software and owner of the OpenFOAM® trademark.
15.2.6 mergePatchPairs
The mergePatchPairs list contains pairs of patches that need to be connected by the mesher.
Nothing to merge
This entry can be omitted. Listing 112 shows the message issued by blockMesh when mergePatchPairs is
omitted.
Patches to merge
When two patches need to be merged, then the patch pair needs to be stated in the mergePatchPairs list. The
first patch of the pair is considered the master patch the second is the slave patch. The reason and consequences
of this are described in the official User Manual [52].
m er ge Pa t ch Pa ir s
(
( master slave )
);
boundary
(
master
{
type patch ;
faces
(
(1 2 6 5)
);
}
slave
{
type patch ;
faces
(
(12 15 11 8)
);
}
...
);
Listing 114: The patch definitions needed to connect the blocks of Figure 15 with mergePatchPairs in the
boundary sub-dictionary
blockMesh creates hanging nodes in order to connect the mesh of the blocks. Figure 12 shows the mesh of
two merged blocks. Figure 13 shows the larger of the two blocks. The diagonal lines – one of them is marked
with a red square in Figure 13 – are artefacts of the depiction of ParaView. The diagonal line that divides the
L-shaped area is not present in the mesh. The right image in Figure 13 was edited with an image manipulation
program to reflect the actual situation of the mesh. During the merging operation the face touching the second
block is divided to match the second block. Thus, a quadrangular cell face is divided to two faces. The face
denoted with the red 1 consists of 6 nodes and the face with the red 2 constists of four nodes.
This offering is not approved or endorsed by ESI® Group, ESI-OpenCFD® or the OpenFOAM®
III 82
Foundation, the producer of the OpenFOAM® software and owner of the OpenFOAM® trademark.
Figure 12: The mesh of two merged blocks
Figure 13: The mesh of two merged blocks. Left: screenshot of ParaView. Right: edited image to depict the
actual faces.
This offering is not approved or endorsed by ESI® Group, ESI-OpenCFD® or the OpenFOAM®
III 83
Foundation, the producer of the OpenFOAM® software and owner of the OpenFOAM® trademark.
15.3 Create multiple blocks
A single block is almost never sufficient to model the geometry of a CFD problem. blockMesh offers the possibility
to create an arbitrary number of blocks which can be connected. If blocks are constructed in a fashion that
they share vertices, then they are connected by blockMesh by default.
7 6
11
4 5
8
3 2 10
0 1
Figure 14: Two connected blocks
Listing 115 shows the blocks sub-dictionary to create two connected blocks as they are depicted in Figure
14. The global vertex numbering is arbitrary. However, the order in which the vertex numbers are listed after
the hex keyword corresponds with the local vertex numbering of the generic block in Figure 8.
blocks
(
hex (0 1 2 3 4 5 6 7) (10 10 10) simpleGrading (1 1 1)
hex (1 9 10 2 5 8 11 6) (10 10 10) simpleGrading (1 1 1)
);
Listing 115: The blocks entries in blockMeshDict to create the connected blocks of Figure 14
Listing 116 shows the blocks sub-dictionary to create two unconnected blocks as they are depicted in Figure
15.
blocks
(
hex (0 1 2 3 4 5 6 7) (10 10 10) simpleGrading (1 1 1)
hex (8 9 10 11 12 13 14 15) (10 10 10) simpleGrading (1 1 1)
);
Listing 116: The blocks entries in blockMeshDict to create the unconnected blocks of Figure 15
This offering is not approved or endorsed by ESI® Group, ESI-OpenCFD® or the OpenFOAM®
III 84
Foundation, the producer of the OpenFOAM® software and owner of the OpenFOAM® trademark.
7 6
15 14
4 5
12 13
3 11 2 10
8 9
0 1
Figure 15: Two unconnected blocks
In order to generate a connected mesh of the two blocks, the mergePatchPairs section of the blockMeshDict
has to be provided with the two touching patches.
15.4 Grading
In the file blockMeshDict the grading can be defined globally for the edges of the block or for all edges
individually. The grading is specified by the expansion ratio. This is the ratio of the widths of the first and the
last cell along an edge. The direction of an edge is defined in the general definition of a block (see OpenFOAM
Users Manual [52]).
simpleGrading
The global grading is defined for all edges parallel to the local x, y and z direction of the block. In Listing 117
the grading of all edges parallel to the local x axis oy the block is one, the grading of all edges parallel to the
local y axis is two and the grading of all edges parallel to the local z axis is three.
simpleGrading (1 2 3)
edgeGrading
With the keyword edgeGrading the grading of each edge of the block is specified individually. Therefore, the
value of this keyword is a list with 12 numbers. The numbering of the edges – the list index corresponds to the
edge number – is defined in the general definition of a block (see OpenFOAM Users Manual [52]). Listing 118
has the same effect as Listing 117.
edgeGrading (1 1 1 1 2 2 2 2 3 3 3 3)
This offering is not approved or endorsed by ESI® Group, ESI-OpenCFD® or the OpenFOAM®
III 85
Foundation, the producer of the OpenFOAM® software and owner of the OpenFOAM® trademark.
languages – from 0. Therefore, block 8 is the ninth block.
blocks
(
hex (0 16 20 4 1 17 21 5) (30 5 10) simpleGrading (1 0.5 0.33) // 1
hex (1 17 21 5 2 18 22 6) (30 5 2) simpleGrading (1 0.5 1) // 2
hex (2 18 22 6 3 19 23 7) (30 5 15) simpleGrading (1 0.5 3) // 3
FOAM exiting
blocks
(
hex (0 1 5 4 8 9 13 12 ) (9 1 44) simpleGrading (1 1 1) // 1
hex (1 2 6 5 9 10 14 13 ) (2 1 45) simpleGrading (1 1 1) // 2
hex (2 3 7 6 10 11 15 14 ) (9 1 45) simpleGrading (1 1 1) // 3
);
FOAM exiting
Interesting observation
The source code also allows to state a list with only one entry. This is not documented in the official User
Manual [52].
Listing 123 prooves this observation in the form of the responsible source code. The first command reads a
scalar list from the input stream is. Then the three valid cases – one, three or twelve entries – are handled If
none of the three branches of the if-else branching is entered an error is reported.
This offering is not approved or endorsed by ESI® Group, ESI-OpenCFD® or the OpenFOAM®
III 86
Foundation, the producer of the OpenFOAM® software and owner of the OpenFOAM® trademark.
This code listing is a beautiful example of deducting the behaviour of a program from its source code. Un-
fortunately not all parts of OpenFOAMs source code are that easy to read and understand.
1 scalarList expRatios ( is )
2
3 if ( expRatios . size () == 1)
4 {
5 // identical in x / y /z - directions
6 expand_ = expRatios [0];
7 }
8 else if ( expRatios . size () == 3)
9 {
10 // x - direction
11 expand_ [0] = expRatios [0];
12 expand_ [1] = expRatios [0];
13 expand_ [2] = expRatios [0];
14 expand_ [3] = expRatios [0];
15
16 // y - direction
17 expand_ [4] = expRatios [1];
18 expand_ [5] = expRatios [1];
19 expand_ [6] = expRatios [1];
20 expand_ [7] = expRatios [1];
21
22 // z - direction
23 expand_ [8] = expRatios [2];
24 expand_ [9] = expRatios [2];
25 expand_ [10] = expRatios [2];
26 expand_ [11] = expRatios [2];
27 }
28 else if ( expRatios . size () == 12)
29 {
30 expand_ = expRatios ;
31 }
32 else
33 {
34 FatalErrorIn
35 (
36 " bl oc kD e scri pt o r :: b lo ck D es cr ip t or "
37 " ( const pointField & , const c urvedEdg eList & , Istream &) "
38 ) << " Unknown definition of expansion ratios : " << expRatios
39 << exit ( FatalError ) ;
40 }
Patches
----------------
patch 0 ( start : 118329 size : 14) name : inlet
patch 1 ( start : 118343 size : 7) name : outlet
patch 2 ( start : 118350 size : 1577) name : walls
patch 3 ( start : 119927 size : 6) name : axis
patch 4 ( start : 119933 size : 59938) name : front
patch 5 ( start : 179871 size : 59938) name : back
This offering is not approved or endorsed by ESI® Group, ESI-OpenCFD® or the OpenFOAM®
III 87
Foundation, the producer of the OpenFOAM® software and owner of the OpenFOAM® trademark.
Listing 124: The patch list of an axisymmetric case with a non-empty axis patch.
Having a non-empty axis patch poses no problem for blockMesh during mesh-creation, however, all other
tools and solvers fail to construct a proper mesh. Listing 125 shows an example of the error message issued by
OpenFOAM. Unfortunately, this error message is relatively inexpressive.
Listing 125: The result of having an axisymmetric case with a non-empty axis patch.
This problem was overcome by manually changing the patch type in constant/polyMesh/boundary of the
axis patch from empty to patch, running collapseEdges, and finally manually changing the patch type back to
empty. The manual changing of the patch type is necessary for collapseEdges to be able to read and construct
the mesh. In Listing 126 we see the output of checkMesh after the solution procedure was applied to that
example case. Now, the axis patch is empty, i.e. it contains no faces. Whether the patch is of the type empty
or of the type patch, is not printed by checkMesh.
Listing 126: The patch list of an axisymmetric case after fixing the problem with the non-empty axis patch.
Simply, increasing the writePrecision or switching to writing in binary format did not resolve the problem.
blocks
(
hex (0 1 5 4 8 9 13 12 ) ( N1x 1 N1z ) simpleGrading (1 1 1) // 1
hex (1 2 6 5 9 10 14 13 ) ( N2x 1 N1z ) simpleGrading (1 1 1) // 2
hex (2 3 7 6 10 11 15 14 ) ( N1x 1 N1z ) simpleGrading (1 1 1) // 3
);
This offering is not approved or endorsed by ESI® Group, ESI-OpenCFD® or the OpenFOAM®
III 88
Foundation, the producer of the OpenFOAM® software and owner of the OpenFOAM® trademark.
15.5.2 The macro programming language m4
In order to replace the symbols of the prototype with meaningful numbers, the prototype has to be processed
by a macro programming language interpreter. In this case the programming language m4 48 is used. The
interpreter of this language scans the prototype for valid expressions (macros) and replaces them with their
result.
To replace a symbol of the prototype with a meaningful number, a macro has to be defined. Listing 128
shows the definition of the symbols used in Listing 127. In the first line a general variable h is defined. The
second and the third instruction calculate the number of cells in the local x direction based on the variable h.
The last instruction calculates the number of cells in the local z direction.
define (h ,2)
This kind of parametrisation allows to specify a multiplier for the number of cells. The discretisation length
can not be refined gradually this way. Specifying the discretisation length requires more complex math than
integer operations.
This offering is not approved or endorsed by ESI® Group, ESI-OpenCFD® or the OpenFOAM®
III 89
Foundation, the producer of the OpenFOAM® software and owner of the OpenFOAM® trademark.
Listing 129: Block definition of the prototype
Listing 129 allows to calculate the number of cells from a specified discretisation length. Due to rounding
operations the specified discretisation length is not exactly met. Listing 130 shows the result after the macros
from Listings 127 and 129 have been processed.
blocks
(
hex (0 1 5 4 8 9 13 12 ) (11 1 40) simpleGrading (1 1 1) // 1
hex (1 2 6 5 9 10 14 13 ) (7 1 40) simpleGrading (1 1 1) // 2
hex (2 3 7 6 10 11 15 14 ) (11 1 40) simpleGrading (1 1 1) // 3
);
1 changecom (//)
2 changequote ([ ,])
3
4 define ( calc , [ esyscmd ( perl -e ’ print ( $1 ) ’) ])
5
6 define ( rb , 0.5)
7 define ( Rb , 0.7)
8
9 define ( ri , calc (0.5*( rb + Rb ) ) )
10
11 define ( pi , 3.14159265)
12 define ( ca0 , calc ( cos (( pi /180) * a0 ) ) )
15.5.3 Conclusion
Parametric meshes can be created by using the macro language m4, this is demonstrated in real live by the
OpenFOAM tutorials. Also the author of this work has done so; up to a level which prompted his colleagues
50 See http://www.perl.org/
This offering is not approved or endorsed by ESI® Group, ESI-OpenCFD® or the OpenFOAM®
III 90
Foundation, the producer of the OpenFOAM® software and owner of the OpenFOAM® trademark.
to make fun of him. This highlights the major shortcoming of using m4 for parametric meshes. At some point,
the parametric geometry creation poses the need for complex math or even high-level data structures. Thus,
we soon are in need of a general purpose programming (or scripting) language.
The mesh in Figure 16 was created with a parametric geometry. It features a variable, user-selectable number
of rotor-paddles nb and stator-baffles np , with the contraint of that numbers being an integer divisor of 12. The
two numbers nb and np are independent of each other, as demonstrated in Figure 16. The infinitely thin baf-
fles and paddles are created by preventing selected blocks from getting connected by the use of collocated points.
In total the mesh shown in Figure 16 consists of 459 blocks. This mesh (most probably51 ) would have
been impossible to create using m4. The scripting language of choice for this mesh was python 52 , which is an
interpreted high-level, general-purpose programming language.
Figure 16: The mesh of a stirred tank with a Rushton impeller, stator baffles and an aeration device.
Thus, we conclude this section on using m4 for geometry creation with Eric S. Raymond’s view on m4 :
The m4 macro language supports conditionals and recursion. The combination can be used to
implement loops, and this was intended; m4 is deliberately Turing-complete. But actually trying to
use m4 as a general-purpose language would be deeply perverse.
This quote from Eric S. Raymond [22] should not be seen as trying to discourage the use of m4 for simple
task. It is intended to point out the limitations of macro languages. The limitation met and experienced by the
author are the following:
Math In the sections above, we discussed two ways to perform complex mathematical operations within an
m4 script, by utilizing bc or perl via a system call. In python, we can do complex math directly, without
having to perform system calls to programs which, might or might not be installed on the user’s system.
Data structures The mesh generation script for the stirred tank makes use of python’s high-level data struc-
ture reflecting the organisation of the points on the geometry Thus, the resulting script is far better to
understand than an even less complex m4 script.
51 After some initial attempts, the author gave up.
52 https://www.python.org/
This offering is not approved or endorsed by ESI® Group, ESI-OpenCFD® or the OpenFOAM®
III 91
Foundation, the producer of the OpenFOAM® software and owner of the OpenFOAM® trademark.
File I/O With m4, all we can do is macro substitution. Thus, everything comes from one file and goes to
one file. With a high-level language such as python, we can write several files. Thus, all files containing
geometric information can be written by the same script, e.g. the blockMeshDict and the topoSetDict(s).
This improves maintainability and reduces code duplication and manual labour.
Listing 132: Using the #calc directive for inline calculations in blockMeshDict.
Listing 133: OpenFOAM creates and runs this code from the #calc directive in Line 2 of Listing 132.
Use the following command to find examples on the use of the #calc directive in the OpenFOAM tutorials:
Listing 134: Find usage examples of the #calc directive in the tutorials.
This offering is not approved or endorsed by ESI® Group, ESI-OpenCFD® or the OpenFOAM®
III 92
Foundation, the producer of the OpenFOAM® software and owner of the OpenFOAM® trademark.
Drawback
Using OpenFOAM to do the math, or any other tasks, has the drawback that we don’t get to see the final
blockMeshDict file. If we have an error in our math or our logic, then blockMesh will interpret its input in the
blockMeshDict file, and the error will lead to an error in mesh-creation. The result will be an error message
on the part of OpenFOAM. However, since the process is as follows, and everything happens within blockMesh,
debugging will be more difficult.
• Read and interpret the blockMeshDict
• Run all blocks of code
15.6 Trouble-shooting
15.6.1 Don’t be misled by error messages
During manually building a small mesh with blockMesh by hand, i.e. writing the blockMeshDict using nothing
but an ordinary text editor, I made a rather interesting observation. To save myself the effort of scrolling back
and forth between the vertex list and the patch definition, I copied a part of the vertex list and pasted it right
where I specified the boundary faces. Thus, vertex definitions ended up, where patch definitions are expected.
After I ran blockMesh without removing the vertex definitions from the list of patches, blockMesh unsurprisingly
failed. However, this example shows that OpenFOAM’s error messages can be misleading.
Listing 135 shows the output of blockMesh resulting from the above outlined scenario. The warning message
correctly reports an unexpected input, the error message however, reports a hanging pointer. The hanging
pointer is certainly caused by the faulty entry, however, the error message does not indicate an error within the
blockMeshDict. In this case, the warning message bears the relevant information, hence users are advised to
carefully read OpenFOAM’s output (warning and error messages) in case something goes wrong.
...
From function const T & Foam :: UPtrList <T >:: operator []( Foam :: label ) const [ with T = Foam ::
entry ; Foam :: label = int ]
in file / home / user / OpenFOAM / OpenFOAM -4.0/ src / OpenFOAM / lnInclude / UPtrListI . H at line 107.
FOAM aborting
Listing 135: The output of blockMesh with a faulty blockMeshDict. The red dots indicate removed warning
messages were removed for brevity.
This observation the warning message carries more useful information than the error message might apply
also to other parts of the OpenFOAM framework.
This offering is not approved or endorsed by ESI® Group, ESI-OpenCFD® or the OpenFOAM®
III 93
Foundation, the producer of the OpenFOAM® software and owner of the OpenFOAM® trademark.
15.6.2 Viewing the blocks with ParaView
A mesh created by blockMesh consists of blocks. Listing 136 shows how ParaView can be used to visualise the
blocks.
paraFoam - block
This way, only the blocks are displayed. ParaView only reads the file blockMeshDict. Figure 17 shows the
blocks of a parametric mesh. It consists of nine blocks. The image shows also the numbers of the vertices.
This offering is not approved or endorsed by ESI® Group, ESI-OpenCFD® or the OpenFOAM®
III 94
Foundation, the producer of the OpenFOAM® software and owner of the OpenFOAM® trademark.
16 snappyHexMesh
snappyHexMesh, also referred to as snappy, is a meshing tool that is able to mesh the space around an ar-
bitrary triangulated surface, e.g. an STL surface-mesh. This is generally the case in external aerodynamics.
snappyHexMesh can only be used in conjunction with blockMesh, since it requires a background mesh.
16.1 Documentation
Unfortunately, the complexity of snappyHexMesh outweighs the available on-board documentation. The on-
board documentation (User Guide) can be found in doc/Guides-a4 or doc/Guides-usletter of your lo-
cal OpenFOAM installation or online at http://www.openfoam.org/docs/user/. You find a commented
snappyHexMeshDict at $FOAM_UTILITIES/mesh/generation/snappyHexMesh. This is the case for all utilities
which are controlled by an utility-specific dictionary file, such as decomposePar, topoSet and many more.
Individual features of snappy are in some cases discussed in the release notes of the release with which
these features were rolled out. Another source of good documentation of snappy are presentations held at the
OpenFOAM Workshops. An internet search with appropriate keywords will point the reader to them, since
some of them are publicly available on the internets.
As with any other tool, the reader is encouraged to run the tutorials provided by OpenFOAM and play
around with them. The tutorial cases also provide a good starting base for building your own cases.
(a) Castellating
The tri-surface is approximated by splitting and removing cells outside the tri-surface.
Cell splitting The cells of the background mesh near the objects surface are refined.
Cell removal Cells of the background mesh inside the object are removed.
(b) Snapping
Cell snapping The remaining background mesh is modified in order to reconstruct the surface of
the object.
(c) Layer addition
Layer addition Additional hexahedral cells are introduced on the boundary surface of the object
to ensure a good mesh quality.
This offering is not approved or endorsed by ESI® Group, ESI-OpenCFD® or the OpenFOAM®
III 95
Foundation, the producer of the OpenFOAM® software and owner of the OpenFOAM® trademark.
Figure 18: A bath tub. The outlet patch is marked grey at the very bottom of the drain tube.
featureAngle
The featureAngle is the angle between two consecutive faces. This parameter controls the behaviour of the
layer addition stage at corners and bends.
Figure 19: A badly chosen featureAngle causes snappy to add incomplete boundary layers.
This offering is not approved or endorsed by ESI® Group, ESI-OpenCFD® or the OpenFOAM®
III 96
Foundation, the producer of the OpenFOAM® software and owner of the OpenFOAM® trademark.
slipFeatureAngle
At the outlet patch of our domain, the layer added to the wall patch meets the outlet patch, i.e. vertices need
to be added to the outlet patch in order to properly grow a layer of cells onto the wall patch. See the left side of
Figure 20. In order to achieve this, we must be able to alter the outlet patch during layer addition even though,
we do not add a layer to the outlet patch itself.
This feature is discussed in the release notes53 of OpenFOAM-2.2.0.
Figure 20: The boundary layers added by snappy. On the left, layer addition went as we intended it to do; on
the right, we see the effect of the (missing) keyword slipFeatureAngle of the addLayersControls dictionary
of snappyHexMeshDict.
Exclude patches
We have to freedom to tell snappyHexMesh to leave patches alone. Thus, during layer addition these patches
remain untouched. This allows us to reverse the effect we achieved with the slipFeatureAngle parameter. By
specifically exluding the outlet from any layer addition activity (see Listing 137), we end up with a collapsing
cell layer at the boundary of the outlet patch, see Figure 21.
layers
{
bathTub
{
nSur faceLaye rs 2;
}
outlet
{
nSur faceLaye rs 0;
}
}
Listing 137: The layers sub-dictionary of the addLayersControl dictionary: specifically excluding a patch
from layer addition.
This example of use may most probably not meet practical requirements, however, it demonstrates how
snappy works. The take-away message might be that nSurfaceLayers beats slipFeatureAngle.
A non-academic (read less-useless) theoretical use-case for excluding patches from layer addition might be,
when we later merge different meshes. In that case, we might want to preserve some patches for the merging
operation.
53 http://www.openfoam.org/version2.2.0/snappyHexMesh.php
This offering is not approved or endorsed by ESI® Group, ESI-OpenCFD® or the OpenFOAM®
III 97
Foundation, the producer of the OpenFOAM® software and owner of the OpenFOAM® trademark.
Figure 21: A collapsing boundary layer. Maybe we did not want the mesh that way, however, we told snappy
to create it exactly that way.
Units
When creating a mesh with snappyHexMesh different scales (meter vs. millimeter) of the background mesh and
the STL-mesh are a frequent source of error. Check the following things:
1. The unit of the vertex coordinates in blockMeshDict
2. The value of the convertToMeters keyword in blockMeshDict
This offering is not approved or endorsed by ESI® Group, ESI-OpenCFD® or the OpenFOAM®
III 98
Foundation, the producer of the OpenFOAM® software and owner of the OpenFOAM® trademark.
17 foamyHexMesh
With OpenFOAM-2.3.054 the new meshing tool foamyHexMesh was released. This tool is to some degree
similar to snappyHexMesh. The main distinction between foamyHexMesh and snappyHexMesh is that meshes
by foamyHexMesh are better aligned with the boundary surfaces. This is achieved by a different mode of
operation. foamyHexMesh generates an internal tetrahedral mesh fitting the boundaries, and then generates
and massages the dual mesh of this internal tetrahedral mesh.
Figure 22: A bath tub with a background mesh enclosing the STL-surface of the bath tub.
17.1.1 SnappyBathTub
A first, the bath tub is meshed using snappyHexMesh. Figure 23 shows the resulting mesh. We clearly see, that
the interior cells are aligned with the global coordinate axes. At the side walls, this leads to some minor flaws.
This offering is not approved or endorsed by ESI® Group, ESI-OpenCFD® or the OpenFOAM®
III 99
Foundation, the producer of the OpenFOAM® software and owner of the OpenFOAM® trademark.
17.1.2 FoamyBathTub
Next, the bath tub was meshed using foamyHexMesh. In Figure 24 we see a good alignment of the cells with
the boundaries. The interior cells are not aligned with the global coordinate axes.
This offering is not approved or endorsed by ESI® Group, ESI-OpenCFD® or the OpenFOAM®
III 100
Foundation, the producer of the OpenFOAM® software and owner of the OpenFOAM® trademark.
18 cfMesh
cfMesh is a collection of meshing tools55 provided by the company Creative Fields. This company offers the
basic cfMesh suite under the GPL for free. At the time of writing cfMesh consists of four meshing tools which
offer a workflow comparable to the workflow offered by snappy- and foamyHexMesh.
The meshing tools of cfMesh generate their mesh based on a user-provided surface-triangulation of the
geometry. There is no need for a background mesh similar as it is the case with foamyHexMesh. All of the
tools are capable of generating boundary layers on all or on selected surfaces. All the tools are controlled by a
dictionary named meshDict, which resides in the system directory. In general the control of the user over the
meshing tools is not as tight as with snappy- or foamyHexMesh. However, this less tight control manifests itself
in a lightweight control dictionary compared to snappy- and foamyHexMesh.
The meshers of cfMesh are:
18.1 Usage
18.1.1 To treat feature edges, or not to ...
Feature edges must be specified explicitely by the user for cfMesh to obey theses edges.
In the case of the bath tub, which has a single patch a boundary, we see the effect of not providing feature
edges explicitely in Figure 25. In this case the provided STL surface was not obeyed perfectly in favour of nicer
cells. If we wanted to resolve the feature edge, we need to split the boundary of the geometry into more than
one patch. As the edges between neighbouring patches are resolved by default by the mesher, diving the bath
tub’s boundary into several patches would solve the problem shown in Figure 25.
55 http://cfmesh.com/
This offering is not approved or endorsed by ESI® Group, ESI-OpenCFD® or the OpenFOAM®
III 101
Foundation, the producer of the OpenFOAM® software and owner of the OpenFOAM® trademark.
Figure 25: Poor feature edge resolution caused by not providing information on feature edges. Note, the whole
geometry is bounded by a single patch.
If we want to resolve a feature edge which is not the boundary of two patches, we can use the utility tool
surfaceFeatureEdges to extract the feature edges from the geometry. This tools checks the angles of neighbour-
ing triangles of the surface triangulation and creates additional patches. E.g. the patch wall is divided into the
patches wall_0 to wall_N, if the specified feature angle results in wall being divided into N individual zones.
cfMesh resolves the edges between neighbouring patches by default. Thus, the mesher is agnostic of our feature
edge treatment. After finishing meshing, the mesher can rename patches. This feature of the mesher allows us
to combine all the intermediate patches back into our initial wall patch.
This offering is not approved or endorsed by ESI® Group, ESI-OpenCFD® or the OpenFOAM®
III 102
Foundation, the producer of the OpenFOAM® software and owner of the OpenFOAM® trademark.
Figure 26: Resolved feature edge of the bath tub. In this case, the boundary consists of two patches: the top
surface and the rest.
We note in Figure 26 the hanging nodes inserted by the mesher to join the different refinement levels. These
hanging nodes protrude from the face they are inserted into. This prevents the faces connecting the cells of
different refinement level from being coplanar, as it is the case with snappyHexMesh.
This offering is not approved or endorsed by ESI® Group, ESI-OpenCFD® or the OpenFOAM®
III 103
Foundation, the producer of the OpenFOAM® software and owner of the OpenFOAM® trademark.
19 checkMesh
checkMesh is a tool to perform tests on an existing mesh. checkMesh is simply invoked by its name. Like other
tools, checkMesh assumes to be called from the case directory. When checkMesh is to be called from an other
location than the case directory, the path to the case directory has to be specified with the option -case.
Listing 138 shows an error message produced by checkMesh, if checkMesh has been called with no mesh
present. In this case the tool can’t find the files specified in Section 13.1.
From function Time :: findInstance ( const fileName & , const word & , const IOobject :: readOption ,
const word &)
in file db / Time / findInstance . C at line 188.
FOAM exiting
A more thorough testing is performed when checkMesh is called with two additional options. Then checkMesh
performs some further tests.
checkMesh has also the -latestTime option like many other OpenFOAM tools. This option is particularly
useful when examining meshes created by snappyHexMesh. snappyHexMesh stores intermediate meshes if it is
not told otherwise. By default, after a completed run of snappyHexMesh there are the background mesh and the
results of the three basic stages of a snappyHexMesh run (castellation, snapping and layer addition). Depending
on which of these steps are active up to four meshes may be present. Restricting checkMesh to the final mesh
reduces runtime and avoids the unnecessary examination of an intermediate mesh.
19.1 Definitions
In order to understand the output of checkMesh it is necessary to define some quantities calculated by checkMesh.
Internal faces
Each internal face connects two cells. The non-orthogonality is the angle between the vector connecting the cell
centres and the face normal vector. In Figure 27 the vector connecting the cell centres is denoted d and the
face normal vector56 S.
S
P θ N
f d
face.
This offering is not approved or endorsed by ESI® Group, ESI-OpenCFD® or the OpenFOAM®
III 104
Foundation, the producer of the OpenFOAM® software and owner of the OpenFOAM® trademark.
In a perfectly orthogonal mesh the vectors d and S are parallel. If a mesh is non-orthogonal these vectors
draw an angle as in Figure 27. This angle can be calculated from d and S by Eq. 10.
Eq. 10 can also be found in the sources of OpenFOAM in the function faceNonOrthogonality in the file
cellQuality.C57 . Listing 140 shows a loop over all faces. For each face the non-orthogonality is computed.
The vectors d and s are the connecting vector between the cell centres, and the face area vector, respectively.
The scalar cosDDotS is the angle θ of Figure 27.
Note the two precautions that were taken to avoid numerical issues. First, the denominator is the sum of
the product of the magnitudes and VSMALL. VSMALL is a number with a very small value to prevent division by
zero. Second, the argument of the acos function is min(1.0, (d & s)/(mag(d)*magS + VSMALL)). Keeping
the argument of the arc-cosine equal or below 1 makes perfectly sense, because the arc-cosine is defined only
for values between -1 and 1. The limit of -1 is inherently ensured. The inner product of two vectors is always
positive. VSMALL is also positive.
The non-orthogonality reported by checkMesh is the angle θ of Figure 27. Therefore the reported non-
orthogonality lies in the range between 0 and 90. A non-orthogonality of 0 means the mesh is orthogonal and
consists of hexahedra (cuboids) or regular tetrahedra. Listing 144 shows the output of checkMesh. In this case
the mesh is orthogonal, the maximum and average non-orthogonality is 0.
Listing 146 shows the output of checkMesh in case of a non-orthogonal mesh. Listing 147 indicates that a
non-orthogonality of above 70 triggers checkMesh to issue a warning message.
Boundary faces
Non-orthogonality is also defined for boundary faces. Figure 28 shows a schematic boundary face with its face
center f . Non-orthogonality of boundary faces is defined as the angle in degrees between the face area vector S
and the vector d, which connects the cell center P and the face center f .
S
P d θ
f
57 In the file cellQuality.C there are two methods defined: nonOrthogonality() and faceNonOrthogonality(). Comparing the
code of this two methods reveals, that they compute the same thing. However, the method nonOrthogonality() returns the affected
cells, whereas faceNonOrthogonality() returns the affected faces.
This offering is not approved or endorsed by ESI® Group, ESI-OpenCFD® or the OpenFOAM®
III 105
Foundation, the producer of the OpenFOAM® software and owner of the OpenFOAM® trademark.
1 const labelUList & faceCells = mesh_ . boundaryMesh () [ patchI ]. faceCells () ;
2 const vectorField :: subField faceCentres = mesh_ . boundaryMesh () [ patchI ]. faceCentres () ;
3 const vectorField :: subField faceAreas = mesh_ . boundaryMesh () [ patchI ]. faceAreas () ;
4
5 forAll ( nei , faceI )
6 {
7 vector d = faceCentres [ faceI ] - centres [ faceCells [ faceI ]];
8 vector s = areas [ faceI ];
9 scalar magS = mag ( s ) ;
10
11 scalar cosDDotS =
12 radToDeg ( Foam :: acos ( min (1.0 , ( d & s ) /( mag ( d ) * magS + VSMALL ) ) ) ) ;
13 result [ globalFaceI ++] = cosDDotS ;
14 }
Internal faces
Each internal face connects two cells. Figure 29 shows the cell centres P and N of two adjacent cells. The
face faceP N is the face connecting these two cells. The point F is the face centre of the face faceP N . The line
c = P N connects the cell centres. This connecting line intersects with the face faceP N . This intersection point
I divides the line c into the two parts c1 and c2 .
F
Af
do
P dOwn dNei X
c1
I
dn
c2
faceP N N
To calculate the location of I the length of c1 is of key interest because the skewness is defined in Eq. 11.
The location (the vector to) the points P , N and F are easily obtained. From this three vectors do , dn and c
is computed. With do and dn the inner product with the face area vector Af is computed to obtain dOwn and
dNei58 .
58 dOwn and dNei are actual variable names. Therefore these symbols are written in typewriter font.
This offering is not approved or endorsed by ESI® Group, ESI-OpenCFD® or the OpenFOAM®
III 106
Foundation, the producer of the OpenFOAM® software and owner of the OpenFOAM® trademark.
|IF |
skewness = (11)
|P N |
do = F − P~
~ (12)
dn = F~ − N~ (13)
c=N ~ − P~ (14)
d o · Af
dOwn = (15)
||Af ||
dn · Af
dNei = (16)
||Af ||
6 (XP N ) = α (17)
dOwn dOwn + dNei dOwn + dNei
cos(α) = = = (18)
c1 c1 + c2 ||c||
dOwn
c1 = ||c|| (19)
dOwn + dNei
I~ = P~ + c1 c (20)
||F~ − I||
~
skewness = (21)
||c||
Note that both P~ and c are vectors. The reader hopefully excuses this lack of consistency in mathematical
notation. P~ denotes the position vector of the point P . In this case the symbol P~ is prefered to P in order to
use symbols that can be found in Figure 29.
Listing 142 shows a detail of the function faceSkewness from the file cellQuality.C59 . There a loop over
all internal faces is traversed. The loop body contains the calculation of the skewness. First dOwn and dNei
are computed. Then the location of the point I is determined. The variable faceIntersection of the type
point contains the position vector to the point I – the point at which the connection line between the cell
centres intersects the face. Finally, the skewness is calculated (compare Eq. 21). Notice the precaution against
a possible division by zero (adding VSMALL to the denominator).
59 In the file cellQuality.C there are two methods defined: skewness() and faceSkewness(). Comparing the code of this
two methods reveals, that they compute the same thing. However, the method skewness() returns the affected cells, whereas
faceSkewness() returns the affected faces.
This offering is not approved or endorsed by ESI® Group, ESI-OpenCFD® or the OpenFOAM®
III 107
Foundation, the producer of the OpenFOAM® software and owner of the OpenFOAM® trademark.
Boundary faces
Skewness is also defined and checked for boundary faces. Figure 30 shows the sketch of a boundary face with
its face center FC . The vector d from the cell center P to the face center FC is depicted in red. At the point
FC we see the face normal vector n. If we project the vector d on the vector n we gain the face-intersection
point FI . This is the point, where the face normal departing from the cell center intersects with the face. The
face-intersection does not necessarily need to be part of the face, as it is the case in Figure 30.
We then compute the vector f , which is the connection between the points FI and FC . The ratio of the
magnitudes of the vectors f and d defines the skewness of a boundary face.
Listing 143 shows the code that computes the skewness of the boundary faces. The points P and FC are
FI
P
f
d FC n
returned by the methods faceCells() and faceCentres(). The normal vector n is easily computed from the
face-area vector given by the method faceAreas().
n = faceAreas[faceI]/mag(faceAreas[faceI]) (22)
d = faceCentres[faceI] - cellCtrs[faceCells[faceI]] (23)
F~I = cellCtrs[faceCells[faceI]] + ((faceCentres[faceI] - cellCtrs[faceCells[faceI]])&n)*n
(24)
~ ~
FI = P + (d · n)n (25)
f = faceCentres[faceI] - faceIntersection (26)
f = F~C − F~I (27)
This offering is not approved or endorsed by ESI® Group, ESI-OpenCFD® or the OpenFOAM®
III 108
Foundation, the producer of the OpenFOAM® software and owner of the OpenFOAM® trademark.
12
13 forAll ( faceCentres , faceI )
14 {
15 vector n = faceAreas [ faceI ]/ mag ( faceAreas [ faceI ]) ;
16
17 point f a c eI n t e r s ec t i o n = cellCtrs [ faceCells [ faceI ]]
18 + (( faceCentres [ faceI ] - cellCtrs [ faceCells [ faceI ]]) & n ) * n ;
19
20 result [ globalFaceI ++] = mag ( faceCentres [ faceI ] - f a c e I n t e r s e c t i o n )
21 /(
22 mag ( faceCentres [ faceI ] - cellCtrs [ faceCells [ faceI ]])
23 + VSMALL
24 );
25 }
26 }
6
Sf
7 S2
S1
cf
4 5
Figure 31: Face warpage
If we decompose the face into individual triangles, we can compare the individual triangle area vectors to the
face normal vector. In Figure 31 a crude decomposition is chosen for simplicity. In OpenFOAM’s internals, the
individual triangles are defined by the face center and two consecutive vertices of the face. As, face vertices need
to be stored consecutive, a simple loop over the vertices of a face is sufficient to generate all individual triangles.
Thus, in OpenFOAM’s implementation of the test for warpage, the face of Figure 31 would be decomposed into
four triangles, as indicated by the thin dashed lines.
We bear in mind, that in OpenFOAM a face area vector has two important properties. It is normal to
the face’s plane and its magnitude is proportional to the face’s area60 . By diving the face area vector by its
magnitude we gain the face normal vector, see (29).
OpenFOAM checks for warpage by computing the inner product of the triangle area vectors with the face
normal vector, and summing up the results, see (30). This sum is equal to the magnitude of the face area vector,
when all vertices are in-plane. If the two vectors of an inner product are not parallel, then the magnitude of
the inner product is smaller by the cosine of the enclosed angle.
60 Since a length can not be an area in terms of physical units, we avoid the statement, that the face normal vectors length is the
This offering is not approved or endorsed by ESI® Group, ESI-OpenCFD® or the OpenFOAM®
III 109
Foundation, the producer of the OpenFOAM® software and owner of the OpenFOAM® trademark.
ka·bk = kakkbk cos(α) (28)
Sf
nf = (29)
kSf k
?
X
Sf = nf ·Si (30)
i
19.2 Pitfalls
The results of checkMesh need to be taken with a grain of salt. Therefore, it is helpful to know how checkMesh
defines the qualitity measures it tests for (Section 19.1) and also to know about the shortcomings of the tests
performed by checkMesh (Section 19.2).
The tests performed by checkMesh do not necessarily guarantee the mesh to be suitable for simulation.
Furthermore, if a mesh fails a test, that does not necessariliy mean that it is unsuitable for calculation.
Mesh OK .
End
Listing 144: checkMesh output for a mesh with high aspect ratio
This offering is not approved or endorsed by ESI® Group, ESI-OpenCFD® or the OpenFOAM®
III 110
Foundation, the producer of the OpenFOAM® software and owner of the OpenFOAM® trademark.
hex (0 1 2 3 4 5 6 7) (20 20 2) edgeGrading (3 0.33 3 0.33 1 1 1 1 1 1 1 1)
checkMesh issues no warnings for the value pair 3 and 0.33. The values 4 and 0.25 cause a warning about severly
non-orthogonal faces.
However, a simulation is impossible for much lower values. The simulation runs for the value pair 1.33 and
0.75. The values 1.4 and 0.714 cause the simulation to crash. The limits of stability of a simulation are therefore
reached earlier than the limits of checkMesh.
To conclude this section, the user should bear the folling statement in mind. Numerical problems of a sim-
ulation may be caused by bad mesh quality. In some cases – like the one presented above – bad mesh quality is
the root of the problem, but checkMesh issues no warnings. However, the values of the quality characteristics
may give a hint. Some manuals of CFD software propose numerical ranges for characteristics like aspect ratio
to ensure good quality.
Mesh OK .
End
Listing 146: checkMesh output for the distorted mesh; grading ratios 3 and 0.33
This offering is not approved or endorsed by ESI® Group, ESI-OpenCFD® or the OpenFOAM®
III 111
Foundation, the producer of the OpenFOAM® software and owner of the OpenFOAM® trademark.
Min volume = 1.00882 e -07. Max volume = 1.84055 e -07. Total volume = 0.0001. Cell volumes OK
.
Mesh non - orthogonality Max : 73.1635 average : 36.2131
* Number of severely non - orthogonal faces : 80.
Non - orthogonality check OK .
<< Writing 80 non - orthogonal faces to set nonOrthoFaces
Face pyramids OK .
Max skewness = 2.93978 OK .
Coupled point location match ( average 0) OK .
Mesh OK .
End
Listing 147: checkMesh output for the distorted mesh; grading ratios 4 and 0.25
Listing 148: checkMesh output for a 2D mesh with -allTopology option set.
If this message appears when a 3D mesh is examined, then there is probably some error in the definition of
the mesh. A cell in a 3D mesh should have at least three internal faces. A message stating the presence of cells
with two internal faces in a 3D mesh indicates non-connected regions.
If there are, in a 3D mesh, cells present with only two internal faces – this is sometimes the case with
tetrahedral meshes and the tet-cells in corners – then these cells will be written into a twoInternalFacesCells
cell set, furthermore, these cells will also be written into a cell set named underdeterminedCells.
Listing 149 and Figure 33 show such an example. An all-tet, 3D-mesh has be checked by checkMesh, and it
complained about cells with two internal faces, and underdetermined cells. In both cases the number of affected
cells was the same. Comparing the actual cellSets, as shown in Listing 149, revealed that in-fact, all cells with
two internal faces are considered under-determined, as the contents of the two files exactly match with the name
of the cell set being the only exception.
g e r h a r d @ g e r h a r d W o r k :/ home / user / OpenFOAM / user -6/ case - directory / constant / polyMesh / sets$ diff
twoInternalFacesCells underdeterminedCells
14 c14
< object twoInternalFacesCells ;
---
> object underdeterminedCells ;
Listing 149: Comparing the cell sets twoInternalFacesCells and underdeterminedCells in a case with an all-tet,
3D-mesh.
61 When the -allTopology option is enabled, checkMesh performs two additional topological checks. Checking the face connec-
tivity is one of these checks.
This offering is not approved or endorsed by ESI® Group, ESI-OpenCFD® or the OpenFOAM®
III 112
Foundation, the producer of the OpenFOAM® software and owner of the OpenFOAM® trademark.
Figure 33: The cells with two internal faces in an all-tet, 3D-mesh.
End
Listing 150: checkMesh output for a 2D, axi-symmetric mesh with -allGeometry and -allTopology option
set.
In Figure 34, wee see the under-determined cells, which were found by checkMesh. From Listing 150, we see
that the cells have a high aspect ratio, with the maximum aspect ratio well above 250. However, checkMesh
This offering is not approved or endorsed by ESI® Group, ESI-OpenCFD® or the OpenFOAM®
III 113
Foundation, the producer of the OpenFOAM® software and owner of the OpenFOAM® trademark.
determined the test for the aspect ratio to be OK, yet checkMesh found under-determined cells. However, these
cells, depicted in Figure 34 are regular hex cells, although quite thin ones.
As the simulation, this mesh was created for, runs perfectly fine, the reported under-determined cells pose no
problem for the numerics of OpenFOAM. Most likely some threshold value was exceeded by these high-aspect
ratio cells, which triggered checkMesh to report under-determined cells.
quite
Figure 34: The under-determined cells, which were found by checkMesh in the mesh of an axi-symmetric
simulation. These cells are on a far corner of the 2-D domain, and grading towards the more interesting regions
led them to have a high aspect ratio. In fact, these cells have the highest aspect ratio of the whole mesh. The
proximity to the lower wall results in these cells to be quite fine in the y-direction. Since, these cells are furthest
from the axis of symmetry, they are relatively large in radial and tangential direction.
This offering is not approved or endorsed by ESI® Group, ESI-OpenCFD® or the OpenFOAM®
III 114
Foundation, the producer of the OpenFOAM® software and owner of the OpenFOAM® trademark.
.
0
p
U
constant
polyMesh
blockMeshDict
boundary
faces
neighbour
owner
points
sets
lowQualityTetFaces
nonOrthoFaces
skewFaces
underdeterminedCells
transportProperties
system
controlDict
fvSchemes
fvSolution
This offering is not approved or endorsed by ESI® Group, ESI-OpenCFD® or the OpenFOAM®
III 115
Foundation, the producer of the OpenFOAM® software and owner of the OpenFOAM® trademark.
20 extrudeMesh
extrudeMesh is a rather special tool. OpenFOAM lists extrudeMesh under the mesh generation tools, however,
extrudeMesh has a role between mesh generation and mesh manipulation. We can do mesh generation, e.g.
extruding one cell layer from a 2D STL surface in order to prepare the mesh for a 2D study in OpenFOAM.
However, we can also do mesh manipulation, which is essentially mesh extension, as we “grow” cell layers on
surfaces.
20.1 Control
extrudeMesh is controlled by the file extrudeMeshDict. This file contains all necessary settings for using this
tool, which can roughly be divided into the categories: “where to grow”, “what to grow”, and “how to grow”.
20.1.1 constructFrom
The constructFrom setting is used to determine the source of the extrusion. This basis for cell extrusion can be
either a patch of an existing mesh or an STL surface. In the case of a patch of an mesh, the source may also be
a patch from another case, e.g. extrude patch X from case Y to create the mesh of case Z.
For the case of an STL surface, the corresponding STL file needs to be provided using the surface keyword.
If we use the patch of a mesh, we can choose between retaining the source mesh or discarding it. Figure 36
shows the difference between these two options, when extruding a patch from the current case.
Figure 36: Extrude the wall patch from a cylinder mesh. left: constructFrom mesh. right: constructFrom
patch.
expansionRatio
Note, that the expansion ratio describes the expansion of thickness from one layer to the other. This is in contrast
to the expansion ratio we use with the grading feature of blockMesh, there the expansion ratio describes the
thickness ratio between the smallest and the largest cells at the boundaries of a block.
This offering is not approved or endorsed by ESI® Group, ESI-OpenCFD® or the OpenFOAM®
III 116
Foundation, the producer of the OpenFOAM® software and owner of the OpenFOAM® trademark.
20.1.3 Extrusion models
The extrusion models control the “how to grow”. There is a number of models available, some of which will be
discussed below.
Plane extrusion
The plane extrusion model is specifically for the creation of (quasi) 2D meshes. A single layer of cells is extruded
in normal direction to the povided surface. By default the front and back patches are created to be of type
empty.
In Figure 37 we see the mesh created from an STL, which was created by GMSH. In this case we could also
have used GMSH to create a mesh with a single cell in thickness direction.
Figure 37: The mesh for a 2D study generated from an STL surface.
Sector extrusion
Figure 38 shows the result of the sector extrusion model. For this model, the user needs to specify a point in
space (axisPnt), an axis of rotation (axis) and an angle. In this case the outlet patch of the original mesh
(shown in grey) was extruded. The original mesh was created by blockMesh and consists of 5 blocks (easily
scripted with e.g. Python). The axisPnt lies in the plane of the outlet patch, however, the point is well outside
the patch. The distance between the axisPnt and the centerline of the original pipe mesh determines the radius
of the pipe bend. The positive x-axis was selected as axis. The newly generated cells are by default added to
a cellSet named addedCells.
This use of extrudeMesh opens a rather cheap way to create good meshes of pipe bends. The blockMeshDict
for a straight pipe is easily scripted, and by extruding along the section of a circle, the mesh is continued along
a bend. Directly scripting the blockMeshDict for a pipe bend would definitely be a little bit harder.
The sector extrusion model also has a 2D “cousin”, which is called wedge. The class underlying the wedge
extrusion model is derived from the sector model. However, the wedge model is the axisymmetric analogue of
the plane model. Thus, only one cell layer is created, which is centered about the source surface, i.e. the cell
layer is extruded half the angle in both directions from the source surface.
This offering is not approved or endorsed by ESI® Group, ESI-OpenCFD® or the OpenFOAM®
III 117
Foundation, the producer of the OpenFOAM® software and owner of the OpenFOAM® trademark.
Figure 38: A cheap 90° pipe bend. The outlet patch of the original mesh was extruded along the sector of a
circle.
Linear extrusion
There are two models for linear extrusion in extrudeMesh. There is linearNormal, which extrudes in normal
direction of the underlying surface. This can be used to grow a cell layer on the pipe’s wall, see Figure 40.
Furthermore, there is linearDirection, which extrudes cells along a specified direction.
In Figure 39 we see the result of subsequent use of extrudeMesh. Unfortunately, at the time of writing
(using OpenFOAM-4.0), extrudeMesh does not offer the -dict option. Thus, we need to repeatedly edit the
extrudeMeshDict for subsequent applications of extrudeMesh. First, a bend was created by using the sector
model. Afterwards a straight pipe section was created using linearNormal, which is followed by a slanted pipe
section, which was created using linearDirection.
This offering is not approved or endorsed by ESI® Group, ESI-OpenCFD® or the OpenFOAM®
III 118
Foundation, the producer of the OpenFOAM® software and owner of the OpenFOAM® trademark.
Figure 40: Grow a wall! The walls patch of the pipe mesh was extruded using the linearNormal model.
Figure 41: Snappy two-dimensional meshing. The side patch of a snappy mesh was extruded using the
linearNormal model, with the base mesh being discarded. Thus, we remain with a snappy-like mesh for
the two-dimensional flow around a cylinder.
This offering is not approved or endorsed by ESI® Group, ESI-OpenCFD® or the OpenFOAM®
III 119
Foundation, the producer of the OpenFOAM® software and owner of the OpenFOAM® trademark.
20.2.2 Pitfall: extruding a too narrow 2D slice
The mesh for an axi-symmetric simulation is a slice of the full 3D domain, which is 1 cell in circumferential
direction. Figure 42 shows two examples, which differ only in the angle of the slice. Both seem like valid meshes,
when viewed in ParaView.
Yet, with the narrow angle, OpenFOAM complains of the wedge-type patches being non-planar. Listing 151
shows an example of such a warning message. Increasing the angle from 1 to 5 degrees solved this problem.
This problem could not be solved by increasing the write precision to large values.
Figure 42: Extruding a slice. Left: a 1 degree sector extrusion, Right: a 5 degrees sector extrusion.
Figure 43: Extruding the mesh for a 2-D slice of a hollow sphere.
This offering is not approved or endorsed by ESI® Group, ESI-OpenCFD® or the OpenFOAM®
III 120
Foundation, the producer of the OpenFOAM® software and owner of the OpenFOAM® trademark.
After extruding the mesh, OpenFOAM was reporting a non-planar patch: the default patch. As it hap-
pened, extrudeMesh also created zero-length faces at the axis of symmetry. A run of collapseEdges fixed the
issue. If we compare the stats of checkMesh shown in Listing 152, we can clearly see that something was not
right after mesh extrusion, i.e. at Time = constant. However, at Time = 0.005, i.e. after the execution of
collapseEdges, the mesh’s stats look much more reasonable.
Time = constant
Mesh stats
points : 288
faces : 488
internal faces : 202
cells : 115
faces per cell : 6
boundary patches : 4
Mesh stats
points : 276
faces : 478
internal faces : 202
cells : 115
faces per cell : 5.913
boundary patches : 4
Listing 152: The most relevant lines of checkMesh’s output, before and after executing collapseEdges.
A clear indicator of the problem encountered is the number of cell types. This mesh of a 2-D slice should not
contain only hexahedra, since at the axis the cells should be prisms. This is the case after fixing the problem.
Further indication of the problem can be found in the numerous warnings about zero-area faces. Note the
This offering is not approved or endorsed by ESI® Group, ESI-OpenCFD® or the OpenFOAM®
III 121
Foundation, the producer of the OpenFOAM® software and owner of the OpenFOAM® trademark.
reduced number of points and faces before and after calling collapseEdges, this is a further indication that
faces due to zero-length edges have been removed.
The removed zero-area faces were perpendicular to the blue patch shown in Figure 43. Since these zero-area
faces would have been part of the blue patch of Figure 43, OpenFOAM was rightly complaining of this patch
not being planar.
Figure 44: Creating an axi-symmetric mesh by extruding a patch (the patch front shown in blue).
This offering is not approved or endorsed by ESI® Group, ESI-OpenCFD® or the OpenFOAM®
III 122
Foundation, the producer of the OpenFOAM® software and owner of the OpenFOAM® trademark.
21 polyDualMesh
This tool falls into a similar category as extrudeMesh. While it operates on an existing mesh, the result is very
different from the initial mesh, so that this tool can be considered a mesh generation tool.
polyDualMesh takes any valid mesh and computes the dual of the provided mesh. As the dual of a mesh
is a rather abstract concept, this is best explained by a simple example. In Figure 45, the Voronoi diagram
is shown. In this example the centers of the circumcircles of a triangular grid are used to create the Voronoi
diagram. Thus, a polygonal grid can be created from a triangular grid.
polyDualMesh applies this approach to the provided mesh, which can be of any type.
Figure 45: Connecting the centers of the circumcircles produces the Voronoi diagram (in red). Source https:
//commons.wikimedia.org/wiki/File:Delaunay_Voronoi.svg.
polyDualMesh is a vital tool to create polyhedral meshes. Since it takes tetrahedral (tet) meshes as its input,
and tools to create tet meshes are plenty, polyDualMesh is our gateway to running simulations on polyhedral
meshes. Generally we can state, that the more elaborate meshes are to be, the rarer (in case of open source
solutions) or the costlier (in case of proprietary tools) the mesh generation software is.
This offering is not approved or endorsed by ESI® Group, ESI-OpenCFD® or the OpenFOAM®
III 123
Foundation, the producer of the OpenFOAM® software and owner of the OpenFOAM® trademark.
Figure 46: The mesh of the elbow tutorial case; before and after the application of polyDualMesh.
Figure 47: The mesh of the bubble column tutorial case; before and after the application of polyDualMesh.
This offering is not approved or endorsed by ESI® Group, ESI-OpenCFD® or the OpenFOAM®
III 124
Foundation, the producer of the OpenFOAM® software and owner of the OpenFOAM® trademark.
Figure 48: The dual mesh of a single tetrahedron: the original tet-cell is outlined in blue, the face-decomposition
is outlined in black, and one of the resulting cells is shown in grey.
Figure 49: The dual mesh of a single hexahedron: the original hex-cell is outlined in blue, the face-decomposition
is outlined in black, and one of the resulting cells is shown in grey.
This offering is not approved or endorsed by ESI® Group, ESI-OpenCFD® or the OpenFOAM®
III 125
Foundation, the producer of the OpenFOAM® software and owner of the OpenFOAM® trademark.
22 combinePatchFaces
This mesh manipulation tool checks for multiple patch faces on same cell and combines them. Having multiple
patch faces on the same cell might be result of some mesh manipulation operations, e.g. polyDualMesh in the
example of the elbow tutorial created such cells at the domain boundary.
Figure 50: The dual mesh of the elbow tutorial case; before and after the application of combinePatchFaces.
This offering is not approved or endorsed by ESI® Group, ESI-OpenCFD® or the OpenFOAM®
III 126
Foundation, the producer of the OpenFOAM® software and owner of the OpenFOAM® trademark.
23 Salome
The Salome platform is a powerful multitool, which features a meshing module. This meshing module offers a
number of meshing tools.
Figure 51: Mesh export issue in Salome with the UNV format.
Apart from pyramid cells, there is also an issue when the mesh contains edge-groups. While Salome is
perfectly happy to export a mesh containing groups of edges, the converter for making this mesh usable for
OpenFOAM is happy to import groups of edges. This is discussed in Section 26.2.2.
23.1.2 salomeToOpenFOAM
A third-party Python script62 can be used to export a mesh containing pyramid cells to OpenFOAM. This
script directly writes the essential files63 . In order to export a mesh, simply select it in the Object Browser of
Salome and then execute the salomeToOpenFOAM.py Python script. This can be done by using File Load Script
menu.
This offering is not approved or endorsed by ESI® Group, ESI-OpenCFD® or the OpenFOAM®
III 127
Foundation, the producer of the OpenFOAM® software and owner of the OpenFOAM® trademark.
The third party conversion script salomeToOpenFOAM.py makes all patches wall patches, when their names
contain the word wall.
This offering is not approved or endorsed by ESI® Group, ESI-OpenCFD® or the OpenFOAM®
III 128
Foundation, the producer of the OpenFOAM® software and owner of the OpenFOAM® trademark.
Listing 154: exportMeshGroupsUNV.py: a powerful Python script to export all mesh groups into their separate
UNV files.
Figure 52: A big simulation domain with a quite small geometric feature: the geometry.
Figure 53: A big simulation domain with a quite small geometric feature: the blockMesh-only mesh.
23.2.2 Workflow
An alternative to an outcome as shown in Figure 53, we could choose to create a bigger central block which
encompasses the cut-out slot, instead of representing the cut-out. This cut-out block will remain a part of the
mesh, and then we will split the mesh into the cut-out block and the remaining mesh.
This offering is not approved or endorsed by ESI® Group, ESI-OpenCFD® or the OpenFOAM®
III 129
Foundation, the producer of the OpenFOAM® software and owner of the OpenFOAM® trademark.
Then, we create a geometry representation of the cut-out block with the cut-out slot in Salome. When, we
mesh the cut-out block, we follow this workflow.
1. Create groups on the geometry: the sides, the front face and the inner edges
2. Import the surface mesh from the meshed cut-out block, as shown in Figure 54
3. Mesh the geometry with the following sub-meshes, preferably in this order
(a) The sides with the “Import 1D-2D Elements from Another Mesh” algorithm
(b) The inner edges with a suitable 1D algorithm
(c) The front face with a suitable 2D algorithm
(d) The geometry with the “Extrusion 3D” algorithm
Figure 55 shows the mesh, which we created in Salome.
Finally, we need to export our mesh from Salome into OpenFOAM, and combine it with the mesh of the
remaining domain. Figure 56 shows the result of our procedure. Thus, we are able to create a relatively fine
mesh around the fine geometric feature, without the mesh fine-ness spreading out along the principal directions
as in the example shown in Figure 53.
This offering is not approved or endorsed by ESI® Group, ESI-OpenCFD® or the OpenFOAM®
III 130
Foundation, the producer of the OpenFOAM® software and owner of the OpenFOAM® trademark.
Figure 56: Combining blockMesh and salome: the meshed block was re-combined with the initial mesh.
65 As a rule of thumb, this may as well be simply a case of user error. The author is in no way sufficiently expert enough to claim
This offering is not approved or endorsed by ESI® Group, ESI-OpenCFD® or the OpenFOAM®
III 131
Foundation, the producer of the OpenFOAM® software and owner of the OpenFOAM® trademark.
Figure 57: A complex geometry warranting a complex meshing work-flow. Two pipe coils respresent a heat-
exchanger in a box-shaped vessel.
Figure 58: The geometry of a pipe, both ends of a single coil are visible. The geometry was created by extruding
a face along a path.
While we may think that everthing has been settled for Extrusion3D by providing a mesh for the cross-
This offering is not approved or endorsed by ESI® Group, ESI-OpenCFD® or the OpenFOAM®
III 132
Foundation, the producer of the OpenFOAM® software and owner of the OpenFOAM® trademark.
section and a mesh for the pipe’s interior surface, the meshing algorithm disagrees. While we may have fixed
the axial discretisation on the interior surface, the exterior surface is without constraints. Hence, the meshing
algorithm chose a different discretation.
While this only leads to slight visual displeasure in the example shown on the left of Figure 59, this may as
well lead to serious errors .
Figure 59: Left: insufficiently guided extrusion. Right: extrusion with proper guidance.
Figure 60 shows an example of a serious meshing error due to insufficient guidance. The strongly misaligned
axial discretisation leads to some cells having a negative volume, i.e., the cells are distorted to such a degree
that they are turned at least partially inside-out.
Figure 60: Extrusion gone bad: the inner and outer surface of the pipe, shown in grey and red. Cells with
negative volume are shown in green. Note the vertices on the inner and the outer surfaces.
We can avoid these meshing problems when using Extrusion3D, if the specify the axial discretisation also
on the outside of the pipe. Hence, by enforcing the use of the same discretisation on the outside as well as on
the inside of the pipe, we create an error-free and visually pleasing mesh as shown in Figure 59 on the right.
Note, that in order to use the same axial discretisation on the outside of the pipe, the axial discretisation
should be specified in terms of Number of Segments rather than Local Length. Since the length of an axial
edge along the pipe’s outside is larger than the length of an axial edge on the inside, using Local Length for
discretisation might lead to different numbers of element in axial direction for the inside and the outside, which
causes Extrusion3D to fail.
This offering is not approved or endorsed by ESI® Group, ESI-OpenCFD® or the OpenFOAM®
III 133
Foundation, the producer of the OpenFOAM® software and owner of the OpenFOAM® trademark.
parameters might be even more cumbersome.
However, since Salome can be controlled using Python scripts, once a work-flow has been worked out, it is
advantageous to translate this workflow into a Python script. With such a script, we can then adjust individual
parameters, execute the script to create the entire mesh and then check the results.
In Listing 155 contains a snippet of the mesh creation script for the geometry shown in Figure 57. The mesh
of the fluid domain depends on several other meshes. First, the surface meshes of the coils are imported, hence
innerCoilSurface and outerCoilSurface being the first sub-meshes to be created.
One of the next sub-meshes (bottomInOutCorner) imports a surface mesh from another mesh (MeshBot-
tomInOutCorner). Thus, the mesh MeshBottomInOutCorner is created before everything else.
Another sub-mesh (bottomFrontCorner) depends in a similar manner from another mesh (MeshBottomFront-
Corner), which in turn depends on the mesh of the main fluid domain. Hence, the processing chain of events
is split, and the mesh Mesh_bottomFrontCorner is created at the appropriate place in the succession of the
sub-meshes of the main fluid domain, i.e., right between the sub-meshes frontMiddle and bottomFrontCorner.
While the discussion of the script in Listing 155 seems quite academic without the proper reference to the
underlying geometry and mesh definitions, we can nevertheless observe how a bottom-up meshing approach
with specific inter-dependencies can be translated into a script.
Since scripting saves us from the effort of clicking (a lot), time invested in setting up such scripts is generally
well spent.
1 import salome
2 import SMESH
3 from salome . smesh import smeshBuilder
4
5 m y S u b S h a p e S e q u e n c e 1 = list ()
6 m y S u b S h a p e S e q u e n c e 1 . append ( ’ i n n e r C o i l Su r f a c e ’)
7 m y S u b S h a p e S e q u e n c e 1 . append ( ’ o u t e r C o i l Su r f a c e ’)
8 m y S u b S h a p e S e q u e n c e 1 . append ( ’ b o t t o m I n O u t C o r n e r ’)
9 m y S u b S h a p e S e q u e n c e 1 . append ( ’ inOutCorner ’)
10 m y S u b S h a p e S e q u e n c e 1 . append ( ’ frontMiddle ’)
11
12 m y S u b S h a p e S e q u e n c e 2 = list ()
13 m y S u b S h a p e S e q u e n c e 2 . append ( ’ b o t t o m F r o n t C o r n e r ’)
14 m y S u b S h a p e S e q u e n c e 2 . append ( ’ frontCorner ’)
15
16 myMesh_ref = salome . myStudy . F i n d O b je c t B y P a t h ( " / Mesh / FluidDomain " ) . GetObject ()
17 smesh = smeshBuilder . New ()
18 myMesh = smesh . Mesh ( myMesh_ref ) myMesh . Clear ()
19 subMeshes = myMesh_ref . GetSubMeshes ()
20
21 c o r n e r 0 1 M e s h_ r e f = salome . myStudy . F i n dO b j e c t B y P a t h ( " / Mesh / M e s h B o t t o m I n O u t C o r n e r " ) . GetObject ()
22 corner01Mesh = smesh . Mesh ( c o r n e r 0 1 Me s h _ r e f )
23 corner01Mesh . Clear () corner01Mesh . Compute ()
24
25 for shapeName in m y S u b S h a p e S e q u e n c e 1 :
26 for curSubMesh in subMeshes :
27 if curSubMesh . GetSubShape () . GetName () == shapeName :
28 print ( ’ Processing ’ + curSubMesh . GetSubShape () . GetName () )
29 curSubShape = curSubMesh . GetSubShape ()
30 mySubMesh = myMesh_ref . GetSubMesh ( curSubShape , curSubShape . GetName () )
31 mySubMesh . Compute ()
32
33 break
34
35 c o r n e r 0 2 M e s h _r e f = salome . myStudy . F i n d Ob j e c t B y P a t h ( " / Mesh / M e s h B o t t o m F r o n t C o r n e r " ) . GetObject ()
36 corner02Mesh = smesh . Mesh ( c o r n e r 0 2 Me s h _ r e f )
37 corner02Mesh . Clear ()
38 corner02Mesh . Compute ()
39
40 for shapeName in m y S u b S h a p e S e q u e n c e 2 :
41 for curSubMesh in subMeshes :
42 if curSubMesh . GetSubShape () . GetName () == shapeName :
43 print ( ’ Processing ’ + curSubMesh . GetSubShape () . GetName () )
44 curSubShape = curSubMesh . GetSubShape ()
45 mySubMesh = myMesh_ref . GetSubMesh ( curSubShape , curSubShape . GetName () )
46 mySubMesh . Compute ()
47
48 break
This offering is not approved or endorsed by ESI® Group, ESI-OpenCFD® or the OpenFOAM®
III 134
Foundation, the producer of the OpenFOAM® software and owner of the OpenFOAM® trademark.
Listing 155: Creating a bottom-up approach mesh using a Python script.
This offering is not approved or endorsed by ESI® Group, ESI-OpenCFD® or the OpenFOAM®
III 135
Foundation, the producer of the OpenFOAM® software and owner of the OpenFOAM® trademark.
24 Gmsh
Gmsh66 is a 3D finite element meshing software. Gmsh is operated via its GUI or via ASCII input files in
Gmsh’s own scripting language. Gmsh is able to create all cell shapes from tets to hexes. The meshes generated
by GMSH can be converted to OpenFOAM’s format using the gmshToFoam utility.
66 http://gmsh.info/
This offering is not approved or endorsed by ESI® Group, ESI-OpenCFD® or the OpenFOAM®
III 136
Foundation, the producer of the OpenFOAM® software and owner of the OpenFOAM® trademark.
25 enGrid
enGrid67 is an open source mesh generation software with CFD applications in mind. It uses the netgen68
meshing library. enGrid primarily creates tet meshes, however, it also allows for the creation of prismatic
boundary layers and the conversion of tets to polyhedras. enGrid natively exports its meshes to OpenFOAM.
enGrid is operated via its GUI.
Figure 62: Meshes by enGrid: left: tet-mesh with prismatic boundary layer, right: polyhedral mesh with
boundary layer.
67 https://github.com/enGits/engrid/wiki
68 https://sourceforge.net/projects/netgen-mesher/
This offering is not approved or endorsed by ESI® Group, ESI-OpenCFD® or the OpenFOAM®
III 137
Foundation, the producer of the OpenFOAM® software and owner of the OpenFOAM® trademark.
26 Mesh converters
To use meshes created by programs other than blockMesh there is a number of converters. The User Guide [52]
lists the following converters:
• fluentMeshToFoam
• starToFoam
• gambitToFoam
• ideasToFoam
• cfx4ToFoam
The names of the converters are pretty self explanatory.
General recommendations
Always write in ASCII format
Any data exchange between your current installation of OpenFOAM and any other software is best handled in
ASCII format.
26.2 ideasUnvToFoam
ideasUnvToFoam is a converter which is commonly used to convert meshes in the UNV format to OpenFOAM’s
format, Salome is a well-known meshing software, which exports meshes in the UNV format, see Section 23.
This offering is not approved or endorsed by ESI® Group, ESI-OpenCFD® or the OpenFOAM®
III 138
Foundation, the producer of the OpenFOAM® software and owner of the OpenFOAM® trademark.
1 Processing tag :2467
2 Starting reading patches at line 1382.
3 For group 1 named LineThick trying to read 4 patch face indices .
4 For group 2 named L i n e C i r c u m f e r e n c e trying to read 21 patch face indices .
5 For group 3 named faceThick trying to read 84 patch face indices .
6
7 Sorting boundary faces according to group ( patch )
8 0: LineThick is faceZone
9
10 --> FOAM FATAL ERROR : 1 not found in table . Valid entries :
11 218
12 (
13 105
14 106
15 ... further output omitted
Hence, check-for and delete all groups of edges prior to exporting the mesh. Figure 63 shows the relevant
entry in the object browser of Salome.
Figure 63: The entry for groups of edges in the object browser of Salome.
This offering is not approved or endorsed by ESI® Group, ESI-OpenCFD® or the OpenFOAM®
III 139
Foundation, the producer of the OpenFOAM® software and owner of the OpenFOAM® trademark.
as a face-zone. Consequently, the converter created a new patch for the remaining unassigned faces, as indicated
by Line 22 in Listing 157.
After the error was fixed in Salome, conversion finished without error, as can be seen from Listing 158. Now
the number of faces for the inner- as well as the outer-surface is equal, and both surfaces at treated as patches
by the converter.
This offering is not approved or endorsed by ESI® Group, ESI-OpenCFD® or the OpenFOAM®
III 140
Foundation, the producer of the OpenFOAM® software and owner of the OpenFOAM® trademark.
For group 6 named innerSurface trying to read 30550 patch face indices .
Listing 158: The relevant output of the mesh conversion after the error has been fixed.
Always run run checkMesh, ideally with its options -allGeometry and
-allTopology, to, first, check the mesh quality, and secondly, to check the
mesh bounding box. The bounding box will be expressed in metres, as any
other length in OpenFOAM. This will give you a chance to spot a millimetre
vs. metre situation.
Listing 159 shows the relevant lines of checkMesh’s output. Unless, we calculate meteorological flows, a
simulation domain in kilometre scale seems a bit off.
This offering is not approved or endorsed by ESI® Group, ESI-OpenCFD® or the OpenFOAM®
III 141
Foundation, the producer of the OpenFOAM® software and owner of the OpenFOAM® trademark.
27 Other mesh manipulation tools
27.1 transformPoints
The tool transformPoints can be used to scale, translate or rotate the points a mesh. Section 29.3.4 contains a
case in which this tool can be useful.
27.1.1 Rotation
Rotating the geometry can be specified in two ways.
27.2 topoSet
The tool topoSet creates point, face or cell sets from a geometric definition. There are a number of ways to
define the geometric region containing the intended points, faces or cells.
27.2.1 Usage
The dictionary topoSetDict is used to define the geometric region. Find some examples in the tutorials using
the following command.
A face or cell set will contain only faces or cells whose centres lie within the specified geometric region.
Listing 161: Run topoSet in parallel, i.e. apply topoSet on a decomposed case.
This will apply all definitions for the creation of sets and zones to the sub-domains of the decomposed case.
This can also be done with cases that are currently running, e.g. as a long-duration simulation is running,
we are preparing sets and zones for the subsequent post-processing. However, if we apply topoSet on a case,
which is at that time being simulated, we need to take extra care not to alter, remove or mess in any other way
with already existing sets or zones.
The sets and zones we created for the sub-domains of the decomposed case need to be reconstructed, so that
they are present when the case is finished, and the subsequent post-processing is done on the reconstructed case.
We can reconstruct sets and zones, which were created with the decomposed case, by calling reconstructPar
with the -constant command line argument.
This offering is not approved or endorsed by ESI® Group, ESI-OpenCFD® or the OpenFOAM®
III 142
Foundation, the producer of the OpenFOAM® software and owner of the OpenFOAM® trademark.
27.2.3 Pitfall: The definition of the geometric region
To demonstrate the function of topoSet a cell set was defined for the cavity tutorial-case. The mesh of the
cavity case is 1 × 1 × 0.1 m and the box defining the cell set was chosen to be 0.5 × 0.5 × 0.05 m. The dimensions
of this box are simply half the dimensions of the mesh. However, only cells whose cell centre is located in the
box are contained in the cell set. As the mesh is one cell in depth and 0.1 m in depth, all the cell centres are
exactly at z = 0.05 m. Due to inevitable numerical errors in calculating the cell centre70 , the numerical errors
decided whether a cell was included into the cell set or not.
To avoid this error, always make sure the geometric region contains all the intended cells.
Figure 65: A faulty cell set definition. The red cells are part of the cell set. All other cells are blue.
This offering is not approved or endorsed by ESI® Group, ESI-OpenCFD® or the OpenFOAM®
III 143
Foundation, the producer of the OpenFOAM® software and owner of the OpenFOAM® trademark.
To resolve this problem, topoSet needs to be run after renumberMesh. This even works in parallel, when the
case has been decomposed.
27.3 setsToZones
The utility setsToZones serves the purpose to:
27.4 refineMesh
The tool refineMesh is used – just as the name suggests – to refine a mesh.
27.4.1 Usage
First a cell set has to be defined, this can be done using the tool topoSet.
With the dictionary refineMeshDict the rules for refining a particular cell set can be stated. When rules
have been defined in refineMeshDict , then the command line option -dict has to be used.
Figure 66: An example of a refined mesh. The refined region is marked in red.
27.5 refineWallLayer
refineWallLayer is a tool to refine cells that are adjacent to a set of user-specified patches.
This offering is not approved or endorsed by ESI® Group, ESI-OpenCFD® or the OpenFOAM®
III 144
Foundation, the producer of the OpenFOAM® software and owner of the OpenFOAM® trademark.
27.5.1 Control
The list of patches is provided by the user via a command line argument. The next argument is the edge
fraction, which is to be applied in the refinement. Listing 162 shows an example of how this tool is called. The
list of patches and the edge fraction are mandatory arguments.
Listing 162: Invoking refineWallLayer for the cells adjacent to three patches.
Figures 67, 68 and 69 show the results of a successive application of this tool along with the base mesh. In
this case, the patch of the inner void is refined. Figures 68 and 69 show the treatment of sharp, concave edges.
Figure 70 shows the result of refineWallLayer when the cells belonging only one patch are refined.
Figure 67: The base mesh for the wall layer refinement.
This offering is not approved or endorsed by ESI® Group, ESI-OpenCFD® or the OpenFOAM®
III 145
Foundation, the producer of the OpenFOAM® software and owner of the OpenFOAM® trademark.
Figure 70: Applying the wall layer refinement twice on the horizontal patch at a concave edge.
Figures 71 and 72 show how refineWallLayer treats convex edges. If the edge is formed by two distinct
patches, refineWallLayer can be applied to each patch individually, which leads to a different outcome, com-
pare Figures 71 and 73.
Figure 71: Applying the wall layer refinement twice on both patches of a convex edge.
Figure 72: Applying the wall layer refinement twice on one patch of a convex edge.
This offering is not approved or endorsed by ESI® Group, ESI-OpenCFD® or the OpenFOAM®
III 146
Foundation, the producer of the OpenFOAM® software and owner of the OpenFOAM® trademark.
Figure 73: Applying the wall layer refinement successively on two patches of a convex edge. This approach
leads to a different outcome than the one shown in Figure 71.
27.6 renumberMesh
27.6.1 General information
The tool renumberMesh modifies the arrangement of the cells of the mesh in order to create lower bandwidth for
the numerical solution. For further information about the role and the influence of the bandwidth in numerical
simulation see books on the numerical solution of large equation systems, e.g. [37].
Renumbering the mesh can reduce computation times as it re-arranges the data to benefit the numerical
solution of the resulting equation system. The benefit of renumbering the mesh strongly depends on several
factors. However, testing is recommended.
Renumbering the mesh even has an effect at the simplest possible simulation case – the cavity case of the
tutorials. This mesh consists of a single block and it is quasi 2D (i.e. it is only 1 block in depth). The mesh
resolution was chosen to 40 × 40 × 1, resulting in 1600 cells. icoFoam was run for 10 s. Execution time was
reduced by renumberMesh from 6.18 s to 6.08 s.
A simulation with a mesh consisting of 120000 cells defined by 9 blocks was run for 5 s of simulated time
with twoPhaseEulerFoam. Execution time was reduced by renumberMesh from 9383.81 s to 9273.13 s.
Even though the reduction of execution time is small in this examples, this reduction comes at no cost.
Running renumberMesh takes little time and at run-time of the simulation no additional work has to be done.
Run renumberMesh before any other tools which generate sets or zones. Why
the order of execution of certain tools is significant is explained in Section ??
on a case which went slightly wrong.
27.6.2 Background
The discretized finite volume problem results in a linear equation system, which is usually expressed in matrix-
form.
Ax = b (31)
The vector x contains the field values at the cell centers. The matrix A contains non-zero elements for each
pair of neighbouring cells. This is a consequence of our assumption that only adjacent cells interact. If we
used some sort of higher order discretisation or interpolation, we might get into a situation where also second
neighbours interact. However, for sake of ease, we limit ourselves in this discussion to direct neighbours.
Regardless of our computational mesh being one-, two- or three dimensional, we label all cells with positive
ascending integers. Thus, we can store the values of a scalar field into a vector. The number of elements of this
vector (N ) is equal to the number of cells in our domain. Consequently, the matrix A is of the size N × N .
However, as only adjacent cells interact, most of the elements of A will be zero-entries.
This offering is not approved or endorsed by ESI® Group, ESI-OpenCFD® or the OpenFOAM®
III 147
Foundation, the producer of the OpenFOAM® software and owner of the OpenFOAM® trademark.
If the cells with the labels i and j are adjacent, then the elements aij and aji of A will be non-zero. Since
we focus on the general structure of A we do not care whether aij equals aji , or if both of them are actually
non-zero72 .
The arrangement of the cells – or, to be more precise, the labelling – has a strong impact on the structure
of the matrix A, i.e. the distribution of the non-zero elements.
A simple example
Here we examine the effect of cell labelling with a very simple example. Figure 74 shows a simple mesh with 8
cells. Two different cell labelling schemes are indicated by the numbers inside the cells.
In Figure 75 we see the connections between the cells depicted as a graph. A N × N matrix can be from
the interaction perspective seen as a graph with N nodes. An edge between the nodes i and j represents the
non-zero elements aij and aji .
0 1 2 3 0 2 4 6
4 5 6 7 1 3 5 7
Figure 74: A simple mesh with 8 cells and different cell labelling schemes.
0 1 2 3 0 2 4 6
4 5 6 7 1 3 5 7
Figure 76 shows the corresponding matrix structure. The labelling scheme on the right hand side of Figures
74 and 75 results in a matrix with a lower bandwidth.
0 1 2 3 4 5 6 7 0 1 2 3 4 5 6 7
0 ∗ ∗ 0 0 ∗ ∗ 0 0 0 ∗ ∗ ∗ ∗ 0 0 0 0
1 ∗ ∗ ∗ 0 ∗ ∗ ∗ 0 1 ∗ ∗ ∗ ∗ 0 0 0 0
2 0 ∗ ∗ ∗ 0 ∗ ∗ ∗ 2 ∗ ∗ ∗ ∗ ∗ ∗ 0 0
3 0 0 ∗ ∗ 0 0 ∗ ∗ 3 ∗ ∗ ∗ ∗ ∗ ∗ 0 0
4 ∗ ∗ 0 0 ∗ ∗ 0 0 4 0 0 ∗ ∗ ∗ ∗ ∗ ∗
5 ∗ ∗ ∗ 0 ∗ ∗ ∗ 0 5 0 0 ∗ ∗ ∗ ∗ ∗ ∗
6 0 ∗ ∗ ∗ 0 ∗ ∗ ∗ 6 0 0 0 0 ∗ ∗ ∗ ∗
7 0 0 ∗ ∗ 0 0 ∗ ∗ 7 0 0 0 0 ∗ ∗ ∗ ∗
Figure 76: The matrix structure. A * denotes a non-zero element. Notice the lower bandwidth of the matrix on
the right hand side. The number of zero-entries is equal, however, the different distribution leads to a different
numerical behaviour.
72 The upwind differencing scheme causes the downstream cell to depend on the upstream cell. However, the upstream cell is not
This offering is not approved or endorsed by ESI® Group, ESI-OpenCFD® or the OpenFOAM®
III 148
Foundation, the producer of the OpenFOAM® software and owner of the OpenFOAM® trademark.
27.6.3 Pitfall: sets and zones will break my bones
The use of renumberMesh carries a certain risk. In simulation cases which make use of tools like topoSet and
renumberMesh, the order in which those tools are invoked is of importance. Update: This has been resolved
at some point. In OpenFOAM-4.0 this is no issue any more.
The reason behind this, is the way OpenFOAM stores its mesh information. The only actual geometric
information is stored in the list of points in the file constant/polyMesh/points. The faces are defined via the
point labels of the points defining the mesh. Thus, if the points Pk , Pm , Pu and Pw define a face, then the entry
in constant/polyMesh/faces for this very face reads (k m u w). The same principle applys for the definition
of cells. There, the labels of the faces defining the cell are stored. This way, no redundant information is stored.
If we define a cellSet with topoSet e.g. all cells within a certain geometrical region we simply store the cell
labels of all cells for which the condition is fulfilled. Thus, if we now run renumberMesh, we shuffle the cells
within the mesh. No actual change is applied in the mesh, however, the cell with the label A which was at the
location (xA , yA , zA ) before renumbering, may or most certainly will be at location (xB , yB , zB ) with B 6= A
after renumbering.
Figure 77 shows the simulation domain of an aerated stirred tank. The red cells are part of a cellZone
on which source terms using the fvOptions mechanism act73 . A run of renumberMesh after the cellZone was
created caused the cellZone to get scrambled. However, the simulation worked nontheless and yielded some
unexpected results.
Figure 77: Left: The cut-away of the walls of a stirred tank with the rotor (blue) and the aeration device
(red). The aeration device is a cellZone on which source terms are applied via the fvOptions mechanism in
OpenFOAM-2.3.x.
Right: The stirred tank was simulated using parallel processes. After decomposing the domain, a parallel
renumbering of the mesh was conducted. Renumbering the subdomains scrambled the cellZone within their re-
spective subdomains. The transparent iso-volume shows the gas-phase volume fraction 0.25 s into the simulation.
The cells of the cellZone act as source for the gas-phase, although not on their original location.
This offering is not approved or endorsed by ESI® Group, ESI-OpenCFD® or the OpenFOAM®
III 149
Foundation, the producer of the OpenFOAM® software and owner of the OpenFOAM® trademark.
One such occasion of the former need, i.e. convert a mesh from binary to ascii, is when you want to use
tools of several OpenFOAM-variants, e.g. the checkMesh utility tool of foam-extend-4.0 can not read a mesh
in binary format, which was created by a mesh conversion tool (such as fluentMeshToFoam) of OpenFOAM-6.
For some reason, the binary formats of foam-extend and OpenFOAM (foundation release) are not compatible75 .
However, foam-extend is perfectly happy with meshes written by OpenFOAM in ASCII format. This, rather
lengthy prelude, leads us a use-case of the tool renumberMesh, which might be considered harmless abuse: use
the tool to change the format the mesh is stored on disk.
The procedure is rather simple:
1. Create a new case directory, in which the conversion should take place
2. Copy the relevant folders, i.e. constant and system, into this new case directory. Also copy time step
folders, if necessary.
3. Change the writeFormat setting in system/controlDict from binary to ascii.
Figure 78: Renumbering the solution of the cavity case: the case was run, and all time steps prior to 0.3 were
deleted. Then renumberMesh -overwrite was run. As 0.3 was the first time step, the fields in the time step
0.3 were renumbered along with the mesh. The later time steps, however, were left untouched.
Thus, if you want to convert a case with mesh and fields from binary to ASCII format, simply create a copy
of the case with one time step only, and perform the renumbering. The tool renumberMesh only allows the user
to specify one specific time, yet not a range of times. Thus, we consider it not possible to convert a case with
multiple time steps from binary to ASCII, or the other around.
27.7 subsetMesh
subsetMesh is a tool to remove certain cells from a mesh. The tool expects the name of a cellSet as a command
line argument. The cells of this cellSet will remain in the resulting mesh, all other cells are removed.
75 This incompatibility, however, is a uni-directional one. A binary mesh written by foam-extend-4, can be read and used by
OpenFOAM-6.
This offering is not approved or endorsed by ESI® Group, ESI-OpenCFD® or the OpenFOAM®
III 150
Foundation, the producer of the OpenFOAM® software and owner of the OpenFOAM® trademark.
Pitfall: sets and zones will break my bones
At the time of writing (OpenFOAM-4.0), subsetMesh does not treat cellSets or cellZones. Thus, when we use
subsetMesh to remove large parts of the mesh, then the cellSet may contain cells that are no longer part of the
mesh. This error will be felt when the cell indices associated with the cellSet or cellZone are larger than the
total number of cells in the mesh. Otherwise, if the cell indices are smaller than the total number of cells, the
cellSet might still be valid from OpenFOAM’s point of view, but it may contain different cells.
27.8 createPatch
27.8.1 Remove empty patches, i.e., patches without any faces
Apart from creating new patches from existing ones or changing the type of a patch, we can use createPatch
to clean up our mesh. Listing 163 shows an empty createPatchDict file, which is the bare minimum to be
able to run createPatch without error.
Hence, if we run createPatch with such an empty createPatchDict file, createPatch does nothing except
remove patches with zero faces.
/* - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -* - C ++ -* - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -*\
| ========= | |
| \\ / F ield | OpenFOAM : The Open Source CFD Toolbox |
| \\ / O peration | Version : 8 |
| \\ / A nd | Web : www . OpenFOAM . org |
| \\/ M anipulation | |
\* - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - */
FoamFile
{
version 2.0;
format ascii ;
class dictionary ;
object cr ea t eP at ch D ic t ;
}
// * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * //
pointSync false ;
// Patches to create .
patches
(
);
// * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * //
Listing 164 shows the patch list reported by checkMesh after an axi-symmetric mesh has been extruded
from a patch. Note the presence of an empty patch, i.e., a patch with zero faces.
Listing 164: The patches listed by checkMesh of an axi-symmetric mesh after extrusion from a patch.
3
Running createPatch -overwrite with an empty createPatchDict, as shown in Listing 163, removes the
patch with zero faces from the mesh. If we do not remove this patch, OpenFOAM would require us to specify
boundary conditions for it.
This offering is not approved or endorsed by ESI® Group, ESI-OpenCFD® or the OpenFOAM®
III 151
Foundation, the producer of the OpenFOAM® software and owner of the OpenFOAM® trademark.
Checking patch topology for multiply connected surfaces ...
Patch Faces Points Surface topology
inlet 30 61 ok ( non - closed singly connected )
outlet 30 61 ok ( non - closed singly connected )
walls 270 542 ok ( non - closed singly connected )
front 8100 8401 ok ( non - closed singly connected )
back 8100 8401 ok ( non - closed singly connected )
Listing 165: The patches listed by checkMesh of an axi-symmetric mesh after running createPatch -overwrite
with an empty createPatchDict.
27.9 stitchMesh
27.10 tetDecomposition
The mesh manipulation tool tetDecomposition is part of the OpenFOAM variant foam-extend76 , and there is
no comparable tool within the foundation release of OpenFOAM at the time of writing.
This tool takes an OpenFOAM mesh, computes the tet-decomposition and writes the resulting mesh to disk.
Figures 79 and 80 illustrate how this tool works. The faces of the initial cell is decomposed into triangles. With
such a triangle and the centroid of the cell, a sub-tetrahedron can be created.
Depending on the original mesh, the number of cells of the resulting mesh can rise dramatically. The single
tetrahedron of Figure 79 is decomposed into 12 sub-tetrahedra. The initial hexahedron of Figure 80 is decom-
posed into 24 tetrahedra.
Figure 79: A tet-decomposed tetrahedron: the original tet-cell is outlined in blue, the face-decomposition is
outlined in black, and one of the resulting sub-tets is shown in grey.
76 http://www.foam-extend.org/
This offering is not approved or endorsed by ESI® Group, ESI-OpenCFD® or the OpenFOAM®
III 152
Foundation, the producer of the OpenFOAM® software and owner of the OpenFOAM® trademark.
Figure 80: A tet-decomposed hexahedron: the original hex-cell is outlined in blue, the face-decomposition is
outlined in black, and one of the resulting sub-tets is shown in grey.
27.11 decomposePar
The tool decomposePar is used to divide the domain for a parallel simulation run into smaller sub-domains.
Figure 81: The cell distribution of a multi-region case, with 2 regions and 4 sub-domains for parallel processing.
The small region outlined in white is the solid region, the surrounding larger region is the fluid region of this
case. Each sub-domain (colour-coded from 0 to 3) is assigned a chunk of each region.
This offering is not approved or endorsed by ESI® Group, ESI-OpenCFD® or the OpenFOAM®
III 153
Foundation, the producer of the OpenFOAM® software and owner of the OpenFOAM® trademark.
27.12 mirrorMesh
mirrorMesh is, similar to extrudeMesh, a mesh manipulation tool that is somewhere between mesh manipulation
and mesh creation. This tool is controlled by entries in the file system/mirrorMeshDict. The set of parameters
is quite limited, since we only need to provide a definition for the plane which is to act as the mirror, and a
tolerance.
Listing 166 shows an example of a mirrorMeshDict, which consists of a plane definition (here we have three
possible methods to choose from), and the tolerance.
pointAndNormalDict
{
basePoint (0.0 0.0 0.01) ;
normalVector (0 0 1) ;
}
// plane equation : ax + by + cz + d = 0
planeEquationDict
{
a 0;
b 0;
c 1;
d -0.01;
}
embeddedPointsDict
{
point1 (0 0 0.01) ;
point2 (1 0 0.01) ;
point3 (0 1 0.01) ;
}
Listing 166: All the possible entries in the file mirrorMeshDict to mirror the initial mesh around an x − y plane
with a z-component of z = 0.01.
This offering is not approved or endorsed by ESI® Group, ESI-OpenCFD® or the OpenFOAM®
III 154
Foundation, the producer of the OpenFOAM® software and owner of the OpenFOAM® trademark.
Figure 82: A cellSet after running mirrorMesh to mirror the mesh using the x − y plane.
This offering is not approved or endorsed by ESI® Group, ESI-OpenCFD® or the OpenFOAM®
III 155
Foundation, the producer of the OpenFOAM® software and owner of the OpenFOAM® trademark.
28 Surface mesh manipulation tools
OpenFOAM ships with a number of surface mesh manipulation tools. A probable use-case for this kind of tools
is doing some preprocessing on STLs prior to creating a mesh with snappyHexMesh or cfMesh.
28.1 surfaceAdd
This tool can be used to merge two STLs into one file. With the command line switch -mergeRegions regions
with an equal name get joined into one region. Otherwise the two regions would remain separate, regardless of
having the same name.
28.2 surfaceSubset
With this tool a subset of an STL can be extracted. Via the surfaceSubsetDict various conditions can be
specified to define the subset. The user provides the STL to operate on (input.stl) and a file name for the
subset to be stored in (outSubset.stl). The faces of the subset get removed from the original STL.
Listing 168: Usage of surfaceSubset when extracting a certain subset from an STL.
28.3 surfaceFeatureExtract
This is a tool to extract features from an STL. E.g. snappyHexMesh pays extra attention to geometric features
which are explicitely provided, surfaceFeatureExtract is a tool to generate the necessary data. The tool is
controlled by the surfaceFeatureExtractDict. Surface feature extraction is controlled by a user-provided
feature angle, which is used to determine whether an edge between two surface elements constitutes a feature
edge, or not.
This tool writes the feature edges into an *.eMesh file located in the constant/triSurface folder.
In the file surfaceFeatureExtractDict we can enable the switch writeObj, which causes the tool to write
all sorts of extracted data into *.obj files located in the constant/extendedFeatureEdgeMesh folder. These
files can be viewed in ParaView to assess whether all surface features have been correctly and completely been
extracted.
28.4 surfaceFeatureConvert
This tool can be used to convert *.eMesh files to *.vtk files to view them in ParaView. This is important when
trying to find the proper settings, e.g. the feature angle for the file surfaceFeatureExtractDict.
28.5 surfaceTransformPoints
This tool is the surface mesh equivalent to the tool transformPoints, see 27.1, which can be used to scale,
translate and rotate surface meshes. Apart from the obvious transformation options, this tool expects two file
names: first, the input file; and second, the output file.
This offering is not approved or endorsed by ESI® Group, ESI-OpenCFD® or the OpenFOAM®
III 156
Foundation, the producer of the OpenFOAM® software and owner of the OpenFOAM® trademark.
s u r f a c e F e a t u r e E d g e s - angle 30 input . stl out . fts
Listing 169: Usage of surfaceFeatureEdges when extracting feature edges from an STL.
28.6.2 FMSToVTK
The tool FMSToVTK can be used to convert the *.fms files created by the tool surfaceFeatureEdges to the
VTK format. Thus, the user can review how well the feature edges have been identified by surfaceFeatureEdges.
This is important when trying to find the proper setting for the feature angle, which is passed with the -angle
parameter.
This tool, provided by cfMesh (see Section 18).
solid SOLIDNAME
facet normal X Y Z
outer loop
vertex X Y Z
vertex X Y Z
vertex X Y Z
endloop
endfacet
...
endsolid
Listing 170: The basic syntax of an STL in ASCII format. See https://en.wikipedia.org/wiki/STL_(file_
format) for more on this.
This offering is not approved or endorsed by ESI® Group, ESI-OpenCFD® or the OpenFOAM®
III 157
Foundation, the producer of the OpenFOAM® software and owner of the OpenFOAM® trademark.
Listing 172 shows how to join three STLs, each containing one solid, i.e. the information of one patch. The
first line is simply a copy operation. Alternatively, we might use cp or mv for the first operation. Note, that the
resulting STL gets written to a different folder, constant/triSurface is a folder in which some meshing tools
expect STLs. The second and third lines show how to append the output of cat to the specified file.
The difference between the first and the following lines is the redirection operator (> vs. >>), see e.g.
https://en.wikipedia.org/wiki/Redirection_(computing). The > operator simply redirects the output
to the specified file, if this was used in the second line, then the contents from the first line would get overwritten
in myDomainMesh.stl. Using the >> operator redirects and appends the output to the specified file. Using the
> operator in the first line ensures to overwrite an eventual existing file.
This offering is not approved or endorsed by ESI® Group, ESI-OpenCFD® or the OpenFOAM®
III 158
Foundation, the producer of the OpenFOAM® software and owner of the OpenFOAM® trademark.
29 Initialize Fields
29.1 Basics
There are two ways to define the initial value of a field quantity. The first is to set the field to a uniform value.
Listing 173 shows the 0/U file of the cavity tutorial. There the internal field is set to a uniform value.
If a non-uniform initialisation is desired, then a list of values for all cells is needed instead. Listing 180 shows
some lines of such a definition. Entering such a nonuniform list by hand would be very tiresome. To spare the
user of such a painful and exhausting task, there are some tools to provide help.
/* - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -* - C ++ -* - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -*\
| ========= | |
| \\ / F ield | OpenFOAM : The Open Source CFD Toolbox |
| \\ / O peration | Version : 2.1. x |
| \\ / A nd | Web : www . OpenFOAM . org |
| \\/ M anipulation | |
\* - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -*/
FoamFile
{
version 2.0;
format ascii ;
class vol VectorFi eld ;
object U;
}
// * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * //
dimensions [0 1 -1 0 0 0 0];
internalField uniform (0 0 0) ;
boundaryField
{
movingWall
{
type fixedValue ;
value uniform (1 0 0) ;
}
fixedWalls
{
type fixedValue ;
value uniform (0 0 0) ;
}
frontAndBack
{
type empty ;
}
}
// * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * //
29.2 setFields
setFields is a utility that allows to define geometrical regions within the domain and to assign field values
to those regions. setFields reads this definitions from a file in the system-directory – the setFieldsDict. To
initialize the field quantities setFields has to be executed after creating the mesh. setFields needs to read all
files defining the mesh79 .
In Listing 174 a box is defined in which the field alpha1 is set to a different value.
/* - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -* - C ++ -* - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -*\
| ========= | |
| \\ / F ield | OpenFOAM : The Open Source CFD Toolbox |
79 Only the file neighbour can be missing for setFields not to crash.
This offering is not approved or endorsed by ESI® Group, ESI-OpenCFD® or the OpenFOAM®
III 159
Foundation, the producer of the OpenFOAM® software and owner of the OpenFOAM® trademark.
| \\ / O peration | Version : 2.1. x |
| \\ / A nd | Web : www . OpenFOAM . org |
| \\/ M anipulation | |
\* - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -*/
FoamFile
{
version 2.0;
format ascii ;
class dictionary ;
object setFieldsDict ;
}
// * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * //
defaultFieldValues
(
v o l S c a l a r F i e l d V a l u e alpha1 1
);
regions
(
boxToCell
{
box ( -0.3 -0.3 0) (0.3 0.3 0.26) ;
fieldValues
(
v o l S c a l a r F i e l d V a l u e alpha1 0
);
}
);
// * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * //
29.2.2 Pitfalls
A nice, little collection of what may go wrong.
This offering is not approved or endorsed by ESI® Group, ESI-OpenCFD® or the OpenFOAM®
III 160
Foundation, the producer of the OpenFOAM® software and owner of the OpenFOAM® trademark.
c on ve rt T oM et er s 1e -3;
vertices
(
(0 0 0)
(50 0 0)
(50 0 250)
(0 0 250)
(0 50 0)
(50 50 0)
(50 50 250)
(0 50 250)
);
regions
(
boxToCell
{
box (0.0 0.0 0.0) (50.0 50.0 125.0) ;
fieldValues
(
v o l S c a l a r F i e l d V a l u e alpha1 0
);
}
);
file : / home / user / OpenFOAM / user -2.1. x / run / t w o P h a s e E u l e r F o a m / bubbleColumn / system / setFieldsDict ::
d e f a u l t F i e l d V a l u e s at line 19.
FOAM exiting
29.3 mapFields
mapFields is a utility to transfer field data from a source mesh to target mesh. This may be useful after the
mesh of case has been refined and existing solution data is to be used for initialising the case with the refined
This offering is not approved or endorsed by ESI® Group, ESI-OpenCFD® or the OpenFOAM®
III 161
Foundation, the producer of the OpenFOAM® software and owner of the OpenFOAM® trademark.
mesh. mapFields preserves the format of the data, if the source data was stored in binary format, the target
data will also be binary.
To use mapFields the file mapFieldsDict has to be existent in the system folder of the case80 . mapFields
expects as the only mandatory argument the path to the source case. The current directory is assumed to be
the case directory of the target case. If there is no specification regarding time, the latest time steps of both
cases are processes. That means the latest time step of the source case is mapped to the latest time step of the
target case.
Listing 178 shows the last lines of output of mapFields. With lines like interpolating alpha mapFields
indicates that it is processing some field data. Even when source and target meshes are equal and no interpo-
lation is needed, mapFields displays lines like interpolating alpha anyway.
interpolating alpha
interpolating p
interpolating k
interpolating epsilon
interpolating Theta
interpolating Ub
interpolating Ua
End
End
may seem of no use, it has to exist in the system folder, and it has to contain the header and the empty definitions.
This offering is not approved or endorsed by ESI® Group, ESI-OpenCFD® or the OpenFOAM®
III 162
Foundation, the producer of the OpenFOAM® software and owner of the OpenFOAM® trademark.
the list. A wrong value of COUNT leads to reading errors.
If data is to be mapped from a source case, the source case’s data will always be stored as a nonuniform list.
Otherwise, mapping the data would make no sense, as uniform fields are most easily defined. If the data of the
target case is uniform, then mapping makes no problems.
If the data of the target case is nonuniform – for whatever reason – then it is necessary that the nonuniform
lists have the same length. Otherwise, mapFields will exit with an error message like in Listing 181. The target
case should always be set up with uniform fields to avoid such errors. This is most easily done by removing the
definition of the internal field. In the tutorials sometimes files with an .org file extension can be found. This
is a way to preserve the uniform field data in the 0 -directory without causing any trouble.
dimensions [0 1 -1 0 0 0 0];
interpolating alpha
file : / home / user / OpenFOAM / user -2.1. x / run / t w o P h a s e E u l e r F o a m / Case /0/ alpha from line 18 to line
39.
From function Field < Type >:: Field ( const word & keyword , const dictionary & , const label )
in file / home / user / OpenFOAM / OpenFOAM -2.1. x / src / OpenFOAM / lnInclude / Field . C at line 236.
FOAM exiting
The problem
Figure 83 shows the result of the mapFields run. Only the field values inside the 2D domain were altered. The
part of the 3D domain that lies outside the 2D domain remains unchanged. This behaviour is not satisfactory.
The work-around
One way to solve this problem would be to choose the 2D domain of a similar size as the 3D domain. However,
if the 2D is already finished, then it would take some time to re-simulate the case with a redefined geometry.
Another solution is:
1. define the 3D domain to be of the same size as the 2D domain
This offering is not approved or endorsed by ESI® Group, ESI-OpenCFD® or the OpenFOAM®
III 163
Foundation, the producer of the OpenFOAM® software and owner of the OpenFOAM® trademark.
/* - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -* - C ++ -* - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -*\
| ========= | |
| \\ / F ield | OpenFOAM : The Open Source CFD Toolbox |
| \\ / O peration | Version : 2.1. x |
| \\ / A nd | Web : www . OpenFOAM . org |
| \\/ M anipulation | |
\* - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -*/
FoamFile
{
version 2.0;
format ascii ;
class dictionary ;
location " system ";
object mapFieldsDict ;
}
// * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * //
patchMap ( );
cutt ingPatch es ( );
// * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * //
This offering is not approved or endorsed by ESI® Group, ESI-OpenCFD® or the OpenFOAM®
III 164
Foundation, the producer of the OpenFOAM® software and owner of the OpenFOAM® trademark.
2. map the fields
3. redefine the 3D domain to its intended size, without changing the total number of cells
After the mesh transformation the utility mapFields can be used to map the field from the scaled 2D mesh
to the 3D mesh.
This offering is not approved or endorsed by ESI® Group, ESI-OpenCFD® or the OpenFOAM®
III 165
Foundation, the producer of the OpenFOAM® software and owner of the OpenFOAM® trademark.
Figure 84: The unmapped fields
This offering is not approved or endorsed by ESI® Group, ESI-OpenCFD® or the OpenFOAM®
III 166
Foundation, the producer of the OpenFOAM® software and owner of the OpenFOAM® trademark.
30 Case manipulation
This section contains a discussion on tools for the manipulation of the simulation case which to not create or
modify the mesh or are used for initialisation. Utilities for the before mentioned tasks are already disussed in
previous sections.
30.1 changeDictionary
The utility changeDictionary can be used to modify a dictionary, except those residing in system. We can of
course manipulate any of our dictionaries using a simple text editor, even from the command line (emacs, vim,
nano, etc.).
A possible scenario in which changeDictionary comes in handy is when we do spin-up simulations, i.e. run
the simulation for a certain time with e.g. reduced inflow and continue afterwards with full inflow81 . This
approach might improve the stability of the simulation.
Another case in which changeDictionary proofes to be quite important is when we want to change boundary
value of fields we have gained from a previous simulation. Editing ascii files which measure in the megabytes
can be very tiresome with some text editors. If the files are stored in binary, using a text editor might not be
an option anymore. In this changeDictionary provides a neat way to change boundary values.
Listing 184 shows a simple example of the changeDictionaryDict.
dictionaryReplacement
{
U
{
boundaryField
{
inlet
{
type fixedValue ;
value uniform (20 0 0) ;
}
}
}
}
By default changeDictionary operates only on dictionaries living in the time step directories. By adding the
command line option -constant the dictionaries of the constant folder can be edited.
This offering is not approved or endorsed by ESI® Group, ESI-OpenCFD® or the OpenFOAM®
III 167
Foundation, the producer of the OpenFOAM® software and owner of the OpenFOAM® trademark.
Figure 85: The established flow field and the increased inlet boundary condition of the pitzDaily tutorial case
at t = 1 s
In Line 15 changeDictionary is called. This is the step in which, in our example, we increase the inlet
velocity. In Line 16 we use the GNU tool sed to edit controlDict83 .
In Line 19 we call the solver for the second time. Here it is crucial that the keyword startAt is set to
latestTime in controlDict.
In Line 20 we apply the same renaming to the solver-log of the second run. This is not necessary in priciple,
however, if we are to perform to automated processing of the logs, then a consistent naming scheme might be
very helpful.
1 # !/ bin / sh
2 cd $ {0%/*} || exit 1 # run from this directory
3
4 # Source tutorial run functions
5 . $ WM _ PR OJ EC T_ D IR / bin / tools / RunFunctions
6
7 # Create the mesh using blockMesh
8 runA pplicati on blockMesh
9
10 # Run the solver
11 runA pplicati on pimpleFoam
12
13 # prepare second run
14 mv log . pimpleFoam log . p im pl eF o am Ru n0 1
15 runA pplicati on c h a n g e D i c t i o n a r y
16 sed -i ’s / endTime 20/ endTime 40/ g ’ system / controlDict
17
18 # Run the solver again
19 runA pplicati on pimpleFoam
20 mv log . pimpleFoam log . pimpleFoam02
21
22 # - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - end - of - file
The Allrun script was applied to a slightly modified pitzDaily tutorial case. A appropriate changeDictionaryDict
file Listing 184 was added to the system directory, otherwise the tutorial is untouched. Figure 85 shows the
flow field after changeDictionary was called. The increased inlet velocity is displayed as well as the established
flow from the initial run with an inlet velocity of (10 0 0).
format. However, the whole idea of the spin-up simulation idea is to avoid manual intervention.
This offering is not approved or endorsed by ESI® Group, ESI-OpenCFD® or the OpenFOAM®
III 168
Foundation, the producer of the OpenFOAM® software and owner of the OpenFOAM® trademark.
certain boundaries. Thus, when importing these meshes into OpenFOAM, all patches are of the general patch
type. Hence, there is the necessity to change the patch type of the wall patches to the type wall. This could
be done by manually editing the file boundary, yet this approach does not scale – what if we have hundreds of
wall patches – and it is easy to forget this step.
Using changeDictionary to change the patch type is a scalable solution, i.e. once the changes are specified in
the file changeDictionaryDict, there is no additional work if we do the whole process of importing the mesh
and changing the patch type all over again.
The second main advantage of using changeDictionary instead of manual editing, is that using a tool is
scriptable, whereas manual file manipulation is not. Scripting ensures that no intermediate operation is omitted
in any process.
boundary
{
walls
{
type wall ;
}
}
Listing 186: A simple changeDictionaryDict used to change the type of a patch walls to wall.
2. Remove the cells of the other half of the domain with subsetMesh
3. Change the definition of the newly formed boundary to a symmetry plane with createPatch.
This offering is not approved or endorsed by ESI® Group, ESI-OpenCFD® or the OpenFOAM®
III 169
Foundation, the producer of the OpenFOAM® software and owner of the OpenFOAM® trademark.
After executing this steps, the mesh has a new symmetry boundary, however, all the fields retain their
oldInternalFaces boundary introduced by subsetMesh. Thus, we need to rename the boundary condition
in all fields and change the type of the boundary condition to symmetry.
Change BC type
We can change the type of a boundary condition with the tools changeDictionary or foamDictionary. The
task of bulk-renaming is not possible with either of the tools. The tool changeDictionary is controlled by the
changeDictionaryDict file. Within this file, we can use wildcards for the patch names, however, we can not
use a wildcard for field names. Listings 187 and 188 show an allowed use-case of wildcards and one impossible
use-case in changeDictionaryDict.
Our task, change the BC type for all fields, falls under the latter category. We could, however, work around
this issue if we included all fields in the changeDictionaryDict.
T
{
boundaryField
{
".*"
{
type zeroGradient ;
}
}
}
Listing 187: Possible use of wildcards with changeDictionary: Change all boundary conditions of the field T to
zeroGradient.
".*"
{
boundaryField
{
o l d I n t e r n a l Fa c e s
{
type symmetry ;
}
}
}
Listing 188: Impossible use of wildcards with changeDictionary: Change the type of the boundary condition
for the patch oldInternalFaces of all fields to symmetry.
The tool foamDictionary can also be used to change the type of a boundary condition. This tool is controlled
by command line arguments, Listing 189 shows how the tool is called.
foam Dictiona ry FILE - entry boundaryField . o l d I n t e r n a l F a c e s - set "{ type symmetry ;}"
Listing 189: Calling up foamDictionary to change the type of the BC of the patch oldInternalFaces for the
field defined in FILE.
However, we can only pass one file at a time. This is where the Linux Terminal comes into play. With
a simple for loop, we can loop over all files contained in the 0 directory and call foamDictionary for each
individual file. Done!
Listing 190: Changing the type of the BC of the patch oldInternalFaces for all fields.
This offering is not approved or endorsed by ESI® Group, ESI-OpenCFD® or the OpenFOAM®
III 170
Foundation, the producer of the OpenFOAM® software and owner of the OpenFOAM® trademark.
Rename all BCs for all fields
Next, we would like to change the patch name in all field files. This operation is necessary, as createPatch
operates only on the mesh. The fields are untouched by this tool. As we used createPatch to change the name
and the type of the oldInternalFaces boundary for the mesh, we need to change the boundary name also for
the fields.
This operation is a simple find&replace, which can be done with any text editor. For the sake of automa-
tion, we use the stream editor sed. Again, we loop over all files present in the 0 directory and we apply the
find&replace operation on each file.
Listing 191: Changing the name of the of the patch oldInternalFaces for all fields to symmetry.
Listing 192: The content of the 0 directory of the bubble column tutorial.
If we wanted to simulate nitrogen gas in water, we would need to rename all files in order to follow this
convention. Manually renaming files is tedious and can be automated by the use of the tools available in the
Linux Terminal.
Rename files
First, we want to rename all files in order for them to have the proper file extension. This helps avoiding
confusion. Thus, we use find to search for all files with the file extension air and pass them to rename, which
renames the files according to the specified pattern.
Listing 193: Replacing the file extension air with the file extension nitrogen in all files in and below the
current folder.
Replace text
Next, we need to replace the old phase name within the files itself. Again we use find to search for all files and
pass them to sed, which replaces all text fitting the specified pattern. Note: applying sed to all files can lead
to some trouble, as the text “pair” also gets treated and thus becomes “pnitrogen”. However, if the application
of sed causes such a side effect, OpenFOAM will crash if vital entries were damaged in this way.
Listing 194: Replacing the word air with the word nitrogen in all files in and below the current folder.
This offering is not approved or endorsed by ESI® Group, ESI-OpenCFD® or the OpenFOAM®
III 171
Foundation, the producer of the OpenFOAM® software and owner of the OpenFOAM® trademark.
Part IV
Modelling
31 Solution dimensions
In OpenFOAM all meshes are three-dimensional, yet with a single-cell discretisation and a proper assignment of
empty- or wedge-type boundary conditions, a simulation may have 0, 1, 2 or 3 solution dimensions, or solution
directions as they are referred to by OpenFOAM’s checkMesh tool.
0-D simulations
In a 0-D simulation, the mesh consists of only a single cell, and all PDEs simplify into ODEs with time as the
independent variable. This may seem too strong of a simplification, yet 0-D simulations may be useful to test
the temporal development of certain models.
The OpenQBMM project85 uses a 0-D solver to test their population balance model86 . In a 0-D domain,
only sources and sinks can change the value of a field, as convection is ruled out.
1-D simulations
A 1-D simulation is resolved, respectively discretised, in only one spatial direction. This is a valid simplification
for simulations when the axial flow dominates any lateral flow, e.g. very long pipelines. In the OpenFOAM
tutorials, e.g. the shockTube tutorial case is a 1-D simulation.
2-D simulations
Many tutorials of OpenFOAM are 2-D cases, as they are detailled enough to represent realistic flow, yet they
are simple enough to finish in a finite amount of time. 2-D simulations can be planar 2-D cases, e.g. a narrow
channel, which is much greater in depth than it is in length and height; or axi-symmetric, e.g. a slice of a
domain, which features rotational symmetry. The cavity tutorial case is an example of a planar 2-D simulation;
and the movingCone case is an example of an axi-symmetric simulation case in the OpenFOAM tutorials.
3-D simulations
Full 3-D simulation feature no empty- or wedge-type patches.
This offering is not approved or endorsed by ESI® Group, ESI-OpenCFD® or the OpenFOAM®
IV 172
Foundation, the producer of the OpenFOAM® software and owner of the OpenFOAM® trademark.
An empty-type boundary needs to be parallel to a coordinate plane
Listing 196 shows the output of checkMesh, after we rotated the mesh of the cavity tutorial case. Initially, the
empty boundary is parallel to the x-y plane. However, after we rotated the mesh using transformPoints, the
empty boundary normal direction is (1, 1, 1). This, results in checkMesh reporting 0 solution directions. When
we try to run the case, icoFoam fails with a rather obscure error message.
Listing 196: The output of checkMesh after we applied a rotation from (0, 0, 1) to (1, 1, 1) to the simulation
domain of the cavity tutorial.
From function bool Foam :: adjustPhi ( Foam :: s u r f a c e S c a l a r F i e l d & , const volVec torField & , Foam
:: volScal arField &)
in file cfdTools / general / adjustPhi / adjustPhi . C at line 107.
FOAM exiting
Listing 197: The output of icoFoam after we applied a rotation from (0, 0, 1) to (1, 1, 1) to the simulation domain
of the cavity tutorial.
From function virtual void Foam :: wed gePolyPa tch :: calcGeometry ( Foam :: P streamBu ffers &)
in file meshes / polyMesh / polyPatches / constraint / wedge / wedge PolyPatc h . C at line 110.
FOAM exiting
Listing 198: The output of checkMesh when a wedge-type patch is parallel to a coordinate plane.
This offering is not approved or endorsed by ESI® Group, ESI-OpenCFD® or the OpenFOAM®
IV 173
Foundation, the producer of the OpenFOAM® software and owner of the OpenFOAM® trademark.
PIMPLE-loop would always run for the specified maximum number of outer iterations.
PIMPLE : I t e r a t i o n 1
DILUPBiCGStab : S o l v i n g f o r Ux , I n i t i a l r e s i d u a l = 0 . 0 0 0 2 3 9 8 1 , F i n a l r e s i d u a l = 1 . 6 3 4 0 8 e −08 , No I t e r a t i o n s 1
DILUPBiCGStab : S o l v i n g f o r Uy , I n i t i a l r e s i d u a l = 0 . 0 0 0 6 2 6 6 1 , F i n a l r e s i d u a l = 2 . 4 2 2 0 3 e −07 , No I t e r a t i o n s 2
DILUPBiCGStab : S o l v i n g f o r Uz , I n i t i a l r e s i d u a l = 0 . 0 0 8 2 8 6 3 2 , F i n a l r e s i d u a l = 8 . 7 8 6 4 7 e −07 , No I t e r a t i o n s 1
DILUPBiCGStab : S o l v i n g f o r e , I n i t i a l r e s i d u a l = 1 . 5 7 5 1 3 e −05 , F i n a l r e s i d u a l = 6 . 5 1 7 3 8 e −10 , No I t e r a t i o n s 1
...
PIMPLE : I t e r a t i o n 2
DILUPBiCGStab : S o l v i n g f o r Ux , I n i t i a l r e s i d u a l = 3 . 8 6 5 7 4 e −05 , F i n a l r e s i d u a l = 9 . 4 1 5 2 8 e −09 , No I t e r a t i o n s 1
DILUPBiCGStab : S o l v i n g f o r Uy , I n i t i a l r e s i d u a l = 0 . 0 0 0 9 3 2 5 4 , F i n a l r e s i d u a l = 1 . 3 0 6 8 8 6 e −07 , No I t e r a t i o n s 2
DILUPBiCGStab : S o l v i n g f o r Uz , I n i t i a l r e s i d u a l = 0 . 0 0 8 7 3 8 3 , F i n a l r e s i d u a l = 6 . 1 0 1 2 2 5 e −07 , No I t e r a t i o n s 1
DILUPBiCGStab : S o l v i n g f o r e , I n i t i a l r e s i d u a l = 1 . 1 0 4 1 9 e −05 , F i n a l r e s i d u a l = 6 . 1 4 6 4 1 3 e −10 , No I t e r a t i o n s 1
...
PIMPLE : I t e r a t i o n 3
DILUPBiCGStab : S o l v i n g f o r Ux , I n i t i a l r e s i d u a l = 9 . 8 3 8 8 5 e −06 , F i n a l r e s i d u a l = 6 . 7 4 6 4 2 e −09 , No I t e r a t i o n s 1
DILUPBiCGStab : S o l v i n g f o r Uy , I n i t i a l r e s i d u a l = 0 . 0 0 0 9 2 6 1 7 , F i n a l r e s i d u a l = 2 . 2 6 0 1 5 e −07 , No I t e r a t i o n s 2
DILUPBiCGStab : S o l v i n g f o r Uz , I n i t i a l r e s i d u a l = 0 . 0 0 8 8 5 4 4 , F i n a l r e s i d u a l = 6 . 0 8 1 7 3 7 e −07 , No I t e r a t i o n s 1
DILUPBiCGStab : S o l v i n g f o r e , I n i t i a l r e s i d u a l = 6 . 1 8 1 7 3 e −06 , F i n a l r e s i d u a l = 3 . 7 9 4 9 8 5 e −10 , No I t e r a t i o n s 1
...
PIMPLE : C o n v e r g e d
Doing f i n a l i t e r a t i o n
PIMPLE : I t e r a t i o n 4
DILUPBiCGStab : S o l v i n g f o r Ux , I n i t i a l r e s i d u a l = 3 . 9 0 2 5 8 e −06 , F i n a l r e s i d u a l = 5 . 0 4 5 1 7 e −09 , No I t e r a t i o n s 1
DILUPBiCGStab : S o l v i n g f o r Uy , I n i t i a l r e s i d u a l = 0 . 0 0 0 4 8 3 4 1 , F i n a l r e s i d u a l = 1 . 1 5 0 2 9 e −07 , No I t e r a t i o n s 2
DILUPBiCGStab : S o l v i n g f o r Uz , I n i t i a l r e s i d u a l = 0 . 0 0 8 7 9 3 4 , F i n a l r e s i d u a l = 6 . 3 1 7 7 5 9 e −07 , No I t e r a t i o n s 1
DILUPBiCGStab : S o l v i n g f o r e , I n i t i a l r e s i d u a l = 3 . 3 5 1 4 3 e −06 , F i n a l r e s i d u a l = 5 . 0 9 4 5 2 3 e −10 , No I t e r a t i o n s 1
...
DILUPBiCGStab : S o l v i n g f o r omega , I n i t i a l r e s i d u a l = 1 . 4 1 3 0 0 e −05 , F i n a l r e s i d u a l = 9 . 0 0 6 7 4 e −09 , No I t e r a t i o n s 1
DILUPBiCGStab : S o l v i n g f o r k , I n i t i a l r e s i d u a l = 0 . 0 0 0 1 4 1 5 7 , F i n a l r e s i d u a l = 1 . 0 9 9 7 0 1 e −09 , No I t e r a t i o n s 2
PIMPLE : C o n v e r g e d i n 4 i t e r a t i o n s
Listing 199: The solver output for one time step of a transient compressible axi-symmetric case.
This offering is not approved or endorsed by ESI® Group, ESI-OpenCFD® or the OpenFOAM®
IV 174
Foundation, the producer of the OpenFOAM® software and owner of the OpenFOAM® trademark.
32 Turbulence-Models
32.1 Organisation
The way the source for the turbulence models is organized changed over the time87 the author is dealing with
OpenFOAM. With the release of OpenFOAM-2.3.088 a new, (even) more general, way of code organisation was
rolled out.
The old way relied essentially on namespaces and inheritance to achieve generality and abstraction. The new
way to do stuff is based on templates, inheritance and inheritance from templates. This section discusses both
ways of code organisation. Especially the new way – with all its template madness – may lead to difficulties to
understand the code at first glances. Thus, the author hopes to be able to shed some light into the mysteries
of the new way to do things.
With the release of OpenFOAM-3.0, the transition to the new turbulence modelling framework has been
completed89 . There is no $FOAM_SRC/turbulenceModels directory anymore in the sources. Thus, the discussion
of the old ways is on its way to be of purely historical interest. However, the author hopes, that even the outdated
sections of this ever-growing collection of stuff may provide some insights.
This offering is not approved or endorsed by ESI® Group, ESI-OpenCFD® or the OpenFOAM®
IV 175
Foundation, the producer of the OpenFOAM® software and owner of the OpenFOAM® trademark.
regIOobject
Foam::incompressible Foam::compressible
turbulenceModel turbulenceModel
Figure 86: The class hierarchy of the basis of the old turbulence model framework. The namespaces
Foam::incompressible and Foam::compressible are indicated by the colours red and blue.
Initially the new turbulence modelling framework was introduced with an update of the multiphase solvers.
In the OpenFOAM-2.3.0 release only twoPhaseEulerFoam and DPMFoam. As time progresses more and more
solvers are updated to use the new framework instead of the old. By the time of writing this paragraph (October
2015) dozens of solvers in the OpenFOAM-dev repository were already ported.
case-sensitive. In fact, OpenFOAM makes heavy use of case-sensitivity of the file system. Microsoft, however, reminds us not to
expect, e.g. NTFS, to be case-sensitive. See: https://msdn.microsoft.com/en-us/library/aa365247%28VS.85%29.aspx#naming_
conventions
91 Such as turbulence is present in single-phase, multi-phase, compressile, and incompressible flow.
92 This is not a non-statement, however trivial this might sound. We can relate the existence of turbulence modelling to a certain
class, namely turbulenceModel, which is derived from IOdictionary, and serves as the absolute basis for everything further down
the family tree.
This offering is not approved or endorsed by ESI® Group, ESI-OpenCFD® or the OpenFOAM®
IV 176
Foundation, the producer of the OpenFOAM® software and owner of the OpenFOAM® trademark.
that it is a turbulence model. The data of this class is consequently sparse. The most important data members
of this class are references to the run-time object and the mesh. More information can be found in the file
$FOAM_SRC/TurbulenceModels/turbulenceModels/turbulenceModel.H.
From the class turbulenceModel two classes are derived: incompressibleTurbulenceModel and compressibleTurbulenc
These two classes represent the fact, that flow can be considered incompressible or compressible. The conse-
quence of this difference can be seen in the treatment of the density by these two classes. In Figure 87 we see,
that the incompressible turbulence model has a geometricOneField as density data member, in contrast to
the compressible model, which has a reference to the actual density field.
IOdictionary
turbulenceModel
Time& runTime_
fvMesh& mesh_
Time& time()
fvMesh& mesh()
incompressibleTurbulenceModel compressibleTurbulenceModel
geometricOneField rho_ volScalarField& rho_
Figure 87: The class hierarchy of the basis of the new turbulence model framework.
A little note on ancestry: in the class hierarchy of the ye olden ways, see Figure 86, we saw that the base
classes for the turbulence models, were derived from regIObject. Thus, allowing access to the turbulence model
via OpenFOAM’s registry.
In the class hierarchy of the fancy new order, see Figure 87, we see that the base class for all turbulence
models is derived from the class IOdictionary. In Figure 153, all the way down in Section 57.7, we see that the
class IOdictionary is derived from regIOobject93 . Thus, the turbulence model base class is derived indirectly
derived from regIOobject. Thus, allowing access to the turbulence model via OpenFOAM’s registry.
A mere comparison of Figures 86 and 87 might have suggested otherwise, however, as the list of ancestors
got longer for the new modelling framework, this fact (the derivation from regIOobject) has travelled up the
family tree.
regIOobject and dictionary. In earlier versions of OpenFOAM, IOdictionary is directly derived from regIOobject and
dictionary.
94 The header file of the class geometricOneField describes its intention as follows:
A class representing the concept of a GeometricField of 1 used to avoid unnecessary manipulations for objects which are known
to be one at compile-time.
Used for example as the density argument to a function written for compressible to be used for incompressible flow.
This offering is not approved or endorsed by ESI® Group, ESI-OpenCFD® or the OpenFOAM®
IV 177
Foundation, the producer of the OpenFOAM® software and owner of the OpenFOAM® trademark.
The approach, that TurbulenceModel is derived from its template parameter BasicTurbulenceModel, which
is either an incompressibleTurbulenceModel or compressibleTurbulenceModel, which in turn are derived
from a common base class, demonstrates the great flexibility a high-level programming language, such as C++.
However, the presence of templates and their heavy, sophisticated use – as demonstrated in OpenFOAM – raises
the bar when it comes to reading the source code and finding out what is happening.
BasicTurbulenceModel
Alpha
Rho
BasicTurbulenceModel
TransportModel
TurbulenceModel
Alpha& alpha_,
TransportModel& transportModel_
Alpha& alpha()
geometricOneField geometricOneField
geometricOneField Rho
incompressibleTurbulenceModel compressibleTurbulenceModel
TransportModel TransportModel
IncompressibleTurbulenceModel CompressibleTurbulenceModel
Alpha
geometricOneField
incompressibleTurbulenceModel
TransportModel
PhaseIncompressibleTurbulenceModel Alpha
Rho
compressibleTurbulenceModel
TransportModel
PhaseCompressibleTurbulenceModel
Figure 88: The base class TurbulenceModel has four template parameters and it is derived from one of its
template parameters. Note, that the four derived classes – the four incarnations of the turbulence model – differ
in the template parameters.
sqr(this->U_.dimensions()), symmTensor::zero).
This offering is not approved or endorsed by ESI® Group, ESI-OpenCFD® or the OpenFOAM®
IV 178
Foundation, the producer of the OpenFOAM® software and owner of the OpenFOAM® trademark.
The class eddyViscosity is a class which implements the ideas behind the Boussinesq hypothesis, which is
discussed below.
BasicTurbulenceModel ⇒ BTM
BTM BTM
RASModel LESModel
Switch printCoeffs_ Switch printCoeffs_
Switch turbulence_ Switch turbulence_
volScalarField nuEff() volScalarField nuEff()
BTM BTM
eddyViscosityModel laminar
volScalarField nut_
volSymmTensorField R() volSymmTensorField R() = 0
volScalarField nut() = 0
Figure 89: The class hierarchy of the elementary turbulence models of the new turbulence model framework.
Note the shorthand notation BTM for the class BasicTurbulenceModel.
2
R = µt ∇u + ∇uT − ρI k (32)
3
1X 0 0 1 0 0
k= u u = u ·u (33)
2 i i i 2
The quantity k is the specific kinetic energy of the turbulent fluctuations. A great part of literature refers
to k as turbulent kinetic energy [55, 37, 9, 10], most probably for reasons of keeping the vocabulary short. The
unit tensor I is often denoted with the Kronecker delta δij in literature.
The Boussinesq hypothesis is common to both RAS and LES turbulence models. This can be translated into
a class relationship. In Figure 90 we see how the kEpsilon and the Smagorinsky turbulence models are derived.
Those two models are discussed since these are widely used. The class eddyViscosityModel implements the
general idea of the Boussinesq hypothesis, thus, it is the common base for both turbulence models. In the case
of LES models, an intermediate class (lesEddyViscosityModel) is in between the class eddyViscosityModel
and the actual turbulence model. This class serves to hold data and define methods specific to LES models
using the Boussinesq hypothesis.
The distinction between RAS models and LES models is made by the template parameter inserted in
eddyViscosityModel. In the case of RAS models, the template parameter of eddyViscosityModel from which
e.g. the kEpsilon model is derived is RASModel<BasicTurbulenceModel>. Since RASModel is derived from
BasicTurbulenceModel, the class RASModel is a BasicTurbulenceModel. Thus, this operation is perfectly
valid. In the case of LES models, LESModel<BasicTurbulenceModel> is inserted as the template parameter of
eddyViscosityModel.
Sounds complicated, which it probably also is. Nevertheless, we admire the versatility of generality of the
new turbulence modelling framework and stomach the mental pain caused by all the template and inheritance
wizardry.
This offering is not approved or endorsed by ESI® Group, ESI-OpenCFD® or the OpenFOAM®
IV 179
Foundation, the producer of the OpenFOAM® software and owner of the OpenFOAM® trademark.
BasicTurbulenceModel ⇒ BTM
BTM
eddyViscosityModel ⇒ EVM
volScalarField k()
EVM<RASModel<BTM>> EVM<LESModel<BTM>>
BTM BTM
kEpsilon lesEddyViscosityModel
volScalarField k_ dimensionedScalar Ce_
volScalarField epsilon_ volScalarField epsilon()
volScalarField k()
volScalarField epsilon()
BTM
Smagorinsky
dimensionedScalar Ck_
volScalarField k()
Figure 90: The class hierarchy of a selection of turbulence models of the new turbulence model framework.
Note the shorthand notation BTM for the class BasicTurbulenceModel, and EVM for eddyViscosityModel.
The method signature in italics of the class eddyViscosityModel indicates a pure virtual function. This
method has to be implemented by the classes derived from eddyViscosityModel. In the case of the kEpsilon
class it is the class derived directly from eddyViscosityModel which implements k(). In the case of the
Smagorinsky class, the pure virtual function was inherited via lesEddyViscosityModel. A class containing a
pure virtual function can not be instantiated, thus, there can be no usable turbulence model lesEddyViscosityModel.
This class can only serve as an intermediary.
Wall functions
From OpenFOAM-5.0 onwards, there are no special low-Reynolds wall-functions for epsilon, as the standard
and low-Reynolds formulation have been merged into a single wall-function98 .
However, other fields, such as k and nut, still require special wall-functions when a low-Reynolds model is
used.
Disclaimer
Everthing of Section 32 after this point has been created a while ago. The some of the content of the sub-sections
below might be outdated by the time you read this.
98 See https://github.com/OpenFOAM/OpenFOAM-dev/commit/f260780b7310528505137bbfc8d5f85084379120
This offering is not approved or endorsed by ESI® Group, ESI-OpenCFD® or the OpenFOAM®
IV 180
Foundation, the producer of the OpenFOAM® software and owner of the OpenFOAM® trademark.
32.3 Categories
The desired category of turbulence models can be specified in the file turbulenceProperties. There are three
possible entries.
laminar The flow is modelled laminar
RASModel A Reynolds averaged turbulence model (RAS-model) is used.
LESModel Turbulence is modelled by a large-eddy model.
The file turbulenceProperties contains only one entry. In case of a large eddy simulation, this entry reads:
32.4 RAS-Models
The entry in the file turbulenceProperties specifies only the class of turbulence models. The exact turbulence
model is specified in the file RASProperties. This file must contain all necessary parameters.
Listing 290 shows the content of RASProperties. In this case a k- model is used and no further parameters
are necessary.
RASModel kEpsilon ;
turbulence on ;
printCoeffs on ;
32.4.1 Keywords
RASModel The name of the turbulence model. At this place laminar can also be chosen. The banana test
(see Section 11.2.1) delivers a list of available models.
17
(
LRR
LamBr emhorstK E
LaunderGibsonRSTM
L au nd er S ha rm aK E
LienCubicKE
L i e n C u b i c K EL o w R e
LienLeschzinerLowRe
N on li ne a rK ES hi h
RNGkEpsilon
S pa la rt A ll ma ra s
kEpsilon
kOmega
kOmegaSST
kkLOmega
laminar
qZeta
realizableKE
)
This offering is not approved or endorsed by ESI® Group, ESI-OpenCFD® or the OpenFOAM®
IV 181
Foundation, the producer of the OpenFOAM® software and owner of the OpenFOAM® trademark.
turbulence This is a switch to activate or deactivate the turbulence modelling. Allowed values are: on/off,
true/false or yes/no.
If this switch is deactivated, then a laminar simulation is conducted. This way of choosing a laminar
model is not recommended, see Section 32.6.1.
printCoeffs If this switch is enabled, then the solver will display the coefficients of the selected turbulence
model.
Even if the switch turbulence is disabled, the solver will display the coefficients at the beginning of the
simulation, see Listing 209. The coefficients are not displayed only when RASModel laminar is chosen.
optional parameters Some models accept optional parameters to override the default values of the model.
Listing 203 shows how the coefficients of the k- model can be overridden.
kEpsi lonCoeff s
{
Cmu 0.09;
C1 1.44;
C2 1.92;
C3 -0.33;
sigmak 1.0;
sigmaEps 1.11; // Original value :1.44
}
kEps ilonCoef fs
{
Cmu 0.09;
C1 1.44;
C2 1.92;
C3 -0.33;
sigmak 1.0;
sigmaEps 1.11; // Original value :1.44
banana 0.815; // nonsense parameter
}
This offering is not approved or endorsed by ESI® Group, ESI-OpenCFD® or the OpenFOAM®
IV 182
Foundation, the producer of the OpenFOAM® software and owner of the OpenFOAM® trademark.
Listing 205: Solver output
32.5 LES-Models
32.5.1 Keywords
The keywords turbulence and printCoeffs have the same meaning with LES models. There is also the
possibility – depending on the selected model – of defining optional parameters.
LESModel The name of the turbulence model. At this place laminar can also be chosen. The banana test (see
Section 11.2.1) delivers a list of available models. Listing 206 shows the result of such a banana test. The
model dynamicSmagorinsky was loaded from an external library. See Section 11.3.3 for how to include
external libraries.
16
(
DeardorffDiffStress
LRRDiffStress
Smagorinsky
S pa la rt A ll ma ra s
SpalartAllmarasDDES
SpalartAllmarasIDDES
dynLagrangian
dynOneEqEddy
dynamicSmagorinsky
homogeneousDynOneEqEddy
homogeneousDynSmagorinsky
kOmegaSSTSAS
laminar
m i x e d S m a g o ri n s k y
oneEqEddy
spectEddyVisc
)
32.6 Pitfalls
32.6.1 Laminar Simulation
As already mentioned – see Section 32.4 – turbulence modelling can be deactivated in a some ways.
In the following, different ways to conduct a laminar simulation are listed. This list applys only to solvers
that utilize the generic turbulence modelling of OpenFOAM:
This offering is not approved or endorsed by ESI® Group, ESI-OpenCFD® or the OpenFOAM®
IV 183
Foundation, the producer of the OpenFOAM® software and owner of the OpenFOAM® trademark.
1. turbulenceProperties: simulationType laminar
This is the most general way to turn turbulence modelling off. turbulenceProperties controls the generic
turbulence class. The generic turbulence class can take the form of the laminar, RASModel or LESModel
class, see Figure 154. This is controlled by the parameter simulationType.
Solver output
The last two prossibilities to conduct a laminar simulation can lead to confusion because the solver output
contains word like RASmodel or RAS turbulence model. See Listings 208 and 209. In both cases the simulation
is laminar. In order to avoid this source of confusion, the user should use the parameter simulationType to
perform a laminar calculation.
Independent from all other settings, printCoeffs prints the model constants of the selected turbulence
model. This may also lead to confusion, when e.g. turbulence off is chosen to conduct a laminar simulation.
Exceptions
The above explanation only applies to solvers that utilize the generic turbulence models of OpenFOAM. However,
there is no rule without its exceptions.
simpleFoam This solver uses only RAS turbulence models. Therefore, the entries of the file turbulenceProperties
are redundant and the only ways to control turbulence modelling are items 2 and 3 of the list above.
twoPhaseEulerFoam This solver has the k- turbulence model hardcoded. Only item 3 of the list above
applies to this solver. See Section 32.6.2 for a detailled discussion.
bubbleFoam The same as twoPhaseEulerFoam.
multiphaseEulerFoam This solver only uses LES turbulence models. Items 2 and 3 of the list above apply.
This offering is not approved or endorsed by ESI® Group, ESI-OpenCFD® or the OpenFOAM®
IV 184
Foundation, the producer of the OpenFOAM® software and owner of the OpenFOAM® trademark.
32.6.2 Turbulence models in twoPhaseEulerFoam
In the solver twoPhaseEulerFoam, the use of the k- turbulence model is hardcoded. This means that the solver
does not use the generic turbulence modelling ususally used by OpenFOAMs solvers. The only choice the user
of twoPhaseEulerFoam has is whether to enable or disable the k- turbulence model.
For this reason, the file constant/turbulenceProperties is not needed any more. This file can savely be
deleted.
Another consequence of the k- turbulence model being hardcoded into twoPhaseEulerFoam is that the
keyword turbulenceProperties in the file RASproperties is also not needed any more. This entry is only
read if the generic turbulence modelling is used and if there is any choice of which RAS-model to use. The
only mandatory keyword in RASproperties is the switch turbulence. This switch is the only way to decide
whether to use turbulence modelling or not with twoPhaseEulerFoam. Solvers which use the generic turbulence
modelling offer three possible ways to disable turbulence modelling, see Section 32.6.1.
Algebraic models These models add an algebraic equation to the problem. The turbulent viscosity is com-
puted from known quantities using an algebraic equation (e.g. the Baldwin-Lomax model)
One equation models These models introduce an additional transport equation to the problem. The eddy
viscosity is computed from this additional quantity (e.g. the Spalart-Allmaras model)
Two equation models These models introduce two additional transport equations to the problem. The eddy
viscosity is computed from these additional quantities (z.B. k-, k-ω)
Every field quantity of a turbulence model needs its initial and boundary conditions. Consequently, there may
be the need for additional files in the 0 -directory. One way to find out which files are needed is to look at the
tutorials. There, a case may be found which utilises the needed turbulence model.
If a simulation is started and the solver is missing files – i.e. the solver tries to read files which are not
present – then OpenFOAM will issue a corresponding error message. Listing 210 shows an error message of a
case with a missing 0/k file.
FOAM exiting
This offering is not approved or endorsed by ESI® Group, ESI-OpenCFD® or the OpenFOAM®
IV 185
Foundation, the producer of the OpenFOAM® software and owner of the OpenFOAM® trademark.
Listing 211 shows the folder contents before and after a simulation with pisoFoam. The 0 -directory contains
only the mandatory files, in this case pressure and velocity as well as the turbulent quantities k and .
After the simulation has finished, the 0 -directory contains more files. The reason for creating the *.old files
is not known. However, the turbulence model created the file nut for storing the turbulent viscosity.
The file phi as well as the folder uniform is created by the solver.
Listing 211: Folder contents at the begin and the end of a simulation
The 0 -directories of some tutorial cases may already contain such additional files, e.g. nut. In some cases
the 0-directory may also contain several of such files due to a change in the naming scheme. Listing 212 shows
the contents of the 0 -directory of the pitzDaily tutorial case of simpleFoam. The case has not been run, so the
files nut and nuTilda have not been generated by the solver. None of these two files is necessary to run the
case with the k- turbulence model.
Listing 212: The content of the 0 -directory of the pitzDaily tutorial case of simpleFoam
32.6.6 Spalart-Allmaras
The Spalart-Allmaras is a one-equation turbulence model. Although it introduces only one additional equation
to the problem it needs two additional files in the 0-directory. Listing 213 shows the content of the 0 -folder
of the airFoil2D tutorial case of simpleFoam. The files nut and nuTilda are both necessary to run the case.
The former contains the turbulent viscosity and the latter contains the transported quantity of the turbulence
model. Therefore, the rule one additional transport equation entails one additional data file is not violated.
Because the viscosity is not constant it has to be defined in a file in the 0 -directory. And, because the
viscosity is not the transported quantity of the Spalart-Allmaras model another file is added to the 0 -directory.
nut nuTilda p U
Listing 213: The content of the 0 -directory of the airFoil2D tutorial case of simpleFoam
This offering is not approved or endorsed by ESI® Group, ESI-OpenCFD® or the OpenFOAM®
IV 186
Foundation, the producer of the OpenFOAM® software and owner of the OpenFOAM® trademark.
33 Thermophysical modelling
OpenFOAM features a rich selection of models to account for a fluid’s thermophysical properties, reaching from
constant properties to elaborate models. While the official guide, see cfd.direct/openfoam/user-guide/
thermophysical/, does a good job of summarizing the models, I feel the need to share some (non-)wisdom of
mine on this topic.
99 For the interested historians among the readers, visiting the following site is recommended: the repository at sourceforge
https://sourceforge.net/projects/foam/files/foam/, and the archived versions section on the OpenFOAM homepage https:
//openfoam.org/download/archive/.
100 This is the reason that we can’t find any code which reads the temperature field when we study the source code of solvers that
involve temperature in some way, e.g. heat-transfer or compressible solvers. Another hint for the thermophysical model being the
owner respectively the handler of the temperature field is that in chtMultiRegionFoam the temperature is accessed via thermo.T().
This offering is not approved or endorsed by ESI® Group, ESI-OpenCFD® or the OpenFOAM®
IV 187
Foundation, the producer of the OpenFOAM® software and owner of the OpenFOAM® trademark.
IOdictionary
basicThermo
volScalarField& p_
volScalarField T_
volScalarField alpha_
volScalarField& p()
volScalarField& T()
volScalarField& alpha()
volScalarField& rho()
volScalarField& Cp()
volScalarField& kappa()
fluidThermo solidThermo
volScalarField rho_
tmp<scalarField> mu() volScalarField& rho()
volScalarField& psi() tmp<scalarField> Kappa()
rhoThermo psiThermo
volScalarField rho_ volScalarField psi_
volScalarField psi_ volScalarField mu_
volScalarField mu_
tmp<scalarField> rho()
tmp<scalarField> rho() tmp<scalarField> mu()
tmp<scalarField> mu() volScalarField& psi()
volScalarField& psi()
Figure 91: The class hierarchy of the basis of the thermophysical modelling framework in OpenFOAM-7.
The next classes down the family tree are fluidThermo and solidThermo. The class solidThermo is derived
only from basicThermo and it holds a density field. The solidThermo class extends the thermal conductivity
kappa(), which is provided by basicThermo, by an anisotropic thermal conductivity Kappa(). Anisotropic heat
conduction is a property only solids can exhibit.
The class fluidThermo on the other hand is also derived from the class compressibleTransportModel,
which is not shown in Figure 91. fluidThermo does not hold own data members, however it provides methods
which are relevant for fluids, e.g. access to viscosity.
From fluidThermo the two classes rhoThermo and psiThermo are derived, which model thermodynamic
properties based on density respectively compressibility.
The classes discussed in this section are base classes since these clases are used by the solvers of OpenFOAM.
See the Listings 214 and 215, in which the thermophysical model is created, and used to access the temperature
field.
1 Info < < " Reading th ermophys ical properties \ n " << endl ;
2
3 autoPtr < rhoThermo > pThermo ( rhoThermo :: New ( mesh ) ) ;
4 rhoThermo & thermo = pThermo () ;
5 thermo . validate ( args . executable () , " h " , " e " ) ;
6
7 volS calarFie ld rho
8 (
9 IOobject
10 (
11 " rho " ,
12 runTime . timeName () ,
13 mesh ,
14 IOobject :: NO_READ ,
This offering is not approved or endorsed by ESI® Group, ESI-OpenCFD® or the OpenFOAM®
IV 188
Foundation, the producer of the OpenFOAM® software and owner of the OpenFOAM® trademark.
15 IOobject :: NO_WRITE
16 ),
17 thermo . rho ()
18 );
19
20 volS calarFie ld & p = thermo . p () ;
Listing 214: An extract of buoyantPimpleFoam’s createFields.H file. Note the creation and the use of the
thermophysical model.
Listing 215: An extract of chtMultiRegionFoam’s createSolidFields.H file. Note the creation and the use of
the thermophysical model.
This offering is not approved or endorsed by ESI® Group, ESI-OpenCFD® or the OpenFOAM®
IV 189
Foundation, the producer of the OpenFOAM® software and owner of the OpenFOAM® trademark.
20 T_
21 (
22 IOobject
23 (
24 phasePropertyName ("T"),
25 mesh . time () . timeName () ,
26 mesh ,
27 IOobject :: MUST_READ ,
28 IOobject :: AUTO_WRITE
29 ),
30 mesh
31 ),
101 Interestingly, the ReleaseNotes file of OpenFOAM-1.6 talks of a *New* (reinstated) =eThermo= thermodynamics package.
Prior to OpenFOAM-1.6, the specific internal energy e was only used by the sonicFoam solver in the form of a direct implementation
without an underlying thermophysical model based on the internal energy.
102 https://openfoam.org/release/2-2-0/thermophysical-multiphase-energy/
This offering is not approved or endorsed by ESI® Group, ESI-OpenCFD® or the OpenFOAM®
IV 190
Foundation, the producer of the OpenFOAM® software and owner of the OpenFOAM® trademark.
BasicThermo MixtureType
BasicThermo
MixtureType
heThermo
volScalarField& he_
volScalarField& he()
tmp<volScalarField> Cp()
tmp<volScalarField> kappa()
BasicPsiThermo BasicSolidThermo
MixtureType MixtureType
heRhoThermo heSolidThermo
tmp<volVectorField> Kappa()
BasicPsiThermo
MixtureType
hePsiThermo
Figure 92: The class hierarchy of the templated classes of the thermophysical modelling framework in
OpenFOAM-7.
Figure 92 shows the class hierarchy around the class heThermo, which serves the thermophysical modelling
needs of both fluids and solids. As the need for a respresentation of thermal energy is independent of the
simulated medium being a fluid or solid, the class providing this representation serves them both.
If we compare Figures 91 and 92, we see that the class heThermo provides the methods Cp() and kappa(),
which were abstract methods in the class basicThermo. Furthermore, the class heSolidThermo now provides
the method Kappa(), which was an abstract method in the class solidThermo.
thermoType
{
type hePsiThermo ;
mixture pureMixture ;
transport sutherland ;
thermo janaf ;
e qu at io n Of St at e perfectGas ;
specie specie ;
energy sensibleInternalEnergy ;
}
Listing 218: The selection of thermpophysical models in the file thermophysicalProperties in the constant
directory.
The only entry in the thermoType dictionary, which eludes the banana test is the entry for the keyword
specie, since this is the only available option.
This offering is not approved or endorsed by ESI® Group, ESI-OpenCFD® or the OpenFOAM®
IV 191
Foundation, the producer of the OpenFOAM® software and owner of the OpenFOAM® trademark.
33.3 transport models
The transport model deals among others with the computation of the fluid viscosity as well as thermal conduc-
tivity and diffusivity.
33.3.1 const
The constantTransport model provides constant properties. The model reads the dynamic viscosity µ and the
Prandtl number P r from its coefficient-dictionary.
Cp µ
κ= (34)
Pr
33.3.2 Sutherland
The Sutherland transport model computes the viscosity from Sutherland’s formula [60].
Viscosity
The Sutherland formula computes the dynamic viscosity µ from two model parameters As and Ts .
√
T
µ = As (35)
1 + Ts/T
Figure 93: The dynamic viscosity of nitrogen: the model coefficients were fitted to data reporded in [16], the
model is compared to values reported in [2].
Thermal conductivity
For the thermal conductivity κ a modified Eucken correlation is used [54], which computes the thermal con-
ductivity from the viscosity and other properties. This can be done, since the temperature dependence of the
thermal conductivity is approximately the same as the temperature dependence of the viscosity [18, 23, 24].
1.77Rs
κ = µcv 1.32 + (36)
cv
Note that Rs in (36) is the specific gas constant. If we take a look at the actual source code in Listing 219,
then we might be under the impression that we need the universal gas constant R. However, this is not the
case. See Section 33.7.1 for further information.
In Line 8 of Listing 219 we see the modified Eucken relation from Eq. (36) translated into C++ and Open-
FOAM.
This offering is not approved or endorsed by ESI® Group, ESI-OpenCFD® or the OpenFOAM®
IV 192
Foundation, the producer of the OpenFOAM® software and owner of the OpenFOAM® trademark.
1 template < class Thermo >
2 inline Foam :: scalar Foam :: sutherlandTransport < Thermo >:: kappa
3 (
4 const scalar p , const scalar T
5 ) const
6 {
7 scalar Cv_ = this - > Cv (p , T ) ;
8 return mu (p , T ) * Cv_ *(1.32 + 1.77* this - > R () / Cv_ ) ;
9 }
In Figure 94, we compare the thermal conductivity returned by the Sutherland model with data reported
in literature [16, 2]. For the specific heat capacity, we used the JANAF model with OpenFOAM’s model coeffi-
cients for nitrogen, which can be found in the file $FOAM_ETC/thermoData/thermoData. The good fit between
the values of the Sutherland model and the reported data from literature shows the validity of the modified
Eucken correlation.
Figure 94: The thermal conductivity of nitrogen: the model is using a modified Eucken correlation with the
viscosity model, which was fitted to viscosity data reporded in [16], the model is compared to values of thermal
conductivity reported in [2, 16].
33.3.3 WLF
This model is based on the work of Williams et al. [70].
−C1 (T − Tr )
µ = µ0 exp (37)
C2 + T − Tr
The thermal conductivity is provided by this model by using the Prandtl number. Note that rPr_ in Line
8 of Listing 220 is the reciprocal Prandtl number.
103 Technically, OpenFOAM can also use USCS units, yet why would one choose to use non-SI units?
This offering is not approved or endorsed by ESI® Group, ESI-OpenCFD® or the OpenFOAM®
IV 193
Foundation, the producer of the OpenFOAM® software and owner of the OpenFOAM® trademark.
1 template < class Thermo >
2 inline Foam :: scalar Foam :: WLFTransport < Thermo >:: kappa
3 (
4 const scalar p ,
5 const scalar T
6 ) const
7 {
8 return this - > Cp (p , T ) * mu (p , T ) * rPr_ ;
9 }
Listing 220: Definition of the thermal conductivity in the source code of the WLF model.
33.3.4 Andrade
The Andrade model [7, 8] allows to fit viscosity and thermal conductivity separately. This model was introduced
into OpenFOAM sometime after the release of OpenFOAM-9.
Cµ,3
log µ = Cµ,0 + Cµ,1 T + Cµ,2 T 2 + (38)
Cµ,4 + T
Cκ,3
log κ = Cµ,0 + Cκ,1 T + Cκ,2 T 2 + (39)
Cκ,4 + T
Figure 95 shows the curves of the WLF and the Andrade model fitted to some data from literature. Not
shown in the plot, is the divergence of the WLF curve. As one can see from Eq. (37), the denominator van-
ishes for a temperature of approximately 145 K. While this temperature is well out of the reasonable range for
temperatures of a natural convection case involving an aqueous liquid, a viscosity model that returns bounded
values seems nevertheless preferable. The Andrade model, seeing from Eq. (38), can also diverge when the
denominator vanishes, this happens at a temperature of approximately 0.05 K.
Figure 95: The viscosity of a fluid and the viscosity computed by the WLF and Andrade models fitted to the
data.
33.4 thermo
The thermo model deals with the computation of the specific heat and other derived properties.
33.4.1 JANAF
The name JANAF stems from the Joint-Army-Navy-Air Force Thermochemical Working Group, which pub-
lished thermodynamic properties of many compounds from the 1960s onwards. We also find references to
This offering is not approved or endorsed by ESI® Group, ESI-OpenCFD® or the OpenFOAM®
IV 194
Foundation, the producer of the OpenFOAM® software and owner of the OpenFOAM® trademark.
JANNAF, which brings the NASA into the abbreviation. Furthermore, the polynomials underlying the JANAF
tables are also referred to as the NASA polynomials or the 7 term NASA polynomials 104 .
In the time of limited computer recources, especially memory, polynomials were a very effective way of making
the vast body of experimentally determined thermodynamic data usable for computing. Thus, huge amounts
of data were reduced by virtue of polynomial-fitting to a small, finite number of polynomial coefficients [15].
Furthermore, the recursive formulation of (41) is considered most efficient in terms of the involved computational
operations and memory [15].
The JANAF model is one of the thermo models provided by OpenFOAM. The JANAF model depends on
two sets of model coefficients. The lowCpCoeffs are used when the temperature is below the threshold Tcommon,
when temperatures are higher the coefficients in highCpCoeffs are used. Mathematically spoken, the JANAF
model implements the following equation:
(
lowCpCoeffs Tlow <= T < Tcommon
a= (40)
highCpCoeffs Tcommon <= T <= Thigh
Cp = (((a4 T + a3 )T + a2 )T + a1 )T + a0 (41)
The JANAF model coefficients are two sets of 7 coefficients. Using two polynomials allows to cover a wide
temperature range. Thus, the first polynomial usually covers the low temperature region, 200-1000 K, whereas
the second covers the high temperature region, 1000-6000 K. The two polynomials are constrained to yield the
1000 K value. Furthermore, the polynomial for the low temperature region is pinned to 298.15 K, which serves,
in combination with a pressure of 1 bar, as the standard reference state. Pinning the polynomial to the standard
state ensures, that the thermodynamic properties are exactly reproduced at the standard state [15].
The first 5 coefficients of a polynomial are used for computing the specific heat capacity Cp , as shown above.
The remaining two coefficients are used to compute the enthalpy and the entropy. In Listing 221 an example,
for the way JANAF model coefficents are defined, is shown.
mixture
{
ther modynami cs
{
Tlow 200;
Thigh 6000;
Tcommon 1000;
highCpCoeffs ( 3.08793 0.00124597 -4.23719 e -07 6.74775 e -11 -3.97077 e -15 -995.263 5.95961 ) ;
lowCpCoeffs ( 3.5684 -0.000678729 1.55371 e -06 -3.29937 e -12 -4.66395 e -13 -1062.35 3.71583 ) ;
}
}
Listing 221:
The model coefficients of the JANAF thermpophysical model in the file thermophysicalProperties in the
constant directory.
In OpenFOAM’s etc/thermoData/thermoData the JANAF coefficients for a large number of species can be
found. However, if we want to use the JANAF model outside of OpenFOAM, e.g. in a MATLAB/Octave
script, it turns out that these coefficients need to be multiplied by the specific gas constant of the respective
species. As shown in Listing 222, this is done by the constructor automatically, see Lines 14 and 15 of Listing 222.
This offering is not approved or endorsed by ESI® Group, ESI-OpenCFD® or the OpenFOAM®
IV 195
Foundation, the producer of the OpenFOAM® software and owner of the OpenFOAM® trademark.
17
18 chec kInputDa ta () ;
19 }
In Figure 96 the specific heat capacity of air computed with the JANAF model is compared to data from [64].
Figure 96: Specific heat capacity Cp of air computed with the JANAF model compared to data from [64].
33.5 equationOfState
The equation of state covers the computation of the fluid’s density.
33.5.1 rhoConst
The rhoConst model provides a constant density. The model reads a density value from its coefficient dictionary.
33.5.2 perfectGas
This model uses the eponymous perfect gas model to compute the density from the other two state variables,
i.e. pressure and temperature. This model does not require a coefficient dictionary, as it uses three states of
the fluid (pressure, density and temperature), and the specific gas constant, which can readily be determined.
p
ρ= (42)
Rs T
This offering is not approved or endorsed by ESI® Group, ESI-OpenCFD® or the OpenFOAM®
IV 196
Foundation, the producer of the OpenFOAM® software and owner of the OpenFOAM® trademark.
Creating field kinetic energy K
The error message looks different, when a turbulence model other than laminar is selected. In this case, the
error message is slightly more informative, as the error occurs within the turbulence model framework. If such
an error occurs there, then the error message contains at least the method name, in which the error happened.
At some point, at the construction of all the necessary models, OpenFOAM inevitably divides by the density,
which evaluates to zero in the case of zero pressure. In the case shown above, the laminar model was selected,
which does not need to divide by the density.
The remarkable thing with the error message in Listing 223 is, that it contains no information other than
that a floating point exception occured during dividing numbers.
33.6 Energy
The thermophysical modelling framework of OpenFOAM allows for the use of internal energy or enthalpy as
the primary variable describing the energy of the fluid105 .
33.6.1 Solids
For solids, using internal energy seems to be the proper choice, as indicated by the following commit message106 :
chtMultiRegionFoam: Changed solid energy from enthalpy to internal energy
The solid is currently assumed incompressible (the solid pressure is not updated) and in general
would be near incompressible so internal energy is a more appropriate energy choice than enthalpy
which would require a pressure work term currently not implemented. Additionally due to the way
in which the conduction is handled in terms of the gradient of energy the accuracy of the current
enthalpy implementation is sensitive to the pressure distribution as this introduces an enthalpy
gradient from the p/rho term which would need to be corrected; this issue is avoided by solving for
internal energy instead.
This is consistent with the CHT tutorials of OpenFOAM-9.
33.6.2 Fluids
For incompressible or weakly compressible fluids, solving for internal energy seems favourable as indicated by
the following commit message107 :
thermophysicalModels::equationOfState: Completed departure functions for all except adiabaticPer-
fectFluid
Changed liquid thermo from sensibleEnthalpy to sensibleInternalEnergy in tutorials. It is generally
more convergent and stable to solve for internal energy if the fluid is incompressible or weakly
compressible.
In the tutorials, the choice of internal energy versus enthalpy is not that clear as in the case of solids. With
fluids we can find both uses.
105 https://cfd.direct/openfoam/energy-equation/
106 https://github.com/OpenFOAM/OpenFOAM-dev/commit/c109bec4cc3702ac6dba172efdd30ec6916e73a1
107 https://github.com/OpenFOAM/OpenFOAM-dev/commit/f9971f80d72a5318cdc81120a925ab9817b3ec62
This offering is not approved or endorsed by ESI® Group, ESI-OpenCFD® or the OpenFOAM®
IV 197
Foundation, the producer of the OpenFOAM® software and owner of the OpenFOAM® trademark.
Steady-state
However, another commit message states that enthalpy is preferable for steady-state cases108 :
tutorials/heatTransfer/buoyantSimpleFoam: Updated solver settings to improve convergence
Also changed from internal energy to enthalpy which is preferable for steady-state simulations.
1 // - Gas constant [ J / kg / K ]
2 inline scalar R () const ;
Listing 224: The declaration of the method R() in the header-file of the class specie.
Listing 225: The implementation of the method R() in the header-file of the class specie.
The implementation in Listing 225 stongly suggests that the method R() returns a specific gas constant.
This is confirmed by looking at Listing 226.
Listing 226: The declaration of the universal gas constant in the file thermodynamicConstants.H.
In this case, regarding the universal and specific gas constants, OpenFOAM’s notation is not following the
widely used convention to denote the universal gas constant as R, and the specific gas constant as Rs [50].
33.8 Mixture
OpenFOAM can not only deal with pure fluids, it can also deal with mixtures: e.g. a combustion solver solves
for momentum and energy transport for a single gas phase, whereas the gas phase consists of the gaseous
fuel (methane), the gaseous oxidizer (oxygen), the gaseous oxidation products (carbon-dioxide) and inert gases
(nitrogen). The properties of the gas phase are evaluated on a cell-by-cell basis for the mixture of all gaseous
species.
33.8.1 pureMixture
For a pure fluid, a dictionary named mixture contains the model definitions for all necessary sub-models.
mixture
{
specie
{
//
}
ther modynami cs
{
//
}
transport
{
108 https://github.com/OpenFOAM/OpenFOAM-dev/commit/5df9ec5b1e937817764adaf2932b964a1d188754
This offering is not approved or endorsed by ESI® Group, ESI-OpenCFD® or the OpenFOAM®
IV 198
Foundation, the producer of the OpenFOAM® software and owner of the OpenFOAM® trademark.
//
}
}
Listing 227: The definition of thermophysical modelling in the file thermophysicalProperties for a pure fluid.
33.8.2 multiComponentMixture
Thermophysical modelling
With the multiComponentMixture model, we need to provide a list of species, and a definition the thermophys-
ical modelling for each individual species. The thermophysical modelling definition of the individual species
follows the same pattern as the definition of the thermophysical modelling for pure fluids, see Section 33.8.1.
species
(
Ar
H2
);
Ar
{
//
}
H2
{
//
}
Listing 228: The definition of thermophysical modelling in the file thermophysicalProperties for a mixture
of several fluids.
Composition
The composition of a multiComponentMixture is specified with the mass fractions of the individual components.
The user can provide either a Ydefault field, if the mass fractions are to be initialized equally; or a mass fraction
field for each component. In the example of Listing 228, a user can provide the components’ mass fractions as
fields with the name of the components, i.e. Ar and H2. We can also provide specific mass fraction fields for a
subset of components, in this case the value of Ydefault is applied to the remaining components.
Upon construction of the mixture, the mass fractions are normalized, such that the sum of all mass fractions
is equal to one. Thus, the values in the mass fraction fields do not necessarily sum-up to one.
The mixture’s properties are computed using the mass fractions, e.g. below we see the relation for the
mixture’s density depending of the components’ mass fractions and densities.
mmix = m1 + m2 (43)
mmix = ρmix VCV (44)
mmix = ρ1 V1 + ρ2 V2 (45)
mmix = ρmix (V1 + V2 ) (46)
with the following relation for the individual species’ mass mi
mi = Yi mmix = ρi Vi (47)
we can derive a relation for the mixture density
Y1 mmix Y2 mmix
mmix = ρmix + (48)
ρ1 ρ2
Y1 Y2
1 = ρmix + (49)
ρ1 ρ2
1
ρmix = Y1 Y2
(50)
ρ1 + ρ2
This offering is not approved or endorsed by ESI® Group, ESI-OpenCFD® or the OpenFOAM®
IV 199
Foundation, the producer of the OpenFOAM® software and owner of the OpenFOAM® trademark.
33.9 Model combination
Note, that models can not be freely combined.
Listing 229: The selection of thermpophysical models in the file thermophysicalProperties in the constant
directory.
33.10.1 transport
Similar to the thermophysical models for fluids, the transport model for solids is responsible to provide the
thermal conductivity. However, other than with the fluids, no viscosity is provided.
constant
The constant model is the simplest available model. It takes only one model parameter, i.e. the thermal
conductivity.
transport
{
kappa 57.4781;
}
Listing 230: The model coefficients of the constant transport model in the file thermophysicalProperties in
the constant directory.
polynomial
The polynomial model takes the polynomial coefficients as model parameters.
transport
{
kappaCoeffs <8 > (127.821 -0.267 2.844 e -04 -8.84 e -08 -1.3 e -08 9.3 e -12 -3.6 e -15 5.6 e -19) ;
}
This offering is not approved or endorsed by ESI® Group, ESI-OpenCFD® or the OpenFOAM®
IV 200
Foundation, the producer of the OpenFOAM® software and owner of the OpenFOAM® trademark.
Listing 231: The model coefficients of the polynomial transport model in the file thermophysicalProperties
in the constant directory.
exponential
The exponential model requires three model parameters, the constant coefficient κ0 , the exponent n0 and the
reference temperature Tref .
n0
T
κ = κ0 (51)
Tref
transport
{
kappa0 0.166;
n0 1.6187 e -12;
Tref 0.17385;
}
Listing 232: The model coefficients of the exponential transport model in the file thermophysicalProperties
in the constant directory.
constant-anisotropic
A special case of solid materials are anisotropic properties, e.g. fiber composites have a distinct two-dimensional
internal structure as they are made from layers of fabric infused with resin. This may lead to a variation of
properties depending on whether we consider a material property in the plane of the fibers or perpendicular to
this plane. Wood is another prominent example of a solid material exhibiting anisotropic properties.
The constAnIso model allows the user to specify the heat conductivity kappa as a vector.
transport
{
kappa (42.0 48.0 42.0) ;
}
Listing 233: The model coefficients of the constant transport model in the file thermophysicalProperties in
the constant directory.
In addition to the thermal conductivity in the form of a vector, the user must also provide a coordinate
system. The necessity of reading the coordinate system is due to the solver chtMultiRegionFoam. This is
useful, when the relevant local coordinates of the solid are not aligned with the global coordinate system of the
simulation domain.
This offering is not approved or endorsed by ESI® Group, ESI-OpenCFD® or the OpenFOAM®
IV 201
Foundation, the producer of the OpenFOAM® software and owner of the OpenFOAM® trademark.
Figure 97: The thermal conductivity of nickel: data from literature [29], and the available, fitted models of
OpenFOAM.
33.10.2 thermo
The thermo model is, similar to the case of fluids, responsible to provide the specific heat capacity, the entropy
and various enthalpies.
In contrast to fluids, which offer models formulated in terms of enthalpy or internal energy, the thermopyh-
sical modelling of energy in solids is based solely on enthalpy.
hConst
The hConst model provides constant values. It reads in the specific heat capacity cP and the standard enthalpy
of formation Hf .
hPower
The hPower model computes the specific heat capacity according to Eq. (52). The model takes the model
parameters of Eq. (52) and the standard enthalpy of formation Hf as inputs.
n0
T
Cp (T ) = c0 (52)
Tref
hPolynomial
The hPolynomial model computes its properties using user-provided polynomial coefficients. Additionally, it
takes the standard enthalpy of formation Hf and the standard entropy Sf as model parameters.
33.10.3 equationOfState
rhoConst
The only valid equation of state for thermophysical modelling of solids is rhoConst.
33.10.4 energy
sensibleEnthalpy
The only valid model for energy transport for thermophysical modelling of solids is sensibleEnthalpy.
This offering is not approved or endorsed by ESI® Group, ESI-OpenCFD® or the OpenFOAM®
IV 202
Foundation, the producer of the OpenFOAM® software and owner of the OpenFOAM® trademark.
33.10.5 Model combination
Listing 234 shows the available models for solids in OpenFOAM-7. The model choice for solids is a small subset
of the models available for fluids.
Listing 234: The available thermpophysical models for solids; determined with a banana test with the solver
chtMultiRegionFoam.
Boussinesq model
If our fluid features a change of density due to temperature however not due to pressure, then we can use the
Boussinesq model for the equation of state. This equation of state model was introduced with OpenFOAM-4
to make the Boussinesq approximation available to compressible solvers, as the commit message clearly points
out109 :
equationOfState/Boussinesq: New equation of state for the Boussinesq approximation for buoyant
flows
Description Incompressible gas equation of state using the Boussinesq approximation for the density
as a function of temperature only:
\verbatim rho = rho0*(1 - beta*(T - T0)) \endverbatim
To be used with the buoyantPimpleFoam and buoyantSimpleFoam solvers as an alternative to using
buoyantBoussinesqPimpleFoam or buoyantBoussinesqSimpleFoam, providing consistency with all
other solvers and utilities using the thermodynamics package in OpenFOAM.
The two incompressible solvers with the Boussinesq approximation, i.e., buoyantBoussinesqPimpleFoam and
buoyantBoussinesqSimpleFoam, were retired with the release of OpenFOAM-7110 .
Since using the Boussinesq equation of state is akin to the use of an incompressible fluid model from the
perspective of the dependence on pressure, the absolute pressure has little to no meaning as far as the flow is
concerned. Thus, while the fluid density can change (due to temperature), the fluid is an incompressible one
with respect to pressure.
109 https://github.com/OpenFOAM/OpenFOAM-dev/commit/dfecb23b08c04c92401bc0bdf904ed0793c3be66
110 buoyantBoussinesqPimpleFoamorbuoyantBoussinesqSimpleFoam
This offering is not approved or endorsed by ESI® Group, ESI-OpenCFD® or the OpenFOAM®
IV 203
Foundation, the producer of the OpenFOAM® software and owner of the OpenFOAM® trademark.
33.11.3 Compressible fluids
For (fully) compressible fluids, the density does change due to both temperature and pressure. The perfect gas
model is a typical example, however, OpenFOAM also supports tabulated and polynomial relationships of the
fluid density with respect to temperature and pressure.
Table 4: The different settings for pressure in the two compared cases. Case 1 follows the settings of the
hotRoomBoussinesq tutorial, which is a natural convection case with an enclosed domain. Case 2 is based on
the comfortHotRoom tutorial, which is an open domain case using the Boussinesq equation of state.
Figure 98 shows the mesh of our natural convection case. There are two vertical rows of warm pipes which
will drive the natural convection. The mesh is a hybrid mesh, which is less ideal than the blockMesh-based
meshes of the tutorials. Thus, we hope for a more realistic behaviour of this case in contrast to the small,
near-perfect all-hex meshes of the tutorials.
This offering is not approved or endorsed by ESI® Group, ESI-OpenCFD® or the OpenFOAM®
IV 204
Foundation, the producer of the OpenFOAM® software and owner of the OpenFOAM® trademark.
Figure 98: Two rows of warm pipes in a fluid domain. The mesh is a hybrid mesh consisting of hexahedral and
prismatic cells, which was created by extruding a mixed tet-quad mesh.
Figures 99 to 101 show the development of the flow of our cases. While at first, both cases appear to develop
among similar lines, the error near the top patch at some point dominates the flow within the domain.
Figure 99: Onset of natural convection: both cases feature a quite similar velocity field.
This offering is not approved or endorsed by ESI® Group, ESI-OpenCFD® or the OpenFOAM®
IV 205
Foundation, the producer of the OpenFOAM® software and owner of the OpenFOAM® trademark.
Figure 100: On-going development of natural convection: the flow field on the right shows developing errors in
the flow caused by the pressure boundary condition.
Figure 101: Further development of natural convection: in the flow field on the right, the errors in the flow field
now outweigh the proper flow.
This offering is not approved or endorsed by ESI® Group, ESI-OpenCFD® or the OpenFOAM®
IV 206
Foundation, the producer of the OpenFOAM® software and owner of the OpenFOAM® trademark.
34 Radiation modelling
Radiative heat transfer needs to be considered when temperatures are quite high. OpenFOAM offers several
models to account for radiative heat transfer: the discrete ordinates model (fvDOM), the P1 model and the
view factor model.
fvDOM : Created 60 rays with average directions ( dAve ) and solid angles ( omega )
Ray I0 : dAve = (0.010235 0.0381976 0.0904495) , omega = 0.0999985
Ray I1 : dAve = (0.0279626 0.0279626 0.0904495) , omega = 0.0999985
Ray I2 : dAve = (0.0381976 0.010235 0.0904495) , omega = 0.0999985
Ray I3 : dAve = (0.0381976 -0.010235 0.0904495) , omega = 0.0999985
Ray I4 : dAve = (0.0279626 -0.0279626 0.0904495) , omega = 0.0999985
Listing 236: The constructor of the fvDOM radiation model is reporting the discretized directions for radiative
heat transport.
Each direction has its own radiative intensity field named ILambda_XX_YY, which has two suffixes: the first
(XX) is a counter for the direction, and the second suffix (YY) is a counter for the wavelength band. Listing 237
shows an example of this naming scheme, which is taken from OpenFOAM’s tutorials. In this specific case, we
111 See this note on OpenFOAM’s bug tracker explaining the convention: https://bugs.openfoam.org/view.php?id=2722#c9101.
This offering is not approved or endorsed by ESI® Group, ESI-OpenCFD® or the OpenFOAM®
IV 207
Foundation, the producer of the OpenFOAM® software and owner of the OpenFOAM® trademark.
solve for 60 discrete ordinates, which is indicated in Listing 236, and for a single wavelength band. Thus, the
first suffix runs from 0 to 59; and the second counter has only the value 0.
Since specifying identical BCs for each of the dozens of radiative intensity fields, the fvDOM model offers
the possibility to specify BCs using a field named IDefault, which applies to all the fields.
Time = 910
DILUPBiCGStab : Solving for Ux , Initial residual = 0.000484957 , Final residual = 8.59355 e -07 , No Iterations 1
DILUPBiCGStab : Solving for Uy , Initial residual = 0.000636378 , Final residual = 1.3728 e -06 , No Iterations 1
DILUPBiCGStab : Solving for Uz , Initial residual = 0.00100732 , Final residual = 1.64924 e -06 , No Iterations 1
DILUPBiCGStab : Solving for h , Initial residual = 0.000646664 , Final residual = 9.12454 e -07 , No Iterations 1
Radiation solver iter : 0
GAMG : Solving for ILambda_0_0 , Initial residual = 0.000289555 , Final residual = 7.99208 e -16 , No Iterations 1
GAMG : Solving for ILambda_1_0 , Initial residual = 0.000281662 , Final residual = 7.86555 e -16 , No Iterations 1
GAMG : Solving for ILambda_2_0 , Initial residual = 0.00028829 , Final residual = 7.91439 e -16 , No Iterations 1
...
GAMG : Solving for ILambda_59_0 , Initial residual = 0.00312848 , Final residual = 2.98335 e -06 , No Iterations 1
DICPCG : Solving for p_rgh , Initial residual = 0.00253219 , Final residual = 2.296 e -05 , No Iterations 35
time step continuity errors : sum local = 1.18082 e -06 , global = 1.41217 e -19 , cumulative = -7.81505 e -19
rho max / min : 1.16452 0.69867
DILUPBiCGStab : Solving for epsilon , Initial residual = 0.000330527 , Final residual = 6.62334 e -06 , No Iterations 1
DILUPBiCGStab : Solving for k , Initial residual = 0.000939773 , Final residual = 1.06366 e -05 , No Iterations 1
ExecutionTime = 654.13 s ClockTime = 655 s
Listing 237: An extract of the solver output when using the fvDOM radiation model. The solver output for the
radiation model follows the output of the solution for the momentum and energy equations. For each of the
discrete ordiantes a transport equation for the radiative intensity is solved.
When the solver writes a time step to disk, the radiative intensity field for each discrete ordiante is written
into the time step folder. The fvDOM radiation model also writes some additional fields to disk, which are
according to the description in the header file of the fvDOM model:
a Total absorption coefficient [1/m]
G Incident radiation [W/m^2]
qin Incident radiative heat flux [W/m^2]
qem Emitted radiative heat flux [W/m^2]
qr Total radiative heat flux [W/m^2]
34.2 P1
The P1 model is suited for optically thick problems, i.e. the medium through which the radiation is passing
through does absorb or scatter some of the incident radiation.
34.3.1 Pre-processing
The viewFactor model requires some pre-processing, which is a 2 step process that involves the following
pre-processing tools:
112 https://openfoam.org/release/2-0-0/thermophysical-modelling/
This offering is not approved or endorsed by ESI® Group, ESI-OpenCFD® or the OpenFOAM®
IV 208
Foundation, the producer of the OpenFOAM® software and owner of the OpenFOAM® trademark.
faceAgglomerate
The anouncement of the viewFactor model in the release notes of OpenFOAM-2.0.0 has the following to say
about the computational requirements of the viewFactor model:
The computational time and memory requirement of the modelling is largely determined by the
number of faces from which the rays emanate. In OpenFOAM, the cost can be reduced by grouping
faces together using the faceAgglomerate pre-processing utility.
Hence, the faceAgglomerate tool is used in preparation to create a coarser representation of the surface to reduce
computational effort. In Fluent, using face agglomeration to reduce the computational effort is referred to as
clustering [9].
viewFactorsGen
This tool does the actual creation of rays between the involved surfaces, respecively it computes the view factors
between the agglomerated faces.
Figure 102: The result of faceAgglomerate and viewFactorGen applied to a slightly refined cavity case. The
patches movingWall and fixedWalls have both been agglomerated, i.e. for the purposes of computing the view
factor, several faces of a patch form a coarsened face. This is evident from the visualisation of the rays created
by viewFactorGen, each bundle of rays starts from the center of such a coarsened face. The colour of the rays
is a mere ID, not the actual view factor.
This offering is not approved or endorsed by ESI® Group, ESI-OpenCFD® or the OpenFOAM®
IV 209
Foundation, the producer of the OpenFOAM® software and owner of the OpenFOAM® trademark.
34.3.3 Model use
The viewFactor model requires an additional field in the case setup, the new radiative heat flux qr. The unit
of qr is given in the header description of the viewFactor model as W/m2 . In the field definition of qr, the
dimension set corresponds to the unit kg/s3 , which works out to be the same unit once the unit Watt is replaced
by its SI representation.
The model furthermore reads the finalAgglom field, which is created by the faceAgglomerate tool.
Cij qi = bi (53)
1 1
δij −( − 1)Fij qi = (deltaij − Fij ) σTi4 (54)
Ej Ej
With a static mesh, the view factors are constant, and the only major task for the viewFactor model is to
compute the inverse of an N × N matrix C, with N being the number of coarsened faces. As C contains only
constant entries, the inversion only needs to be done once, at the first iteration of the solver.
Thus, for big simulation cases, we can expect the viewFactor model to take long during pre-processing,
especially when creating the rays using viewFactorGen; and it will take especially long, when it computes the
inverse of C during the first iteration. This is compounded by the fact, that the computation of the radiative
flux happens on the master-process, i.e. parallelisation does not accelerate the viewFactor model, since the
major computational work is done by a single process.
Afterwards, howewer, the viewFactor model doesn’t incur significant computational effort anymore, since
the inverse of C is cached, and during each iteration, computing the radiative heat flux reduces to a simple
matrix-vector multiplication. With a cached inverse matrix, we can solve Eq. (53) very efficiently over and
over, since only the RHS changes from time step to time step.
The discussion above, about the computational effort, can be better understood if we take a look at the
relevant code, shown in Listing 238. There, we see that the viewFactor model is only then efficient, when the
emissivities are constant, otherwise we are not able to benefit from caching the inverse of the matrix C, since
it would change from time step to time step.
1 if ( Pstream :: master () )
2 {
3 // Variable emissivity
4 if (! c on s tE m i s s i v i t y _ )
5 {
6 s c a l a r S q u a r e M a t r i x C ( totalNCoarseFaces_ , 0.0) ;
7
8 // build equation system - code removed for brevity
9
10 Info < < " \ nSolving view factor equations ... " << endl ;
11 // Negative coming into the fluid
12 LUsolve (C , q ) ;
13 }
14 else // Constant emissivity
15 {
16 // Initial iter calculates CLU and chaches it
17 if ( iterCounter_ == 0)
18 {
19 // build equation system - code removed for brevity
20
21 if ( debug )
22 {
23 Info InFuncti on
24 << " \ nDecomposing C matrix ... " << endl ;
25 }
26 LUDecompose ( CLU_ () , pivotIndices_ ) ;
This offering is not approved or endorsed by ESI® Group, ESI-OpenCFD® or the OpenFOAM®
IV 210
Foundation, the producer of the OpenFOAM® software and owner of the OpenFOAM® trademark.
Figure 103: One of the aggressively agglomerated faces: On the right boundary the temperature is 300 K,
yet the radiative heat-flux computed by the mean temperature cools the solid down to 165 K, which is very
unphysical for a case that computes a heated solid interacting with a body of gas. No cooling should occur at
all.
27 }
28
29 // build equation system - code removed for brevity
30
31 if ( debug )
32 {
33 Info InFuncti on
34 << " \ nLU Back substitute C matrix .. " << endl ;
35 }
36 L U B a c ks u b s t it u t e ( CLU_ () , pivotIndices_ , q ) ;
37 iterCounter_ ++;
38 }
39 }
This offering is not approved or endorsed by ESI® Group, ESI-OpenCFD® or the OpenFOAM®
IV 211
Foundation, the producer of the OpenFOAM® software and owner of the OpenFOAM® trademark.
Class
Foam :: compressible ::
turbulentTemperatureCoupledBaffleMixedFvPatchScalarField
Description
Mixed boundary condition for temperature , to be used for heat - transfer
on back - to - back baffles .
}
Class
Foam :: compressible ::
t u r b u l e n t T e m p e r a t u r e Rad C o u p l e d M i x e d F v P a t c h S c a l a r F i e l d
Description
Mixed boundary condition for temperature and radiation heat transfer
to be used for in multiregion cases .
}
Listings 239 and 240 show the relevant header-file descriptions of the involved boundary conditions: a
coupled temperature BC without and with radiation.
Listing 241 shows the relevant boundary condition of the temperature field. Note the similar names of the
temperature BCs, i.e., the one without and the one with radiation.
So, what can go wrong if we do not adjust the temperature BC? Simply put, there will be no radiative heat
transfer. Since the viewFactor model is entirely based on boundary surfaces, all the magic happens with the
boundaries. If we get the temperature boundary wrong, we incur ourselves the cost of modelling radiative heat
transfer without the benefit of acutally accounting for radiative heat transfer in our simulation.
1 " S o l i d G a s In t e r f a c e .* "
2 {
3 /* this does not work !
4 type compressible :: t u r b u l e n t T e m p e r a t u r e C o u p l e d B a f f l e M i x e d ;
5 Tnbr T;
6 kappaMethod solidThermo ;
7 value uniform 1800; */
8
9 // this will work
10 type compressible :: t u r b u l e n t T e m p e r a t u r e R a d C o u p l e d M i x e d ;
11 Tnbr T;
12 kappaMethod solidThermo ;
13 qrNbr qr ;
14 qr none ;
15 value uniform 1800;
16 }
Listing 241: Changing the relevant boundary conditions of the field T in a CHT simulation case to enable heat
transfer due to radiation.
Your trusted author of this very collection of pitfalls has failed to make the according adjustment to his case
and was left wondering why heat transfer was glacially slow. Beginner’s errors happen all the time to all kinds
of people, especially when we are beginning to create a new simulation case.
This offering is not approved or endorsed by ESI® Group, ESI-OpenCFD® or the OpenFOAM®
IV 212
Foundation, the producer of the OpenFOAM® software and owner of the OpenFOAM® trademark.
35 Eulerian multiphase modelling
In Eulerian two-phase modelling both phases are considered continua even though one phase might consist of
dispersed phase elements (DPEs) such as bubbles, drops or particles. In these simulations the two phases can
be distinguished into a continuous phase and a dispersed phase. This naming scheme refers to the physical
situation. Within the (Eulerian) mathematical description, however, both phases are continua.
As two momentum equations are solved (one per phase), each phase has its own velocity field. However,
there is only one pressure field. Thus, the pressure is the same for both phases; this also applies to the VOF
method. Due to the fact that two continuity113 and two momentum equations are solved, this approach is often
referred to as two fluid model.
The Eulerian description of multi-phase flow is not limited to two phases, however, for reasons of simplicity,
we limit ourselves to the case of two phases.
gas
liquid
(a) Discrete bubbles in a continuous (b) Continuum approach.
liquid.
As the DPEs are considered to be a continuous phase, their properties are averaged over each cell of the
computational domain. Thus, the properties of the dispersed phase are the mean properties of the dispersed
matter. If all DPEs have equal properties (e.g. diameter, density, etc.), then the dispersed phase is referred to as
being mono-disperse. Only in the case of mono-dispersity, the averaging over the cells introduces no additional
errors. If the DPEs have variable properties (e.g. a diameter range), then the dispersed phase is referred to as
being poly-disperse. The correct handling of poly-dispersity requires additional considerations on the models.
In fluid dynamics phase is a commonly used term. When we intend our code to represent the reality we want
to describe as closely as possible we need to introduce the concept of the phase into our source code. From a
programming point of view properties of a phase – such as viscosity, velocity, etc. – are easy to implement. The
viscosity of a phase is simply a field of values, velocity is another field of values.
113
P !
The constraint that the sum of all volume fraction fields must yield unity, i.e. α = 1, allows for one continuity equation
i i
to be eliminated. In the case of two phases, only one continuity equation needs to be solved. However, both continuity equation
can be combined.
This offering is not approved or endorsed by ESI® Group, ESI-OpenCFD® or the OpenFOAM®
IV 213
Foundation, the producer of the OpenFOAM® software and owner of the OpenFOAM® trademark.
Object orientation allows us to translate the idea of the phase into programming language. The basic idea
is that a phase has a viscosity, it also has a velocity. We now create a class named phaseModel and this class
needs to have a viscosity, a velocity and everthing else a phase needs to fit our needs.
The phase model classes follow the code of best practice in object oriented programming to hide internal
data from the outer world and to provide access via the classes methods (data encapsulation, see http://www.
tutorialspoint.com/cplusplus/cpp_data_encapsulation.htm).
No phases, please
In the single-phase solvers of OpenFOAM – such as simpleFoam – the concept of a phase is not used. As there
is only one temperature and velocity to deal with, the concept of phases is not needed. In the single-phase
solvers the phase-properties (viscosity, velocity, density, etc.) are linked according to the physical relations that
are taken into account, but the concept of a phase is missing.
twoPhaseEulerFoam
The phase model class in twoPhaseEulerFoam-2.2.x collects the properties of a phase and offers an interface
for accessing these properties. Listing 242 shows the essence of the header file of the phase model class. The
listing is syntactically correct, however all pre-processor instruction (e.g. the #include statements) have been
removed. Furthermore, most of the comments have been removed and the formatting has been adapted to
reduce the line number. The purpose of Listing 242 is to present the data members and methods of the class
by actual source code.
1 namespace Foam
2 {
3
4 class phaseModel
5 {
6 // Private data
7 dictionary dict_ ;
8 word name_ ;
9 d i m e n s i o n e d S c a l a r d_ ;
10 d i m e n s i o n e d S c a l a r nu_ ;
11 d i m e n s i o n e d S c a l a r rho_ ;
12 volV ectorFie ld U_ ;
13 autoPtr < surfaceScalarField > phiPtr_ ;
14
15 public :
16 // Member Functions
17 const word & name () const { return name_ ; }
18
19 const d i m e n s i o n e d S c a l a r & d () const { return d_ ; }
20
21 const d i m e n s i o n e d S c a l a r & nu () const { return nu_ ; }
22
23 const d i m e n s i o n e d S c a l a r & rho () const { return rho_ ; }
24
25 const vol VectorFie ld & U () const { return U_ ; }
26
27 volV ectorFie ld & U () { return U_ ; }
28
29 const s u r f a c e S c a l a r F i e l d & phi () const { return phiPtr_ () ; }
30
31 s u r f a c e S c a l a r F i e l d & phi () { return phiPtr_ () ; }
32 };
33
34 } // End namespace Foam
This offering is not approved or endorsed by ESI® Group, ESI-OpenCFD® or the OpenFOAM®
IV 214
Foundation, the producer of the OpenFOAM® software and owner of the OpenFOAM® trademark.
The phase model class of twoPhaseEulerFoam-2.2.x contains all phase properties needed for an incompressible
two-phase solver that makes use of an important consequence of being limited to two phase problems. By
taking a look on the members of the class we see that there is no volume fraction field. In two phase problems
one volume fraction field (alpha1) suffices as the volume fraction field of the other phase is instantly known
(alpha2 = 1 - alpha1). Thus, the volume fraction can be treated seperately from other phase information.
Another missing item is the pressure. Most two- or multi-phase Eulerian solvers assume/use a common
pressure for all phases. Thus, the pressure is independent of the phases and can be treated seperately.
multiphaseEulerFoam
One difference between the phase model class used in twoPhaseEulerFoam and the one used in multiphaseEuler-
Foam follows directly from the simplification made in the two-phase case. When dealing with an arbitrary
number of phases, each phase must keep track of its own volume fraction. Thus, the volume fraction must be
included into the phase model.
The straight-forward way would be to add another reference to the data members. As the volume fraction
field is a scalar field, this reference would be a reference to a volScalarField. In multiphaseEulerFoam a
more subtle approach was chosen. This also presents the application of another object-oriented programming
technique.
The phase model class of multiphaseEulerFoam is derived from the class volScalarField. Thus, the phase
model class is among other things its own the volume fraction field.
Listing 243 shows a stripped version of the header file of multiphaseEulerFoam’s phase model class. Again,
large parts of the file have been removed leaving only the data members and the methods of the class.
1 namespace Foam
2 {
3
4 class phaseModel
5 :
6 public volSca larField
7 {
8 // Private data
9 word name_ ;
10 dictionary phaseDict_ ;
11 d i m e n s i o n e d S c a l a r nu_ ;
12 d i m e n s i o n e d S c a l a r kappa_ ;
13 d i m e n s i o n e d S c a l a r Cp_ ;
14 d i m e n s i o n e d S c a l a r rho_ ;
15 volV ectorFie ld U_ ;
16 volV ectorFie ld DDtU_ ;
17 s u r f a c e S c a l a r F i e l d phiAlpha_ ;
18 autoPtr < surfaceScalarField > phiPtr_ ;
19 autoPtr < diameterModel > dPtr_ ;
20
21 public :
22
23 // Member Functions
24 const word & name () const { return name_ ; }
25
26 const word & keyword () const { return name () ; }
27
28 tmp < volScalarField > d () const ;
29
30 const d i m e n s i o n e d S c a l a r & nu () const { return nu_ ; }
31
32 const d i m e n s i o n e d S c a l a r & kappa () const { return kappa_ ; }
33
34 const d i m e n s i o n e d S c a l a r & Cp () const { return Cp_ ; }
35
36 const d i m e n s i o n e d S c a l a r & rho () const { return rho_ ; }
37
38 const vol VectorFi eld & U () const { return U_ ; }
39
40 volVe ctorFiel d & U () { return U_ ; }
41
42 const vol VectorFi eld & DDtU () const { return DDtU_ ; }
43
This offering is not approved or endorsed by ESI® Group, ESI-OpenCFD® or the OpenFOAM®
IV 215
Foundation, the producer of the OpenFOAM® software and owner of the OpenFOAM® trademark.
44 volV ectorFie ld & DDtU () { return DDtU_ ; }
45
46 const s u r f a c e S c a l a r F i e l d & phi () const { return phiPtr_ () ; }
47
48 s u r f a c e S c a l a r F i e l d & phi () { return phiPtr_ () ; }
49
50 const s u r f a c e S c a l a r F i e l d & phiAlpha () const { return phiAlpha_ ; }
51
52 s u r f a c e S c a l a r F i e l d & phiAlpha () { return phiAlpha_ ; }
53
54 void correct () ;
55
56 bool read ( const dictionary & phaseDict ) ;
57 };
58
59 } // End namespace Foam
The statements following the class keyword and the class name indicates the derivation of a class. The class
name (phaseModel) and the name of the class we are deriving from (volScalarField) are separated by a colon
(:). The name of the base class (volScalarField) is preceded by a visibility specifier (public). Here, we see a
prototype of a class definition. The class we define (phaseModel) is derived from a base class (volScalarField).
This example highlights, that the class phaseModel is derived from the class volScalarField. This infor-
mation alone does no proof that the phase model is its own volume fraction field. However, a glance on the
constructor in the implementation file brings clarity.
In Listing 244 we see, that the first instruction in the initialisation list of the constructor reads the vol-
ume fraction field of the respective phase. This proofes that the phase model is in fact its own volume
fraction field. For an explanation why we come to this conclusion we refer to any C++ textbook or on-
line resource that covers the concept of inheritance, see e.g. http://www.learncpp.com/cpp-tutorial/
114-constructors-and-initialization-of-derived-classes/ or [59].
// * * * * * * * * * * * * * * * * Constructors * * * * * * * * * * * * * * //
Foam :: phaseModel :: phaseModel
(
const word & name ,
const dictionary & phaseDict ,
const fvMesh & mesh
)
:
volS calarFie ld
(
IOobject
(
" alpha " + name ,
mesh . time () . timeName () ,
mesh ,
IOobject :: MUST_READ ,
IOobject :: AUTO_WRITE
),
mesh
),
name_ ( name ) ,
// code continues
Listing 244: The first few lines of the constructor of the phase model.
Besides being its own volume fraction field the phase model class of multiphaseEulerFoam was extended by
several fields bearing information for the simulation of thermodynamics.
We can also observe the rudiment of giving the phase model a more active role. The phase model class
of twoPhaseEulerFoam is simply an information carrier. The phase model of multiphaseEulerFoam features a
This offering is not approved or endorsed by ESI® Group, ESI-OpenCFD® or the OpenFOAM®
IV 216
Foundation, the producer of the OpenFOAM® software and owner of the OpenFOAM® trademark.
method named correct(). The correct() method is used in many models for actions performed at every time
step. However, in multiphaseEulerFoam-2.2.x this method is empty.
With OpenFOAM-2.1.0 the class diameterModel was introduced into multiphaseEulerFoam and compress-
ibleTwoPhaseEulerFoam. The phase model class of multiphaseEulerFoam uses a diameter model class for keep-
ing track of the dispersed phase’s diameter. The diameter model offers the choice of computing the diameter of
the dispersed phase elements from thermodynamic quantities besides using a constant diameter. Thus, the data
member dimensionedScalar d_ is replaced by a reference to a diameter model (autoPtr<diameterModel> dPtr_).
A comment on multiphaseEulerFoam
The phase model class used for multiphaseEulerFoam in OpenFOAM-2.2.x and OpenFOAM-2.3.x differs very
little with respect to the class’s methods and members. Listing 245 shows that the header files of the phaseModel
class of multiphaseEulerFoam differs only in the copyright notice. The implementation file shows slightly greater
differences114 . However, the behaviour of this class can be considered nearly identical in OpenFOAM-2.2.x and
OpenFOAM-2.3.x.
Listing 245: The output of diff for the file phaseModel.H of the solver multiphaseEulerFoam of the versions
OpenFOAM-2.2.x and OpenFOAM-2.3.x as of May 2014115 .
twoPhaseEulerFoam
The two-phase model of twoPhaseEulerFoam-2.3.x makes heavy use of abstractions. The phase model class is
used in conjunction with a class for the two-phase system.
1 namespace Foam
2 {
3
4 c l a s s phaseModel
5 :
6 public volScalarField ,
7 public transportModel
8 {
9 // P r i v a t e data
10 c o n s t twoPhaseSystem& f l u i d _ ;
11 word name_ ;
12 d i c t i o n a r y phaseDict_ ;
13 s c a l a r alphaMax_ ;
14 autoPtr<rhoThermo> thermo_ ;
15 v o l V e c t o r F i e l d U_;
16 s u r f a c e S c a l a r F i e l d alphaPhi_ ;
17 s u r f a c e S c a l a r F i e l d alphaRhoPhi_ ;
18 autoPtr<s u r f a c e S c a l a r F i e l d > phiPtr_ ;
19 autoPtr<diameterModel> dPtr_ ;
20 autoPtr<P h a s e C o m pr e s s i b l e T u r bu l e n c e M o d e l <phaseModel> > t u r b u l e n c e _ ;
21
114 The diff of the implementation file would be too long to be shown at this place. For general information on diff see Section
??.
115 OpenFOAM Builds compared: 2.2.x-61b850bc107b and 2.3.x-0eb39ebe0f07.
This offering is not approved or endorsed by ESI® Group, ESI-OpenCFD® or the OpenFOAM®
IV 217
Foundation, the producer of the OpenFOAM® software and owner of the OpenFOAM® trademark.
22 public :
23
24 // Member F u n c t i o n s
25 c o n s t word& name ( ) c o n s t { r e t u r n name_ ; }
26
27 c o n s t twoPhaseSystem& f l u i d ( ) c o n s t { r e t u r n f l u i d _ ; }
28
29 c o n s t phaseModel& o t h e r P h a s e ( ) c o n s t ;
30
31 s c a l a r alphaMax ( ) c o n s t { r e t u r n alphaMax_ ; }
32
33 tmp<v o l S c a l a r F i e l d > d ( ) c o n s t ;
34
35 c o n s t P h a s eC o m p r e s s i b le T u r b u l e n c e Mo d e l <phaseModel>&
36 turbulence () const ;
37
38 P h a s e Co m p r e s s i b l eT u r b u l e n c e M od e l <phaseModel>&
39 turbulence () ;
40
41 c o n s t rhoThermo& thermo ( ) c o n s t { r e t u r n thermo_ ( ) ; }
42
43 rhoThermo& thermo ( ) { r e t u r n thermo_ ( ) ; }
44
45 tmp<v o l S c a l a r F i e l d > nu ( ) c o n s t { r e t u r n thermo_−>nu ( ) ; }
46
47 tmp<s c a l a r F i e l d > nu ( c o n s t l a b e l p a t c h i ) c o n s t { r e t u r n thermo_−>nu ( p a t c h i ) ; }
48
49 tmp<v o l S c a l a r F i e l d > mu( ) c o n s t { r e t u r n thermo_−>mu( ) ; }
50
51 tmp<s c a l a r F i e l d > mu( c o n s t l a b e l p a t c h i ) c o n s t { r e t u r n thermo_−>mu( p a t c h i ) ; }
52
53 tmp<v o l S c a l a r F i e l d > kappa ( ) c o n s t { r e t u r n thermo_−>kappa ( ) ; }
54
55 tmp<v o l S c a l a r F i e l d > Cp ( ) c o n s t { r e t u r n thermo_−>Cp ( ) ; }
56
57 c o n s t v o l S c a l a r F i e l d& rho ( ) c o n s t { r e t u r n thermo_−>rho ( ) ; }
58
59 c o n s t v o l V e c t o r F i e l d& U( ) c o n s t { r e t u r n U_; }
60
61 v o l V e c t o r F i e l d& U( ) { r e t u r n U_; }
62
63 c o n s t s u r f a c e S c a l a r F i e l d& p h i ( ) c o n s t { r e t u r n phiPtr_ ( ) ; }
64
65 s u r f a c e S c a l a r F i e l d& p h i ( ) { r e t u r n phiPtr_ ( ) ; }
66
67 c o n s t s u r f a c e S c a l a r F i e l d& a l p h a P h i ( ) c o n s t { r e t u r n alphaPhi_ ; }
68
69 s u r f a c e S c a l a r F i e l d& a l p h a P h i ( ) { r e t u r n alphaPhi_ ; }
70
71 c o n s t s u r f a c e S c a l a r F i e l d& alphaRhoPhi ( ) c o n s t { r e t u r n alphaRhoPhi_ ; }
72
73 s u r f a c e S c a l a r F i e l d& alphaRhoPhi ( ) { r e t u r n alphaRhoPhi_ ; }
74
75 void c o r r e c t ( ) ;
76
77 v i r t u a l b o o l r e a d ( c o n s t d i c t i o n a r y& p h a s e P r o p e r t i e s ) ;
78
79 v i r t u a l bool read ( ) { return true ; }
80 };
81
82 } // End namespace Foam
The data members of the phase model class in twoPhaseEulerFoam-2.3.x contain a reference to the two-phase
model class. This makes the phase model class aware of the other phase. The data members also contain a
reference to a turbulence model and a thermophysical model. This is up to now the greatest generalisation we
could observe in the multi-phase solvers of OpenFOAM.
This offering is not approved or endorsed by ESI® Group, ESI-OpenCFD® or the OpenFOAM®
IV 218
Foundation, the producer of the OpenFOAM® software and owner of the OpenFOAM® trademark.
35.2 Phase system classes
In a multiphase solver we can not only create an abstraction for the physical phase, e.g. water. We can
also create an abstraction for the multi-phase system, i.e. the entirety of the involved phases. Again, multi-
phaseEulerFoam was the forerunner for this idea. Since the introduction of multiphaseEulerFoam there is a
class named multiphaseSystem. In twoPhaseEulerFoam-2.3 the class twoPhaseSystem was introduced. The
most obvious purpose of this class is the implementation of the phase continuity equation. In both solvers the
solution of the continuity equation(s) hides behind the function call fluid.solve().
Phase models
Two data members of the class are the two involved phase models phase1_ and phase2_. The class provides
methods to access this phase models. There is also a method to access the other phase. As there are only two
phases involved, this operation is possible.
1 // - Drag model
2 autoPtr < BlendedInterfacialModel < dragModel > > drag_ ;
3 // - Virtual mass model
4 autoPtr < BlendedInterfacialModel < virtualMassModel > > virtualMass_ ;
5 // - Heat transfer model
6 autoPtr < BlendedInterfacialModel < heatTransferModel > > heatTransfer_ ;
7 // - Lift model
8 autoPtr < BlendedInterfacialModel < liftModel > > lift_ ;
9 // - Wall lubrication model
10 autoPtr < BlendedInterfacialModel < wallLubricationModel > > wa l l L u b r i c a t i o n _ ;
11 // - Wall lubrication model
12 autoPtr < BlendedInterfacialModel < turbulentDispersionModel > > t u r b u l e n t D i s p e r s i o n _ ;
Listing 247: The declaration of the momentum exchange members of the class twoPhaseSystem in
twoPhaseSystem.H
A momentum exchange model alone is nice, but what we really need are the contribution to the momentum
equation. Thus, the class twoPhaseSystem provides methods to access the respective force terms or the respec-
tive coefficients. We have seen this force terms and coefficients in action in Section 45.6.
This offering is not approved or endorsed by ESI® Group, ESI-OpenCFD® or the OpenFOAM®
IV 219
Foundation, the producer of the OpenFOAM® software and owner of the OpenFOAM® trademark.
5 // - Return the heat transfer coefficient
6 tmp < volScalarField > h e a t T r a n s f e r C o e f f () const ;
7 // - Return the lift force
8 tmp < volVectorField > liftForce () const ;
9 // - Return the wall lubrication force
10 tmp < volVectorField > w a l l L u b r i c a t i o n F o r c e () const ;
11 // - Return the wall lubrication force
12 tmp < volVectorField > t u r b u l e n t D i s p e r s i o n F o r c e () const ;
Listing 248: The declaration of the accessing methods for the momentum exchange coefficients of the class
twoPhaseSystem in twoPhaseSystem.H
Phase pair
The class multiphaseSystem declares a nested class interfacePair. A nested class is a class definition within
another class. Thus, the nested class is hidden from the outside world116 .
The phase pair class is used to deal with surface tension, which by definition is a property of a pair of phases,
and drag.
Mixture In this approach the turbulence model is evaluated for the mixture of all phases, i.e. the mixture
velocity and mixture density are inserted into the turbulence model. The turbulent quantities of each
individual phase are computed with the density ratio between the mixture and the corresponding phase.
The applicability of this model is described in the Fluent Theory Guide [9] as follows: [...] is applicable
when phases separate, for stratified (or nearly stratified) multiphase flows, and when the density ratio
between phases is close to 1.
Per-phase In this case each phase has its own turbulent properties. Because there are additional transport
equations to be solved per phase, this model is the most computational intensive. The Fluent Theory
Guide [9] states: [...] is the appropriate choice when the turbulence transfer among the phases plays a
dominant role.
This offering is not approved or endorsed by ESI® Group, ESI-OpenCFD® or the OpenFOAM®
IV 220
Foundation, the producer of the OpenFOAM® software and owner of the OpenFOAM® trademark.
The old framework, see Section 32.1.1, allow only for the first two of the described strategies, since only
one turbulence model is employed by the multiphase solvers. The turbulence model is generally a global object
within the solver, as is also the mesh or the run-time object.
The new framework allows for greater flexibility. In the Eulerian multiphase solvers, the turbulence model
has been moved to the phase model. Thus, each phase has its own turbulence model. This allows for all three
modelling strategies discussed in Section 35.3.1. The turbulence modelling employed by twoPhaseEulerFoam
within the new framework is discussed in Section 45.4.
Flift
Fdrag
(a) Drag; the black arrow indicates the relative velocity (b) Lift
Virtual mass
Fvirtual mass
Ft.-disp.
(c) Virtual mass; the purple arrow indicates the relative acceleration (d) Turbulent dispersion
117 The correct denomination would be force density and force density coefficient. In the source files of OpenFOAM related to
these models, Fq,i and Kqp,i are referred to as force and force coefficient, most probably for the sake of reducing typing effort. As
OpenFOAM keeps track of the physical units of its variables, we can see from the actual source codes, that the force Fq,i is in fact
a force density.
This offering is not approved or endorsed by ESI® Group, ESI-OpenCFD® or the OpenFOAM®
IV 221
Foundation, the producer of the OpenFOAM® software and owner of the OpenFOAM® trademark.
OpenFOAM Constant, no model Constant Isothermal IATE
twoPhaseEulerFoam
2.0.x x
2.1.x x
2.2.x x
2.3.x x x x
multiphaseEulerFoam
2.1.x x x
2.2.x x x
2.3.x x x
35.5.1 No model
The older versions of twoPhaseEulerFoam (≤ 2.2.x) use no model for the diameter of the dispersed phase
elements (DPE). In all of these versions the phase diameter is a scalar of type dimensionedScalar that is read
from the transportProperties dictionary.
35.5.2 Constant
The constantDiameter diameter model is the implementation of a constant diameter in a framework that
allows for a variable diameter.
Internally, the diameter is still a scalar which is read from transportProperties respectively from phaseProperties.
However, the phase model returns the diameter as a field quantity. Listing 249 shows how a volScalarField
is returned. The private variable d_ is of the type dimensionedScalar.
35.5.3 Isothermal
Gas bubbles change their diameter as the ambient pressure changes. The isothermalDiameter model imple-
ments this behaviour by assuming the change of state to be isothermal.
Generally, the ideal gas law (55) governs the state of a gas.
pV = nRT (55)
pV = const (56)
This offering is not approved or endorsed by ESI® Group, ESI-OpenCFD® or the OpenFOAM®
IV 222
Foundation, the producer of the OpenFOAM® software and owner of the OpenFOAM® trademark.
Next we introduce the bubble volume
d3 π
V = (57)
6
Thus, we gain the relation
π π
p1 d31 = p2 d32 (58)
6 6
This leads to the isothermal diameter model
r
p1
d2 = 3
d1 (59)
p2
For the isothermalDiameter model the user needs to specify a reference pressure and diameter. Listing
250 shows the d() method of the class isothermalDiameter. The reference pressure p0_ and diameter d0_ are
private data members of the class118 . With Eqn. (59) the local diameter is computed (Line 10).
35.5.4 IATE
IATE stands for interfacial area transport equation. This model is based on [35]. The IATE diameter model
solves a transport equation for the interfacial curvature kappai_.
Solves for the interfacial curvature per unit volume of the phase rather than interfacial area per
unit volume to avoid stability issues relating to the consistency requirements between the phase
fraction and interfacial area per unit volume.
Class description in IATE.H
In Section 65 we cover the derviation of the governing equations implemented in OpenFOAM from the equations
in [35].
118 An underscore (_) as suffix to the variable name apparently indicates private variables. Although the coding style guidelines
of OpenFOAM (http://openfoam.org/contrib/code-style.php) do not explicitely say so. However, this is recommended style by
other communities, e.g. http://geosoft.no/development/cppstyle.html.
This offering is not approved or endorsed by ESI® Group, ESI-OpenCFD® or the OpenFOAM®
IV 223
Foundation, the producer of the OpenFOAM® software and owner of the OpenFOAM® trademark.
boundaryField
{
inlet
{
type flowRateInletVelocity ;
massFlowRate 0.2;
rho thermo : rho . air ;
extrapolateProfile no ;
value uniform (0 0 0) ;
}
// ...
}
Listing 251: Specifying a massflow BC in an U.air file, here we need to specify the phase-density.
In multiphase solvers, access to the density field is generally handled by the phase-model class. Thus, the
multiphase solvers do not create registered density fields, in contrast to compressible single-phase solvers, such
as rhoPimpleFoam. As access to the density is handled via the phase model’s thermophysical model, this reflects
in the way we refer to the phase’s density when we e.g. specify a massflow BC.
Note, that in Line 7 of Listing 251 a single colon (:) is used as a separator. This can potentially be confused
with the double colons (::), which are used in C++ to separate namespace qualifiers. However, in a certain way,
we find that this is also a sort of namespace, since the thermo prefix indicates that this field is a field which is
provided by the thermophysical model, as opposed to solver-managed fields, such as p or U.
writeObjects1
{
type writeObjects ;
libs (" l i b u t i l i t y F u n c t i o n O b j e c t s . so ") ;
objects (
thermo : rho . air
);
writeOption anyWrite ;
}
Listing 252: Writing the gas-density field to disk, using the writeObjects function object.
This offering is not approved or endorsed by ESI® Group, ESI-OpenCFD® or the OpenFOAM®
IV 224
Foundation, the producer of the OpenFOAM® software and owner of the OpenFOAM® trademark.
36 Boundary conditions
When the geometry of a problem is meshed, then the boundary patches – i.e. the faces delimiting the geometry
– need to be specified. Every boundary patch is of a certain type. In Section 36.1 the possible types are
discussed.
wedge If a geometry is axisymmetric, then the problem can be simplified. In this case, only a part of the
geometry – a wedge – is modelled. The additional boundaries are of type wedge.
cyclic Cyclic boundary.
processor A boundary between sub-domains created during the domain decomposition is of type processor.
wall This is a special type for walls. This type is mandatory for using wall models when modelling turbulence.
The boundaries of the types patch and wall need to be specified further. These boundaries can have boundary
conditions of the primitive or derived types.
type fixedValue ;
value uniform (0 0 0) ;
This offering is not approved or endorsed by ESI® Group, ESI-OpenCFD® or the OpenFOAM®
IV 225
Foundation, the producer of the OpenFOAM® software and owner of the OpenFOAM® trademark.
36.3.1 inletOutlet
The behaviour of the inletOutlet boundary condition depends of the flow direction. If the flow is directed out-
wards, then a zeroGradient boundary condition is applied. If the flow is inwards, then a fixed value is prescribed.
The value of the inflowing quantity is provided by the inletvalue keyword. The value keyword has to be
present, but it is not relevant.
type inletOutlet ;
inletValue uniform (0 0 0) ;
value uniform (0 0 0) ;
36.3.2 surfaceNormalFixedValue
The surfaceNormalFixedValue boundary condition prescribes the norm of a vector field. The direction is taken
from the surface normal vector of the patch. A positive value for refValue means, that this quantity is directed
in the same direction as the surface normal vector. A negative value means the opposite direction.
type surfaceNormalFixedValue ;
refValue uniform -0.1;
36.3.3 pressureInletOutletVelocity
This boundary condition is a combination of pressureInletVelocity and inletOutlet.
36.4 Pitfalls
36.4.1 Syntax
When assigning a fixedValue boundary condition, OpenFOAM expects the keyword uniform or nonuniform
after the value keyword.
Listing 256 shows the file 0/k. There the inlet boundary definition differs from Listing 253. Note the missing
uniform keyword. The reaction of OpenFOAM differs from the value after the keyword version.
Listing 257 shows the warning message OpenFOAM issues, when the value after the keyword version is
2.0 like in Listing 256. In this case, OpenFOAM assumes uniform.
If the value after the keyword version is 2.1, then OpenFOAM will issue an error message like in Listing
258.
In both cases OpenFOAM-2.1.x was used. The author assumes the reason for this distinction between version
2.0 and 2.1 lies in an extension of the possible boundary conditions See the release notes of OpenFOAM-2.1.0
(http://www.openfoam.org/version2.1.0/boundary-conditions.php).
FoamFile
{
version 2.0;
format ascii ;
class vol ScalarFi eld ;
object k;
}
// * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * //
dimensions [0 2 -2 0 0 0 0];
boundaryField
{
inlet
This offering is not approved or endorsed by ESI® Group, ESI-OpenCFD® or the OpenFOAM®
IV 226
Foundation, the producer of the OpenFOAM® software and owner of the OpenFOAM® trademark.
{
type fixedValue ;
value 1e -8;
}
file : / home / user / OpenFOAM / user -2.1. x / run / t w o P h a s e E u l e r F o a m / bubblePlume / case /0/ k :: boundaryField
:: inlet from line 25 to line 26.
From function Field < Type >:: Field ( const word & keyword , const dictionary & , const label )
in file / home / user / OpenFOAM / OpenFOAM -2.1. x / src / OpenFOAM / lnInclude / Field . C at line 278.
FOAM exiting
36.5.1 uniformFixedValue
This boundary condition is an generalisation of the fixedValue BC. See http://www.openfoam.org/version2.
1.0/boundary-conditions.php.
Listing 259 shows the definition of a time-variant boundary condition with a fixed value. Between the time
t = 0.0 s and t = 5.0 s the value of the boundary condition is linearly interpolated between the values for both
ends of the interval. After this interval has ended, the value of the boundary condition remains constant.
inlet
{
type uniformFixedValue ;
uniformValue table
(
( 0.0 (0.0 0.0 0.0) )
( 5.0 (0.0 0.0 0.1) )
);
}
This offering is not approved or endorsed by ESI® Group, ESI-OpenCFD® or the OpenFOAM®
IV 227
Foundation, the producer of the OpenFOAM® software and owner of the OpenFOAM® trademark.
37 Mesh interfaces: AMI and ACMI
In a perfect world, the gods of CFD look favourably upon us mere earthly creatures. However, as the world
is far from perfect, the gods of CFD, in their infinite wisdom, blessed us with some of their beloved nasties:
non-conformal meshes, moving meshes and various other things.
However, not all hope is lost. OpenFOAM offers AMI and ACMI to address the issues of unconnected
meshes and moving meshes.
ACMI
With OpenFOAM-2.3120 the AMI method was extended and the arbitrary coupled mesh interface (ACMI) was
introduced. The ACMI allows for having partially overlapping patches.
Figure 106: Our simulation domain. The block structure of outer domain, in blue, does not match the block
structure of the inner domain, in red. However, by keeping the two regions separate, we cen mesh each region
individually, which is fairly easy, and use AMI to essentially connect the two regions. After meshing, we can
rotate the inner domain with respect to the outer domain to change the orientation of the triangle in the center
of the inner domain.
Thus, AMI will deal with the information exchange between the two unconnected mesh regions. When
simulating the flow, the two regions will act as if they were a single one. Furthermore, AMI frees us from the
119 See https://openfoam.org/release/2-1-0/ami/
120 See https://openfoam.org/release/2-3-0/non-conforming-ami/
This offering is not approved or endorsed by ESI® Group, ESI-OpenCFD® or the OpenFOAM®
IV 228
Foundation, the producer of the OpenFOAM® software and owner of the OpenFOAM® trademark.
worry to create a matching mesh on the connecting boundary, i.e. the mesh of the inner patch of the outer
domain, and the mesh of the outer patch of the inner domain do not need to match. The only thing we need
to specify is which patch needs to talk with which other patch, i.e. we need to specify the neighbouring patch
of each AMI patch.
When we study the flow for various orientations of the body in question, we simply rotate the inner domain
with respect to the outer domain to get a proper mesh for current orientation. Thus, while we created a single
mesh, we can study an arbitrary number of orientations without the need to create the same number of meshes.
We simply use the utility moveMesh to rotate the inner domain to the new orientation, and we are good to go.
Figure 107: Varying the orientation of the investigated body. Since the body-fitting mesh of the inner domain
is in an over-all cylindrical shape, we simply can rotate the inner domain with respect to the outer domain, to
change the orientation of the investigated body with respect to the incident flow. After creating the mesh, we
can use moveMesh to rotate the inner domain. With appropriate settings for the angular velocity and the write
interval, we can get a mesh for any orientation of the triangular prism.
This case demonstrates the use of AMI for studies with a purely stationary mesh. If we apply all the steps
described above, to each time step of a simulation, instead of an individual simulation of a parametric study,
we end up with a sliding mesh simulation case. Thus, AMI enables simulations with a dynamic, sliding mesh.
However, AMI can also be used for simulations with purely stationary meshes. Sometimes it is easier to mesh
individual regions of the simulation domain individually, and let AMI handle the connection of this regions. In
the case of two stationary unconnected mesh regions121 , we could alternatively use stitchMesh to connect the
two regions. Using stitchMesh will result in a mesh with one single region.
Figure 108: A 2D simulation of the triangular, prismatic body in laminar cross-flow using AMI to connect the
body fitted mesh of the inner region with the mesh of the outer domain.
This offering is not approved or endorsed by ESI® Group, ESI-OpenCFD® or the OpenFOAM®
IV 229
Foundation, the producer of the OpenFOAM® software and owner of the OpenFOAM® trademark.
37.3.1 Use case - varying body orientation
To demonstrate the ACMI, we use again the example from above. Only this time, our inner domain does not
fill the outer domain completely, see Figure 109. In this example, the remaining void represents the body under
investigation, i.e. a prismatic body with a semi-circular base. Again, by rotating the inner domain with respect
to the outer domain, we change the orientation of the body under investigation.
The inner boundary of the outer domain is a patch with the form of a cylinder shell. The outer boundary
of the inner domain, however, has the shape of the shell of a semi-cylinder. Thus, the two patches forming the
interface of the outer and inner domain overlap only partially.
The ACMI needs to distinguish whether a face has a neighbour, i.e. the face is part of the overlaping section
of the patch; or the face has no neighbour, i.e. the face acts as a wall. Thus, we need a pair of patch defini-
tions for each domain: couple and blockage. In the case of couple, we need to specify the neighbouring patch, as
we needed in the AMI case. In the case of blockage, we need to specify the behaviour, in most cases: being a wall.
Figure 109: A simulation domain with two unconnected regions. Note that the inner region only partially fills
the void of the outer region.
Figure 110: The inner domain in more detail. The block-structure of the inner domain is clearly recognizable.
The remaining void is the body under investigation, in this case a semi-cylinder.
This offering is not approved or endorsed by ESI® Group, ESI-OpenCFD® or the OpenFOAM®
IV 230
Foundation, the producer of the OpenFOAM® software and owner of the OpenFOAM® trademark.
Figure 111: A 2D simulation of the semi-cylinder in laminar cross-flow using ACMI to connect the mesh of the
inner region with the mesh of the outer domain.
This offering is not approved or endorsed by ESI® Group, ESI-OpenCFD® or the OpenFOAM®
IV 231
Foundation, the producer of the OpenFOAM® software and owner of the OpenFOAM® trademark.
38 The MRF method
The MRF method allows for the simulation of rotating machinery without an actually rotating mesh. By using
multiple reference frames, we can simulate the problem with a static mesh. Although, this simplifaction intro-
duces certain modelling errors, the reduced complexity and faster computation times compared to a simulation
with a moving mesh, as well as the sufficient precision on a global scale, justifies this method under the right
circumstances. See Section 66 for the theoretical backgound of the MRF method.
38.1 Usage
The MRF method is applied to cell zones. This is clearly indicated by the cellZone keyword in the MRFProperties
dictionary, see Listing 260. Apart from where to apply the MRF method, we can enable/disable the application
of the MRF method using the active keyword.
Another important input is the list of non-rotating patches, aptly named nonRotatingPatches, as the solid
body rotation according to the rotation of the reference frame is applied to all wall patches. However, there
might be the case of patches within the MRF cell zone, that are actually stationary, hence the option to exclude
individual patches from the application of the MRF method.
Finally, in Listing 260, the nature of the rotation of the reference frame is specifed. This is done by providing
the axis of rotation (axis) and a point in space (origin). The point origin must be located somewhere on the
axis of rotation. The keyword omega is used to specify the rotational velocity.
zone1
{
cellZone rotor ;
active yes ;
origin (0 0 0) ;
axis (0 0 1) ;
omega table
2(
(0 0.0)
(0.75 20.0)
);
}
Listing 260: Specifying the necessary inputs for the MRF method in the MRFProperties dictionary.
Figure 112 shows the cell zone for the mesh of a stirred tank. The cell zone, to which the MRF method is
applied, is shown as white wireframe. Note, that this zone is of cylindrical shape and is aligned with the axis
of rotation.
If we extended the cylinder from the very bottom to the very top, then the bottom and top patches of the
stator would need to be entered into the list of non-rotating patches.
This offering is not approved or endorsed by ESI® Group, ESI-OpenCFD® or the OpenFOAM®
IV 232
Foundation, the producer of the OpenFOAM® software and owner of the OpenFOAM® trademark.
Figure 112: A baffled stirred tank with a Rushton impeller. The stator patch is shown in grey and the rotor
patch is shown in red. The white wireframe shows the boundary of the rotor zone. For all cells of the rotor
zone the MRF method is applied.
Figure 113: Half a baffled stirred tank with a Rushton impeller. The cyclic-type patches are shown as coloured
wireframes, and all other patches are shown as coloured surfaces.
This offering is not approved or endorsed by ESI® Group, ESI-OpenCFD® or the OpenFOAM®
IV 233
Foundation, the producer of the OpenFOAM® software and owner of the OpenFOAM® trademark.
39 The fvOption framework
The fvOption framework handles sources and constraints of our numerical flow model. The fvOption framework
allows us to plug various constraints or sources into an existing solver without any solver modification. Besides
general sources and constraints, there is a number of specialised sources representing a specific physical models,
e.g. the effect of a porous zone on the momentum equation.
The fvOptions framework was introduced with the release of OpenFOAM-2.2.0122 in 2013 and has expanded
since.
Motivation
The use of the fvOption framework is best explained on an example. Equation (60) shows a convective trans-
port equation for a general scalar C, e.g. a passive tracer concentration. On the RHS, we see the general,
linearized source term. If, in our example, the tracer enters the simulation domain through the inlet, then all is
well and an inlet BC for the tracer concentration C suffices. If, however, the tracer is introduced via a probe,
which we do not want to resolve with our mesh123 , then we need a mechanism to introduce the tracer C within
our simulation domain. This is where fvOptions come to the rescue. These offer us to specify, at the location
of the tip of the probe, an injection rate or a fixed value for the field C.
∂C
+ ∇ · (Cu) = Su + Sp C (60)
∂t
The fvOption framework offers a fixed-value constraint and a semi-implicit source, with which we can model
our tracer generating probe.
Application
Below, in Listing 261, we see the energy equation of a compressible flow solver of OpenFOAM. In this Listing,
all calls to the fvOptions framework are marked in red, green and blue. There, we see that the fvOptions
framework can act on the governing equation of a certain field itself, as well as act on the computed field after
the governing equation has been solved.
1 {
2 volS calarFie ld & he = thermo . he () ;
3 fvSc alarMatr ix EEqn
4 (
5 fvm :: ddt ( rho , he ) + fvm :: div ( phi , he )
6 + fvc :: ddt ( rho , K ) + fvc :: div ( phi , K )
7 + (
8 he . name () == " e "
9 ? fvc :: div
10 (
11 fvc :: absolute ( phi / fvc :: interpolate ( rho ) , U ) ,
12 p,
13 " div ( phiv , p ) "
14 )
15 : - dpdt
16 )
17 - fvm :: laplacian ( turbulence - > alphaEff () , he )
18 ==
19 fvOptions(rho, he)
20 );
21
22 EEqn . relax () ;
23 fvOptions.constrain(EEqn);
24 EEqn . solve () ;
25 fvOptions.correct(he);
26 thermo . correct () ;
27 }
Listing 261: The energy equation in the file EEqn.H of the compressible, single-phase solver rhoPimpleFoam
122 https://openfoam.org/release/2-2-0/fv-options/
123 E.g. the smoke probe used in wind tunnels for the study of external aerodynamics.
This offering is not approved or endorsed by ESI® Group, ESI-OpenCFD® or the OpenFOAM®
IV 234
Foundation, the producer of the OpenFOAM® software and owner of the OpenFOAM® trademark.
A solver, that uses the fvOptions framework creates an object of the type fvOptionList, which is a list of
fvOptions. This is also the reason why, for all calls to the fvOptions framework, parameters have to be passed.
Otherwise, the framework would not be able to assign the options to their respective equations. In the case of
a porous zone in the domain of a single-phase simulation, we might use the fvOptions framework to account
for the additional flow resistance in the momentum equation and also to apply certain source terms for the
turbulence model equations. Thus, the list of options has to be traversed to find and apply the proper fvOption
to the respective model equation.
In the Listing 262 below, we see the method fvOptionList::constrain() as an example of how Open-
FOAM applies the fvOptions. We traverse the list of all options, and for each options, we check whether this
option applies to the provided model equation. If the option applies, it is determined whether the option is
enabled, i.e. whether it is active, and if this is the case, the option is applied by calling the constrain() method
of the fvOption class, i.e. calling the constrain() method of the source itself.
1 template < class Type > void Foam :: fv :: optionList :: constrain ( fvMatrix < Type >& eqn )
2 {
3 checkApplied () ;
4 forAll (* this , i )
5 {
6 option & source = this - > operator []( i ) ;
7 label fieldi = source . applyToField ( eqn . psi () . name () ) ;
8 if ( fieldi != -1)
9 {
10 source . setApplied ( fieldi ) ;
11 if ( source . isActive () )
12 {
13 if ( debug )
14 {
15 Info < < " Applying constraint " << source . name ()
16 << " to field " << eqn . psi () . name () << endl ;
17 }
18 source . constrain ( eqn , fieldi ) ;
19 }
20 }
21 }
22 }
The mode of operation shown above is the same for all calls to the fvOptions framework, we see in Listing
261. Each call causes the list of options to be traversed, and all applicable options to be applied.
39.2.1 Constraint
A constraint acts on an already computed field. We can infer this from the point in the code when the method
fvOptions.constrain() is called, the relevant line is high-lighted in green in Listing 261.
With a constraint, fixed values at certain locations can be enforced in an otherwise freely computed field,
e.g. if we are solving the passive transport of a scalar acting as a tracer or marker, we can define certain cells,
This offering is not approved or endorsed by ESI® Group, ESI-OpenCFD® or the OpenFOAM®
IV 235
Foundation, the producer of the OpenFOAM® software and owner of the OpenFOAM® trademark.
in which the value of the scalar has a fixed value. These locations would be points in space, where the tracer is
injected into our simulation domain.
Available constraints, at the time of writing, are:
• fixedValueContraint
• fixedTemperatureConstraint
39.2.2 Correction
A correction is a type of option, that acts on a field after it has been computed. We can infer this from the
point in the code when the method fvOptions.correct() is called, the relevant line is high-lighted in blue in
Listing 261.
Available corrections, at the time of writing, are:
• limitTemperature
• limitVelocity
39.2.3 Source
A source adds source and sink terms to the governing equation of a certain field. Thus, a source influences
a field via the solution process of its governing equation. We can infer this from the point in the code when
fvOptions() is called, the relevant line is high-lighted in red in Listing 261. In contrast to the constraints and
the corrections, the sources call the ()-operator class fvOptionList.
There is a large number of sources available in OpenFOAM, ranging from very general ones, such as
codedSource or semiImplicitSource to specific sources for certain specific purposes, e.g. actuationDiscForce,
buoyancyForce and many others.
39.3 Sources
This sub-section contains an incomplete list of sources from the fvOptions framework.
fixedCoeff
The fixedCoeff model calculates a momentum contribution S which is proportional to the velocity and the
squared velocity. The model features two model constants: α and β.
This offering is not approved or endorsed by ESI® Group, ESI-OpenCFD® or the OpenFOAM®
IV 236
Foundation, the producer of the OpenFOAM® software and owner of the OpenFOAM® trademark.
or a little rearranged
In OpenFOAM’s implementation α and β are vectorial quantities. In addition with a reference coordinate
system for the porous zone, anisotropic porosity can be considered. Isotropic porosity is then a special case
covered by choosing all components of α and β to be equal.
powerLaw
The powerLaw model computes a momentum contribution S, which is proportional to a model constant C0 and
the C1 -th power of the velocity. The powerLaw model does not support anisotropy.
or a little rearranged
S = −ρ C0 |u|C1 eu
DarcyForchheimer
The DarcyForchheimer model is very similar to the fixedCoeff model. It also has two contributions propor-
dp
tional to the linear and the squared velocity. This model is a combination of the Darcy model U = − µκ dx ,
which is valid for laminar flow, and the its extension to higher Reynolds numbers, known as Forchheimer model
dp
− dx = µκ U + kρ2 U 2 . The Darcy model is proportional to κ, the permeability of the porous medium, [κ] = m2 .
The Forchheimer model introduces k2 , the inertial permeability, [k2 ] = m.
There are two model constants of OpenFOAM’s implementation of the DarcyForchheimer model. The
Darcy coefficient d is the inverser permeability d = κ1 , and the Forchheimer coefficient f is the inverse inertial
permeability f = k12 .
or a little rearranged
In OpenFOAM’s implementation d and f are vectorial quantities, as are the coefficients of the fixedCoeff
model. In addition with a reference coordinate system for the porous zone, anisotropic porosity can be consid-
ered. Isotropic porosity is then a special case covered by choosing all components of d and f to be equal.
39.3.2 phaseLimitStabilization
With OpenFOAM-6124 an fvOption source was introduced to specifically, numerically stabilize transport equa-
tions when the phase fraction falls below a certain threshold. This source adds an implicit source term to a
transport equation for all cells in which the phase fraction falls below a certain limit.
Solving transport equations, which are formulated using a phase fraction field, becomes numerically more
and more difficult when the phase fraction field tends to zero in some cells. Adding an implicit source term
in those cells ensures the discretized equation system does not become ill-posed. When a transport equation
becomes ill-posed due to a phase fraction tending towards zero, the solver of the linear equation system fails
with a floating-point error.
Listing 264 shows the code of the relevant method of this source class. The max() statement ensures that
the source is only applied to cells in which the phase fraction alpha is smaller than the limit residualAlpha.
1 template < class Type > void Foam :: fv :: PhaseLimitStabilization < Type >:: addSup
2 (
3 const volS calarFie ld & alpha ,
4 const volS calarFie ld & rho ,
124 https://openfoam.org/release/6/
This offering is not approved or endorsed by ESI® Group, ESI-OpenCFD® or the OpenFOAM®
IV 237
Foundation, the producer of the OpenFOAM® software and owner of the OpenFOAM® trademark.
5 fvMatrix < Type >& eqn ,
6 const label fieldi
7 )
8 {
9 const GeometricField < Type , fvPatchField , volMesh >& psi = eqn . psi () ;
10 u n i f o r m D i m e n s i o n e d S c a l a r F i e l d & rate =
11 mesh_ . lookupObjectRef < u nif orm Di men sio ned Sca lar Fi eld >( rateName_ ) ;
12
13 eqn -= fvm :: Sp ( max ( resi dualAlph a_ - alpha , scalar (0) ) * rho * rate , psi ) ;
14 }
We see from the code in Listing 264, that a uniformDimensionedScalarField rate is used to compute
the implicit source. This uniformDimensionedScalarField rate can be created by a codedFunctionObject
and then be registered with the mesh. Only when the uniformDimensionedScalarField rate is registered
with the mesh, can the PhaseLimitStabilization source access it via the lookup() method of the mesh. Listing
265 shows an example of how this can be done. The relevant line of code to register the computed rate field is
high-lighted in red. If this line is omitted, then the fvOption source will abort with an error caused by trying
to lookup a non-existent field. See Section 57.7 for in-depth information on the object registry.
functions
{
rate
{
libs ( " l i b u t i l i t y F u n c t i o n O b j e c t s . so " ) ;
type coded ;
name rate ;
codeRead
#{
static autoPtr < uni for mD ime nsi one dSc ala rFi el d > pField ;
if (! pField . valid () )
{
pField . set
(
new u n i f o r m D i m e n s i o n e d S c a l a r F i e l d
(
IOobject
(
" rate . water " ,
mesh () . time () . timeName () ,
mesh () ,
IOobject :: NO_READ ,
IOobject :: NO_WRITE
),
d i m e n s i o n e d S c a l a r ( " rateInit " , dimensionSet (0 , 0 , -1 , 0 , 0 , 0 , 0) , 1.0)
)
);
}
u n i f o r m D i m e n s i o n e d S c a l a r F i e l d & rate = pField () ;
rate.checkIn();
#};
}
}
Listing 265: Computation of a rate field using a codedFunctionObject in the file controlDict.
This offering is not approved or endorsed by ESI® Group, ESI-OpenCFD® or the OpenFOAM®
IV 238
Foundation, the producer of the OpenFOAM® software and owner of the OpenFOAM® trademark.
40 The Lagrangian world
In OpenFOAM not only the finite volume method (FVM), which is part of the Eulerian world, is implemented.
There are also Lagrangian methods available. The Lagrangian methods available in OpenFOAM cover fields
such as:
• molecular dynamics
• discrete particle method
• sprays
• general Lagrangian particle tracking
• reacting and combusting particles
This section covers general Lagrangian particle tracking. The basics behind the Lagrangian methods apply to
all models listed above, e.g. the molecule and the spray parcel are based on the particle class.
40.1 Background
40.1.1 Interaction between Lagrangian particles and Eulerian flow
The coupling between Lagrangian particles and the surrounding (Eulerian) flow can be characterised by their
degree of interaction.
Barycentric tracking
With the release of OpenFOAM-5.0, the LPT algorithm was changed to barycentric tracking125 , see also the
relevant commit message126 . Barycentric tracking has been implemented to increase the robustness of the
tracking algorithm.
125 https://cfd.direct/openfoam/free-software/barycentric-tracking/
126 https://github.com/OpenFOAM/OpenFOAM-dev/commit/371762757dbe3cd38a3841a547a9bc8c1aff0b85
This offering is not approved or endorsed by ESI® Group, ESI-OpenCFD® or the OpenFOAM®
IV 239
Foundation, the producer of the OpenFOAM® software and owner of the OpenFOAM® trademark.
40.2 Libraries
OpenFOAM offers two choices for implementing or using Lagrangian particle tracking (LPT). A discussion on
these can be found in [44].
particle
The class particle is the root of all LPT in OpenFOAM, since it implements the tracking (i.e. the motion) of
the particles itself.
1 namespace Foam
2 {
3 typedef R e a c t i n g M u l t i p h a s e P a r c e l
4 <
5 Reac tingParc el
6 <
7 ThermoParcel
8 <
9 K in em at i cP ar ce l
10 <
11 particle
12 >
13 >
14 >
15 > basicReactingMultiphaseParcel ;
16
17 /* the rest of the code ... */
The class KinematicParcel is an example for the hardships one faces when trying to understand C++.
KinematicParcel is a templated class, with ParcelType as template parameter. In addition KinematicParcel
also is derived from its template parameter ParcelType.
Thus, KinematicParcel is a templated class built around ParcelType, however, it is a ParcelType too (by
inheritance).
LIBBIN)/liblagrangianIntermediate.
128 http://www.openfoam.org/download/version1.5beta.php
This offering is not approved or endorsed by ESI® Group, ESI-OpenCFD® or the OpenFOAM®
IV 240
Foundation, the producer of the OpenFOAM® software and owner of the OpenFOAM® trademark.
6 public :
7
8 /* the rest of the code ... */
1 namespace Foam
2 {
3 typedef KinematicParcel < particle > b a s i c K i n e m a t i c P a r c e l ;
4
5 template < >
6 inline bool contiguous < basicKinematicParcel >()
7 {
8 return true ;
9 }
10 }
The Cloud
A class is best described by taking a look on the code that actually defines it. Listing 269 shows from which
classes Cloud is derived from. Looking at the inheritance actually tells us what the class Cloud is, since an
inheritance relation is an “is a” relation. If A is derived from B, then A is a B.
The listing shows us, that Cloud is a cloud and a IDLList. This poses two new questions, what is a cloud
and a IDLList?
Listing 269: The class definition of Cloud in the file Cloud.H; the ancestry.
In anticipation of the following paragraphs we can state, that the inheritance from two base classes is an
example of applied division of labour. As we will see, the cloud heritage is in charge of input and output (I/O)
whereas the IDLList legacy deals with the management of the single particles which form the cloud.
129 Not to be mixed up with the “cloud” in terms of information technology (IT) as in cloud storage, cloud computing, etc..
This offering is not approved or endorsed by ESI® Group, ESI-OpenCFD® or the OpenFOAM®
IV 241
Foundation, the producer of the OpenFOAM® software and owner of the OpenFOAM® trademark.
The cloud
The class cloud is an object registry similar to the mesh class130 . cloud is derived from the class objectRegistry,
and so are fvMesh and Time. This enables us to register fields with the particle cloud. The class objectRegistry
is in turn derived from regIOobject which is in turn derived from IOobject. Thus, the ancestry of cloud allows
us to read and write the particle cloud to disk131 . See Sections 57.7 and 57.8 for a more detailed discussion on
I/O and the concepts around the class regIOobject.
Disk I/O is most often seen in code that creates or reads fields. Via the cloud branch of a Lagrangian cloud’s
ancestry, disk I/O is controlled in a similar fashion. If we were able to sneak the line of code in Listing 270
e.g. into DPMFoam, right after the construction of the kinematicCloud object, then writing the Lagrangian
solution data to disk would be permanently disabled.
The IDLList
The IDLList is an intrusive doubly-linked list. The concept of a linked list is taught at programming classes
when it comes to objects and data-structures. The traditional linked-list consists of a list class and a node class.
The node class contains a pointer to, or the list-element itself. If the node class is implemented in a generic
fashion, using templates, then one list implementation is sufficient for all datatypes. Otherwise, the node class
would need to be implemented specifically for every datatype that is to be used by the list.
An intrusive linked-list is a very efficient implementation of a linked-list. However, the actual layout differs
from the standard layout of a linked list132 . In an intrusive list, the list element serves also as the node. Figure
114 compares the schematic layouts of traditional and intrusive linked lists.
Intrusive linked-lists are generally considered as being much more efficient than traditional linked-lists133 .
One of the downsides of using intrusive lists is that the implementation of the datatype which is to be used within
the list is mangled with the implementation of the list itself. Generally, this (mangling the implementation
of unrelated concepts) is considered a bad practice in object-oriented design (OOD). However, due to the
performance gain, intrusive lists are widely used in fields where performance beats conformity with standards,
such as computer games or number crunching.
List
Node* head
Node Node
Node* prev Node* prev ...
Node* next Node* next
MyClass* val MyClass* val
MyClass MyClass
Link prev Link prev
MyClass MyClass Link next Link next ...
elem elem // class data // class data
(a) Traditional doubly-linked list. (b) Intrusive doubly-linked list.
or an utility application is of the type fvMesh. Almost all solvers and utilties include the file createMesh.H, which resides in
OpenFOAM/include of your installation.
131 Fields, such as volScalarField and others, are also derived from regIOobject via GeometricField and DimensionedField.
132 http://www.boost.org/doc/libs/1_43_0/doc/html/intrusive/intrusive_vs_nontrusive.html
133 http://www.boost.org/doc/libs/1_58_0/doc/html/intrusive/performance.html
This offering is not approved or endorsed by ESI® Group, ESI-OpenCFD® or the OpenFOAM®
IV 242
Foundation, the producer of the OpenFOAM® software and owner of the OpenFOAM® trademark.
Again, we can take a look at the actual source code to find out what is really going on. Figure 115 shows the
class diagram behind the singly- and doubly-linked intrusive lists. This diagram is in fact a great example of
how far C++ developers can go with abstraction and encapsulation. The classes SLListBase and DLListBase
define the behaviour as being single-linked or doubly-linked. The classes UILList and ILList are more or
less helper or base classes. The class UILList provides STL-conforming iterators, whereas ILList adds some
member functions. The reason for UILList and ILList being separate classes is unknown to the author.
In the case of classic linked lists (non-intrusive lists, either singly- or doubly-linked), the class LList derived
from its template parameter LListBase provides the base class for concrete non-intrusive linked lists.
T* first()
T* last()
ListBase, T
ILList
clear()
DLListBase SLListBase
IDLList ISLList
Figure 115: The class hierarchy needed for intrusive lists of objects of type T; this diagram can be regarded as
a subset of the class diagram for singly- and doubly-linked lists, both classic and intrusive.
thermoCloud
Also the virtual abstract class thermoCloud declares some abstract methods, i.e. methods that a derived class
must implement.
This offering is not approved or endorsed by ESI® Group, ESI-OpenCFD® or the OpenFOAM®
IV 243
Foundation, the producer of the OpenFOAM® software and owner of the OpenFOAM® trademark.
40.4.2 Templates
There are two kinds of cloud templates: the ones that are derived from a base class and their template parameter
CloudType, and the ones that are solely derived from their template parameter. In the following we try to shed
some light into the tempest of templates.
1 namespace Foam
2 {
3 d e f i n e T y p e N a m e A n d D e b u g ( thermoCloud , 0) ;
4 }
Listing 271: Introduction of thermoCloud into the debugging mechanism in the file thermoCloud.C
Template parameter
The classes CollidingCloud and MPPICCloud are templated clouds, which are derived only from their template
parameter. Both classes provide modelling for particle-particle interactions134 .
ParticleType
kinematicCloud Cloud
label nParcels()
CloudType : Cloud
KinematicCloud
label nParcels()
This offering is not approved or endorsed by ESI® Group, ESI-OpenCFD® or the OpenFOAM®
IV 244
Foundation, the producer of the OpenFOAM® software and owner of the OpenFOAM® trademark.
We note, that the kinematic cloud is a cloud of kinematic particles. The kinematic particle class provides
the means to move the particle around and the kinematic cloud type provides the means to move the particles
collectively. This is useful since a solver using Lagrangian particles does not operate on the individual particles.
1 namespace Foam {
2 typedef KinematicCloud < Cloud < basicKinematicParcel > > b a s i c K i n e m a t i c C l o u d ;
3 }
1 namespace Foam {
2 typedef KinematicParcel < particle > b a s i c K i n e m a t i c P a r c e l ;
3 }
1 namespace Foam {
2 typedef ThermoCloud
3 <
4 Kine maticClo ud
5 <
6 Cloud
7 <
8 basicThermoParcel
9 >
10 >
11 > b a s i c T h er m oC l o u d ;
12 }
1 namespace Foam {
2 typedef ThermoParcel < KinematicParcel < particle > > b a s i c T h e r m o P a r c e l ;
3 }
This offering is not approved or endorsed by ESI® Group, ESI-OpenCFD® or the OpenFOAM®
IV 245
Foundation, the producer of the OpenFOAM® software and owner of the OpenFOAM® trademark.
40.5.1 Evolution calling
What happens exactly, when the evolve() method of the cloud is called? To answer this question, we have to
travel the family tree. Figure 117 shows some of the involved methods and classes when a call to evolve() is
made by a solver using a Lagrangian particle cloud.
The sequence shown in Figure 117 is more important to the developer than to the user. Cloud function
objects do offer methods that are evaluated at various stages over this sequence. The names of the methods are
quite telling: preEvolve(), postEvolve(), etc., with these it is important for the developer to understand the
sequence of events.
This offering is not approved or endorsed by ESI® Group, ESI-OpenCFD® or the OpenFOAM®
IV 246
Foundation, the producer of the OpenFOAM® software and owner of the OpenFOAM® trademark.
40.7 Times of Use
40.7.1 Not so telling error messages
Out of domain
As OpenFOAM’s Lagrangian particle framework keeps track of the cells in which a particle is located, a
Lagrangian solver needs to determine the cell label of each particle’s initial position. OpenFOAM’s particle
tracking algorithm is described among other resources in [45, 42, 49].
When a particle is placed outside the domain, i.e. the position in the positions file is outside the domain,
OpenFOAM is unable to find a cell label for this very particle. Note that failing to find a cell which contains the
particle’s location may happen also for other reasons than placing it outside the domain. As the error message
in Listing 277 suggests, this might also happen through a combination of insufficient write precision and do-
main decomposition or reconstruction. However, plainly putting them outside the domain is also a possibility,
especially, when a script is used to create the initial particle distribution.
cell , tetFace and tetPt search failure at position (0.0026 0.0026 0.4502)
for requested cell 0
If this is a restart or rec onstruct ion / decomposition etc . it is likely that the write
precision is not sufficient .
Either increase ’ writePrecision ’ or set ’ writeFormat ’ to ’ binary ’
FOAM aborting
Listing 277: Error message issued by OpenFOAM when a Lagrangian simulation is started with particle positions
defined outside of the domain; checkMesh reports for this case an Overall domain bounding box (0 0 0) (0.15
0.15 0.45); Note the position (Line 3) at which the search failure occurs
ManualInjection
The manualInjection model is probably the simplest model. The user needs to provide the to-be-injected
particle mass and the injection positions. All parcels are introduced at SOI.
CellZoneInjection
The cellZoneInjection model works similar to the manual injection model. The locations at which parcels
are injected, however, are determined using a user-provided cellSet. The actual injection locations are randomly
distributed across the cellSet. The number of inserted parcels is determined by the volume of the cellSet and
the user-specified target parcel number density. All parcels are introduced at once at SOI.
FieldActivatedInjection
The fieldActivatedInjection model is also related to the manual injection model. In addition to the user-
provided injection locations, a scalar factor and the names of a threshold field and a referenceField have to be
This offering is not approved or endorsed by ESI® Group, ESI-OpenCFD® or the OpenFOAM®
IV 247
Foundation, the producer of the OpenFOAM® software and owner of the OpenFOAM® trademark.
specified. Parcels are injected only at locations at which the following relation holds:
Parcel injection is controlled by the injector positions read from the positions file. All positions, which fulfil
the condition above are valid injector positions. Furthermore, the number of parcels per injector (parcelsPerInjector)
has to be specified. Each injector injects parcelsPerInjector parcels which account for a parcelsPerInjector-
th of massTotal. Parcels are injected from SOI onwards until massTotal is reached.
PatchInjection
The patchInjection model introduces parcels at a patch rather than within a volume like the models discussed
above. This injection model implements a classical inflow condition for Lagrangian particles. The injection
position on the patch is chosen randomly. Parcels are injected from SOI until massTotal is reached.
40.8.2 CloudFunctionObjects
CloudFunctionObject are, similar to the standard functionObjects for fields, function objects for Lagrangian
clouds. The main purpose of OpenFOAM’s cloud function objects – judging by the implemented ones at the
time of writing – is post-processing. However, cloud function objects can also be used to actively influence the
Lagrangian particles.
PatchPostProcessing
This cloud function object can be used to accumulate data from all particles leaving the domain through a
specified patch. Thus, e.g. a residence time distribution (RTD) can be generated using this data.
FacePostProcessing
This cloud function object serves a similar purpose as the PatchPostProcessing cloud function object, only this
one acts on face sets.
VoidFraction
This cloud function object can be used to create the volume fraction field associated with the particles. Thus,
the name VoidFraction can be misleading.
If we take a look at the code, we clearly see that the volume fraction of the particles is computed. In Listing
278, we see the two methods of this cloud function object which are responsible for computing the result. The
field theta is initialized to zero, this is not shown in the listing. In the method postMove(), which is called for
each parcel after it has moved within the current timestep, the particle’s volume is added to the field theta.
In the method postEvolve(), which is called after evolving the Lagrangian cloud for the current time step has
been completed, the field theta is divided by the mesh’s volume, i.e. a field in which the value of a cell is that
cell’s volume.
Thus, as in each cell the volume of the particles is accumulated and subsequently divided by the volume of
the cell, we end up with the volume fraction of the particles.
1 template < class CloudType > void Foam :: VoidFraction < CloudType >:: postMove
2 (
3 // ...
4 )
5 {
6 volS calarFie ld & theta = thetaPtr_ () ;
7 theta [ celli ] += dt * p . nParticle () * p . volume () ;
8 }
9
10 template < class CloudType > void Foam :: VoidFraction < CloudType >:: postEvolve ()
11 {
12 volS calarFie ld & theta = thetaPtr_ () ;
13 const fvMesh & mesh = this - > owner () . mesh () ;
14 theta . p r i mi t i v e F i e l d R e f () /= mesh . time () . deltaTValue () * mesh . V () ;
15 CloudFunctionObject < CloudType >:: postEvolve () ;
This offering is not approved or endorsed by ESI® Group, ESI-OpenCFD® or the OpenFOAM®
IV 248
Foundation, the producer of the OpenFOAM® software and owner of the OpenFOAM® trademark.
16 }
ParticleCollector
The ParticleCollector cloud function object can be used to count particles traversing an arbitrary surface defined
by a set of polygons or the area enclosed by concentric circles. The data accumulated by this cloud function
object involves the accumulated particle mass and the mass flow rate passing through the surface.
Optionally, counted particles can be removed from the simulation.
Figure 118: A set of polygons has been defined to count and remove traversing particles. In this case of a cylinder
in laminar cross-flow, particles are inserted through the inlet patch. The ParticleCollector cloud function object
was set to remove all counted particles, which is clearly visible in this snapshot.
This offering is not approved or endorsed by ESI® Group, ESI-OpenCFD® or the OpenFOAM®
IV 249
Foundation, the producer of the OpenFOAM® software and owner of the OpenFOAM® trademark.
Part V
Solver
41 Solution Algorithms
The solution of the Navier-Stokes equations require solving the coupled equations of velocity and pressure fields.
There are several solution algorithms that try to decouple the equations and compute the velocity and pressure
separately. In order to decouple the computation of velocity and pressure, a predictor-corrector strategy is
followed. This approach is referred to in literature on numerical methods as segregated solution.
The alternative to solving for velocity and pressure in a segregated fashion is to solve for the fully coupled –
also referred to as block coupled – equation system. In general, the momentum equation yields three equations
for the three velocity components and the pressure equation, which is derived from the continuity equation,
yields an equation for pressure. Instead of solving each of the four discretized equations individually, the fully
coupled set of equations could also be solved for. This translates a possible improvement in converge rate,
however, it also encompasses a much larger memory requirement and an altered convergence behaviour.
This section will deal with the segregated solution methods, as they are the most commonly used. In the
last sub-section we will briefly discuss coupled methods.
41.1 SIMPLE
Figure 119 shows the flow chart of the SIMPLE algorithm. The SIMPLE algorithm predicts the velocity and
then corrects both the pressure and the velocity. This is repeated until a convergence criteria is reached. The
labels in Figure 119 are related to the terminology used in the source code of the simpleFoam solver. The
solution procedure can be described as follows
1. Check if convergence is reached – simple.loop()
2. Predict the velocities using the momentum predictor– UEqn.H
3. Correct the pressure and the velocities– pEqn.H
41.1.1 Predictor
The predictor of simpleFoam is a momentum predictor.
1 // Momentum predictor
2 tmp < fvVectorMatrix > UEqn
3 (
4 fvm :: div ( phi , U )
5 + turbulence - > divDevReff ( U )
6 ==
7 sources ( U )
8 );
9
10 UEqn () . relax () ;
11
12 sources . constrain ( UEqn () ) ;
13
14 solve ( UEqn () == - fvc :: grad ( p ) ) ;
136 In case of a laminar simulation an empty function is called. Turbulence is modelled in OpenFOAM in a very generic way.
This offering is not approved or endorsed by ESI® Group, ESI-OpenCFD® or the OpenFOAM®
V 250
Foundation, the producer of the OpenFOAM® software and owner of the OpenFOAM® trademark.
Start of time step
f alse
simple.loop() End of time step
true
UEqn.H
pEqn.H
turbulence->correct()
41.1.2 Corrector
The corrector is used to correct the pressure field by using the predicted velocity. This corrected pressure is
used to correct the velocities by solving the continuity equation.
The non-orthogonal pressure corrector loop is necessary only for non-orthogonal meshes [52].
p . boundaryField () . updateCoeffs () ;
pEqn . solve () ;
if ( simple . f i n a l N o n O r t h o g o n a l I t e r () )
{
phi -= pEqn . flux () ;
}
}
// Momentum corrector
U -= rAU * fvc :: grad ( p ) ;
U . c o r r e c t B o u n d a r y C o n d i t i o n s () ;
sources . correct ( U ) ;
This offering is not approved or endorsed by ESI® Group, ESI-OpenCFD® or the OpenFOAM®
V 251
Foundation, the producer of the OpenFOAM® software and owner of the OpenFOAM® trademark.
41.2 PISO
The PISO algorithm also follows the predictor-corrector strategy. Figure 120 shows the flow chart of the PISO
algorithm. The velocity is predicted using the momentum predictor. Then, the pressure and the velocity
is corrected until a predefined number of iterations is reached. Afterwards, the transport equations of the
turbulence model are solved.
UEqn.H
true
PISO loop pEqn.H
f alse
turbulence->correct()
41.3 PIMPLE
The PIMPLE algorithm, which is a combination of the SIMPLE and PISO algorithms, is discussed further in
Sections 42 and 42.2.
blockCoupledScalarTransportFoam
This solver is derived from the standard scalarTransportFoam solver and solves the transport of two coupled
passive scalars.
pUCoupledFoam
This solver is a steady state solver for incompressible, turbulent single phase flow. This solver solves for velocity
and pressure simultaneously.
This offering is not approved or endorsed by ESI® Group, ESI-OpenCFD® or the OpenFOAM®
V 252
Foundation, the producer of the OpenFOAM® software and owner of the OpenFOAM® trademark.
42 pimpleFoam
pimpleFoam is a transient incompressible solver using the PIMPLE alogorithm, which is a combination of PISO
and SIMPLE. The solver is described in the file pimpleFoam.C as follows:
Large time-step transient solver for incompressible, flow using the PIMPLE
(merged PISO-SIMPLE) algorithm.
∂ρ
+ ∇ · (ρu) = 0 (67)
∂t
we now assume incompressible fluids: ρ = const
∇·u = 0 (68)
or in alternative notation
div(u) = 0 (69)
∂ui
=0 (70)
∂xi
∂ρu
+ ∇(ρuu) + ∇ · τ = −∇p + g (71)
∂t
because we assume a constant density we can divide by ρ
∂u 1 ∇p g
+ ∇(uu) + ∇ · τ = − + (72)
∂t ρ ρ ρ
The last term is defined a general source term
∂u 1 ∇p
+ ∇(uu) + ∇ · τ = − +Q (73)
∂t ρ ρ
τ p
the shear stresses and the pressure are denoted by new symbols: ρ = Ref f und ρ =p
∂u
+ ∇(uu) + ∇ · Ref f = −∇p + Q (74)
∂t
The Boussinesq hypothesis allows us to add the Reynolds stresses to the shear stresses. This stress tensor
– containing shear as well as Reynolds stresses – is denoted Ref f , the effective stress tensor. Both RAS as well
as LES turbulence models are based on the Boussinesq hypothesis.
Ref f = −ν ef f ∇u + (∇u)T
(75)
ef f ef f ∂ui ∂uj
Rij = −ν + (76)
∂xj ∂xi
This offering is not approved or endorsed by ESI® Group, ESI-OpenCFD® or the OpenFOAM®
V 253
Foundation, the producer of the OpenFOAM® software and owner of the OpenFOAM® trademark.
The trace of τ fulfills the continuity equation for incompressible fluids
ef f ∂ui
tr(Ref f ) = Rii = −2ν ef f =0 (77)
∂xi
∂ui
= ∇·u = 0 (78)
∂xi
Ref f = −ν ef f ∇u + (∇u)T
(75)
to gain
∂u
+ ∇(uu) + ∇ · dev(−ν ef f ∇u + (∇u)T ) = −∇p + Q
(82)
∂t
42.1.3 Implementation
The momentum equation is implemented in the file UEqn.H. The first two terms of Eq. (82) can easily be
identified in the source code in Listing 281.
The first term is the local derivative of the momentum – due to the incompressibility of the fluid, the density
was eliminated – can be found in line 5 of Listing 281. Here, the instruction in the source code reads very much
the same as the mathematical notation.
∂u
⇔ fvm::ddt(U)
∂t
The second term of Eq. (82) is the convective transport of momentum. The use of the identifier phi should
not lead to confusion. In order to read the equations from the source code, phi can be replaced with U without
changing the meaning of the equations. The reason why phi is used in the source code lies in the solution
procedure. See Section 64 for a detailled discussion about phi.
∇(uu) ⇔ fvm::div(phi, U)
| {z }
div(uu)
The third term of Eq. (82) is the diffusive momentum transport term. Diffusive momentum transport is
caused by the laminar viscosity as well as turbulence. Therefore, the turbulence model handles this term. See
line 7 of Listing 281.
∇ · dev(Ref f )
⇔ turbulence->divDevReff(U)
| {z }
=div(dev(Ref f ))
This offering is not approved or endorsed by ESI® Group, ESI-OpenCFD® or the OpenFOAM®
V 254
Foundation, the producer of the OpenFOAM® software and owner of the OpenFOAM® trademark.
The terms on the rhs of Eq. (82) are the pressure gradient and the source term.
−∇p ⇔ -fvc::grad(p))
| {z }
=−grad p
Q ⇔ sources(U)
137 In case of a k- model, there are two transport equations to be solved. Other turbulence models require the solution of less or
This offering is not approved or endorsed by ESI® Group, ESI-OpenCFD® or the OpenFOAM®
V 255
Foundation, the producer of the OpenFOAM® software and owner of the OpenFOAM® trademark.
20 if ( pimple . turbCorr () )
21 {
22 turbulence - > correct () ;
23 }
24 }
25
26 runTime . write () ;
27 }
Figure 121 shows the flow chart of the PIMPLE algorithm. This algorithm is executed every time step. If the
PIMPLE loop is entered only once, then the algorithm is essentially the same as the PISO algorithm. Listing
289 draws this conclusion from the code itself.
f alse
pimple.loop() End of time step
true
UEqn.H
true
pimple.correct() pEqn.H
f alse
f alse
turbCorr()
true
turbulence->correct()
42.2.1 readTimeControls.H
In line 3 of Listing 282 the file readTimeControls.H is included to the source code using the #include prepro-
cessor macro. This is a very common way to give the code of OpenFOAM structure and order. Code which is
used repeatedly is outsourced into a seperate file. This file is then included with the #include macro. Thus,
code duplication is prevented. The file readTimeControls.H might be included into every solver that is able to
use variable time steps. If this code was not outsourced into a seperate file, this code would be found in every
variable time step solver. Maintaining this code, would be tiresome and prone to errors.
Listing 440 shows the contents of readTimeControls.H. The first instruction reads from controlDict the
adjustTimeStep parameter. If there is no entry matching the name of the parameter ("adjustTimeStep"), then
This offering is not approved or endorsed by ESI® Group, ESI-OpenCFD® or the OpenFOAM®
V 256
Foundation, the producer of the OpenFOAM® software and owner of the OpenFOAM® trademark.
1 const bool a djustTim eStep =
2 runTime . controlDict () . l oo ku p Or De fa u lt ( " ad justTime Step " , false ) ;
3 scalar maxCo =
4 runTime . controlDict () . lookupOrDefault < scalar >( " maxCo " , 1.0) ;
5 scalar maxDeltaT =
6 runTime . controlDict () . lookupOrDefault < scalar >( " maxDeltaT " , GREAT ) ;
a default value is used. So, omitting the parameter adjustTimeStep in controlDict will result in a simulation
with a fixed time step.
This is a very straight forward example of determining the behaviour of a solver using only the source code.
In this case the names of the source file as well as variable and function names are rather self explaining. In
other cases one has to dig deeply into the code to learn about what a certain command does.
42.2.2 pimpleControl
Examining the files pimpleControl.H and pimpleControl.C will generate some knowledge of the inner life of
pimpleFoam.
Solution controls
Listings 284 and 285 show parts of pimpleControl.H and pimpleControl.C. Listing 284 shows the declaration
of protected139 data in pimpleControl.H.
1 // Protected data
2 // Solution controls
3 // - Maximum number of PIMPLE correctors
4 label nCorrPIMPLE_ ;
5
6 // - Maximum number of PISO correctors
7 label nCorrPISO_ ;
8
9 // - Current PISO corrector
10 label corrPISO_ ;
11
12 // - Flag to indicate whether to only solve turbulence on final iter
13 bool t u r b O n F i n a l I t e r O n l y _ ;
14
15 // - Converged flag
16 bool converged_ ;
that the variables can be accessed only inside the class pimpleControl and all classes inherited from pimpleControl.
This offering is not approved or endorsed by ESI® Group, ESI-OpenCFD® or the OpenFOAM®
V 257
Foundation, the producer of the OpenFOAM® software and owner of the OpenFOAM® trademark.
Reading the code we can see which keyword in the PIMPLE dictionary – it is a part of the fvSolution dictionary
(see Section 11.5) – is connected to which variable in the code. Three of the protected variables of Listing 284
are assigned in Listing 285. One of them has the same name in both the code and the dictionary. The other
two have different names.
This offering is not approved or endorsed by ESI® Group, ESI-OpenCFD® or the OpenFOAM®
V 258
Foundation, the producer of the OpenFOAM® software and owner of the OpenFOAM® trademark.
Listing 287: The constructor of the class solutionControl in solutionControl.C
The keyword nCorrectors translates – with the help of Listing 285 to the variable nCorrPISO_. This
variable controls how often the PISO loop – or the corrector loop – is traversed. Listing 284 shows, that there
are two variables related to the PISO loop, nCorrPISO_ and corrPISO_. The first variable is the limit and the
second is the counter.
nCorrPISO_ is read from the fvSolution dictionary by the use of the nCorrectors keyword. This number
tells the solver, how many times the corrector loop should be traversed. The corrector loop is a feature of the
PISO algorithm. Hence, the maximum number of corrector loop iterations is called nCorrPISO_.
The variable corrPISO_ is declared in the constructor of the class pimpleControl, see Listing 289. There
the variable is initialised to zero.
Listing 288 shows the definition of the function correct() of the class pimpleControl. The return value of
this function controls if the corrector loop is entered. In line 3 the counter corrPISO_ is incremented every time
this function is called. In line 10 the value of the counter is compared to the maximum number of corrector
loop iterations.
This offering is not approved or endorsed by ESI® Group, ESI-OpenCFD® or the OpenFOAM®
V 259
Foundation, the producer of the OpenFOAM® software and owner of the OpenFOAM® trademark.
19 }
A note on OpenFOAM-6
With OpenFOAM-6141 the residual-control framework of the PIMPLE solution control class was reorganized,
making it consistent with the SIMPLE solution control class. With this changes, residualControl acts on
the simulation as a whole, whereas the new outerCorrectorResidualControl manages the outer-loop of the
PIMPLE algorithm.
PIMPLE
{
// ...
outerCorrectorResidualControl
{
p_rgh
{
relTol 0;
tolerance 0.0001;
}
}
}
141 https://github.com/OpenFOAM/OpenFOAM-dev/commit/4c8122783aedaa7dadf0486163a98350e625db32#
diff-13b1708e0fc8512ad44fa3edd4175459
This offering is not approved or endorsed by ESI® Group, ESI-OpenCFD® or the OpenFOAM®
V 260
Foundation, the producer of the OpenFOAM® software and owner of the OpenFOAM® trademark.
43 rhoPimpleFoam
43.1 General remarks
rhoPimpleFoam is a compressible, single-phase solver.
1 {
2 fvSc alarMatr ix rhoEqn
3 (
4 fvm :: ddt ( rho )
5 + fvc :: div ( phi )
6 ==
7 fvOptions ( rho )
8 );
9
10 fvOptions . constrain ( rhoEqn ) ;
11
12 rhoEqn . solve () ;
13
14 fvOptions . correct ( rho ) ;
15 }
p
ρ= (83)
RT
In the example of a perfect gas, using the equation of state has the advantage that the density is computed
from the pressure and the temperature, which have already been computed.
This option was described in the relevant commit message142 as follows:
With this option the density is updated from thermodynamics rather than continuity after the
pressure equation which is better behaved if pressure is relaxed and/or solved to a loose relative
tolerance.
142 https://github.com/OpenFOAM/OpenFOAM-dev/commit/79ff91350ef6092b2dd864029a6023bec2b66b50
This offering is not approved or endorsed by ESI® Group, ESI-OpenCFD® or the OpenFOAM®
V 261
Foundation, the producer of the OpenFOAM® software and owner of the OpenFOAM® trademark.
44 twoPhaseEulerFoam
This section is valid for OpenFOAM-2.0 til OpenFOAM-2.2.
44.1.1 Turbulence
twoPhaseEulerFoam can only use the k- turbulence model. This model is so to say hardcoded and can only be
turned on or off.
This offering is not approved or endorsed by ESI® Group, ESI-OpenCFD® or the OpenFOAM®
V 262
Foundation, the producer of the OpenFOAM® software and owner of the OpenFOAM® trademark.
24 }
25 }
Figure 122 shows the flow chart of all operations that are performed during one time step.
f alse
pimple.loop() End of time step
true
alphaEqn.H
liftDrag.H
UEqn.H
true
pimple.correct() pEqn.H
f alse
DDtU.H
correctAlpha() f alse
& !finalIter()
f alse
turbCorr() true
alphaEqn.H
true
kEpsilon.H
44.2.1 Continuity
The continuity equation is implemented in the file alphaEqn.H.
Second call
In line 15 of Listing 292 the continuity equation is called again inside an if-statement. The condition depends
on two boolean expressions.
This offering is not approved or endorsed by ESI® Group, ESI-OpenCFD® or the OpenFOAM®
V 263
Foundation, the producer of the OpenFOAM® software and owner of the OpenFOAM® trademark.
The first, correctAlpha, is controlled by the fvSolution dictionary. Assigning a value to this keyword – the
keyword has the same name as the boolean variable in the source code – is mandatory. The reading operation
of this keyword from the dictionary can be found in the source file readTwoPhaseEulerFoamControls.H and is
shown in Listing 293.
Three keywords are looked up from the fvSolution dictionary. All of them are related to the solving
algorithm for the continuity equation. Those entries are read from the dictionary by invoking the function
lookup(). See Section 57.3 for a detailed discussion about looking up keywords from dictionaries.
The second boolean expression controlling the second call in line 15 of Listing 292 is controlled by the number
of iterations of the PIMPLE loop. See Section 42.2 for a discussion about the PIMPLE algorithm.
The expression pimple.finalIter() is true when the last iteration of the PIMPLE algorithm is entered.
Therefore, the expression !pimple.finalIter() is true if, and only if, the value of nOuterCorrectors or
nCorrPIMPLE_ is greater than one. Because only then, there is more than one PIMPLE iteration and only then,
there is an iteration other than the final one.
If the PIMPLE loop is traversed only once, then alphaEqn.H is not entered a second time.
• Gibilaro
• GidaspowErgunWenYu
• GidaspowSchillerNaumann
• SchillerNaumann
• SyamlalOBrien
• WenYu
The equations behind this models can be found in [27] or [65].
Drag is considered in the governing equations by the use of the so-called drag-function K. This drag-function
is either computed directly, or it is computed by the use of the drag coefficient Cd . The drag force is the product
of the drag-function and the relative velocity between the phases Ur [27].
This offering is not approved or endorsed by ESI® Group, ESI-OpenCFD® or the OpenFOAM®
V 264
Foundation, the producer of the OpenFOAM® software and owner of the OpenFOAM® trademark.
Start
true
true
sub-cycle solve continuity
f alse
alpha2 = scalar(1)
- alpha1
Schiller-Naumann drag
We use the Schiller-Naumann drag model as an expample to demonstrate how OpenFOAM calculates the drag
force. This drag model utilizes a drag coefficient that is a function of the Reynolds number.
(
24
Re 1 + 0.15Re0.687 if Re ≤ 1000
Cd = (84)
0.44 if Re > 1000
3 Ur
K= Cd ρB (85)
4 dA
The drag coefficient is dimensionless, whereas the product of the drag-function K and the relative velocity
has the dimension of a force density.
Ur kg m 1 kg
[K] = [Cd ] · [ρB ] · [ ] = 1· 3 · = 3
dA m s m m s
kg m kgm 1 N
[K · Ur ] = 3 · = 2 · 3 = 3
m s s s m m
Listing 294 shows, how the drag-function is computed by the Schiller-Naumann drag model.
This offering is not approved or endorsed by ESI® Group, ESI-OpenCFD® or the OpenFOAM®
V 265
Foundation, the producer of the OpenFOAM® software and owner of the OpenFOAM® trademark.
neg ( Re - 1000) *(24.0*(1.0 + 0.15* pow ( Re , 0.687) ) / Re )
+ pos ( Re - 1000) *0.44
);
The drag force contributes to the momentum balance. Probably for numerical reasons, one part of the drag
is considered in the momentum equation and the other part is considered in the pressure equation.
44.3.2 Lift
The lift model of twoPhaseEulerFoam is described in [56]. The lift model computes the lift force on a rigid
sphere in shear flow. The force density is calculated from the relative velocity between the phases and the
vorticity of the mixture.
FL
= CL ρc |Ur × (∇ × Uc )| (86)
VB
mit
Ur = UA − UB
Uc = αUA + (1 − α) UB
| {z }
=β
ρc = αρA + βρB
The lift force is computed in the file liftDragCoeffs.H. The vector field liftCoeff contains the lift force
density.
kg m 1 m kgm 1 N
[lif tCoef f ] = [CL ] · [ρc ] · [Ur × (∇ × Uc )] = 1 · · = 2 · 3 = 3
m3 s m s s m m
ρB D B UB DA UA
MA,V M = β CV M − (87)
ρA Dt Dt
In the source code, the momentum exchange term due to virtual mass is split into two parts. One part is
included in the rhs of the momentum equation, the other is considered in the lhs. This seperation is probably
for numerical reasons.
UaEqn =
(
( scalar (1) + Cvm * rhob * beta / rhoa ) *
(
fvm :: ddt ( Ua )
+ fvm :: div ( phia , Ua , " div ( phia , Ua ) " )
- fvm :: Sp ( fvc :: div ( phia ) , Ua )
)
This offering is not approved or endorsed by ESI® Group, ESI-OpenCFD® or the OpenFOAM®
V 266
Foundation, the producer of the OpenFOAM® software and owner of the OpenFOAM® trademark.
+ /* other terms */
==
/* other terms */
- beta / rhoa *( liftCoeff - Cvm * rhob * DDtUb )
);
This offering is not approved or endorsed by ESI® Group, ESI-OpenCFD® or the OpenFOAM®
V 267
Foundation, the producer of the OpenFOAM® software and owner of the OpenFOAM® trademark.
45 twoPhaseEulerFoam-2.3
This section is valid for OpenFOAM-2.3.
With the release of OpenFOAM-2.3 the two-phase Eulerian solver twoPhaseEulerFoam has seen some major
changes. See the release notes for further details: http://www.openfoam.org/version2.3.0/multiphase.php.
45.1 Physics
The most important change in twoPhaseEulerFoam from version ≤ 2.2.x to 2.3 is that the solver is based on
a completely different set of physical models. In version 2.3 phases are modelled using OpenFOAMs thermo-
physical models. The phases are considered compressible, therefore all simplifications when considering a phase
incompressible do not hold anymore.
45.1.1 Pressure
In twoPhaseEulerFoam-2.3 the pressure is now a real physical pressure. In an incompressible simulation the
absolute value of the pressure has no meaning, only pressure differences count. In a compressible model, the
absolute value of the pressure has an effect, e.g. when using the isothermalDiameter diameter model to
determine the diameter of the dispersed phase elements.
Thus, when migrating a simulation case from OpenFOAM-2.2 or lower to 2.3, check the pressure initial
condition and the boundary conditions.
45.1.2 Temperature
As the new version of the solver uses thermo-physical models for the phases, the user is required to specify not
only the thermo-physical properties of the phases, the user also has to provide initial and boundary conditions
for the temperature of both phases. Thus, two additional fields are present – or need to be present – in the
time directories, e.g. T.air and T.water.
This offering is not approved or endorsed by ESI® Group, ESI-OpenCFD® or the OpenFOAM®
V 268
Foundation, the producer of the OpenFOAM® software and owner of the OpenFOAM® trademark.
k . water
nut . air
nut . water
p
T . air
Theta
T . water
U . air
U . water
user@host :∼/ OpenFOAM / OpenFOAM -2.3. x / tutorials / multiphase / t w o P h a s e E u l e r F o a m / RAS / bubbleColumn$
ls constant -1
g
p ha se Pr o pe rt ie s
polyMesh
t h e r m o p h y s i c a l P r o p e r t i e s . air
t h e r m o p h y s i c a l P r o p e r t i e s . water
t u r b u l e n c e P r o p e r t i e s . air
t u r b u l e n c e P r o p e r t i e s . water
Listing 297: Content of the 0 and constant folders of the bubble column tutorial case of twoPhaseEulerFoam
in OpenFOAM-2.3.x
6
(
LaheyKEpsilon
continuousGasKEpsilon
kEpsilon
kineticTheory
m ix tu re K Ep si lo n
phasePressure
)
5
(
NicenoKEqn
143 http://www.openfoam.org/version2.3.0/multiphase.php
This offering is not approved or endorsed by ESI® Group, ESI-OpenCFD® or the OpenFOAM®
V 269
Foundation, the producer of the OpenFOAM® software and owner of the OpenFOAM® trademark.
Smagorinsky
S m a g o r i n s k y Zh a n g
continuousGasKEqn
kEqn
)
45.4.2 kEpsilon
Listing 300 shows the governing equations of the compressible multi-phase formulation of the k − model. The
governing equations are largely equivalent to the compressible formulation of the single-phase k − model. The
formulation deviates from the compressible single-phase formulation in two aspects. First, the convective term
is corrected with the continuity error, see Lines 5 and 18. Furthermore, there is an additional source term on
the RHS, see Lines 11 and 24.
45.4.3 LaheyKEpsilon
The LaheyKEpsilon turbulence model is a derivation of the standard kEpsilon turbulence model, see Listing
301. The LaheyKEpsilon turbulence model is an extension of the standard k − model to account for the effect
of the dispersed phase on the turbulence of the continuous phase. This effect is referred to as bubble induced
turbulence (BIT).
There are essentially two ways to account for BIT. One follows the idea of Sato and Sekoguchi [57], there
an additional viscosity models the effect of the increased turbulence caused by the wakes of the bubbles. The
This offering is not approved or endorsed by ESI® Group, ESI-OpenCFD® or the OpenFOAM®
V 270
Foundation, the producer of the OpenFOAM® software and owner of the OpenFOAM® trademark.
other approach is based on the work of Pfleger and Becker [53]. They included additional source terms in the
transport equations for k and .
The Lahey model uses with its standard coefficients both approaches.
Listing 301: The first lines of the LaheyKEpsilon turbulence model definition.
This offering is not approved or endorsed by ESI® Group, ESI-OpenCFD® or the OpenFOAM®
V 271
Foundation, the producer of the OpenFOAM® software and owner of the OpenFOAM® trademark.
Pitfall: the dispersed phase
It is not possible to assign the LaheyKEpsilon turbulence model to the dispersed phase, either to the dispersed
phase alone or to both phases. In any case the attempt to do so results in a segmentation fault when first using
the turbulence model at the initialisation of the simulation case. The reason for this is not entirely known to
the author.
45.4.4 mixtureKEpsilon
Usage
The k − model is computed for the mixture, i.e. the transport equations are solved for using the mixture
properties. Thus, the solution variables are named km and epsilonm, see Listing 304.
DILUPBiCG : Solving for epsilonm , Initial residual = 0.0114325 , Final residual = 2.79117 e -09 ,
No Iterations 2
DILUPBiCG : Solving for km , Initial residual = 0.0078252 , Final residual = 6.13173 e -09 , No
Iterations 2
Listing 304: Solver output of twoPhaseEulerFoam using the mixtureKEpsilon turbulence model.
In order to use the mixture k − model, it needs to be specified in both turbulenceProperties files. Listing
305 shows the resulting error message when mixtureKEpsilon is specified for only one of the phases. As the
turbulence model for the mixture applies to both phases, it needs to be specified for both phases.
From function objectR egistry :: lookupObject < Type >( const word &) const
in file / home / user / OpenFOAM / OpenFOAM -2.3. x / src / OpenFOAM / lnInclude / o b j e c t R e g i s t r y T e m p l a t e s .
C at line 181.
FOAM aborting
Listing 305: Solver output of twoPhaseEulerFoam when the mixtureKEpsilon turbulence model is specified for
only one of the two phases.
Theory
The governing equations of the mixture k− model can be found in the sources at \$FOAM_SRC/TurbulenceModels/
phaseCompressible/RAS/mixtureKEpsilon and in [12]. The biggest difference between the equations stated
in [12] and the code of mixtureKEpsilon can be found in the Lines 5 and 18 of Listing 306. There, the con-
tinuity equation of the mixture appears on the of the governing equations. This minor difference between the
formulation of the equation can be resolved in two steps. First, we take a look on the first two terms of the
governing equations in [12] (local derivative and convective term), see Eqns. (88) to (91).
∂ρm m
+ ∇ · (ρm um m ) + . . . (88)
∂t
∂m ∂ρm
ρm + m + m ∇ · (ρm um ) + ρm um · ∇m + . . . (89)
∂t ∂t
∂m ∂ρm
ρm + m + ∇ · (ρm um ) +ρm um · ∇m + . . . (90)
∂t ∂t
| {z }
=0
∂m
ρm + ρm um · ∇m + . . . (91)
∂t
In order to derive equations equivalent to the code implemented in OpenFOAM, we begin with Eq. (91) and
use the product rule of differentiation, cf. Eqns. (88) and (89).
This offering is not approved or endorsed by ESI® Group, ESI-OpenCFD® or the OpenFOAM®
V 272
Foundation, the producer of the OpenFOAM® software and owner of the OpenFOAM® trademark.
∂m
ρm + ρm um · ∇m + . . . (91)
∂t
∂ρm m ∂ρm
− m + ∇ · (ρm um m ) − m ∇ · (ρm um ) + . . . (92)
∂t ∂t
∂ρm m ∂ρm
+ ∇ · (ρm um m ) − m + ∇ · (ρm um ) + . . . (93)
∂t ∂t
Eq (93) is now equivalent to the first terms of the equation of Listing 306. The exact reason why this formu-
lation was chosen is unknown to the author, a probable reason might be a better numerical behaviour.
The basic relations between the turbulent quantities of the mixture and the turbulence quantities of the
individual phases are based on the turbulence response coefficient Ct , which is the ratio between the r.m.s.
values of the velocity fluctuations of the dispersed and the continuous phase [12].
Ud0
Ct = (94)
Uc0
with this coefficient, we can now express the following relations, which we can find in the file mixtureKEpsilon.C
ρm = αc ρc + αd ρd (95)
ρm
Cc2 = (96)
αc ρc + Ct2 αd ρd
kc = Cc2 km (97)
2
kd = C − t kc (98)
c = Cc2 m (99)
d = Ct2 c (100)
2
km
νt = C µ (101)
m
νc,ef f = νc + νt (102)
νc
νd,ef f = νd + Ct2 νt (103)
νd
This offering is not approved or endorsed by ESI® Group, ESI-OpenCFD® or the OpenFOAM®
V 273
Foundation, the producer of the OpenFOAM® software and owner of the OpenFOAM® trademark.
What remains to clarify is how the turbulence response coefficient Ct is determined. OpenFOAM imple-
ments the model proposed by Issa [36] and validated by Hill [28] [56, 12]. Furthermore, the turbulence response
coefficient is modified to account for the influence of the dispersed phase’s volume fraction αd , see e.g. [56, 12].
3+β
Ct,0 = (104)
1 + β + 2ρd/ρc
2Ad L2e
β= (105)
ρc νc Ret
U 0 Le
Ret = c (106)
νc
3/2
kc
Le = Cµ (107)
r c
2kc
Uc0 = (108)
3
Ct (αd ) = 1 + (Ct,0 − 1)e−f (αd ) (109)
f (αd ) = 180αd − 4.71·103 αd2 + 4.26·104 αd3 (110)
This offering is not approved or endorsed by ESI® Group, ESI-OpenCFD® or the OpenFOAM®
V 274
Foundation, the producer of the OpenFOAM® software and owner of the OpenFOAM® trademark.
Solution via model choice
The following example demonstrates the problems which may be faced when dealing with phase inversion. An
air-water bubble column is modelled including some of the air above the water surface. Figure 124 shows the
air volume fraction within the bubble column.
When mixtureKEpsilon is selected as turbulence model, the volume fraction is not included in the governing
equation, so phase inversion poses no big problem, see Listing 306 or Eq. (93).
When kEpsilon is selected for the liquid phase, the volume fraction in the governing equations is the volume
fraction of the liquid phase. This volume fraction vanishes above the water surface. Thus, in parts of the domain
the solution of the governing equations faces numerical problems. The governing equations can still be solved in
this case, but preconditioning the resulting matrix equation fails. Preconditioning is a step that is intended to
improve the iterative solution of the resulting matrix equation. In the case of the kEpsilon turbulence model
for the liquid phase, the only way to avoid crashing the simulation is to use a CG-solver with no preconditioning.
The GAMG-solver and the smooth solver fail completely.
Figure 124: Air volume fraction of the bubble column. Initial field (left) and solution at t = 10 s (right).
Table 7 lists possible model choices for two-phase simulations including phase-inversion.
This offering is not approved or endorsed by ESI® Group, ESI-OpenCFD® or the OpenFOAM®
V 275
Foundation, the producer of the OpenFOAM® software and owner of the OpenFOAM® trademark.
In our example, we can use the phaseLimitStabilization fvOption to stabilize the transport equations for the
turbulence fields. This way, we can also eliminate, or alleviate, the problems caused by phase inversion, as in
all regions with a vanishing phase fraction, the phaseLimitStabilization source prevents the transport equations
from becoming ill-posed.
1 2
Ki = |Ui | (111)
2
Info < < " Creating field kinetic energy K \ n " << endl ;
volS calarFie ld K1 ( IOobject :: groupName ( " K " , phase1 . name () ) , 0.5* magSqr ( U1 ) ) ;
volS calarFie ld K2 ( IOobject :: groupName ( " K " , phase2 . name () ) , 0.5* magSqr ( U2 ) ) ;
Listing 308: Definition of the kinetic energy field in the file createFields.H of twoPhaseEulerFoam.
The solution of the energy equation can not be deactivated. Even if thermophysical parameters are chosen
to represent incompressible phases, the energy equation will be solved each time step.
This offering is not approved or endorsed by ESI® Group, ESI-OpenCFD® or the OpenFOAM®
V 276
Foundation, the producer of the OpenFOAM® software and owner of the OpenFOAM® trademark.
4 - fvm :: Sp ( contErr1 , he1 )
5 + fvc :: ddt ( alpha1 , rho1 , K1 ) + fvc :: div ( alphaRhoPhi1 , K1 )
6 - contErr1 * K1
7 + (
8 he1 . name () == thermo1 . p h a s e P r o p e r t y N a m e ( " e " )
9 ? fvc :: ddt ( alpha1 ) * p + fvc :: div ( alphaPhi1 , p )
10 : - alpha1 * dpdt
11 )
12 - fvm :: laplacian
13 (
14 fvc :: interpolate ( alpha1 )
15 * fvc :: interpolate ( thermo1 . alphaEff ( phase1 . turbulence () . mut () ) ) ,
16 he1
17 )
18 ==
19 h e a t T r a n s f e r C o e f f *( thermo2 . T () - thermo1 . T () )
20 + h e a t T ra n s f e r C o e f f * he1 / Cpv1
21 - fvm :: Sp ( h e a t T r a n s f e r C o e f f / Cpv1 , he1 )
22 + fvOptions ( alpha1 , rho1 , he1 )
23 );
∂αq ρq uq X X
+ ∇ · (αq ρq uq uq ) − ∇ · τq = Fq,i + Kpq,i (up − uq ) (112)
∂t i i
with
Kpq,i = −Kqp,i
Kqq,i = 0
45.6.1 Units
Now we shall take a short look on the units of this equation. Each term of the equation has to have the same
unit. We take the local derivative to determine the unit of all terms in this equation.
∂αq ρq uq 1 kg m 1 kg m N
= 3
= 3 2 = 3 (113)
∂t sm s m | {z
s } m
N
We see that all terms of the momentum equation have the unit of a force density. On the RHS of the
momentum equation we have two kinds of source terms.
The first kind of source terms – Fi – can be referred to as body forces, e.g. the gravitational force. This is
consistent with our observation, that this terms have the unit of a force density.
N kg !
= 2 2
[Fi ] = (114)
m3 m s
The second kind of source terms – Kpq,i (up − uq ) – are phase interaction terms. This terms are the product
of a coefficient Kpq,i with the relative velocity uR = up − uq . Such a phase interaction term might be due to
drag. Now we determine the unit of the interphase momentum exchange coefficient Kpq,i .
! N 1 kg m
[Kpq,i (up − uq )] = 3
= (115)
m s m3 s
kg
[Kpq,i ] = 3 (116)
m s
146 The phase q is the considered phase and phase p denotes the other phase.
This offering is not approved or endorsed by ESI® Group, ESI-OpenCFD® or the OpenFOAM®
V 277
Foundation, the producer of the OpenFOAM® software and owner of the OpenFOAM® trademark.
45.6.2 Implemented equations
Listing 310 shows one of the momentum conservation equations. On Line 3 we see the local derivative and the
convective term. The origin of the term in Line 4 is explained in 60.3. On Line 5 we see a term stemming from
the MRF approach. On Line 6 is the momentum diffusion.
On the RHS there are a number of force terms. Although, they are named *Force, they are in fact force
density terms. On Line we see a part of the drag force. The force due to gravity and the other part of the drag
are considered in the pressure equation [56].
1 U1Eqn =
2 (
3 fvm :: ddt ( alpha1 , rho1 , U1 ) + fvm :: div ( alphaRhoPhi1 , U1 )
4 - fvm :: Sp ( contErr1 , U1 )
5 + mrfZones ( alpha1 * rho1 + virtualMassCoeff , U1 )
6 + phase1 . turbulence () . divDevRhoReff ( U1 )
7 ==
8 - liftForce
9 - wallLubricationForce
10 - turbulentDispersionForce
11 - v i r t u a l M a s sC o e f f
12 *(
13 fvm :: ddt ( U1 )
14 + fvm :: div ( phi1 , U1 )
15 - fvm :: Sp ( fvc :: div ( phi1 ) , U1 )
16 - DDtU2
17 )
18 + fvOptions ( alpha1 , rho1 , U1 )
19 );
20 U1Eqn . relax () ;
21 U1Eqn += fvm :: Sp ( dragCoeff , U1 ) ;
22 fvOptions . constrain ( U1Eqn ) ;
Listing 310: The code of the momentum conservation equation of phase 1 of twoPhaseEulerFoam in UEqns.H
The interfacial momentum exchange terms are computed prior to the construction of the momentum equa-
tion. Listing 311 shows the relevant lines of the file Ueqns.H. Wee see that the momentum exchange terms are
provided by some methods. We know that the variable fluid is of the type twoPhaseSystem. Thus, the meth-
ods called to compute the momentum exchange terms are methods of the class twoPhaseSystem, see Section
35.2.1.
Listing 311: The definition of the interfacial momentum exchange force terms of the momentum conservation
equations of twoPhaseEulerFoam in UEqns.H
// create x
if ( model_ . valid () )
{
x () += model_ - > K () *( f1 () - f2 () ) ;
This offering is not approved or endorsed by ESI® Group, ESI-OpenCFD® or the OpenFOAM®
V 278
Foundation, the producer of the OpenFOAM® software and owner of the OpenFOAM® trademark.
}
if ( model1In2_ . valid () )
{
x () += model1In2_ - > K () *(1 - f1 ) ;
}
if ( model2In1_ . valid () )
{
x () += model2In1_ - > K () * f2 ;
}
// other code
return x ;
Listing 312: The application of blending; part of the method K() in BlendedInterfacialModel.C
No Blending
The blending model none, which is defined in the files noBlending.H and noBlending.C, is quite instructive.
This blending model, which is essentially a non-model, returns the blending factors f1 and f2 as it is demanded
by the base class of all blending models.
As there is no blending with the none blending model, the user needs to specify which phase is the contin-
uous phase. In twoPhaseEulerFoam-2.3 there is no implicit assumption on which phase is the dispersed and
which is continuous. Listing 313 shows how the none blending model is selected. There we also see the explicit
specification of the continuous phase.
blending
{
default
{
type none ;
c on ti nu ous Ph as e water ;
}
}
Now, we have a look on the blending factors returned by the none model. Listing 314 shows the definition of
the methods f1() and f2(). These methods return a newly created temporary scalar field (volScalarField)
that is in turn created from a constant expression.
In the case of f1(), the constant expression is phase2.name() != continuousPhase\_ which returns a
boolean value. In the case of f2() the corresonding expression is phase1.name() == continuousPhase\_,
which also returns a boolean value. Here, we enter the realm of implicit type conversions147 . Implicit type
conversions are part of the language’s standard. Thus, if we look up the working draft of the C++11standard,
we find the following sentence in the section on Integral promotions:
A prvalue of type bool can be converted to a prvalue of type int, with false becoming zero and
true becoming one.
Thus, we find that the blending factors returned by none are of the values zero or one, which is the set of
values we would expect in this case. If the boolean expressions yield the correct factors can be tried out with a
simple pen-and-paper test. Choose a continuous phase (i.e. phase2 is the continuous phase) and evaluate all ex-
pressions (i.e. determine the values of f1 and f2, and apply these values on the expressions found in Listing 312.).
This offering is not approved or endorsed by ESI® Group, ESI-OpenCFD® or the OpenFOAM®
V 279
Foundation, the producer of the OpenFOAM® software and owner of the OpenFOAM® trademark.
return
tmp < volScalarField >
(
new volScala rField
(
IOobject ( /* arguments removed */ ) ,
mesh ,
dimensionedScalar
(
"f",
dimless ,
phase2 . name () != c o n t i n u o u s P ha s e _
)
)
);
}
Foam :: tmp < Foam :: volScalarField > Foam :: bl e nd in gM et h od s :: noBlending :: f2
(
const phaseModel & phase1 , const phaseModel & phase2
) const
{
const fvMesh & mesh ( phase1 . mesh () ) ;
return
tmp < volScalarField >
(
new volScala rField
(
IOobject ( /* arguments removed */ ) ,
mesh ,
dimensionedScalar
(
"f",
dimless ,
phase1 . name () == c o n t i n u o u s P ha s e _
)
)
);
}
Listing 314: Computing the blending factors. The arguments of the constructor of the IOobject class have
been removed to save space.
Linear
As we saw from the none model, the blending factors f1 and f2 have two extreme values, i.e. zero and one.
The model name linear suggests that this models yields a linear variation between these two limiting values.
The linear blending model was two model parameters, shown in Listing 315. These represent the limits up
to which a phase can be considered to be fully dispersed, i.e. a clear distinction between dispersed phase and
continuous phase is possible. The second parameter is the limit up to which the phases can be considered partly
dispersed. These two limits are necessary, as the solver is intended to handle phase inversion, i.e. situations in
which one phase is the dispersed phase in only parts of the domain.
The definition of the blending factor f1 is shown in Listing 316. We limit the discussion on f1, as the other
blending factor is defined analogously. The interested reader is encouraged to analyse f2. The code of Listing
316 can be translated into equation (117).
1
if α ≤ maxFullyDispersedAlpha
α − maxFullyDispersedAlpha
f1 (α) = if α ≤ maxPartlyDispersedAlpha (117)
maxPartlyDispersedAlpha−maxFullyDispersedAlpha
0 if α > maxPartlyDispersedAlpha
This offering is not approved or endorsed by ESI® Group, ESI-OpenCFD® or the OpenFOAM®
V 280
Foundation, the producer of the OpenFOAM® software and owner of the OpenFOAM® trademark.
// - Maximum fraction of phases which can be considered partly dispersed
HashTable < dimensionedScalar , word , word :: hash >
maxPartlyDispersedAlpha_ ;
Listing 315: Model parameters of the linear blending model; declaration in the file linear.H
return
min
(
max
(
( phase1 - maxFullAlpha )
/( maxPartAlpha - maxFullAlpha + SMALL ) ,
scalar (0.0)
),
scalar (1.0)
);
}
Listing 316: Computing the linear blending factor f1 in the file linear.C
f1
1.0
0.8
0.6
0.4
0.2
α
0.2 0.4 0.6 0.8 1.0
Figure 125: The value of f1 over α; model parameters are set to maxFullAlpha = 0.3 and maxPartAlpha = 0.5;
these settings are taken from the bubble column tutorial case of twoPhaseEulerFoam.
Hyperbolic
The hyperbolic blending model offers a continuous function for the blending factor for the whole range of the
dispersed phase’s volume fraction, see Figure 126. Again, we analyse only the definition of f1 and leave the
reader the opportunity to follow the argument made, with the definition of f2.
The hyperbolic blending model needs in total three model parameters. The parameter transitionAlphaScale
controls how steep the transition between 0 and 1 is. The other two parameters are maxDispersedAlpha for
each phase. At this parameter the blending function (118) has the value 1/2.
1 4(α − maxDispersedAlpha
f1 (α) = 1 + tanh ) (118)
2 transitionAlphaScale
This offering is not approved or endorsed by ESI® Group, ESI-OpenCFD® or the OpenFOAM®
V 281
Foundation, the producer of the OpenFOAM® software and owner of the OpenFOAM® trademark.
f1
1.0
0.8
0.6
0.4
0.2
α
0.2 0.4 0.6 0.8 1.0
Figure 126: The value of f1 over α; model parameters are set to maxDispersedAlpha = 0.6 and
transitionAlphaScale = 0.4;
We find the same structure in the terms of the implemented equations. The Listing below shows one part
of the drag term – as the drag term consists of the coefficient and a velocity difference, we can split the term
up into two contributing parts.
As we know from our considerations about the units of the terms of the momentum equation, the drag force
contribution in general needs to have the unit of a force density. Thus, we determined the unit of the coefficient,
see Eqn. (116).
! kg
[dragCoeff] = (120)
m3 s
By having a close look on the base class for the drag models, we can check the unit of the coefficient. The
base class of the drag model has a static data member that carries the information about the unit of the provided
coefficient. In fact, all interfacial momentum exchange models have such a member. In the header file of the
base class for the drag models, a constant static member148 dimK is declared.
// - Coefficient dimensions
static const dimensionSet dimK ;
In the implementation file, the static data member is initialised to the appropriate value. In Section 9 we
reviewed OpenFOAMs feature to provide physical units. There we can see, that the order of units in a
dimensionSet is [kg m s K mol].
Thus, we see, that the drag force coefficient has indeed the unit we derived from our earlier considerations.
148 A static data member of a class exists only once for all instances of this class, i.e. regardless of how many actual objects of this
class exist, the data member exists only once. This makes perfect sense for common properties such as the unit of the coefficient,
which is the same for all drag models.
This offering is not approved or endorsed by ESI® Group, ESI-OpenCFD® or the OpenFOAM®
V 282
Foundation, the producer of the OpenFOAM® software and owner of the OpenFOAM® trademark.
Returning the output
Other than the drag models of prior versions of twoPhaseEulerFoam (version 2.2 and below), the drag models in
twoPhaseEulerFoam-2.3 return the product of drag coefficient CD and the Reynolds number Re. Consequently,
the method returning the output of the individual drag models is named CdRe().
The drag model itself, i.e. the base class returns the drag force coefficient K. This drag force coefficient is
provided by the method K() which is a method of the base class dragModel. The base class also has a pure
virtual method named CdRe(). Pure virtual means that derived classes need to implement this method and that
we are unable to create an instance of the base class itself. We only can create instances of one of the derived
classes. As a derived class must implement all pure virtual methods, we are guaranteed that these methods
actually exist. The Listings 317 and 318 show the relevant parts of code of the class dragModel. The method
K() calls the method CdRe(), see Line 5 of Listing 318.
1 // - Drag coefficient
2 virtual tmp < volScalarField > CdRe () const = 0;
3
4 // - The drag function K used in the momentum equation
5 // ddt ( alpha1 * rho1 * U1 ) + ... = ... K *( U1 - U2 )
6 // ddt ( alpha2 * rho2 * U2 ) + ... = ... K *( U2 - U1 )
7 virtual tmp < volScalarField > K () const ;
Listing 317: The declaration of the methods K() and CdRe() in dragModel.H
3 ρC ν C
K= CD Re αCS 2 (121)
4 dB
Again, we find the proper physical unit for the drag force coefficient.
Here we show the definition of the method CdRe() from the class SchillerNaumann as an example since the
Schiller Naumann drag model is well known.
1 Foam :: tmp < Foam :: volScalarField > Foam :: dragModels :: S ch i ll er Na u ma nn :: CdRe () const
2 {
3 volS calarFie ld Re ( pair_ . Re () ) ;
4
5 return
This offering is not approved or endorsed by ESI® Group, ESI-OpenCFD® or the OpenFOAM®
V 283
Foundation, the producer of the OpenFOAM® software and owner of the OpenFOAM® trademark.
6 neg ( Re - 1000) *24.0*(1.0 + 0.15* pow ( Re , 0.687) )
7 + pos ( Re - 1000) *0.44* max ( Re , residualRe_ ) ;
8 }
Swarm correction
The drag models offer swarm correction of the drag force, since it is observed that swarms of bubbles behave
different from single bubbles. At the time of writing (September 2014) there are two choices.
Both swarm correction models are derived from an abstract base class swarmCorrection. Thus the frame-
work is ready for future extension of model choice.
45.8.2 Lift
The lift force on a dispersed phase element (DPE) is defined as
with
Units
In contrast to the drag model, the lift model provides the actual force term for the governing equations. The
base class of the lift models declares a static consant data member dimF for storing the unit of the force term
computed by the list model.
// - Force dimensions
static const dimensionSet dimF ;
In the implementation file liftModel.C the static data member is initialized and it has indeed the unit of
a force density. Note: the order of units in a dimensionSet is [kg m s K mol].
! N kg
[Fi ] = 3
= 2 2 (114)
m m s
This offering is not approved or endorsed by ESI® Group, ESI-OpenCFD® or the OpenFOAM®
V 284
Foundation, the producer of the OpenFOAM® software and owner of the OpenFOAM® trademark.
Returning the output
The general computation of the lift force is done – similar to the drag models – within the method F() of the
base class. The base class calls the method Cl() of the concrete lift model for the lift force coefficient. This is
similar to the method K() of the drag model base class calling the method CdRe() of the concrete drag model
classes.
The method F() of the base class returns the force density field due to the lift force.
1 // - Lift coefficient
2 virtual tmp < volScalarField > Cl () const = 0;
3
4 // - Lift force
5 virtual tmp < volVectorField > F () const ;
Listing 320: The declaration of the methods F() and Cl() in liftModel.H
The actual lift force coefficient is provided by the concrete lift force model. Again, analogue to the drag
model classes, the base class for the lift models declares the pure virtual method Cl(). This means, every lift
model derived from the base class has to implement Cl() and we are not able to create an instance of the base
class itself. Thus, the existance of the method Cl() is guaranteed. The implementation of Cl() is the remaining
degree of freedom for the individual lift force models.
There are several choices available to the user:
noLift this model returns a zero field when either F() or Cl() is called. This class overwrites the method
F() which is inherited from the base class with its own implementation. Thus, when F() is called,
the implementation of the class noLift is called, i.e. noLift::F(). All other lift force models do not
implement F(), thus, liftModel::F() is called.
constantCoefficient this model is the easiest implementation of a lift force model. The constant lift force coef-
ficient CL is provided by the user. Cl() simply returns this value in the form of the appropriate data type,
i.e. the coefficient provided by the user is a dimensionless number (declared as const dimensionedScalar Cl_;),
however, the method Cl() returns a volScalarField.
lift force model X there are several models available that compute the lift force coefficient from flow proper-
ties.
FV M = CV M αρC (127)
with
This offering is not approved or endorsed by ESI® Group, ESI-OpenCFD® or the OpenFOAM®
V 285
Foundation, the producer of the OpenFOAM® software and owner of the OpenFOAM® trademark.
The derived classes provide the virtual mass coefficient CV M via the method Cvm(). The user has the choice
between:
noVirtualMass this class returns zero when F() is called. This model overwrites the method F() with its
own implementation returning a zero field. All other classes make use of the base classes implementation
of F() which all derived classes inherited. The method Cvm() also returns a zero field.
constantVirtualMassCoefficient this class computes the contribution due to virtual mass based on a con-
stant virtual mass coefficient CV M which is provided by the user.
Lamb this model computes the virtual mass coefficient CV M depending on the aspect ratio of the dispersed
phase elements. With the help of aspect ratio models a particle shape different from spheres and even
shape variation can be modelled within some limits.
The second command is a combination of a find command and a grep command. find finds all files with the
file extension .C and grep searches this files for the pattern pair_.E(). This pattern is the function call which
returns the aspect ratio E of a phase pair.
This offering is not approved or endorsed by ESI® Group, ESI-OpenCFD® or the OpenFOAM®
V 286
Foundation, the producer of the OpenFOAM® software and owner of the OpenFOAM® trademark.
constantTurbulentDispersionCoefficient
The constant coefficient model implements the following model for the force due to turbulent dispersion.
FT D = CT D αρC kC ∇α (128)
with
CT D turbulent dispersion coefficient
α volume fraction of the dispersed phase
ρC density of the continuous phase
kC kinetic turbulent energy of the continuous phase
Burns
The Burns model implements the following model for the force due to turbulent dispersion.
νC,t α
FT D = KDrag ∇α 1 + (129)
σ 1−α
with
KDrag drag force coefficient due to drag
α volume fraction of the dispersed phase
νC,t turbulent viscosity of the continuous phase
σ surface tension
Note that Kdrag is not evaluated by calling method K() of the class dragModel. Listing 322 shows the actual
code that computes the force term of the Burns model.
The reason for computing the drag force coefficient K “by hand” rather than calling dragModel::K() might
be the run-time. By not calling K() we can save one virtual function call149 . The operations to compute K
have to be done anyway, so there is a net saving of one virtual function call.
Listing 322: The definition of the method F() in the file Burns.C
149 Virtual function calls are considered to be more expensive in terms of run-time than direct function calls, since the correct
This offering is not approved or endorsed by ESI® Group, ESI-OpenCFD® or the OpenFOAM®
V 287
Foundation, the producer of the OpenFOAM® software and owner of the OpenFOAM® trademark.
Gosman
The Gosman model implements the following model for the force due to turbulent dispersion.
νC,t
FT D = KDrag ∇α (130)
σ
Figure 127: Velocity vectors of the gaseous phase at the inlet boundary (red vectors) in an aerated stirred tank.
That the gas inlet boundary lies within the MRF zone. On the left, we see the initial condition and on the right
we see the boundary condition after the constraints by the MRF method have been applied.
This offering is not approved or endorsed by ESI® Group, ESI-OpenCFD® or the OpenFOAM®
V 288
Foundation, the producer of the OpenFOAM® software and owner of the OpenFOAM® trademark.
46 reactingTwoPhaseEulerFoam
With the release of OpenFOAM-3.0.0150 in 2015 the solvers reactingTwoPhaseEulerFoam and reactingMul-
tiphaseEulerFoam were introduced. These solvers feature expanded modelling capabilities compared to the
ancestors twoPhaseEulerFoam and multiphaseEulerFoam. These two solvers are one of the results of a collabo-
ration of companies from the chemical and process industries, and the makers of OpenFOAM151 .
reactingTwoPhaseEulerFoam and reactingMultiphaseEulerFoam form the reactingEulerFoam family of Euler-
Euler solvers. These two solvers use a largely common code base for underlying models, such as phase-models,
interfacial momentum-transfer models and interfacial composition models. Many of the developments that went
into the evolution of the twoPhaseEulerFoam solver from OpenFOAM-2.2 and earlier to OpenFOAM-2.3 have
been continued and led to a further generalization of the code base.
Since both solvers derive from a largely common code base, this section mostly applies to both reactingT-
woPhaseEulerFoam and reactingMultiphaseEulerFoam.
phaseModel
This is the base class for all phase models, and it defines the behaviour of a phase. This class is itself derived
from the class volScalarField. Thus, the phase model is its own volume fraction field. This class holds very
little data, apart from the phase’s index, its name and a pointer to the phase’s diameter model.
However, this class defines a large number of abstract methods, which the various template classes need to
implement.
MovingPhaseModel
This class template provides the functionality and the data for a moving phase, i.e. it holds the velocity field
and the flux fields. This class also provides a momentum equation for the phase. This class also holds a pointer
to the turbulence model.
150 https://openfoam.org/release/3-0-0/
151 https://openfoam.org/chemical-process-engineering/
This offering is not approved or endorsed by ESI® Group, ESI-OpenCFD® or the OpenFOAM®
V 289
Foundation, the producer of the OpenFOAM® software and owner of the OpenFOAM® trademark.
8 return
9 (
10 fvm :: ddt ( alpha , rho , U_ )
11 + fvm :: div ( alphaRhoPhi_ , U_ )
12 + fvm :: SuSp ( - this - > c on t in ui ty E rr or () , U_ )
13 + this - > fluid () . MRF () . DDt ( alpha * rho , U_ )
14 + turbulence_ - > divDevRhoReff ( U_ )
15 );
16 }
Listing 323: Constructing the momentum equation of a moving phase in the class MovingPhaseModel
The momentum equation provided by this class template bears a striking resemblance to the momentum
equation of a compressible solver. If we compare the Listings 323 and 324, we recognize the four of the five
terms from Listing 323 as the RHS of the momentum equation of Listing 324. The only difference is, that the
terms of the multi-phase momentum equation contain the volume fraction field alpha, which takes a uniform
value of 1 in the single-phase solver.
Listing 324: Constructing the momentum equation of a compressible, single-phase solver, on the example of
rhoPimpleFoam
As the list of options is read and created by the solver, the phase model is oblivious to the presence of any
options. Thus, there are no calls to the fvOptions framework within the phase models. This is a task for the
solver to deal with options from the fvOptions framework.
AnisothermalPhaseModel
This class template provides the data and the methods necessary to implement energy transfer, i.e. an energy
equation.
IsothermalPhaseModel
This class is the counterpart of the AnisothermalPhaseModel, it implements all abstract methods associated
with the transport of thermal energy in a trivial manner.
MultiComponentPhaseModel
This template class provides the data and methods associated with species transport within a phase, e.g. the
gas phase consisting of several gases.
PurePhaseModel
This template class is used for phases that consist of a single species. Thus there is no need to solve species trans-
port equations. Hence, this class template implements all abstract methods defined in the base class phaseModel
in a trivial manner, e.g. it returns an empty list of mass fractions when the method phaseModel::Y() is called,
which is intended to return the species mass fractions.
InertPhaseModel
This template class is used for non-reactive phases, and it implements all methods dealing with reactions in a
trivial way. Thus, it returns zero for the heat release rate and the mass transfer rate.
This offering is not approved or endorsed by ESI® Group, ESI-OpenCFD® or the OpenFOAM®
V 290
Foundation, the producer of the OpenFOAM® software and owner of the OpenFOAM® trademark.
ReactingPhaseModel
This template class is used for reactive phases. Thus, the heat release rate and the mass transfer rate are
computed by the underlying reaction model and returned.
1 U1Eqn =
2 (
3 phase1 . UEqn ()
4 ==
5 * m o m e n t u m T r a n s f er [ phase1 . name () ]
6 + fvOptions ( alpha1 , rho1 , U1 )
7 );
8 U1Eqn . relax () ;
9 fvOptions . constrain ( U1Eqn ) ;
10 fvOptions . correct ( U1 ) ;
Listing 325: Constructing the momentum equation of the first phase in reactingTwoPhaseEulerFoam
47 multiphaseEulerFoam
multiphaseEulerFoam is an Eulerian solver for n phases. This solver differs in some points from the solver
twoPhaseEulerFoam.
47.1 Fields
The naming scheme of the fields differs from other multiphase solvers. multiphaseEulerFoam directly uses names
(e.g. Uair, Uwater, Uoil, etc.).
This offering is not approved or endorsed by ESI® Group, ESI-OpenCFD® or the OpenFOAM®
V 291
Foundation, the producer of the OpenFOAM® software and owner of the OpenFOAM® trademark.
47.1.1 alphas
A specialty of multiphaseEulerFoam is the field alphas. This field does not represent the volume fraction of
a certain phase and is therefore not bounded by 0 and 1. This field is used to represent all phases in a single
scalar field. alphas is computed by summing up the products of phase index and phase fraction.
n−1
X
alphas = i ∗ αi (131)
i=0
Because alphas is computed quantity, the file alphas can be missing in the 0 -directory.
47.2.1 drag
drag
(
( air water )
{
type blended ;
air
{
type S ch il le r Na um an n ;
r e s i d u a l P h a s e F r a c t i o n 0;
residualSlip 0;
}
water
{
type S ch il le r Na um an n ;
r e s i d u a l P h a s e F r a c t i o n 0;
residualSlip 0;
}
r e s i d u a l P h a s e F r a c t i o n 1e -2;
residualSlip 1e -2;
}
/* further d e f i n i t i o n s */
Listing 326: Pair-wise definition of the drag model in the file transportProperties
virtualMass
(
( air water ) 0.5
( air oil ) 0.5
( air mercury ) 0.5
( water oil ) 0.5
( water mercury ) 0.5
( oil mercury ) 0.5
);
Listing 327: Pair-wise definition of Coefficients for virtual mass in the file transportProperties
This offering is not approved or endorsed by ESI® Group, ESI-OpenCFD® or the OpenFOAM®
V 292
Foundation, the producer of the OpenFOAM® software and owner of the OpenFOAM® trademark.
48 driftFluxFoam
driftFluxFoam is a solver of OpenFOAM to simulate e.g. settling of disperse particles in a liquid. driftFluxFoam
is the successor of settlingFoam, which has been discontinued with the release of OpenFOAM-2.3.1152 .
settlingFoam was used by Brennan [14] in his thesis, which contains a lot of information on deriving the
drift flux model from the Eulerian two-fluid model equations. The header of driftFluxFoam describes this
solver as follows:
Solver for 2 incompressible fluids using the mixture approach with the drift-flux approximation for
relative motion of the phases.
Used for simulating the settling of the dispersed phase and other similar separation problems.
driftFluxFoam complys with the generic solver design of OpenFOAM, thus this solver can use all available
turbulence models. It also can use the MRF method and the fvOptions framework.
∂αk ρk
+ ∇· (αk ρk uk ) = 0 (132)
∂t
with the constitutive relations
ρm = α1 ρ1 + α2 ρ2 (133)
ρm um = α1 ρ1 u1 + α2 ρ2 u2 (134)
we gain
∂ρm
+ ∇· (ρm um ) = 0 (135)
∂t
∂ρm um X
+ ∇· (ρm um um ) = −∇pm + ∇· τ + τt − αk ρk ukm ukm + ρm g + Mk (136)
∂t
P
we pay special attention to the diffusion stress αk ρk ukm ukm , which represents momentum diffusion due to
the relative motion between the phases.
X
αk ρk ukm ukm = α1 ρ1 u1m u1m + α2 ρ2 u2m u2m (137)
For convenience we introduce the symbol τdm for the diffusion stress
X
τdm = αk ρk ukm ukm (138)
152 http://www.openfoam.org/version2.3.1/
This offering is not approved or endorsed by ESI® Group, ESI-OpenCFD® or the OpenFOAM®
V 293
Foundation, the producer of the OpenFOAM® software and owner of the OpenFOAM® trademark.
with ukm , the velocity of the phase k relative to the mixture’s centre of mass; ukm is also referred to as diffusion
velocity of the phase k
ukm = uk − um (139)
Ishii and Hibiki [33] states a relation between the diffusion velocities of the two phases:
Implementation
From the source code in Listing 328 we see the diffusion stress an the fourth term on the LHS of the momentum
equation.
This offering is not approved or endorsed by ESI® Group, ESI-OpenCFD® or the OpenFOAM®
V 294
Foundation, the producer of the OpenFOAM® software and owner of the OpenFOAM® trademark.
And now, we translate the source code into some math:
2 2
τbm = βd udm + βc ucm (146)
with
βd = α d ρ d (147)
βc = αc ρc (148)
βd
ucm = udm (149)
βc
we gain
2
2 βd 2
τbm = βd udm + βc udm (150)
βc
2 βd
τbm = βd udm 1 + (151)
βc
2 α d ρd
τbm = αd ρd udm 1 + (152)
αc ρc
2 α ρ
c c + αd ρd
τbm = αd ρd udm (153)
αc ρc
2 ρm
τbm = αd ρd udm (154)
αc ρc
αd ρd 2
τbm = ρm u (155)
αc ρc dm
We notice, that (155) derived from the source code, equals (145), derived from literature with phase 2 being
the disperse phase d.
Relative velocity
The diffusion velocity udm and the drift velocity udj are linked by a constitutive relation:
ρ1
udm = udj (156)
ρm
We find this relation also in the source code in Listings 334 and 335. Ishii and Hibiki [33] state, that in the
case of dispersed two-phase flow the drag correlation should be expressed in terms of the drift velocity udj .
The relative velocity models provide a method that returns udm , however, in the source code of the Listings
334 and 335 we find relation (156) translated into C++. There, the expression for udm consists of the density
ratio and a relation for the drift velocity, which links the terminal velocity of a single particle and the volume
fraction of the disperse phase.
48.2 incompressibleTwoPhaseInteractingMixture
The class incompressibleTwoPhaseInteractingMixture serves as the transport model for driftFluxFoam.
This class holds all the information of the two phases and provides the mixture quantities. driftFluxFoam
solves the momentum and pressure equations for the mixture. Thus, this solver is in between a single-phase
solver and a full two-fluid solver such as twoPhaseEulerFoam.
Via this transport model, the mixture quantities propagate to the turbulence model, since the turbulence
model receives a transport model class as template parameter at construction. This is one example for the
versatility of the new, templated turbulence modelling framework. The precursor settlingFoam had a hard-
coded k − turbulence model. Also the viscosity model was kind of hard-coded.
This offering is not approved or endorsed by ESI® Group, ESI-OpenCFD® or the OpenFOAM®
V 295
Foundation, the producer of the OpenFOAM® software and owner of the OpenFOAM® trademark.
48.3.1 mixtureViscosityModel
The class mixtureViscosityModel is the abstract base class for the actual viscosity models. This class serves a
similar purpose as the base class for the single-phase viscosity models viscosityModel located in $FOAM_SRC/
transportModels/incompressible/viscosityModels/viscosityModel. These two base classes are rather
similar and there are only slight differences in their implementations.
48.3.2 slurry
The slurry mixture viscosity model is a correction for the Newtonian viscosity with reference to Thomas [62].
Listing 330: The calculation of the mixture viscosity by the slurry mixture viscosity model.
48.3.3 plastic
The plastic viscosity model is based on a generic viscosity model (158) for liquids exhibiting plastic behaviour.
τ = aC b α (158)
The plastic model implemented in driftFluxFoam translates to:
µ = min [µc + k ∗ (10n α − 1) , µmax ] (159)
Listing 331 shows the source code computing the mixture viscosity. The -1 in the second term ensures, that
we retain the laminar viscosity of the continuous phase in the case the dispersed volume fraction vanishes, since
anything to the power of zero equals one.
Listing 331: The calculation of the mixture viscosity by the plastic mixture viscosity model.
48.3.4 BinghamPlastic
BinghamPlastic is a Bingham plastic model.
This offering is not approved or endorsed by ESI® Group, ESI-OpenCFD® or the OpenFOAM®
V 296
Foundation, the producer of the OpenFOAM® software and owner of the OpenFOAM® trademark.
48.4 Relative velocity models - hindered settling
In this section we use the symbol v for the velocity to follow the notation of Brennan [14] as well as the source
code of OpenFOAM.
1 Udm_
2 (
3 IOobject
4 (
5 " Udm " ,
6 alphac_ . time () . timeName () ,
7 alphac_ . mesh () ,
8 IOobject :: NO_READ ,
9 IOobject :: AUTO_WRITE
10 ),
11 alphac_ . mesh () ,
12 d i m e n s i o n ed V e c t o r ( " Udm " , dimVelocity , vector :: zero ) ,
13 mixture . U () . boundaryField () . types ()
14 )
Listing 332: The initializer entry for Udm_ in the constructor of the relativeVelocityModel class.
For the interpretation of Listing 332 we need to dig out the appropriate constructor of the class GeometricField153 .
In Listing 333 we see that the constructor receives five arguments, of which the last has a default value. If we
pass only four arguments, the fifth will be determined from the default value.
1 // - Constructor given IOobject , mesh , dimensioned < Type > and patch types .
2 Geom etricFie ld
3 (
4 const IOobject & ,
5 const Mesh & ,
6 const dimensioned < Type >& ,
7 const wordList & wantedPatchTypes ,
8 const wordList & a c t u a l P a t c h T y p e s = wordList ()
9 );
Listing 333: The signature of the constructor called by the code in Listing 332.
If we compare the arguments of the constructor call of Listing 332 and the signature in Listing 333, we see
that the first argument passed is clearly an IOobject. The second argument is a reference to the mesh itself,
which is obvious from the call to alphac_.mesh() in Listing 332.
The third argument determines the type of the field as well as the initial value. The template parameter
Type determines whether the field is a scalar, a vector or a tensor field. As a dimensionedVector is passed in
Listing 332, Type evaluates to vector154 .
153 Bear in mind, that volVectorField and others are specialisations of the templated class GeometricField.
154 Bear in mind, that dimensionedVector is a specialisation of the templated class dimensioned<Type> and dimensionedVector
is a shorthand for dimensioned<vector>.
This offering is not approved or endorsed by ESI® Group, ESI-OpenCFD® or the OpenFOAM®
V 297
Foundation, the producer of the OpenFOAM® software and owner of the OpenFOAM® trademark.
The fourth argument is a list of patch types, since we passed only one dimensioned value as the third
argument, there has been no information passed on the boundary conditions of the field up to now. By passing
the list of boundary types of the mixture velocity field (mixture.U()), the boundary conditions of the field
Udm_ are specified.
As there is no fifth argument passed in Listing 332, the return value of the call wordList() is used.
48.4.2 simple
The model named simple is similar to the model used by Brennan [14] with attribution to Dahl [19]. This
model is very similar to the Vesilind [67] model (161), Brennan [14] explains the change of the base from the
Euler number e to the base 10 with a closer fit to experimental data gathered by Dahl [19].
vs = v0 10−kα (160)
The implementation of the simple model is more or less a direct translation from math (160) to C++. In
the exponent the maximum of the dispersed volume fraction and zero is taken to avoid numerical trouble from
negative values of the volume fraction. Reversing the sign in an exponent is never a good idea in numerical
simulation.
Listing 334: The calculation of the dispersed diffusion velocity Udm_ by the simple relative velocity model.
48.4.3 general
The model referred to as general is most probably basedon the model of Takács [61], there is no reference to
any literature in the header file. The Takács [61] model (162) is a so-called double-exponential model based on
the model of Vesilind [67], see (161) [30, 14].
vs = v0 e−nX (161)
−rh X −rp X
vs = v0 e −e (162)
with
vs settling velocity
v0 maximum settling velocity
n model parameter
(163)
rh settling parameter for hindered settling
rp settling parameter for low solids concentration
X suspended solids concentration
The implementation .
Listing 335: The calculation of the dispersed diffusion velocity Udm_ by the general relative velocity model.
This offering is not approved or endorsed by ESI® Group, ESI-OpenCFD® or the OpenFOAM®
V 298
Foundation, the producer of the OpenFOAM® software and owner of the OpenFOAM® trademark.
48.5 settlingFoam
Here we take a closer look on settlingFoam (of OpenFOAM-2.2.x), which is the predecessor of driftFluxFoam.
By comparing the implementations of these two solvers we can observe the transition of the OpenFOAM source
code base to a more encapsulated approach.
1 {
2 /* compute plastic viscosity */
3 mul = muc +
4 p l a s t i c V i s c os i t y
5 (
6 /* code removed for brevity */
7 );
8
9 if ( BinghamP lastic )
10 {
11 volS calarFie ld tauy = yieldStress
12 (
13 /* see yieldStress . H */
14 );
15 mul =
16 /* compute contribution of yield stress */
17 + mul ;
18 }
19
20 mul = min ( mul , muMax ) ;
21 }
Listing 336: The calculation of the mixture viscosity in the file correctViscosity.H of settlingFoam of
OpenFOAM-2.2.x. Comments added by the author.
This offering is not approved or endorsed by ESI® Group, ESI-OpenCFD® or the OpenFOAM®
V 299
Foundation, the producer of the OpenFOAM® software and owner of the OpenFOAM® trademark.
19
20 Vdj . c o r r e c t B o u n d a r y C o n d i t i o n s () ;
Listing 337: The calculation of the relative velocity in the file calcVdj.H of settlingFoam of OpenFOAM-2.2.x.
48.5.3 Turbulence
Turbulence in settlingFoam was/is implemented in a similar fashion as in twoPhaseEulerFoam of that time.
Both solvers feature a hard-coded k − turbulence model, which is adapted to the solvers needs.
This offering is not approved or endorsed by ESI® Group, ESI-OpenCFD® or the OpenFOAM®
V 300
Foundation, the producer of the OpenFOAM® software and owner of the OpenFOAM® trademark.
Part VI
Postprocessing
There are two principal possibilities for post processing in OpenFOAM. First, there are tools that are executed
after a simulation has finished. This tools work on the written data of the solution. sample and paraView are
two examples for such tools.
Besides that, there is run-time post processing. Run-time post processing performs certain operations on the
solution data as it is generated. Consequently, run-time post processing allows for a much finer time resolution.
The functions objects – e.g. for calculating forces or force coefficients – are an example for run-time post
processing. The big disadvantage of this method is, that the user has to know the intended post processing
steps before starting a simulation. See http://www.openfoam.com/features/runtime-postprocessing.php
for more information about run-time post processing.
This offering is not approved or endorsed by ESI® Group, ESI-OpenCFD® or the OpenFOAM®
VI 301
Foundation, the producer of the OpenFOAM® software and owner of the OpenFOAM® trademark.
49 functions
A function objects - in general - are objects, which are used in a similar manner as a function. This main benefit
of function objects is that they can have a permanent state. This state can be used to store data between “calls”
of the function object. A very illustrative example is OpenFOAM’s function object fieldAverage, which computes
the temporal average of fields. This function object needs to update itself with every time step computed and
the current time-averaged fields need to be preserved between “calls” of fieldAverage.
Function objects usually serve one specific purpose, e.g. compute the time average of a field quantity. Thus,
there is a large, ever growing number of function objects available in OpenFOAM. Some of which are listed
below to give an impression of the wide range of tasks currently covered by OpenFOAM’s function objects:
fieldAverage compute the temporal average of field quantities
the fieldValue family compute the spatial average (or other operations) of field quantities
forces compute the forces on a body (surface)
forceCoeffs compute force coefficients, e.g. for drag, lift and torque
sampledSet save the field values of a certain region, e.g. along a line
probes save field values at certain points
streamLine compute streamlines
scalarTransport solve a passive scalar transport equation
49.2 Definition
Function objects are defined in the file controlDict. There, a function dictionary is created which contains all
necessary informations. Listing 338 shows the basic structure of such a definition.
Every function has a name. This name is stated at the place of the NAME placeholder in Listing 338. This
name is also the name of the folder OpenFOAM creates in the case directory. There, all data generated by the
function object is stored.
155 New users might hate this statement, but the documentation is in the code.
156 Asan illustrative example, the function object for processing field values within a cell set has changed its name from cellSource
(OpenFOAM-3.0) over volRegion (OpenFOAM-4.0) to volFieldValue (OpenFOAM-5.0). This has been done, most probably, to
keep the naming scheme consistent with the underlying class names or make the name descriptive of its task. However, as in many
aspects of life in general, there is no unique, best way to do things. In this case, the function object’s name can describe what it is
or what it does. Both ways are equally valid and there might even be more aspects to choose from.
157 The same is the case for migrating cases to older versions, however, using the current version should be the norm.
This offering is not approved or endorsed by ESI® Group, ESI-OpenCFD® or the OpenFOAM®
VI 302
Foundation, the producer of the OpenFOAM® software and owner of the OpenFOAM® trademark.
Each function object also has a type. This type needs to be specified at the place of the TYPE placeholder.
The type needs to be from the list of the available functions. To find out, which functions are available, the
banana-trick 158 can be used. Listing 339 shows the error message that is caused by the banana-trick.
The placeholder LIBRARY marks the place where the name of the library needs to entered. A function object
is not a program that is executeable on its own. It is merely a library that is used by other programs. In
our case, the function objects are called by the solvers. Therefore, the function objects are not compiled into
executeables. The compiler creates libraries when the function objects are compiled. This libraries contain the
functions in a machine readable form.
The keyword enabled is optional. With this keyword function objects can be excluded from execution.
functions
{
NAME
{
type TYPE ;
f u n c t i o n O b j e c t L i b s (" LIBRARY ") ;
enabled true ;
/*
Definition
*/
}
}
13
(
cellSource
faceSource
fieldAverage
fieldCoordinateSystemTransform
fieldMinMax
near WallFiel ds
patchProbes
probes
readFields
sets
streamLine
surfaceInterpolateFields
surfaces
)
49.3 Control
All function objects are related more or less directly to the base class functionObject, which is defined in the
file $FOAM_SRC/OpenFOAM/db/functionObjects/functionObject/functionObject.H. This class defines the
smallest common behaviour of all function objects. Thus, it may pay off to study this class, as all we learn from
it applies to all function objects.
This offering is not approved or endorsed by ESI® Group, ESI-OpenCFD® or the OpenFOAM®
VI 303
Foundation, the producer of the OpenFOAM® software and owner of the OpenFOAM® trademark.
under the latter category, e.g. the function object surfaceRegion from the fieldValue family of function
objects simply writes the data from specified patches to disk. This is done only at write time.
On the other hand, function objects might need to compute data from the solution data and thus need an
internal state, e.g. the fieldAverage function object needs to continuously update its internal fields for the
temporal averages, even if it writes them less frequently to disk.
Thus, the operational stages of a function object are divided in execute (for updating its internal state) and
write (for writing data, and computing to-be-written-data, which is not an internal state).
Enablement
The enabled flag controls whether the function object is enabled. This takes a boolean value and control
whether to execute the function object or not. This might be useful for testing or debugging simulation cases.
This flag allows you to define function objects and stop them from being used without deleting them from
controlDict. A rather brute-force alternative to this flag, from the case file editing perspective, would be to
comment the function object definition. However, changing the flag from on to off and vice-versa requires less
characters changed than commenting and uncommenting159 .
The pair timeStart and timeEnd control when to begin using a function object and when to stop. These
controls are optional and are in most cases omitted. The default behaviour, when these controls are omitted, is
to execute function objects from the start of the simulation and to execute them until the simulation finishes.
In fact, the default values are a negative, ridiculously large number160 for timeStart and a ridiculously large
number for timeEnd. Thus, no reasonable simulation will start before the default value of timeStart or run
any longer than the default value of timeEnd. This way, there is no need for conditional statements, a simple
comparison against the current time suffices.
49.4 probes
The function probes saves the values of certain field quantities at specific points in space. Listing 340 shows an
example of the definition of a probes function object.
159 Admittedly, with the use of multi line comments (/* no comment */), the amount of changed characters is four, compared to
one or two when using the enabled flag. Potential savings are minuscule.
160 The source code of the scalar class defines a static variable VGREAT, which is close to the maximum representable floating point
number. VGREAT and similar static variables are frequently used for initialisation of variables.
161 The class regionFunctionObject inherits two pure virtual methods from its base class functionObjecttexttt which it does
This offering is not approved or endorsed by ESI® Group, ESI-OpenCFD® or the OpenFOAM®
VI 304
Foundation, the producer of the OpenFOAM® software and owner of the OpenFOAM® trademark.
This function object is of the type probes. The name of the function object is probes1. The data generated
by this function is stored in the directory probes1. This directory contains a sub-directory. The name of
this sub-directory corresponds to the time at which the simulation is started. This prevents files from being
overwritten in case a simulation is continued at some point in time.
Figure 128 shows the directory tree after a simulation ended. There, the folder probes1 contains a sub-
directory named 0. This is the time the simulation started. The 0 folder contains the files p and U.
The keywords outputControl and outputInterval are optional. They control – as their names suggest –
the way the data is written to the hard drive.
fields contains the names of the fields that are of interest. probeLocations contains a set of points. The
data of a specified field is computed for this locations and written to a file. The name of this file is the fields of
interest. Listing 340 will result in two files. The file p contains the values of the pressure for all locations, the
file U will contain the values of the velocity at all locations.
The function probes is contained in the file libsampling.so. This information can be gained from the
tutorials. See Section 67.3 for more information about how to search the tutorials for specific information.
functions
{
probes1
{
type probes ;
f u n c t i o n O bj e c t L i b s (" libsampling . so ") ;
enabled true ;
outputControl timeStep ;
outp utInterv al 1;
fields
(
p
U
);
prob eLocatio ns
(
( 0.0254 0.0253 0 )
( 0.0508 0.0253 0 )
);
}
}
caseDirectory
0
More time steps
constant
polyMesh
probes1
0
p
U
system
Figure 128: A part of the directory tree after the simulation ended
49.4.1 Pitfalls
Probe location outside the domain
If the probe location is outside of the domain OpenFOAM will issue a warning message and continue with the
simulation.
This offering is not approved or endorsed by ESI® Group, ESI-OpenCFD® or the OpenFOAM®
VI 305
Foundation, the producer of the OpenFOAM® software and owner of the OpenFOAM® trademark.
--> FOAM Warning :
From function findElements :: findElements ( const fvMesh &)
in file probes / probes . C at line 102
Did not find location (0.075 0 0.48) in any cell . Skipping location .
When using moving meshes, add the fixedLocations flag to your probesDict, as shown in Listing 343
below.
fields
(
...
)
prob eLocatio ns
(
...
)
Listing 343: Add the fixedLocations flag to the probesDict when using probes with moving meshes
49.5 fieldAverage
fieldAverage computes time-averaged fields. Listing lst:fieldAverageControlDict shows an example of how this
function is set up.
functions
{
fieldAverage1
{
type fieldAverage ;
This offering is not approved or endorsed by ESI® Group, ESI-OpenCFD® or the OpenFOAM®
VI 306
Foundation, the producer of the OpenFOAM® software and owner of the OpenFOAM® trademark.
f u n c t i o n O bj e c t L i b s ( " l i b f i e l d F u n c t i o n O b j e c t s . so " ) ;
enabled true ;
outputControl outputTime ;
fields
(
Ua
{
mean on ;
prime2Mean off ;
base time ;
}
);
}
}
The fieldAverage function object can be provided with a averaging window size and name to compute a
sliding average. In this case, the resulting averaged field bears the window name as a file name suffix besides
the field name and the suffix Mean. With this feature, multiple averages of a field can be computed. Listing 345
shows two averages of the field U.water.
If no window is specified, fieldAverage computes the average from the start time of the function object. The
resulting field bears the name of the to-be-averaged field and the suffix Mean. If a window size and a window
name is specified, the resulting field’s name is extended with the window name.
49.6 faceSource
49.6.1 Average over a plane
faceSource extracts data from surfaces (faces). Listing 346 shows how the average of a field quantity over a
cutting plane is set up.
functions
{
faceObj1
{
type faceSource ;
f u n c t i o n O bj e c t L i b s (" l i b f i e l d F u n c t i o n O b j e c t s . so ") ;
enabled true ;
outputControl outputTime ;
sampledSurfaceDict
{
// Sampling on triSurface
type cuttingPlane ;
planeType point AndNorma l ;
pointAndNormalDict
{
basePoint ( 0 0 0.3 ) ;
normalVector ( 0 0 1 ) ;
}
interpolate true ;
}
This offering is not approved or endorsed by ESI® Group, ESI-OpenCFD® or the OpenFOAM®
VI 307
Foundation, the producer of the OpenFOAM® software and owner of the OpenFOAM® trademark.
// Operation : areaAverage / sum / we ig ht e dA ve ra g e ...
operation areaAverage ;
fields
(
alpha
);
}
}
functions
{
faceIn
{
type faceSource ;
f u n c t i o n O b j e c t L i b s (" l i b f i e l d F u n c t i o n O b j e c t s . so ") ;
enabled true ;
outputControl timeStep ;
log true ;
valueOutput false ;
source patch ;
sourceName spargerInlet ;
surfaceFormat raw ;
operation sum;
weightField alpha1;
fields
(
phi1
);
}
}
This offering is not approved or endorsed by ESI® Group, ESI-OpenCFD® or the OpenFOAM®
VI 308
Foundation, the producer of the OpenFOAM® software and owner of the OpenFOAM® trademark.
postProcessing
faceObj1
0
faceSource.dat
surface
0.1
phi_patch_outlet.raw
p_patch_outlet.raw
U_patch_outlet.raw
0.2
phi_patch_outlet.raw
p_patch_outlet.raw
U_patch_outlet.raw
49.7 cellSource
The cellSource function object acts on all cells of the mesh or on the cells of a cellZone.
Listing 348 shows the definition of a cellSource function object. In this case, a part of the domain is contained
in the cellZone left. The function object calculates the volume-average value of the volume fraction of air. The
keyword valueOutput is set to the value false and marked as evil by the comment for reasons explained in
Section 49.6.3.
1 functions
2 {
3 a ir Co nt e nt _l ef t
4 {
5 type cellSource ;
6 f u n c t i o n O b j e c t L i b s ( " l i b f i e l d F u n c t i o n O b j e c t s . so " ) ;
7 enabled true ;
8 outputControl timeStep ;
9 log true ;
10 valueOutput false ; // evil
11 source cellZone ;
12 sourceName left ;
13 operation volAverage ;
14
15 fields
16 (
17 alpha . air
18 );
19 }
20 }
49.8 readFields
If we want to post-process a case, which we computed with a custom solver that created custom fields, and the
post-processing involves these custom fields, it is very likely that OpenFOAM will complain of those fields not
being present in the database when we run our post-processing function objects. That’s when readFields comes
into play.
The description in the header files reads:
Reads fields from the time directories and adds them to the mesh database for further post-
processing.
This function object serves the purpose to read specified fields, and add those to the database. Thus, adding
this function object to our post-processing function objects allows us to post-process any custom fields with
OpenFOAM’s standard function objects.
This offering is not approved or endorsed by ESI® Group, ESI-OpenCFD® or the OpenFOAM®
VI 309
Foundation, the producer of the OpenFOAM® software and owner of the OpenFOAM® trademark.
49.9 writeObjects
If we want to post-process fields, that are not written by default, then we can tell OpenFOAM to write specified
fields to disk. The description of the header file for this function object states:
Allows specification of different writing frequency of objects registered to the database.
1 extraInfo
2 {
3 type coded ;
4 f u n c t i o n O b j e c t L i b s ( " l i b u t i l i t y F u n c t i o n O b j e c t s . so " ) ;
5 redirectType average ;
6 code
7 #{
8 const volVectorFie ld & U1 = mesh () . lookupObject < volVectorField >( " U1 " ) ;
9 const volVectorFie ld & U2 = mesh () . lookupObject < volVectorField >( " U2 " ) ;
10 Info << " max U1 = " << max ( mag ( U1 ) ) . value () << " , U2 = " << max ( mag ( U2 ) ) . value () << endl ;
11 const volScalarFie ld & p = mesh () . lookupObject < volScalarField >( " p " ) ;
12 Info << " p min / max = " << min ( p ) . value () << " , " << max ( p ) . value () << endl ;
13 #};
14 }
Using dynamicCode for func tionObje ct extraInfo at line 69 in "/ home / user / OpenFOAM / user -2.1. x /
run / t w o P h a s e E u l e r F o a m / bubbleColumn / system / controlDict :: functions :: extraInfo "
Creating new library in " dynamicCode / average / platforms / li nu x 64 Gc c DP Op t / lib /
l i b a v e r a g e _ 7 3 1 f e d 8 6 8 e d c 5 a 1 d 7 5 9 8 8 8 0 8 6 4 9 a c 8 7 4 c f 0 0 e 0 4 4 . so "
Invoking " wmake -s libso / home / user / OpenFOAM / user -2.1. x / run / t w o P h a s e E u l e r F o a m / bubbleColumn /
dynamicCode / average "
wmak eLnInclu de : linking include files to ./ lnInclude
Making dependency list for source file f u n c t i o n O b j e c t T e m p l a t e . C
Making dependency list for source file F i l t e r F u n c t i o n O b j e c t T e m p l a t e . C
’/ home / user / OpenFOAM / user -2.1. x / run / t w o P h a s e E u l e r F o a m / bubbleColumn / dynamicCode / average /../
platforms / l in ux 6 4G cc D PO pt / lib / l i b a v e r a g e _ 7 3 1 f e d 8 6 8 e d c 5 a 1 d 7 5 9 8 8 8 0 8 6 4 9 a c 8 7 4 c f 0 0 e 0 4 4 . so ’ is
up to date .
Courant Number mean : 1.68517 e -05 max : 0.00363
Max Ur Courant Number = 0.00363
Time = 0.001
org/version2.0.0/
This offering is not approved or endorsed by ESI® Group, ESI-OpenCFD® or the OpenFOAM®
VI 310
Foundation, the producer of the OpenFOAM® software and owner of the OpenFOAM® trademark.
OpenFOAM creates a directory named dynamicCode in the case directory. There, all files related to the
coded functionObject can be found, source files as well as binaries. Figure 130 shows the directory tree after
OpenFOAM compiled the coded functionObject.
caseDirectory
0
constant
polyMesh
dynamicMesh
average
lnInclude
Make
linux64GccDPOpt
platforms
linux64GccDPOpt
libs
system
49.11 wallHeatFlux
The wallHeatFlux function object can be used to determine the wall heat flux. By default, wallHeatFlux
computes the wall heat flux for all patches of the type wall. Alternatively a list of patches can be passed to
the function object using the patches keyword.
This offering is not approved or endorsed by ESI® Group, ESI-OpenCFD® or the OpenFOAM®
VI 311
Foundation, the producer of the OpenFOAM® software and owner of the OpenFOAM® trademark.
16 {
17 wall HeatFlux Bf [ patchi ] = alphaBf [ patchi ]* heBf [ patchi ]. snGrad () ;
18 }
19 }
The wallHeatFlux function object, not only computes the wall heat flux as a field, it also prints the extrema
and the integral-value per patch to the Terminal, and also writes those values into a data file. The integral
value is of course the amount of energy transferred per-patch in terms of Watts.
FoamFile
{
version 2.0;
format ascii ;
class dictionary ;
location " system ";
object functionDict ;
}
// * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * //
functions
{
probes1
{
type probes ;
f u n c t i o n O b j e c t L i b s (" libsampling . so ") ;
dictionary probesDict ;
}
}
Run execFlowFunctionObejcts
execFlowFunctionObjects has to be told, that the functions are defined in a seperate file. By default, the tool
reads the file controlDict. By using the parameter -dict the user can specify an alternative file containing
the function dictionary.
This offering is not approved or endorsed by ESI® Group, ESI-OpenCFD® or the OpenFOAM®
VI 312
Foundation, the producer of the OpenFOAM® software and owner of the OpenFOAM® trademark.
50 sample
sample is a simple post processor. This tool is controlled by the file sampleDict. sample extracts data from
the solution of a specific region. sample can extract data from the following geometric regions:
• from one or several points in space
• along a line
• on a face
sample is usually executed after a simulation has finished.
50.1 Usage
The simplest way to use sample is to call the command sample. In this case sample looks for a file named
sampleDict located in the system directory. With the -dict an alternative file with a different name can be
specified. However, this file has to reside in the system directory.
By default sample operates on all time steps. The option -latestTime can be used to sample only the latest
solution data. The option -time can be used to specify a certain time or a time range to operate on.
Specifying a limited number of time steps to perform sampling on significantly reduces the time needed for
this operation. The disk space used by the data generated by sample is usually in the order of up to a few
megabytes. Therefore saving hard disk space is not an issue when using sample.
50.2 sampleDict
The file sampleDict controls what and where data is to be sampled.
50.2.2 Fields
The fields that are to be sampled are listed in the list fields.
Invalid entries are ignored, without any warning message. In the example of Listing 355 the list of fields
contains the name banana. However, there is no field named banana, so sample will simply ignore this entry –
sample will not issue any warning or error message. Thus, a typo in the sampleDict is not that easy to find.
sample reports no warning but the intended field is not sampled. Always double check the entries in the fields
sub-dictionary for typos, especially when sampling fields with composite names, e.g. U2Mean or U2Prime2Mean.
// Fields to sample .
fields
(
alpha
banana
Ua
Ub
);
This offering is not approved or endorsed by ESI® Group, ESI-OpenCFD® or the OpenFOAM®
VI 313
Foundation, the producer of the OpenFOAM® software and owner of the OpenFOAM® trademark.
50.2.3 Geometric regions
The geometric regions on which sample can operate are
sets A set can contain one or several points or a line. Along a line, points can be distributed in an equidistant
fashion.
surfaces A surface can be defined in several ways. Possible are, among others, cutting planes or iso-surfaces.
50.2.4 Pitfalls
Missing keywords
If the keywords sets and surfaces are missing in sampleDict, sample will run without producing any error mes-
sages or any data. If in Listing 356 the word banana would be replaced by sets and orange by surfaces, sample
would work as expected. If sample is called with a sampleDict like in Listing 356, sample produces no data and
issues no warning.
setFormat raw ;
surfaceFormat vtk ;
formatOptions
{
ensight
{
format ascii ;
}
}
i n t e r p o l a t i o n S c h e m e cellPoint ;
fields
(
p
U
);
banana
(
lineX1
{
type uniform ;
axis distance ;
start (0.0015 0.5027 0.05) ;
end (0.0995 0.5027 0.05) ;
nPoints 20;
}
);
orange
(
);
This offering is not approved or endorsed by ESI® Group, ESI-OpenCFD® or the OpenFOAM®
VI 314
Foundation, the producer of the OpenFOAM® software and owner of the OpenFOAM® trademark.
Sample set lineX0 has zero points .
x,p
0 ,100001
0.00055 ,100001
0.0011 ,100001
0.00165 ,100001
0.0022 ,100001
0.00275 ,100001
...
Listing 358: Sampling the pressure field of a compressible case with a write precision of 6 digits.
Even worse is the result when using only 5 digits. In this case, see Listing 359, OpenFOAM switches to
scientific notation, and is only able to represent the ambient pressure. The small variation of pressure is now
completely lost.
x,p
0 ,1 e +05
0.00055 ,1 e +05
0.0011 ,1 e +05
0.00165 ,1 e +05
0.0022 ,1 e +05
0.00275 ,1 e +05
...
Listing 359: Sampling the pressure field of a compressible case with a write precision of 5 digits.
Using a sufficient number of digits ensures that the pressure variation within the solution domain can be
sampled and processed further.
x,p
0 ,100001.1161
0.00055 ,100001.116
0.0011 ,100001.1153
0.00165 ,100001.1145
0.0022 ,100001.1134
0.00275 ,100001.1123
...
Listing 360: Sampling the pressure field of a compressible case with a write precision of 10 digits.
Choosing a sufficient number of digits seems like really obvious solution. So, when do we run into the
problem of sampling data with an insufficient number of digits? When we run a simulation using the binary
write format for the field data. In this case, the pressure field is written to disk in binary format, with maximum
precision. However, the sampled data will always be written to disk in ascii format. This is when we run into
This offering is not approved or endorsed by ESI® Group, ESI-OpenCFD® or the OpenFOAM®
VI 315
Foundation, the producer of the OpenFOAM® software and owner of the OpenFOAM® trademark.
the troubles discussed in this section. When we simply do not care about the number of digits, because we feel
save by using the binary format.
This offering is not approved or endorsed by ESI® Group, ESI-OpenCFD® or the OpenFOAM®
VI 316
Foundation, the producer of the OpenFOAM® software and owner of the OpenFOAM® trademark.
51 ParaView
ParaView is a graphical post-processor. This program is called by invoking the command paraFoam. paraFoam
is a script that calls ParaView with additional OpenFOAM libraries.
Figure 131: Launching ParaView with OpenFOAM’s reader for OpenFOAM cases.
This offering is not approved or endorsed by ESI® Group, ESI-OpenCFD® or the OpenFOAM®
VI 317
Foundation, the producer of the OpenFOAM® software and owner of the OpenFOAM® trademark.
Decomposed cases
One major advantage of the native reader is, that it is fully parallelized. Thus, we can post-process decomposed
cases without prior reconstruction of the case. Thus, we can avoid the duplication of data when post-processing
an ongoing case. Figure 132 shows a screenshot, when opening a case-file for the native reader. In the properties
panel on the left, there is a drop-down menu, which shows the setting Reconstructed Case in Figure 132. This
setting can be changed to Decomposed Case, in order to read the parallelized case data.
The native ParaView reader is considered to potentially encounter problems with complex dictionary input.
Figure 132: Launching ParaView with its native reader for OpenFOAM cases.
Multi-region cases
Another neat feature of the native reader is that it recognizes multi-region cases. Thus, by simply opening a
*.foam file, the reader automatically reads-in the individual regions of the case. See Figure 133 for an example.
Figure 133: Using ParaView with its native reader to read a multi-region OpenFOAM case.
This offering is not approved or endorsed by ESI® Group, ESI-OpenCFD® or the OpenFOAM®
VI 318
Foundation, the producer of the OpenFOAM® software and owner of the OpenFOAM® trademark.
Pitfall: decomposed multi-region cases with constant/polyMesh still being present
One instance, the native reader struggles is when the mesh of a multi-region case has been created from a
single-region mesh, and the initial mesh is still around. When such a case is decomposed, then the native
reader will encounter the initial single-region mesh and the individual region-meshes in the constant directory,
however, in the processor* directories, only the region-meshes are present.
In Listing 134 shows the directories of a case that triggers the problem described above. The mesh of this
case has been created by subsequent execution of blockMesh, topoSet and splitMeshRegions; which created
the initial mesh, created cellZones and split the mesh into regions according to the cellZones. Since there is no
way to decompose both the initial mesh and the region-meshes, which would by the way make no sense at all,
we need to remove the initial mesh in constant/polyMesh for the native reader to work properly.
.
0.org
heater
region1
constant
heater
polyMesh
polyMesh
region1
polyMesh
processor0
constant
heater
region1
processor1
constant
heater
region1
system
heater
region1
Figure 134: The case directories of a decomposed, multi-region case with the initial mesh still present. This
directory tree was generated by calling the following command from the case directory: tree -L 3 -d
This offering is not approved or endorsed by ESI® Group, ESI-OpenCFD® or the OpenFOAM®
VI 319
Foundation, the producer of the OpenFOAM® software and owner of the OpenFOAM® trademark.
Figure 135: Select the proper representation to view the mesh
If we want to correctly display the mesh, we need to check the box labelled Use VTK Polyhedron in the
properties panel. In Figure 131, this is the second box from the top. If we check this box, and read the case,
or check this box and refresh ParaView’s state by clicking on the Apply button, the displayed mesh changes to
the representation shown in Figure 137. Now we can clearly see the polyhedral cell shapes.
This offering is not approved or endorsed by ESI® Group, ESI-OpenCFD® or the OpenFOAM®
VI 320
Foundation, the producer of the OpenFOAM® software and owner of the OpenFOAM® trademark.
Figure 137: Viewing a polyhedral mesh with adjusted settings.
Figure 138: Viewing a polyhedral mesh with ParaView’s native OpenFOAM reader.
file : / home / user / OpenFOAM / user -2.1. x / run / icoFoam / case01 /0/ p :: boundaryField from line 25 to
line 35.
This offering is not approved or endorsed by ESI® Group, ESI-OpenCFD® or the OpenFOAM®
VI 321
Foundation, the producer of the OpenFOAM® software and owner of the OpenFOAM® trademark.
FOAM exiting
Using FFmpeg
In this example we use FFmpeg, which is a widely available, open source multimedia library. See https:
//en.wikipedia.org/wiki/FFmpeg and https://ffmpeg.org for more information. Listing 363 shows an
example of how an animation can be created from the individual images saved by ParaView. Here, we assume
that we saved our view under the file name velField.png, ParaView then automatically inserts sequential
167 ParaView appears to support only the OGV format, at least with the tested versions 5.4.0 and 5.6.0. For the OGV format, see
This offering is not approved or endorsed by ESI® Group, ESI-OpenCFD® or the OpenFOAM®
VI 322
Foundation, the producer of the OpenFOAM® software and owner of the OpenFOAM® trademark.
numbering. In the call to FFmpeg, we specify a frame rate in frames per second using the -r command line
argument.
With the command line argument -i we specify the input for our animation. Here, we use the file name
we used earlier to save the individual frames, however, we account for the sequential numbering by inserting a
place-holder, i.e. %04d, which stands for a zero-padded integer with a fixed width of 4 characters. FFmpeg will
insert sequential numbers starting from 0.
If we wanted to start our animation from a frame other than the one named velField.0000.png, we can
provide an alternative starting number with the command line argument -start_number.
The last argument of the command in Listing 363 is the name of the resulting video file.
This offering is not approved or endorsed by ESI® Group, ESI-OpenCFD® or the OpenFOAM®
VI 323
Foundation, the producer of the OpenFOAM® software and owner of the OpenFOAM® trademark.
Figure 141: Left: an extruded mesh created from an STL surface mesh. Right: the mesh after tetrahedralisation.
Export VTK
Exporting the tetrahedralized mesh in the VTK format can simply be done in ParaView by selecting the
Tetrahedralize item in the Model Tree and using the Save Data command of the File menu, i.e. select File
Save Data in the menu bar of ParaView. The subsequent dialogue will ask for a format and a file name.
After we have provided a file name and selected the VTK format, we are asked in a subsequent step whether
to write time steps; whether to write the file in ASCII or binary format; and whether to compress the exported
files.
Figure 142: Exporting data from ParaView using the Save Data command from the File menu.
ParaView will export a couple of files from the tetrahedralized mesh. A VTK Multi Block File is written to
the case directory, which is basically a manifest of the other exported files. These files are written into an export-
folder, which has the same name as the Multi Block File with the exception of the file extension. Within this
folder, the other files are written, which contain the volume mesh as well as the patches. In the example shown
in Listing 364 the file exportedVTK_0_0.vtu contains the volume mesh, and the other files contain a patch each.
user@host :∼/ OpenFOAM / user -7/ run / meshing / m e s h M a n i p u l a t i o n $ cat exportedVTK . vtm
< VTKFile type = " v t k M u l t i B l o c k D a t a S e t " version = " 1.0 " byte_order = " LittleEndian " header_type = "
UInt64 " >
< vtkMultiBlockDataSet >
< Block index = " 0 " name = " unzoned " >
< DataSet index = " 0 " name = " internalMesh " file = " exportedVTK / ex po rt ed V TK _0 _0 . vtu " / >
</ Block >
< Block index = " 1 " name = " patches " >
< DataSet index = " 0 " name = " sides " file = " exportedVTK / e xp or te d VT K_ 1_ 0 . vtu " / >
< DataSet index = " 1 " name = " originalPatch " file = " exportedVTK / ex po r te dV TK _ 2_ 0 . vtu " / >
< DataSet index = " 2 " name = " otherSide " file = " exportedVTK / ex p or te dV T K_ 3_ 0 . vtu " / >
</ Block >
</ vtkMultiBlockDataSet >
This offering is not approved or endorsed by ESI® Group, ESI-OpenCFD® or the OpenFOAM®
VI 324
Foundation, the producer of the OpenFOAM® software and owner of the OpenFOAM® trademark.
< FieldData >
< DataArray type = " Float64 " Name = " TimeValue " Number OfTuples = " 1 " format = " ascii " RangeMin = " 0 "
RangeMax = " 0 " >
0
</ DataArray >
</ FieldData >
</ VTKFile >
user@host :∼/ OpenFOAM / user -7/ run / meshing / m e s h M a n i p u l a t i o n $ ls exportedVTK
e xp or te d VT K_ 0_ 0 . vtu ex p or te dV T K_ 1_ 0 . vtu ex p or te dV T K_ 2_ 0 . vtu ex p or te dV TK _ 3_ 0 . vtu
user@host :∼/ OpenFOAM / user -7/ run / meshing / m e s h M a n i p u l a t i o n $
Listing 364: The content of the VTK Multi Block File viewed in the Terminal; and the files written into the
export-folder.
Legacy VTK
If we wanted to use the Legacy VTK format for our exported mesh, we need to open the exported file containing
the internal mesh with ParaView again. In our case, we need to open the file exportedVTK_0_0.vtu from the
export folder. This data is then again exported using the Save Data command from the File menu. Now that
we are dealing with pure VTK data, we can select to write the data in the Legacy VTK format.
Figure 143: Export data from ParaView in the Legacy VTK format.
This offering is not approved or endorsed by ESI® Group, ESI-OpenCFD® or the OpenFOAM®
VI 325
Foundation, the producer of the OpenFOAM® software and owner of the OpenFOAM® trademark.
52 postProcess
With OpenFOAM-4.0 the function object framework was rewritten. In the course of this rewrite a postProcess
utility was introduced and a postProcess option was added to most of the solvers168 . The postProcess utility
also supersedes certain post-processing utilities, e.g. sample.
52.1 Usage
52.1.1 Pre-configured function objects
There are a number of pre-configured function objects, which are ready to use with postProcess. These
can be found in $FOAM_ETC/caseDicts/postProcessing. They can also be listed using the -list option of
postProcess.
user@host :∼$ postProcess - fields ’( U . air U . water ) ’ - func " m in Ma xM a gn it ud e ( U . air , U . water ) "
user@host :∼$ postProcess - fields ’( U . air ) ’ - func " m in Ma xM a gn it ud e ( U . air , location = off ) "
Listing 368: Determine the extrema by magnitude of a velocity field with no location
After running our function objects, we see that data was written into the postProcessing directory. We note
that the folder names correspond to the argument passed via the -func option.
Listing 369: The contents of the postProcessing directory after running two function objects from the above
listings
which 73 included the postProcess.H header file, which provided the postProcess option. The second number was determined with
the following command: find $FOAM_SOLVERS -name ’*.C’ | xargs grep ’\#include[[:space:]]\"postProcess.H\"’ | wc.
This offering is not approved or endorsed by ESI® Group, ESI-OpenCFD® or the OpenFOAM®
VI 326
Foundation, the producer of the OpenFOAM® software and owner of the OpenFOAM® trademark.
Part VII
External Tools
Besides paraView, there are a number of other useful tools, which do not come from the OpenFOAM Foundation.
This section will cover such tools.
This offering is not approved or endorsed by ESI® Group, ESI-OpenCFD® or the OpenFOAM®
VII 327
Foundation, the producer of the OpenFOAM® software and owner of the OpenFOAM® trademark.
53 pyFoam
pyFoam is a collection of useful Python169 scripts. These scripts are mostly written to serve one specific task.
Further information can be found at http://openfoamwiki.net/index.php/Contrib_PyFoam.
53.1 Installation
The installation of pyFoam is described at http://openfoamwiki.net/index.php/Contrib_PyFoam#Installation.
The major prerequisite for the use of pyFoam is, that a Python interpreter is installed. To check if a Python
interpreter is installed on the system, simply type python --version in the Terminal. If a version number is
displayed, like Python 2.7.3, then Python is installed. Otherwise, the operating system would display an error
message, stating that the command python can not be found.
Further information about Python are found at http://python.org/ and http://docs.python.org/.
53.2 pyFoamPlotRunner
The script pyFoamPlotRunner starts a simulation and plots the residuals like Fluent would do.
What to plot
------------
Predefined quantities that the program looks for and plots
--no - default Switch off the default plots ( linear , continuity and
bound )
--no - linear Don ’ t plot the linear solver convergence
--no - continuity Don ’ t plot the continuity info
--no - bound Don ’ t plot the bounding of variables
-- with - iterations Plot the number of iterations of the linear solver
-- with - courant Plot the courant - numbers of the flow
-- with - execution Plot the execution time of each time - step
-- with - deltat ’ Plot the timestep - size time - step
-- with - all Switch all possible plots on
53.3 pyFoamPlotWatcher
The script pyFoamPlotWatcher is intended to visualize solution data (e.g. residuals, time steps, Courant number,
etc.) after the simulation has finished. This requires that the solver output is written into a file, see Section
12.1.1. pyFoamPlotWatcher does essentially the same job as pyFoamPlotRunner with the difference that the
former tool is for finished simulations and the latter monitors a running simulation. So the description of the
features of pyFoamPlotWatcher holds also true for pyFoamPlotRunner.
user@host :∼/ OpenFOAM / user -2.1. x / run / t w o P h a s e E u l e r F o a m / columnCase$ p y F o a m P l o t W a t c h e r . py LOGFILE
By default pyFoamPlotWatcher plots the curves of the residuals, continuity information and bounded vari-
ables. With options several other curves can be plotted (e.g. time step, iterations, Courant number, etc.). With
regular expressions user specified data can be extracted from the log file.
169 Python is an interpreted programming language.
This offering is not approved or endorsed by ESI® Group, ESI-OpenCFD® or the OpenFOAM®
VII 328
Foundation, the producer of the OpenFOAM® software and owner of the OpenFOAM® trademark.
Listing 374 shows the invokation of pyFoamPlotWatcher to plot additionally to the default selection also the
Courant number. The processing of the solver output stored in the file LOGFILE is limited with the option --end
with a specific value – 0.1 s in this case. There is also a --start option. The plot created by the command in
Listing 374 is shown in Figure 144.
General information
pyFoamPlotWatcher has no option to display the history of the Courant number based on Ur, the relative velocity
between the phases. Listing 375 shows some lines of the solver output of the two-phase solver twoPhaseEuler-
Foam. The line in red displays the Courant number based on the relative velocity Ur. The line above the
red colored line displays the Courant number based on the mixture velocity, see Section 57.6.4 and 57.6.4
for information on the definition of the Courant number and the Courant number of the two-phase solver
twoPhaseEulerFoam.
DILUPBiCG : Solving for k , Initial residual = 0.000824921 , Final residual = 1.47595 e -06 , No
Iterations 2
ExecutionTime = 70870.7 s ClockTime = 71186 s
Calculating averages
This offering is not approved or endorsed by ESI® Group, ESI-OpenCFD® or the OpenFOAM®
VII 329
Foundation, the producer of the OpenFOAM® software and owner of the OpenFOAM® trademark.
Extracting the information
To extract the information from the log file we need to create a file containing the regular expression.
{" expr ":" Max Ur Courant Number = (% f %) " ," name ":" UrCoNum "}
If pyFoamPlotWatcher finds a file named customRegexp in the case directory, this file will be processed
automatically. If the file containing the regular expression has another name or is located inanother place the
option --regexp-file=REG_EXP_FILE can be used to specify the path to that file.
Listing 376 contains comma seperated entries ("expr" and "name"). The values are seperated by a colon
from the name of the entries (e.g. "name":"UrCoNum"). The first entry contains the regular expression to
extract the data. The second provides the name of the extracted data, but this entry can be omitted.
Figure 145: The Courant number based on the relative velocity plotted with pyFoamPlotWatcher
The absurdly high value of the Courant number indicates that the simulation did not go well. The need
for plotting the Courant number based on Ur emanated from a trouble-shooting episode. Thus this section was
written to preserve the gained knowledge.
DILUPBiCG : Solving for beta , Initial residual = 0.000307666 , Final residual = 7.36162 e -08 , No
Iterations 2
DILUPBiCG : Solving for T , Initial residual = 0.000514273 , Final residual = 2.57279 e -07 , No
Iterations 1
Concentration = 0.0509085 Min T = 0.00498731 Max T = 0.218343
Bubble load = 0.00623198 Min beta = 0 Max beta = 0.0677904
Time = 19.96
This offering is not approved or endorsed by ESI® Group, ESI-OpenCFD® or the OpenFOAM®
VII 330
Foundation, the producer of the OpenFOAM® software and owner of the OpenFOAM® trademark.
{" expr ":" Concentration = (% f %) Min T = (% f %) Max T = (% f %) " ," name ":" Concentration " ," titles
":[" avg " ," min " ," max "]}
Custom01
{
accumulation first ;
enabled yes ;
expr " Concentration = (% f %) Min T = (% f %) Max T = (% f %) ";
name C u s t o m 0 1 _ C o n c e n t r a t i o n ;
persist no ;
raisit no ;
theTitle " Custom 1 - Concentration ";
titles
(
avg
min
max
);
type regular ;
with lines ;
xlabel " Time [ s ]";
}
Time = 19.9957
Listing 381: The regular expression to extract the information about the volume fraction
Not only the parentheses have a special meaning in regular expressions. An internet search170 or detailed
knowledge on regular expressions will yield the knowledge which characters have to be escaped.
This offering is not approved or endorsed by ESI® Group, ESI-OpenCFD® or the OpenFOAM®
VII 331
Foundation, the producer of the OpenFOAM® software and owner of the OpenFOAM® trademark.
– we could also delete parts of the expression since we are only interested in the first number – but if we are
interested in the first and the third number, then we need to ignore the second number.
0.02
0.015
0.01
0.005
0
0 2 4 6 8 10 12 14 16 18 20
Time [s]
Figure 146: The average volume fraction plotted with pyFoamPlotWatcher and a custom regular expression
Figure 147: The execution time plotted over time with pyFoamPlotWatcher. The occasional writing of the data
to harddisk are clearly visible as spikes in the execution time.
This offering is not approved or endorsed by ESI® Group, ESI-OpenCFD® or the OpenFOAM®
VII 332
Foundation, the producer of the OpenFOAM® software and owner of the OpenFOAM® trademark.
53.4 pyFoamClearCase
As the name implies, pyFoamClearCase cleans the case directory. This script deletes all time directories save
the 0 directory. By the use of command line options, a finer control of the actions of pyFoamClearCase is
possible. Some of these options are:
–keep-last keep the last time step
–keep-regular keep all time steps
–after=T delete all time steps for t > T
–remove-processor delete the processor* directories
The script is invoked by typing its name in the Terminal. Listing 382 shows how this script is executed. The
options cause pyFoamClearCase to keep the last time directory and to remove all processor* folders.
Note the file ending .py after the name of the script. This ending indicates, that the script is written in Python.
It also indicates, that pyFoamClearCase is an executable script rather than a program on its own.
53.5 pyFoamCloneCase
This script is used to copy a case. By default the 0, the constant and the system directory are copied. Addi-
tionally, there are various command line arguments to control the operation of the script, e.g. copy also the
latest time step or the processor* directories.
53.6 pyFoamDecompose
This script is used to decompose the computational domain. Other than the tool decomposePar, this script
does not need an existing decomposeParDict. This script receives command line arguments, generates the
decomposeParDict and calls decomposePar.
In Listing 383 the script is called with two arguments. The first argument is the path to the case directory.
In this case the dot refers to the currect directory. The second argument is the number of sub-domains. From
this arguments, pyFoamDecompose creates a decomposeParDict. The first argument is necessary to tell the
script where to save the newly created file. The second argument is the most fundamental information for
domain decomposition – the number of sub-domains.
There is a large number of additional arguments which allow to exert more control over the way the domain
is decomposed.
p yF oa mD e co mp os e . py . 4
Listing 384 contains the decomposeParDict created by the command of Listing 383.
// * * * * * * * * * //
FoamFile
{
version 0.5;
format ascii ;
root " ROOT " ;
case " CASE " ;
class dictionary ;
object nix ;
}
method scotch ;
n u m b e r O f S u b d o m a i n s 4;
scotchCoeffs
This offering is not approved or endorsed by ESI® Group, ESI-OpenCFD® or the OpenFOAM®
VII 333
Foundation, the producer of the OpenFOAM® software and owner of the OpenFOAM® trademark.
{
}
53.7 pyFoamDisplayBlockMesh
If there is a problem with mesh topology and one isn’t able to find the error in the blockMeshDict, this tool
can be of great help. pyFoamDisplayBlockMesh does exactly what the name of the tool suggests. It reads
blockMeshDict and displays the topology of the mesh. One might think, that that’s exactly what is described in
Section 15.6.2 (display the blocks with paraView). However, if the definition of the mesh is erroneous, blockMesh
will not create a mesh and paraView is therefore not able to display the blocks.
pyFoamDisplayBlockMesh is a tool that allows the user to visualise a faulty mesh. This is of great help
to find e.g. an error in the block definition, especially when there are more than one blocks. In Figure 148 a
screenshot of the GUI of this tool is shown. In the main panel the vertices and the edges are displayed. With
the two sliders below single blocks as well as patches can be marked and coloured. The local axes of a single
block are displayed as tubes labelled with the corresponding names of the axes.
The blocks shown in Figure 148 have a faulty definition, so blockMesh produces an error message instead of
creating a mesh. With the help of this tool, the cause for the error is easily found. The marked block should
be in the right part of the geometry, so vertex number 5 should not be part of this block.
Right of the main panel the output of the standard meshing utilities blockMesh and checkMesh can be
displayed (not shown in the picture). These utilities can be executed from the menu of this tool. Moreover, the
blockMeshDict can be edited with this tool.
53.8 pyFoamCaseReport
The tool pyFoamCaseReport generates a summary of the simulation case. The amount of information displayed
can be controlled by command line flags. Listing 385 shows how to create a full summary of a case. However,
the full information lies within the dictionaries of the case. This tool provides only selected information.
This offering is not approved or endorsed by ESI® Group, ESI-OpenCFD® or the OpenFOAM®
VII 334
Foundation, the producer of the OpenFOAM® software and owner of the OpenFOAM® trademark.
p y F o a m C a s e R ep o r t . py -- full - report .
This offering is not approved or endorsed by ESI® Group, ESI-OpenCFD® or the OpenFOAM®
VII 335
Foundation, the producer of the OpenFOAM® software and owner of the OpenFOAM® trademark.
54 swak4foam
The name swak4foam comes from SWiss Army Knife for Foam. swak4foam evolved from a collection of tools
like groovyBC, funkySetFields and simpleFunctionObjects. The documentation of swak4foam is located at http:
//openfoamwiki.net/index.php/Contrib/swak4Foam.
54.1 Installation
To install swak4foam one needs to download the source code and compile them. The source code of swak4foam
is managed by the use of a subversion 171 repository. Listing 386 shows how the source code is downloaded
by subversion. The first command changes the working directory of the terminal to ~/OpenFOAM. The second
command creates a directory named swak4foam. The third command changes the working directory of the
terminal to the newly created folder and the last commands actually downloads the source code to the current
directory.
cd ∼/ OpenFOAM
mkdir swak4foam
cd swak4foam
svn checkout https :// openfoam - extend . svn . sourceforge . net / svnroot / openfoam - extend / trunk /
Breeder_2 .0/ libraries / swak4Foam /
54.2 simpleSwakFunctionObjects
simpleSwakFunctionObjects is an extension of simpleFunctionObjects. The functions of this library are used to
post process data and extend functionality of OpenFOAM.
DILUPBiCG : Solving for alpha , Initial residual = 3.48391 e -05 , Final residual = 2.94111 e -12 ,
No Iterations 2
Dispersed phase volume fraction = 0.00824276 Min ( alpha ) = -1.66816 e -19 Max ( alpha ) = 0.6
DILUPBiCG : Solving for alpha , Initial residual = 3.71563 e -07 , Final residual = 8.16115 e -14 ,
No Iterations 2
Dispersed phase volume fraction = 0.00824276 Min ( alpha ) = -3.31819 e -19 Max ( alpha ) = 0.6
swakExpression
The function to do the job is called swakExpression. This function is part of the library libsimpleSwakFunc-
tionObjects. Listing 388 shows how this function is set up as a function object in the file controlDict. In this
example the minimal value of the field alpha is saved. Notice the statement in last line of the Listing. This
statement tells the solver to use the specified library. This library contains the function swakExpression. See
Section 11.3.3 for further information about using external libraries.
171 subversion, abbreviated SVN, is a version control software to manage software projects.
This offering is not approved or endorsed by ESI® Group, ESI-OpenCFD® or the OpenFOAM®
VII 336
Foundation, the producer of the OpenFOAM® software and owner of the OpenFOAM® trademark.
functions
{
minAlpha
{
type swakExpr ession ;
verbose true ;
accumulations ( min ) ;
valueType internalField ;
expression " min ( alpha ) ";
}
}
Keywords
This section explains the most important keywords of Listing 388.
172 http://www.cfd-online.com/Forums/openfoam/103504-swak4foam-calculating-velocity-transformations.html
This offering is not approved or endorsed by ESI® Group, ESI-OpenCFD® or the OpenFOAM®
VII 337
Foundation, the producer of the OpenFOAM® software and owner of the OpenFOAM® trademark.
55 blockMeshDG
blockMeshDG is a modification of the meshing tool blockMesh to allow for double grading. Double grading
means, that the ratio between the discretisation length of the middle and the ends of an edge is prescribed.
This tool was developed by some users of OpenFOAM and is was published in the CFD-Online OpenFOAM
Forum (http://www.cfd-online.com/Forums/openfoam/70798-blockmesh-double-grading.html). There
is also a page in the OpenFOAM Wiki (http://openfoamwiki.net/index.php/Contrib_blockMeshDG).
Notice
This topic is outdated, as blockMesh of standard OpenFOAM already includes a feature for the discussed
purpose. This was introduced with OpenFOAM-3.0173 .
55.1 Installation
The downloaded source code is ready for compilation after unpacking. All necessary entries have already been
made to prevent the new utility to collide with the standard utilities of OpenFOAM. The make script creates
an executable named blockMeshDG.
55.2 Usage
To discern between normal grading and double grading, the expansion ratio needs to be negative for double
grading174 . A positive entry causes normal grading to be applied just like it is the case with the standard utility.
55.3 Pitfalls
55.3.1 Uneven number of cells
blockMeshDG obviously has a problem with an uneven number of cells. Figure 149 shows the resulting mesh,
when 15 cells are used for the double graded edge. In this case, although the mesh is of bad quality, checkMesh
reports no error. However, the output of checkMesh contains some indications that something is not alright.
Listing 389 shows some lines of the output of checkMesh. The very high aspect ratio is an indicator that
something is wrong with the mesh. Also the fact that the minimum and maximum values of face area or cell
volume differ by up to three orders of magnitude should lead to the same conclusion. Unfortunately, checkMesh
issues not even a warning message.
So far, the only solution to this problem is to use an even number of cells.
173 https://openfoam.org/release/3-0-0/
174 A negative entry unequal to unity causes blockMesh to crash with a floating point exception. Therefore, using negative entries
This offering is not approved or endorsed by ESI® Group, ESI-OpenCFD® or the OpenFOAM®
VII 338
Foundation, the producer of the OpenFOAM® software and owner of the OpenFOAM® trademark.
Figure 149: Double grading problem
This offering is not approved or endorsed by ESI® Group, ESI-OpenCFD® or the OpenFOAM®
VII 339
Foundation, the producer of the OpenFOAM® software and owner of the OpenFOAM® trademark.
Part VIII
Source Code & Programming
56 Understanding some C and C++
In this Section some features of the C++ programming language are discussed.
1 namespace Foam
2 {
3
4 class phaseModel ;
5
6 class phas eInterfa ce
7 {
8 // lots of C ++ code
9 };
10
11 }
56.2 Namespaces
Namespaces are a feature of C++ to support a logical structure within the program. The basic idea behind
namespaces put in simple words is to keep things (variables and functions) visible where they need to be visible.
Like any other method of keeping things neat and tidy you could also survive without namespaces. However,
to loosely quote Prof. Jasak, one of the founders of OpenFOAM: OpenFOAM is an example of how to make
proper use of C++. Therefore, we have a closer look on namespaces in OpenFOAM.
General information about the concept of namespaces can be found here:
• http://www.cplusplus.com/doc/tutorial/namespaces/
• http://www.cprogramming.com/tutorial/namespaces.html
• http://www.learncpp.com/cpp-tutorial/711-namespaces/
Some OpenFOAM specific aspects related to namespaces are discussed in Section 57.2.
This offering is not approved or endorsed by ESI® Group, ESI-OpenCFD® or the OpenFOAM®
VIII 340
Foundation, the producer of the OpenFOAM® software and owner of the OpenFOAM® trademark.
56.3 const correctness
The const keyword has several uses and using const has some implications.
std :: cout << " The pointer points to " << * pointer << std :: endl ;
std :: cout << " The pointer points to " << * pointer << std :: endl ;
std :: cout << " The pointer points to " << * pointer << std :: endl ;
A constant pointer
A pointer can be constant regardless of the variable it points to. So, the address stored in the pointer can not
be changed, the pointer will always point to the same variable. However, the variable itself can be altered.
Listing 394 shows an example.
std :: cout << " The constant pointer points to " << * constPointer1 << std :: endl ;
variable = 79;
std :: cout << " The constant pointer points to " << * constPointer1 << std :: endl ;
This offering is not approved or endorsed by ESI® Group, ESI-OpenCFD® or the OpenFOAM®
VIII 341
Foundation, the producer of the OpenFOAM® software and owner of the OpenFOAM® trademark.
The constant pointer points to 11
The constant pointer points to 79
The use of the inline statement does not guarantee that the compiler replaces the function call. This depends
on the compiler and the compiler settings.
This offering is not approved or endorsed by ESI® Group, ESI-OpenCFD® or the OpenFOAM®
VIII 342
Foundation, the producer of the OpenFOAM® software and owner of the OpenFOAM® trademark.
OpenFOAM specifics
The OpenFOAM Code Style Guide (http://www.openfoam.org/contrib/code-style.php) demands from
programmers to seperate the definition of inline and non-inline functions.
1 class Point
2 {
3 int xPos ;
4 int yPos ;
5
6 public :
7 Point ()
8 {
9 /* constructor code */
10 xPos = 0;
11 yPos = 0;
12 }
13 Point ( int x , int y )
14 {
15 xPos = x ;
16 yPos = y ;
17 }
18 };
ming. The term function is also used in procedural programming and does not automatically indicate the use of OOP.
This offering is not approved or endorsed by ESI® Group, ESI-OpenCFD® or the OpenFOAM®
VIII 343
Foundation, the producer of the OpenFOAM® software and owner of the OpenFOAM® trademark.
Listing 400 demonstrates hot to create new variables of the type Point. The first line creates a variable of
the type Point. Because no arguments are passed in this line, the first constructor of Listing 399 is called by
the compiler.
The second line creates also a point. The numbers inside the parenthesis are passed to the constructor.
Therefore the second constructor of Listing 399 is called and the member variables are initialised based on the
arguments.
1 Point p1 ;
2 Point p2 (3 , 8) ;
56.5.2 Copy-Constructor
The copy constructor is used to create a copy of an object. The C++ compiler will create a default copy con-
structor if the programmer does not write one. However, the default copy constructor has restrictions regarding
the handling of complex classes.
1 class Point
2 {
3 private :
4 Point ( Point & p ) ;
5 };
1 class tu rb ul e nc eM od el
2 :
3 public regIOobject
4 {
5 private :
6 // Private Member Functions
7
8 // - Disallow default bitwise copy construct
9 t ur bu le n ce Mo de l ( const tu r bu le nc e Mo de l &) ;
10
11 /* code continues */
This offering is not approved or endorsed by ESI® Group, ESI-OpenCFD® or the OpenFOAM®
VIII 344
Foundation, the producer of the OpenFOAM® software and owner of the OpenFOAM® trademark.
56.5.3 Initialisation list
A class in C++ can have member variables of any type. Complex classes may need some kind of initialisation
to ensure all variables have a defined state. When an instance of a class is created by the constructor, the
initialisation list contains all statements to initialise member variables of the class.
Listing 404 shows a simple example of a constructor with an initialisation list. Listing 509 in Section 62.2.2
shows an usage example of an initialisation list in the OpenFOAM sources.
1 class Rectangle
2 {
3 Point topLeft ;
4 Point bottomRight ;
5
6 public :
7 Rectangle ()
8 {
9 topLeft = Point () ;
10 bottomRight = Point () ;
11 }
12
13 Rectangle ( Point a , Point b )
14 :
15 topLeft ( a ) ,
16 bottomRight ( b )
17 {
18 /* constructor code */
19 }
20 }
56.7 Templates
OpenFOAM makes heavy176 , clever use of templates. Templates are a language feature of C++ that allow for
generic programming. An illustrative example for the use of templates in programming is the implementation
of container classes, e.g. linked lists. Without the use templates, the multiplicity of possible container contents
would force us to implement a vast number of specialized classes, e.g. nodeList, faceList and cellList for
lists of nodes, faces and cells.
Such a problem could be solved by the use of multiple inheritance. This way, we would need to implement
one base class for a list. The specialized classes would then inherit from the base list class and from the class
of the intended content. This solution, however, has several disadvantages [5]. As complexity grows, the path
via multiple inheritance is doomed to become a problem in its own, instead of alleviating or solving the original
problem.
Templates offer us a way to tell a class: use the type T, which can be any type the compiler allows. Thus,
we create one templated container class. Later, when we need to create lists of nodes, faces and cells, we tell
the compiler to substitute T for the concrete types. The compiler then generates the appropriate code. Checks
done by the compiler ensure, that specializing a valid templated class produces little to no surprises.
Listing 405 shows the use of templates. We first implement a generic list. Later, we specialize this list for
the types of nodes, faces and cells. The typedef instruction allows us to define a convenient name. Once this
names are defined, we may even stop being aware that we are using a templated class.
176 The command find $FOAM_SRC -name ’*.[CH]’ | xargs grep ’template’ | wc yields – at the time of writing – 24646 occu-
rances of the word template in $FOAM_SRC. This makes 12323 occurances within the source code itself – remember the presence and
the use of the lnInclude directories.
This offering is not approved or endorsed by ESI® Group, ESI-OpenCFD® or the OpenFOAM®
VIII 345
Foundation, the producer of the OpenFOAM® software and owner of the OpenFOAM® trademark.
template < class T >
class list
{
// define a list of type T
}
OpenFOAM follows a similar strategy, who would guess from the top-level code, that volScalarField is in
fact a templated class with three template parameters, see Listing reflst:volScalarField. Besides being a more
convenient name177 we also save a lot of typing effort due to the shorter name178 . The use of type definitions
– typedef statements – is not mere convencience. Using the full specialisation of GeometricField instead
of volScalarField translates to hardcoding. If the developers of OpenFOAM, at some point, decide to base
volScalarField on the class smartScalar instead of scalar, only one line of code needs to be changed instead
of thousands. Thus, the use of typedefs strongs supports code readability and maintainability [5].
177 volScalarField field carries roughly the same essential information as GeometricField<scalar, fvPatchField, volMesh>.
178 We count 15 versus 46 characters. At the time of writing, with the command find $FOAM_SRC -name ’*.[CH]’ | xargs grep
’volScalarField’ | wc we count 8752 occurances of volScalarField in the source code of OpenFOAM-dev at the time of writing.
This leads to an estimated 4376 occurances in the code itself.
This offering is not approved or endorsed by ESI® Group, ESI-OpenCFD® or the OpenFOAM®
VIII 346
Foundation, the producer of the OpenFOAM® software and owner of the OpenFOAM® trademark.
57 Under the hood of OpenFOAM
This section contains short code examples that in some way explain the behaviour of OpenFOAM in certain
situations. All examples in this section are motivated by other parts of this manual. In some cases the source
code of some applications is examined somewhere else.
57.2 Namespaces
57.2.1 Constants
Physics is full of constants. Therefore it would be nice to have a central location in which physical or mathe-
matical constants are defined. OpenFOAM provides constants within the namespace Foam::constant. There
the pre-defined constants are divided into the groups, such as
• electromagnetic
• physicoChemical
• mathematical
– pi - π
– e - the Euler number
In Listing 407 it is demonstrated how to access the constant pi within the source code. Listing 408 shows all
the mathematical constants defined in OpenFOAM-2.2.x. From a computational performance point of view it
makes perfect sense to pre-define often used constants such as two pi. Also note that instead of diving pi by 2.0
it is multiplied with 0.5. Mathematically these operations are equivalent, however, in terms of computational
cost the floating point multiplication is to be preferred over the floating point division as it is much faster [1].
Also note that OpenFOAM does not define e and π on its own, it rather uses the constants provided by the
system library. See e.g. http://www.gnu.org/software/libc/manual/html_node/Mathematical-Constants.
html for the mathematical constants provided by the GNU C library (glibc). Thus e and pi are defined by
accessing M_E and M_PI.
Further note that the constants are declared with the const specifier, which is the only sane way to define
constants in C and C++.
Listing 407: A useless code example demonstrating the access to π with OpenFOAM’s source code
In the FOAM-extend the access to e.g. the mathematical constants works the same way. Only the namespace
is named mathematicalConstants instead of constant::mathematical. This is due to the fact that FOAM-
extend is largely based on OpenFOAM-1.6.
This offering is not approved or endorsed by ESI® Group, ESI-OpenCFD® or the OpenFOAM®
VIII 347
Foundation, the producer of the OpenFOAM® software and owner of the OpenFOAM® trademark.
57.3 Keyword lookup from dictionary
There are generally two kinds of keywords in a dictionary. There are mandatory keywords and optional ones.
The code
Line 32 in Listing 410 shows, that the function lookup() simply calls value of lookupEntry(). This method
also calls another method (lookupEntryPtr()) and does the error handling. The error handling routine clearly
shows, that OpenFOAM will terminate in case the keyword wasn’t found (see line 19).
This offering is not approved or endorsed by ESI® Group, ESI-OpenCFD® or the OpenFOAM®
VIII 348
Foundation, the producer of the OpenFOAM® software and owner of the OpenFOAM® trademark.
Listing 411 shows the reading operation for three optional keywords. The read function is called with two
arguments. The first is the keyword and the second is the default value. If the function lookupOrDefault()
finds no entry, then the default value is returned.
The code
Listing 412 shows the definition of the function lookupOrDefault(). This function also calls another function
to lookup the keyword – actually it looks for the value assigned to the specified keyword in the dictionary –
and enters a conditional branch. In case the keyword was found, the corresponding value is returned (line 14).
If the keyword was not found, then the default value is returned (line 18).
In Listing 412 the function is defined with four input arguments. However, in Listing 411 this function is
called with only two arguments.
The solution for this contradiction can be found in the file dictionary.H, where this function is declared.
This declaration can also be found in Listing 413. There, in lines 6 and 7, default values for two arguments are
specified. Therefore, the function can be called with only two arguments – with the two arguments that have
no default value179 . If the function is called with all its arguments, the passed argument overrides the default
value.
When declaring a function that uses default values for its arguments, the arguments without default value
must precede the arguments that have a default value. Otherwise, there could be ambiguity.
179 The function could also be called with three argmuents, then the default value of the third argument would be overridden and
This offering is not approved or endorsed by ESI® Group, ESI-OpenCFD® or the OpenFOAM®
VIII 349
Foundation, the producer of the OpenFOAM® software and owner of the OpenFOAM® trademark.
57.3.3 Superseding mandatory keywords
In some cases, a base class might demand the presence of a keyword, which some derived classes make use of
and others do not. This creates the situation that a keyword-value pair must be specified, which, depending on
the user’s choice, has an effect or not.
However, as the keyword is demanded by the base class, it remains mandatory, regardless of the derived
class’ behaviour. A derived class can not alter the behaviour of its base class. Thus, in some edge cases a
keyword-value pair has to be provided even though it does nothing.
The decision of how to distribute the necessary data among the base class and its derived classes may not
always be as straight forward. Apart from the two obvious limiting cases: data needed only by one specific
derived class, and data needed by all derived classes; the decision of what data to put where is up to the software
designers.
If a sufficient number of derived classes are very similar to eachother, then an intermediate base class might
be warranted. With an intermediate base class, data common to all classes derived from the intermediate base
class can be handed over to the intermediate base class. However, the class hierarchy of a certain model can
not always exactly reflect the inner logic of data usage of that model family.
In Figure 150 we see such an example of an intermediate base class. The data members shown in the class di-
agram are read by their respective classes as mandatory entries. The base class InjectionModel reads the scalar
massTotal, which is used to determine how many particles to inject. However, some derived injection models
allow for a direct specification of the number of particles, thus rendering the mandatory value for massTotal
moot. In these cases, the injection model issues a warning message informing the user that massTotal has no
effect.
InjectionModel
scalar massTotal_
setPositionAndCell()
patchInjectionBase
word patchName_
PatchInjection
CellZoneInjection ManualInjection PatchFlowRateInjection
TimeFunction1<scalar>
word cellZoneName_ word positionsFile_ word phiName_
flowRateProfile_
Figure 150: Class hierarchy of some injection models for Lagrangian particles. An intermediate base class is
used to reduce code duplication from closely related, yet different injection models.
1 // NB : values chosen such that bitwise ’& ’ 0 x1 yields the bool value
2 // INVALID is also evaluates to false , but don ’t rely on that
3 const char * Foam :: Switch :: names [ Foam :: Switch :: INVALID +1] =
4 {
5 " false " , " true " ,
6 " off " , " on " ,
This offering is not approved or endorsed by ESI® Group, ESI-OpenCFD® or the OpenFOAM®
VIII 350
Foundation, the producer of the OpenFOAM® software and owner of the OpenFOAM® trademark.
7 " no " , " yes " ,
8 "n", "y",
9 "f", "t",
10 " none " , " true " , // is there a reasonable counterpart to " none "?
11 " invalid "
12 };
1 Switch testSwitch ( t r a n s p o r t P r o p e r t i e s . lookupOrDefault < Switch >( " testSwitch " , Switch ( false ) ) ) ;
1 namespace Foam
2 {
3 typedef int label ;
4
5 static const label labelMin = INT_MIN ;
6 static const label labelMax = INT_MAX ;
7
8 inline label readLabel ( Istream & is )
9 {
10 return readInt ( is ) ;
11 }
12
13 } // End namespace Foam
180 In C as well as in C++ the domain of long is greater or equal than the domain of int. long long was defined in the C99
standard of C and was later introduced to the C++11 standard. The domain of long long is again larger or equal than the domain
of long. The type long long uses at least 64 bit. So it is on 64 bit systems the largest possible datatype. The datatype long can
use – depending on the compiler – 32 or 64 bit. The type long long guarantees the use of 64 bit.
181 See http://en.cppreference.com/w/cpp/language/types
182 See http://en.cppreference.com/w/cpp/types/integer
This offering is not approved or endorsed by ESI® Group, ESI-OpenCFD® or the OpenFOAM®
VIII 351
Foundation, the producer of the OpenFOAM® software and owner of the OpenFOAM® trademark.
1 # define INT_ADD_SIZE (x ,s , y ) x ## s ## y
2 # define I N T _ A D D _ DE F _ S I Z E (x ,s , y ) INT_ADD_SIZE (x ,s , y )
3 # define INT_SIZE (x , y ) I N T _ A D D _ D E F _ S IZ E (x , WM_LABEL_SIZE , y )
4
5 # if WM_LABEL_SIZE != 32 && WM_LABEL_SIZE != 64
6 # error " label . H : WM_LABEL_SIZE must be set to either 32 or 64 "
7 # endif
8
9 namespace Foam
10 {
11
12 typedef INT_SIZE ( int , _t ) label ;
13
14 /* code removed for brevity */
15
16 }
In Listing 417, we see some helper macros, and a sanity check. The sanity check throws an error if the label
size is not 32 or 64. The last line of Listing 417 is the actual typedef for the label data type183 . The macro
INT_SIZE is used via several helper macros and the compiler option WM_LABEL_SIZE to construct a fixed-width
integer data type int32_t or int64_t. The ## operator in the INT_ADD_SIZE macro is used to concatenate the
macro’s arguments184 .
1 namespace Foam
2 {
3
4 typedef float floatScalar ;
5
6 /* code removed for brevity */
This offering is not approved or endorsed by ESI® Group, ESI-OpenCFD® or the OpenFOAM®
VIII 352
Foundation, the producer of the OpenFOAM® software and owner of the OpenFOAM® trademark.
Listing 419 shows the relevant lines of the file scalar.H which defines the type scalar based on the evalua-
tion of WM_SP or WM_DP. Depending on whether WM_SP or WM_DP has been defined, the type scalar refers to
floatScalar or doubleScalar.
1 # if defined ( WM_SP )
2
3 // Define scalar as a float
4 namespace Foam
5 {
6 typedef floatScalar scalar ;
7 /* code removed for brevity */
8 }
9
10 # elif defined ( WM_DP )
11
12 // Define scalar as a double
13 namespace Foam
14 {
15 typedef doubleScalar scalar ;
16 /* code removed for brevity */
17 }
18
19 # endif
This offering is not approved or endorsed by ESI® Group, ESI-OpenCFD® or the OpenFOAM®
VIII 353
Foundation, the producer of the OpenFOAM® software and owner of the OpenFOAM® trademark.
13
14 volS calarFie ld alpha2
15 (
16 IOobject
17 (
18 " alpha2 " ,
19 runTime . timeName () ,
20 mesh ,
21 IOobject :: NO_READ ,
22 IOobject :: NO_WRITE
23 ),
24 scalar (1) - alpha1
25 );
1 IOdictionary ppProperties
2 (
3 IOobject
4 (
5 " ppProperties " ,
6 runTime . constant () ,
7 mesh ,
8 IOobject :: MUST_READ_IF_MODIFIED ,
9 IOobject :: NO_WRITE
10 )
11 );
Listing 422: Definition of the object states and read/write flags of IOobject in IOobject.H
189 http://www.openfoam.org/version2.0.0/runtime-control.php
This offering is not approved or endorsed by ESI® Group, ESI-OpenCFD® or the OpenFOAM®
VIII 354
Foundation, the producer of the OpenFOAM® software and owner of the OpenFOAM® trademark.
Pitfall: Solving for a NO_READ field
The author stumbled across an interesting error during modifying a solver. This falls into the category copy &
paste error. However, the author wishes to share the experience.
If we like to extend an existing solver with a scalar transport equation, we need to create the field we want
to solve for, in our case a volScalarField. There are plenty of files from which we can copy the relevant code.
Listing 423 shows an example. The name of the field was changed as was the write flag. Since we want to create
colourful images, the write flags needs to be set to AUTO_WRITE. However, no care was taken of the read flag.
1 volS calarFie ld T
2 (
3 IOobject
4 (
5 "T",
6 runTime . timeName () ,
7 mesh ,
8 IOobject :: NO_READ ,
9 IOobject :: AUTO_WRITE
10 ),
11 mesh ,
12 d i m e n s i o n e d S c a l a r ( " zero " , dimensionSet (0 , 0 , 0 , 0 , 0) , 0.0)
13 );
After we created out field T, and composed the transport equation for this field (TEqn), we want to solve
this transport equation. However, the call TEqn.solve() yields some unexpected outcome. Listing 424 shows
the error message issued by OpenFOAM.
on patch inlet of field T in file "/ home / user / OpenFOAM / user -2.3. x / run / foo / case /0/ T "
You are probably trying to solve for a field with a default boundary condition .
From function calculatedFvPatchField < Type >:: v a l u e I n t e r n a l C o e f f s ( const tmp < scalarField >&)
const
in file fields / fvPatchFields / basic / calculated / c a l c u l a t e d F v P a t c h F i e l d . C at line 154.
FOAM exiting
Listing 424: Error message of OpenFOAM caused by trying to solve for a no-read field.
At first, the message seems counter-intuitive, since we checked the boundary conditions in the file T over
and over. Also changing the boundary conditions does not produce a different outcome.
The error message says, we wanted to solve for a field with default boundary conditions. This is perfectly
true, however, we need to find out why. Since, we created the field with a NO_READ flag, no boundary conditions
were provided. Thus, OpenFOAM assigns default boundary conditions. This is also the case if we leave patches
in the boundaryField dictionary of the files that are read from disk.
Continued Problems
Changing the read flag in Listing 423 alone does not solve the problem. Changing the read flag from NO_READ
to MUST_READ yields the same error message as in Listing 424.
The reason for this are the arguments of the constructor call in Listing 423. If a field is to be read from
disk, we must not pass a value (Line 12 in Listing 423).
For our modified solver to work, we need to remove the argument passed in Line 12 in Listing 423. The
developers of OpenFOAM have forseen this case, thus OpenFOAM issues a warning message, when a value is
passed to a constructor with a MUST_READ or MUST_READ_IF_MODIFIED read flag, see Listing 425.
This offering is not approved or endorsed by ESI® Group, ESI-OpenCFD® or the OpenFOAM®
VIII 355
Foundation, the producer of the OpenFOAM® software and owner of the OpenFOAM® trademark.
in file / home / user / OpenFOAM / OpenFOAM -2.3. x / src / OpenFOAM / lnInclude / Geometr icField . C at line
108
read option IOobject :: MUST_READ or M U S T _ R E A D _ I F _ M O D I F I E D suggests that
a read constructor for field T would be more appropriate .
Listing 425: Warning message of OpenFOAM caused by inappropriate constructor arguments concerning read
flags and initial values.
1 // random stuff
2 # include " Random . H "
3 Random ranGen (0) ;
4
5 for ( int j = 0; j < 20; j ++)
6 {
7 Info << ranGen . integer (1 , 100) << endl ;
8 }
In order to obtain different sequences, we need to choose a better seed value. In fact, we need to choose a
seed value that is different every time we run our application. The time would be a perfect example for such a
seed value. However, we need to make errors in order to learn something. In the sources, we came across the
method osRandomInteger(). This sounds great, use a random number to seed a random number generator.
On a second thought, this sounds more of a chicken-egg problems, but let’s continue.
So we implement the code of Listing 427, which is simply a different seed value. However, when we run the
code, we find out, that we obtain the same sequences over and over, just as in the previous case.
Digging into the code, we find out, that osRandomInteger() uses the random number generator provided
by POSIX. However, there seems to be no proper seeding of the POSIX random number generator.
1 // random stuff
2 # include " Random . H "
3 Random ranGen ( os Ra n do mI nt eg e r () ) ;
4
5 for ( int j = 0; j < 20; j ++)
6 {
7 Info << ranGen . integer (1 , 100) << endl ;
8 }
As mentioned above, the time is the perfect seed value. However, since we are now at the good solution,
we need something other than time. In Listing 428, we use the PID of the application as the seed value for the
RNG. The PID is unlikely to be equal when the application is run several times. In fact, the kernel of the OS
assigns the PIDs sequentially from a range of integer numbers, e.g. on the authors Linux machine the PID of
This offering is not approved or endorsed by ESI® Group, ESI-OpenCFD® or the OpenFOAM®
VIII 356
Foundation, the producer of the OpenFOAM® software and owner of the OpenFOAM® trademark.
a process is in the range between 1 and 32768. If the end of the number range is reached, the kernel starts all
over, skipping numbers which are still in use. Furthermore, the PID is guaranteed to be different, when running
an application in parallel, i.e. all the sub-processes have a unique PID.
1 // random stuff
2 # include " Random . H "
3 Random ranGen ( pid () ) ;
4
5 for ( int j = 0; j < 20; j ++)
6 {
7 Info << ranGen . integer (1 , 100) << endl ;
8 }
1 // random stuff
2 # include " Random . H "
3 # include " clock . H "
4 Random ranGen ( clock :: getTime () ) ;
5
6 for ( int j = 0; j < 20; j ++)
7 {
8 Info << ranGen . integer (1 , 100) << endl ;
9 }
Listing 429: A simple test for random numbers; the even better.
The perfect
The solution above is nearly perfect, the only issue left is running in parallel. This might seem a non-issue when
we just want to implement random numbers for an application we only will use in serial. However, the trick is
rather easy.
We use the current time as seed value and add the PID. This will ensure, that when multiple processes are
spawned at the same time, when starting a parallel run, each process has its unique seed value thanks to the
contribution of the PID.
1 // random stuff
2 # include " Random . H "
3 # include " clock . H "
4 Random ranGen ( clock :: getTime () + pid () ) ;
5
6 for ( int j = 0; j < 20; j ++)
7 {
8 Info << ranGen . integer (1 , 100) << endl ;
9 }
190 https://en.wikipedia.org/wiki/Year_2038_problem
This offering is not approved or endorsed by ESI® Group, ESI-OpenCFD® or the OpenFOAM®
VIII 357
Foundation, the producer of the OpenFOAM® software and owner of the OpenFOAM® trademark.
57.5 OpenFOAM specific macros for convenient programming
57.5.1 For-loops
... for lists
The UList class defines some macros for looping over the contents of the list. We frequently encounter for loops
using statements such as forAll, forAllIter or forAllConstIter. These statements, however, are not part
of the C or C++ programming language, they are macros provided by the UList class.
In Listing 431 we see the definition of the forAll macro.
When the forAll macro is in use, a for-loop might look as the example in Listing 432.
1 forAll ( someList , i )
2 {
3 // list body
4 }
The code in Listing 432 is, at compile time, expanded into the code shown in Listing 433.
Listing 433: Expanding the forAll macro. This is what the C++ pre-processor does with Listing 432.
In the example below, in Listing 435, a cloud of Lagrangian particles is traversed, and each particle can be
accessed via the iterator. This piece of code, respectively the developer working on this code, is completely
oblivious of the underlying data structure which the Lagrangian cloud class uses.
By using the iterator for traversing the cloud, and accessing its elements, the developers of OpenFOAM
could change the cloud’s internal way of storing the data without breaking the higher-level code.
191 https://en.wikipedia.org/wiki/Iterator_pattern
This offering is not approved or endorsed by ESI® Group, ESI-OpenCFD® or the OpenFOAM®
VIII 358
Foundation, the producer of the OpenFOAM® software and owner of the OpenFOAM® trademark.
1 forAllIter ( Cloud < solidParticle > , c , iter )
2 {
3 solidParticle & p = iter () ;
4
5 // ...
6 }
Listing 435: Using the forAllIter macro to access all particles in a Lagrangian particle cloud.
pimpleFoam
Listing 436 shows the beginning of the main loop of pimpleFoam. After the three include instructions, the
runTime object is incremented. This means, the current time step is incremented to the next time step.
pisoFoam
Listing 437 shows the beginning of the main loop of pisoFoam.
This offering is not approved or endorsed by ESI® Group, ESI-OpenCFD® or the OpenFOAM®
VIII 359
Foundation, the producer of the OpenFOAM® software and owner of the OpenFOAM® trademark.
14 /* code continues */
There, there is no incrementation of any runTime object. The explanation for this, lies in the condition
of the while statement. In pisoFoam, the while statement is controlled by the return value of the function
call runTime.loop(). Whereas, in pimpleFoam, the while statement is controlled by the return value of the
function call runTime.run().
Let’s have a closer look on runTime.loop(). Listing 438 shows, that the function loop() calls the function
run() and then increments the runTime object by calling operator++().
This offering is not approved or endorsed by ESI® Group, ESI-OpenCFD® or the OpenFOAM®
VIII 360
Foundation, the producer of the OpenFOAM® software and owner of the OpenFOAM® trademark.
1 const bool a djustTim eStep =
2 runTime . controlDict () . l oo ku p Or De fa u lt ( " ad justTime Step " , false ) ;
3 scalar maxCo =
4 runTime . controlDict () . lookupOrDefault < scalar >( " maxCo " , 1.0) ;
5 scalar maxDeltaT =
6 runTime . controlDict () . lookupOrDefault < scalar >( " maxDeltaT " , GREAT ) ;
1 if ( adjustTi meStep )
2 {
3 scalar maxDeltaTFact = maxCo /( CoNum + SMALL ) ;
4 scalar deltaTFact = min ( min ( maxDeltaTFact , 1.0 + 0.1* maxDeltaTFact ) , 1.2) ;
5
6 runTime . setDeltaT
7 (
8 min
9 (
10 deltaTFact * runTime . deltaTValue () ,
11 maxDeltaT
12 )
13 );
14
15 Info < < " deltaT = " << runTime . deltaTValue () << endl ;
16 }
maxCo
maxDeltaTFact = (166)
Co + SMALL
deltaTFact = min( min( maxDeltaTFact, 1.0 + 0.1 ∗ maxDeltaTFact), 1.2) (167)
The scalar maxDeltaTFact (Line 3 in Listing 441 and Eq. (166)) is the relation between the maximum
Courant number and the current Courant number (see Section 57.6.4 on how the Courant number is determined).
The role of the constant SMALL is to prevent division by zero, which would cause the solver to crash.
The scalar deltaTFact is computed from maxDeltaTFact. This line of code (Line 4 and Eq. (167)) imple-
ments the damping, i.e. the rate of increase of the time step is limited. The nested use of two min() functions
determines the minimum of three values. The most obvious of these three values is the last argument. If this
value is the smallest, then the next time step is 20 % larger than the last one.
Eq. (167) shows the minimum of the first two arguments in a mathematical way. Figure 151 shows the
three arguments of Eq. (167). We use the symbol x for the scalar maxDeltaTFact. In Figure 151 the values
for x are greater than one. Eq. (169) elaborates why this is the case. x is the ratio of the maximum Courant
number Comax and the current Courant number Co. As the current Courant number is always smaller than
the maximum Courant number we replace Co with f Comax , with f < 1. After cancelling Comax the inverse of
f remains. Thus x is always greater than one.
(
10
x x< 9
min(x, 1 + 0.1x) = 10
(168)
1 + 0.1x x> 9
Comax Comax 1
x= = = (169)
Co f Comax f
<1
⇒x>1 (170)
This offering is not approved or endorsed by ESI® Group, ESI-OpenCFD® or the OpenFOAM®
VIII 361
Foundation, the producer of the OpenFOAM® software and owner of the OpenFOAM® trademark.
1.5
y=x
y = 1 + 0.1x
y = 1.2
1.4
1.3
y
1.2
1.1
1
1 1.2 1.4 1.6 1.8 2 2.2 2.4 2.6 2.8 3
x
The argument of the function setDeltaT() contains the abidance of the first limit, the maximum time step.
There the minimum of the newly calculated and the maximum time step is passed on.
Class design
A quick glance at the file Time.H reveals some very interesting information on the nature of time, or more
precisely, the nature of the Time class. Listing 442 shows us, that the class Time class inherits from five base
classes192 .
class Time
:
public clock ,
public cpuTime ,
public TimePaths ,
public objectRegistry ,
public TimeState
{
/* class definition */
}
Listing 442: The information on inheritance of the Time class; an extract of Time.H.
class TimeState
:
public d i me n s i o n e d S c a l a r
{
/* class definition */
}
Listing 443: The information on inheritance of the TimeState class; an extract of TimeState.H.
192 Literarily spoken, the Time class is not only Dr. Jekyll and Mr. Hyde, it is also Citizen Kane, Mrs. Robinson and the Tambourine
Man.
This offering is not approved or endorsed by ESI® Group, ESI-OpenCFD® or the OpenFOAM®
VIII 362
Foundation, the producer of the OpenFOAM® software and owner of the OpenFOAM® trademark.
Distinguishing between time steps
The fact that Time is a TimeState which in turn is a dimensionedScalar helps to understand the Lines 6, 13
and 21 of Listing 444. There, the name() method of the dimensionedScalar name space is called.
Listing 444: The increment operator (++) of the Time class; an extract of Time.C.
From Line 23 to 27 of Listing 444 we see the code which generates the warning message we saw in Listing
43 in Section 11.3.2.
In Lines 21 and 29 we find the hard-coded limit for the time precision. If the time precision reaches a value
of 100, then it is no more increased.
a string representation of the time. It is important to note, that the string representation of the time is different than the actual
value of the time.
194 It is this method which creates the time name 0.102 from the time value 0.1023, when precision is set to three digits, as it is
This offering is not approved or endorsed by ESI® Group, ESI-OpenCFD® or the OpenFOAM®
VIII 363
Foundation, the producer of the OpenFOAM® software and owner of the OpenFOAM® trademark.
1 // - Return time name of given scalar time
2 Foam :: word Foam :: Time :: timeName ( const scalar t )
3 {
4 std :: ostringstream buf ;
5 buf . setf ( ios_base :: fmtflags ( format_ ) , ios_base :: floatfield ) ;
6 buf . precision ( precision_ ) ;
7 buf << t ;
8 return buf . str () ;
9 }
Listing 445: The method timeName(const scalar) of the class Time; an extract of Time.C. Note, that the
descriptive comment is taken from the header file Time.H.
When the time is advanced, e.g. using the increment operator of the Time class, the method setTime() is
called. Listing 446 shows the definition of this method. The new time value is passed to this method. In the
second instruction we see how the time name is updated to the new value195 .
1 void Foam :: Time :: setTime ( const scalar newTime , const label newIndex )
2 {
3 value () = newTime ;
4 d i m e n s i o n e d S c a l a r :: name () = timeName ( time ToUserTi me ( newTime ) ) ;
5 timeIndex_ = newIndex ;
6 }
Listing 446: The method setTime() of the class Time; an extract of Time.C.
The method setTime() gets called e.g. by the operator * of the Time class, see Line 8 of Listing 444. There,
the time index is increased by one. From the header file of the TimeState class, we see, that the time index
is of the data type label, which is essentially an integer data type. Thus, we see, that the time index is a
consecutive number counting the time steps.
u∆t
Co = (171)
∆x
u∆t u∆t A φ∆t
Co = = = (172)
∆x ∆x A ∆V
|φE |−|φW |
2 ∆t 1 (|φ E | − |φW |)∆t
Co = = (173)
∆V 2 ∆V
implementation in the engineTime class, which keeps track of time in terms of engine RPM and crank-shaft angle. engineTime is
derived from Time.
This offering is not approved or endorsed by ESI® Group, ESI-OpenCFD® or the OpenFOAM®
VIII 364
Foundation, the producer of the OpenFOAM® software and owner of the OpenFOAM® trademark.
Eq. (175) is the mathematical representation of line 11. There the maximum value of the ratio between the
values of sumPhi and the cell volume is determined. Both variables sumPhi and mesh.V() contain values for
every cell. Therefore the gMax() function returns the maximum value.
Eq. (176) represents line 14.
X
sumPhi = |φfi | (174)
fi
1 sumPhi
CoNum = max ∆t (175)
2 all cells Vcell
P
1 sumPhi
meanCoNum = P ∆t (176)
2 Vcell
Discussion
The way to compute the Courant number in a three dimensional case is not straight forward as mentioned
above. This section reflects the authors way of understanding. So there is no guarantee of validity. The factor
of 1/2 and the summation of φfi is explained by the author as follows.
We base our reflections on a two dimensional control volume. Eq. (178) shows the summation written in
the long form. This equation is then rearranged to yield Eq. (179). In Eq. (179) the summation is reduced to
two terms. These terms are the arithmetic mean of the face flux in the principal directions N − S and W − E.
This summation is then identified as the L1 norm of the mean face fluxes in the principal directions.
The reason for choosing the L1 norm is not self-evident. In any case is the L1 norm computationally cheaper
than the Euklidian or L2 norm. However, the use of the L1 norm seems justified since it measures the distance
covered by a movement, see http://en.wikipedia.org/wiki/Taxicab_geometry.
P
1 fi |φfi |
Co = ∆t (177)
2 Vcell
1 |φN | + |φE | + |φS | + |φW |
Co = ∆t (178)
2 Vcell
|φN |+|φS |
2 + |φE |+|φ
2
W|
Co = ∆t (179)
Vcell
NS WE
|φ| + |φ|
Co = ∆t (180)
Vcell
xi
k |φ| k1
Co = ∆t (181)
Vcell
This offering is not approved or endorsed by ESI® Group, ESI-OpenCFD® or the OpenFOAM®
VIII 365
Foundation, the producer of the OpenFOAM® software and owner of the OpenFOAM® trademark.
We indroduce the following symbols
1X xi
|φfi | = k |φ| k1 = kΦk1 (182)
2
fi
kΦk1
Co = ∆t (183)
Vcell
The way the mean Courant number is computed seems incorrect at the first glance but it isn’t.
kΦk1
Co = ∆t (183)
Vcell
The mean value of the quantity x is defined as follows
N
1 X
x= xi (184)
N i=1
Next we write the mean value of the Courant number. An unmarked summation is a summation over all cells.
1 X kΦk1
Co = ∆t (185)
N Vcell
P P
1 V kΦk1 X kΦk1
Co = P cell P ∆t (186)
N Vcell kΦk1 Vcell
| {z } | {z }
=1 =1
P P X kΦk1
kΦk1 1 V
Co = P P cell ∆t (187)
Vcell N kΦk1 Vcell
| {z }
X
Eq. (187) now resembles Eq. (176). Now we concentrate on the term X which is the only difference between
Eqns. (187) and (176).
P
1 Vcell X kΦk1
X= P (188)
N kΦk1 Vcell
P
X kΦk1
Vcell 1
X= P (189)
| N{z } kΦk1 Vcell
=Vcell
Vcell X kΦk1
X=P (190)
kΦk1 Vcell
!
1 X kΦk1
X=P Vcell
(191)
kΦk1
Vcell
Vcell
We assume Vcell
≈1
1 X kΦk1
X=P (192)
kΦk1 1
P
kΦk1
X=P =1 (193)
kΦk1
Thus we have shown that the way the mean Courant number meanCoNum is computed is actually the mean
Courant number Co. However, this attempt of a proof is based on some assumptions.
First, the way the author explains the meaning of the summation of the face fluxes relies on hexahedral
cells. The argument made seems not to be applicable on tetrahedral cells. Secondly, the assumption VVcell ≈ 1
cell
is valid for homogeneous grids. For a uniform grid this assumption would be ideally fulfilled. If the volume of
the largest and smallest cells differs a lot this assumption is not justified.
This offering is not approved or endorsed by ESI® Group, ESI-OpenCFD® or the OpenFOAM®
VIII 366
Foundation, the producer of the OpenFOAM® software and owner of the OpenFOAM® trademark.
Some thoughts on the computational costs
Why the formula for the mean Courant number is rearranged from
1 X kΦk1
Co = ∆t (194)
N Vcell
to
P
kΦk1
Co = P ∆t (195)
Vcell
is unknown to the author.
It is the opinion of the author that this is made for reasons of computational cost. Two times the summation
over all values of a field plus one division is computationally cheaper than an elementwise division of two fields
and one subsequent summation over all elements of the resulting field.
This would be the case if the division operation takes more time than the summation operation which is
very likely the case. Depending on the system the floating point division operation can take several times longer
than a floating point multiplication.
In the first case n times one division and one addition needs to be made, with n the number of field values.
In the second case 2n times additions and one division is to be made.
This offering is not approved or endorsed by ESI® Group, ESI-OpenCFD® or the OpenFOAM®
VIII 367
Foundation, the producer of the OpenFOAM® software and owner of the OpenFOAM® trademark.
1 # include " CourantNo . H "
2
3 {
4 scalar UrCoNum = 0.5* gMax
5 (
6 fvc :: surfaceSum ( mag ( phi1 - phi2 ) ) () . internalField () / mesh . V () . field ()
7 ) * runTime . deltaTValue () ;
8
9 Info < < " Max Ur Courant Number = " << UrCoNum << endl ;
10
11 CoNum = max ( CoNum , UrCoNum ) ;
12 }
IOobject
regIOobject
writeData()
Time
Figure 152: A partial view of the class hierarchy involving regIOobject; note that this diagram is complete
only for the classes IOobject and regIOobject – meaning IOobject is not derived from any other class and
regIOobject is derived from only IOobject; the other classes have more base classes than shown in this
diagram.
IOobject
This class provides the basic facilities for I/O. In Section 57.4.5 the practical or typical use of this class is shown.
This offering is not approved or endorsed by ESI® Group, ESI-OpenCFD® or the OpenFOAM®
VIII 368
Foundation, the producer of the OpenFOAM® software and owner of the OpenFOAM® trademark.
regIOobject
This class is an abstract class as the description in the header mentions. In Figure 152 the name of the pure
virtual method which makes this class an abstract class is shown in an italic font. This means all classes derived
from regIOobject must implement this pure virtual method. This also means, that we can not create an object
of the type regIOobject directly. Thus, in all of OpenFOAM’s sources we find a constructor call for the class
regIOobject only in the initializer list of classes derived from regIOobject.
objectRegistry
The objectRegistry is eponymous to this section. In fact there is not the one registry in OpenFOAM, there
are several. Among others, the classes Time, cloud, and polyMesh are derived from objectRegistry. Figure
153 shows the classes from which objectRegistry is derived.
regIOobject HashTable<regIOobject*>
writeData()
objectRegistry
Time& time()
objectRegistry& parent()
T& lookupObject(word)
Figure 153: The base classes of the class objectRegistry; this class is derived from regIOobject and
a HashTable; note that the template parameter of the HashTable is a pointer to regIOobject; thus
objectRegistry is an regIOobject as well as a HashTable of regIOobject pointers – this is C++’s tem-
plate madness and inheritance wizardry in action.
This offering is not approved or endorsed by ESI® Group, ESI-OpenCFD® or the OpenFOAM®
VIII 369
Foundation, the producer of the OpenFOAM® software and owner of the OpenFOAM® trademark.
the list is the cell centre value of cell i. Furthermore, the field also needs a connection to the actual time state
of the simulation, otherwise there would be no meaningful way to define or calculate a temporal derivative.
Listing 449: Find and scan files with file extension .C for the pattern lookupObject and count the hits
The command of Listing 449 results in 1068 hits in the author’s OpenFOAM-2.3.x installation at the time of
writing. 537 of these hits come from symbolic links of lnInclude directories. This means that lookupObject()
gets used a lot. So what is lookupObject() good for?
subsequent paragraphs.
197 The lnInclude folders collect links to all files of a certain library, thus when compiling a solver that uses this library we need
to include only the lnInclude folder and not the whole directory tree of the library’s sources. This minimizes the number of entries
in the Make/options files.
198 Information hiding and encapsulation are often used synonymously, however, strictly spoken they are not exactly the same.
This offering is not approved or endorsed by ESI® Group, ESI-OpenCFD® or the OpenFOAM®
VIII 370
Foundation, the producer of the OpenFOAM® software and owner of the OpenFOAM® trademark.
shared library. Thus, when these files are compiled, the compiler knows nothing of the objects in the namespace
Foam created in e.g. createFields.H.
namespace Foam
{
namespace diame terModel s
{
class isothermal
:
public diameterModel
{
// code removed
}
Listing 450: The class definition of the isothermal class, derived from the class diameterModel in
isothermalDiameter.H
Looking up stuff
Listing 451 shows the definition of the method d() of the class isothermal. For the reasons explained above
isothermal.C and createFields.H being in different compilation units, we can not access the pressure field p
directly from within the method body, even though p is part of the namespace Foam. However, other diameter
models do not need to access the pressure field, e.g. constant which implements a constant diameter.
Foam :: tmp < Foam :: volScalarField > Foam :: d iameterM odels :: isothermal :: d () const
{
const volS calarFie ld & p = phase_ . U () . db () . lookupObject < volScalarField >
(
"p"
);
Listing 451: The definition of the method d() of the class diameterModel in isothermalDiameter.C
The example above shows the value of the lookup mechanism. Since some sub-models operate on some
fields, it is easy to get a reference to the mesh from the field, as it is done in phase_.U().db(). phase_ is a
member of the base class of the diameter models199 . The call phase_.U() returns a reference to the velocity
field of the phase in question. As the velocity field is registered with the mesh otherwise we wouldn’t know
which velocity value belongs to a certain cell we get a reference to the mesh by calling db(), which is a method
of the class IOobject. This handy mechanism saves us from polluting sub-models with references to the mesh,
the time, to fields we might need at some point or some derived classes might need in special cases.
Thus the lookupObject() method provides a tool for us to get references to fields which at compile-time
may not be declared and thus usable. Remember, the pressure field is declared in the solver’s createFields.H
file, which is in a different compilation unit as the library we are compiling our diameter model for. If the code
of the diameter model and the solver would be in the same compilation unit (the solver’s executable) we would
not need the lookup mechanism. However, since the developers of OpenFOAM aim for modularity, placing
everything into a single compilation unit is against the design principles of modularity and reusability.
The lookupObject() method is templated since we can register anything with the mesh, in fact anything
that is derived from regIOobject, since an objectRegistry is a HashTable of regIOobject pointers. Thus,
at compile-time the method and the compiler do not know exactly which data types it is going to handle.
This is where templates come into play. The templated method is implemented once for the template pa-
rameter, and when we use the method, we simply replace the template parameter with the actual type, as in
lookupObject<volScalarField>("p"). The compiler then does the rest of the work and generates the appro-
priate code. We could resolve this issue without templates by using function overloading at the price of massive
code duplication and poor maintainability.
199 It is a convention of OpenFOAM’s developers to append an underscore character (_) to the names of the data members of a
This offering is not approved or endorsed by ESI® Group, ESI-OpenCFD® or the OpenFOAM®
VIII 371
Foundation, the producer of the OpenFOAM® software and owner of the OpenFOAM® trademark.
57.7.3 Printing the registry
If you are curious you can add the following lines of code to a test utility of yours to check what is registered
with the mesh and the runTime object registry. Note that mesh and runTime must be accessible from the place
you put the code into. Also the names of the objects might differ in some cases.
Info << " mesh . names () " << mesh . names () << nl << endl ;
Info << " runTime . names () " << runTime . names () << endl ;
Listing 452: Printing the contents of the object registries mesh and runTime to Terminal
return 0;
}
int main ()
{
std :: cout << " Hello World ! " << std :: endl ;
return 0;
}
OpenFOAM implements its own stream library. The generic stream library of OpenFOAM is based on the
class IOstream. The description of this class in its header file sheds some light on the reasons for doing so:
An IOstream is an abstract base class for all input/output systems; be they streams, files, token
lists etc.
The basic operations are construct, close, read token, read primitive and read binary block. In
addition version control and line number counting is incorporated. Usually one would use the read
primitive member functions, but if one were reading a stream on unknown data sequence one can
read token by token, and then analyse.
OpenFOAM handles all kinds of communication in terms of streams, among others: Terminal I/O with the
user, file I/O and inter-process communication for parallel processing. The Hello World! example for the
OpenFOAM world in Listing 455 looks very similar to the example of C++.
This offering is not approved or endorsed by ESI® Group, ESI-OpenCFD® or the OpenFOAM®
VIII 372
Foundation, the producer of the OpenFOAM® software and owner of the OpenFOAM® trademark.
# include " Istream . H "
return 0;
}
argList :: noBanner () ;
argList :: noParallel () ;
argList :: addBoolOption
(
" verbose " ,
" control the chatty - ness of me "
);
Foam :: argList args ( argc , argv ) ;
if ( verbose ) Info << " ... and hello to all other non - OpenFOAM worlds ! " << endl ;
return 0;
}
Listing 456: The Hello World! example written in OpenFOAM with conditional chattiness.
201 Have you ever come across -v or --verbose command line switches when using UNIX or LINUX computers?
This offering is not approved or endorsed by ESI® Group, ESI-OpenCFD® or the OpenFOAM®
VIII 373
Foundation, the producer of the OpenFOAM® software and owner of the OpenFOAM® trademark.
In addition to the boolean command line switch, we added a note informing the user about the executable.
This note gets displayed, when the usage message is shown by invoking the executable with the command line
option -help. OpenFOAM adds a number of command line parameters by default, thus we remove some of
them (the ones that make no sense for a Hello World! program, such as the parallel option).
The second to last line of code is the one that actually controls the conditional output. This is done by a
good old if statement.
In the source code of the function objects of OpenFOAM-2.3.x we observed another possiblity to define
conditional output. There, we can pass an argument to Info. With OpenFOAM-2.4.x and higher versions this
does not compile anymore. Listing 457
// OpenFOAM -2.3. x
Info ( log_ ) << " Including porosity effects " << endl ;
Listing 457: Implementing conditional output, controlled by the Switch log_, in different OpenFOAM versions.
This example is taken from the force function object. See the file force.C.
A variant of the conditional Info(log_) statement was reinstated in May 2016202 , with the Log macro,
which is defined as follows:
Listing 458: The definition of the Log macro, originally for conditional output of function objects. See the file
messageStream.H.
57.8.2 The registry and the I/O or the truth behind runTime.write()
Registering fields with the runTime object registry also allows makes our lives easier when we want to write
the current state of the simulation to disk. In a great number of solvers, possibly in all of them, we find an
instruction like runTime.write() within the main loop of the main method. This call to the method write()
causes fields to be written to disk. As every solver write a different set of fields to disk, we may ask ourselves how
the solver or OpenFOAM knows which fields to write when we call the write() method of the runTime object?
Here, the registry nature of the Time class comes into play. Since we register all our fields, which we eventually
want to read or write, with the runTime object, the runTime object has a list of objects (regIOobjects in fact)
which are to (or might) be written203 . In fact, since objectRegistry is derived from the type HashTable, an
object registry is a list of objects which are to (or might) be written204 . The call of the write method of the
Time class causes Time to iterate over its self (runTime is a list of regIOobjects by inheritance205 ) and call the
write() method of every single item within the list. The method write() is defined in the regIOobject class.
The closer look into the sources is revealing if we take some of C++’s rules into consideration. Listing 459
shows us the method that is called when we call write() on runTime, bear in mind that Time is derived in
second generation from regIOobject via the class objectRegistry. The listing shows a call of the method
writeObject().
description in the header file of the HashTable class describes the class as being An STL-conforming hash table.
205 think around the family tree, e.g. in Figure 153
This offering is not approved or endorsed by ESI® Group, ESI-OpenCFD® or the OpenFOAM®
VIII 374
Foundation, the producer of the OpenFOAM® software and owner of the OpenFOAM® trademark.
1 bool Foam :: Time :: writeObject
2 (
3 IOstream :: streamFormat fmt ,
4 IOstream :: versionNumber ver ,
5 IOstream :: c om pr e ss io nT y pe cmp
6 ) const
7 {
8 if ( outputTime () )
9 {
10 // some code removed
11
12 timeDict . regIOobject :: writeObject ( fmt , ver , cmp ) ;
13 bool writeOK = obj ectRegis try :: writeObject ( fmt , ver , cmp ) ;
14
15 // further code removed
Listing 460: Parts of the method writeObject() of the class Time in TimeIO.C
);
}
If we search the sources of Time and all its base classes we find out that Time, regIOobject and objectRegistry
all define a method called writeObject()206 . All of these three methods share the same signature207 , i.e. they
receive the same function arguments. Since the call of writeObject() is not further specified for a certain
namespace, it is the method writeObject() of the class Time, which is called when we call runTime.write()
as runTime is of the type Time.
In Listing 460 we see a portion of the definition of the method writeObject() of the class Time. There we
also see calls explicitely to the methods writeObject() of the classes regIOobject and objectRegistry.
Thus, the method writeObject() of all three classes (Time, regIOobject and objectRegistry) are called
when runTime.write() is called. It is worth noticing that the call of regIOobject::writeObject() is invoked
on the timeDict object. The definition of this object is part of the removed code prior to the call. A look into
the source code reveals, that timeDict is an IOdictionary which is a class also derived from regIOobject,
see Figure 152. The call of timeDict.writeObject() is the piece of code which creates the uniform folders
within the time step directories208 .
The method writeObject() of the class objectRegistry does the actual iteration over all elements within
the registry. Listing 461 shows the actual iteration over the hash table of regIOobject pointers. For each
element writeObject() is called if the write flag is not set to NO_WRITE. Now the method writeObject() of
the class regIOobject is called, since the iteration is over regIOobject pointers. This call on Line 16 of Listing
461 causes a registered field to be written to disk.
with an empty parameter list. This can be checked via these commands: find $FOAM_SRC -name ’*.[CH]’ | xargs grep
’writeObject()’
207 The function signature consists of the name of the function and its parameters.
208 In case you ever wondered where these come from.
This offering is not approved or endorsed by ESI® Group, ESI-OpenCFD® or the OpenFOAM®
VIII 375
Foundation, the producer of the OpenFOAM® software and owner of the OpenFOAM® trademark.
16 ok = iter () -> writeObject ( fmt , ver , cmp ) && ok ;
17 }
18 }
19
20 return ok ;
21 }
Listing 461: Parts of the method writeObject() of the class objectRegistry in objectRegistry.C
In conclusion we have learned by digging the source code of OpenFOAM the magical inner workings of
the call runTime.write(). First the Time class writes its state to disk into the uniform folder and then the
objectRegistry part of the runTime object writes all registered fields. It was already mentioned in Section 57.6
that the class Time has a multiply divided personality. And some of those even bring along an ancestry. This
highlights the need to have a certain understanding of C++ in order to be able to deduce what’s going on from
the sources of OpenFOAM as OpenFOAM makes very heavy use of C++’s language features such as multiple
inheritance, polymorphism and templates. In the context of programming paradigms involved, OpenFOAM
makes use of (among others): object-orientation and generic programming.
argList :: addBoolOption
(
" verbose " ,
" be more talkative "
);
Listing 462: The order of things in the source code for defining command line arguments
209 In C++ argc is the number of command line arguments, and argv is the actual command line arguments. argc and argv
are passed from the Terminal to the main() method of the application, see main()’s method signature: int main(int argc, char
*argv[])
This offering is not approved or endorsed by ESI® Group, ESI-OpenCFD® or the OpenFOAM®
VIII 376
Foundation, the producer of the OpenFOAM® software and owner of the OpenFOAM® trademark.
57.9.2 Dealing with SPAAAACE!
Having a space in an argument’s name is not really a good idea, since the Terminal generally interprets a
space as the end of an argument. In common UNIX/Linux tools multi-word arguments are generally seperated
with hyphens, e.g. --auto-compress. In the OpenFOAM universe, we see the use of camel case210 , e.g.
-noFunctionObjects to deal with multi-word argument names.
However, if we really want to have spaces within our argument’s name, OpenFOAM allows us to do so.
Listing 464 demonstrates how to define an argument named search point.
argList :: addOption
(
" search point " ,
" vector " ,
" find the cell containing the specified coords at < vector > - eg , ’(1 0 0) ’"
)
/* no comment */
vector v ;
if ( args . o p t i o n R e a d I f P r e s e n t ( " search point " , v ) )
{
Info < < " Searching cell at point : " << v << endl ;
}
Using an argument with a space in it, requires taking special care, as shown in Listing 465. Quotes are used
to prevent the Terminal from interpreting the space within the argument’s name as the end of the argument’s
name.
Listing 466 shows the danger of defining arguments with spaces. In this case the quotes were not used, just
as we are used to.
Listing 465: Passing a point’s coordinate to an application; note the quotes around the argument’s name
...
FOAM exiting
Listing 466: Passing a point’s coordinate to an application; omitting the quotes around the argument’s name
leads to a misinterpretation
1. A laminar simulation
2. Using a RAS turbulence model
3. Using a LES turbulence model
This statement is reflected in the relationship between the classes implementing the turbulence models in
OpenFOAM. Object oriented programming allowes the programmer to translate relationships directly from
human language to source code. Two statements can be made about turbulence models
210 https://en.wikipedia.org/wiki/Camel_case
This offering is not approved or endorsed by ESI® Group, ESI-OpenCFD® or the OpenFOAM®
VIII 377
Foundation, the producer of the OpenFOAM® software and owner of the OpenFOAM® trademark.
1. All RAS turbulence models are turbulence models, but not all turbulence models are RAS turbulence
models.
2. A RAS turbulence model is not the same as an LES turbulence model, however, both are turbulence
models.
Both statements are reflected by the class diagram of the turbulence models. On the top is the abstract class
turbulenceModel. This abstract class, provides the framework for all derived turbulence classes. Also, all
functionality common to all possible turbulence classes can be defined in this class. All derived classes will then
inherit this functionality.
Each turbulence model is derived from this abstract base class. Each turbulence class will implement specific
functionality individually.
turbulence
divDevReff():
The base class contains not only virtual functions. It also contains functions that are the same for all derived
classes. Consequently, this functions are implemented by the base class. Listing 468 shows the implementation
of the function nu(). This function is used to access the laminar or molecular viscosity. The laminar viscosity
is a property of the fluid itself and has nothing to do with turbulence. However, the turbulence models need to
access the laminar viscosity.
Every class derived from an abstract class must at least override the abstract methods. The non-abstract
methods of the base class – like nu() from Listing 468 – can be used by the derived classes. No matter if a RAS
or a LES turbulence model is used, the laminar viscosity will always be the same.
211 A class that contains one or more abstract methods is called an abstract class. If a class contains only abstract methods, then
This offering is not approved or endorsed by ESI® Group, ESI-OpenCFD® or the OpenFOAM®
VIII 378
Foundation, the producer of the OpenFOAM® software and owner of the OpenFOAM® trademark.
57.10.2 The class RASModel
The class RASModel is derived from the abstract class turbulenceModel. The class RASModel itself is the base
class for all RAS turbulence models. It is also an abstract class because it does not override all abstract methods
inherited from turbulenceModel.
However, the class RASModel implements all methods that are common to all RAS turbulence models. List-
ing 469 shows the implementation of the method nuEff() in the class RASModel.
The effective viscosity nuEff is calculated from the laminar viscosity, which is a property of the fluid, and the
turbulent viscosity. The turbulent viscosity is a property of the turbulence model. The function nu() in Listing
469 is implemented in the class turbulenceModel, see Listing 468. The function nut() is not implemented by
the class RASModel. Therefore, this method must be implemented by the classes derived from RASModel.
RASModel
divDevReff():
class kEpsilon
:
public RASModel
{
/* class definition */
}
The function nut() has to be implemented by kEpsilon. Listing 471 shows how the function nut() is
implemented. This function simply returns the class member nut_.
This offering is not approved or endorsed by ESI® Group, ESI-OpenCFD® or the OpenFOAM®
VIII 379
Foundation, the producer of the OpenFOAM® software and owner of the OpenFOAM® trademark.
// - Return the turbulence viscosity
virtual tmp < volScalarField > nut () const
{
return nut_ ;
}
The way how nut_ is calculated differs between the RAS turbulence models. See Listing 507 in Section
62.2.2.
DebugSwitches
{
D e f a u l t S t a b il i t y 0;
YoonLuttrellAttachment 1;
}
Listing 473: Solver output when specifying debug switches in the case’s controlDict
212 http://openfoamwiki.net/index.php/HowTo_debugging#Getting_built-in_feedback_from_OpenFOAM
213 http://www.openfoam.org/version2.2.0/runtime-control.php
214 See http://oopweb.com/CPP/Documents/DebugCPP/Volume/techniques.html or http://en.wikipedia.org/wiki/Debugging#
Techniques
215 See Section 57.12 on the background of the debugging mechanism.
This offering is not approved or endorsed by ESI® Group, ESI-OpenCFD® or the OpenFOAM®
VIII 380
Foundation, the producer of the OpenFOAM® software and owner of the OpenFOAM® trademark.
57.11.2 Use case: Write intermediate fields
Listing 475 shows the definition of a method named Ea. For debugging purposes we want to write intermediate
fields to disk. In Line 7 of Listing 475 we compute a Reynolds number and store it in ReB. This is used to
generate the return value of the method. In normal operation only the return value is of interest. When
debugging also intermediate results may be of interest. The field ReB is by default not written to disk and
ceases to exist when the scope leaves the method, i.e. when the method is reaches its end the variable ReB is
automatically deleted216 .
Note the arguments passed in Line 7. The first is the name of the field. We could omit this argument,
however, when we write the variable ReB to disk the first argument determines the file name. If this argument
was omitted, then an automatically generated name – based on the way the field was generated – would be used.
In this very case the file written would be named max(((mag((U1-U2))*d)|nu),0.001). We easily recognize
the formula of Line 7. A file name containing special characters (non-alphanumerical characters) is generally
not advisible217 .
In Line 14 we manually call the write() method. This method is available to all registered input/output
objects218 . As we construct the local variable ReB from the registered i/o object Ur we can savely assume that
ReB will also be of this type.
1 namespace Foam
216 This behaviour is subsumed under the term automatic variable. See e.g. http://en.cppreference.com/w/cpp/language/
storage_duration
217 See e.g. http://www.teamdrive.com/Invalid_characters_in_file_and_folder_names.html
218 See http://openfoamwiki.net/index.php/OpenFOAM_guide/Input_and_Output_operations_using_dictionaries_and_the_
IOobject_class and http://openfoamwiki.net/index.php/OpenFOAM_guide/objectRegistry
This offering is not approved or endorsed by ESI® Group, ESI-OpenCFD® or the OpenFOAM®
VIII 381
Foundation, the producer of the OpenFOAM® software and owner of the OpenFOAM® trademark.
2 {
3 class Sc hi lle rN au ma nn
4 :
5 public dragModel
6 {
7
8 public :
9 // - Runtime type information
10 TypeName ( " S ch il l er Na um a nn " ) ;
11 }
12 }
1 namespace Foam
2 {
3 d e f i n e T y p e N a m e A n d D e b u g ( SchillerNaumann , 0) ;
4 }
What looks like a function call is actually a preprocesser macro219 with parameters220 . The macroTypeName
is defined in the file typeInfo.H. Listing 478 shows its definition.
A \#define macro consists of at least two parts. First comes the identifier, then comes the optional pa-
rameter list in parentheses and at least the replacement token list until the end of the line221 . As the macro
is expanded by the preprocessor, the identifier (in this case TypeName) is replaced with the replacement tokes
(all instructions after the parameter list). A macro can not cover more than one line, however, by using the
backslash (\\) the current line is continued with the next line222 .
The second line is a function definition. As this function definition is made by the macro, this function is
defined for every class where the TypeName macro is stated in the class definition. This demonstrates one of the
major reasons for using preprocessor macros – the ability to write recurring pieces of code just once.
The first line of the above listing is itself a macro. Listing 479 shows the macro definitions that are necessary
to expand the ClassName macro.
This offering is not approved or endorsed by ESI® Group, ESI-OpenCFD® or the OpenFOAM®
VIII 382
Foundation, the producer of the OpenFOAM® software and owner of the OpenFOAM® trademark.
6
7 // - Add typeName information from argument \ a TypeN ameStrin g to a class .
8 // Without debug information
9 # define C l a s s N a m eN o D e b u g ( TypeName String ) \
10 static const char * typeName_ () { return Type NameStri ng ; } \
11 static const :: Foam :: word typeName
As the TypeName("SchillerNaumann") macro was put into the class definition of the verb+SchillerNaumann+
class, the macro added two function definitions (first and last line), one of which is a static method, and two
static variables (the two center line).
Static elements of class (variables or methods) are elements that exist only once for all instances of a class223 .
In the case of a two-phase Eulerian solver two instances of the SchillerNaumann class might exist – in the case
this model was specified for both phases. No matter which of the two instances of the class call the method
typeName() it is always the same function called. In this case – returning the name of the class – the use of a
static method makes perfect sense and is the only sensible way to implement this task.
The TypeName("SchillerNaumann") macro is used to create a method that returns the name of the class and
a method that return the name of the type. Obviously, the class name and the type name were not considered
equivalent when designing OpenFOAM224 . The variables created by the TypeName("SchillerNaumann") macro
are a static variable containing the type name and a static variable named debug. This debug variable controls
the debug mechanism covered in Section 57.11.
d e f i n e T y p e N a m e A n d D e b u g ( SchillerNaumann , 0) ;
defi neTypeNa me ( Sc hi ll e rN au ma n n ) ;
d e f i n e D e b u g S w i t c h ( SchillerNaumann , 0) ;
Listing 481 shows the macro definitions necessary to expand the above two macros.
223 http://www.tutorialspoint.com/cplusplus/cpp_static_members.htm
224 See Section 57.12.3 for an example when class name and type name are different.
This offering is not approved or endorsed by ESI® Group, ESI-OpenCFD® or the OpenFOAM®
VIII 383
Foundation, the producer of the OpenFOAM® software and owner of the OpenFOAM® trademark.
9 // - Define the debug information , lookup as \ a Name
10 # define d e f i n e D e b u g S w i t c h W i t h N a m e ( Type , Name , DebugSwitch ) \
11 int Type :: debug (:: Foam :: debug :: debugSwitch ( Name , DebugSwitch ) )
12
13 // - Define the debug information
14 # define d e f i n eD e b u g S w i t c h ( Type , DebugSwitch ) \
15 d e f i n e D e b u g S w i t c h W i t h N a m e ( Type , Type :: typeName_ () , DebugSwitch ) ; \
16 r e g i s t e r D e b u g S w i t c h W i t h N a m e ( Type , Type , Type :: typeName_ () )
The first line of the expansion of the macro defineTypeNameAndDebug(SchillerNaumann, 0) assigns the
return value of the function typeName_() to the static variable typeName. This has the effect that the class
name and the type name have an equal value. However, the way this framework is set up allows for different
names.
The second line assigns the return value of the function call ::Foam::debug::debugSwitch(SchillerNaumann, 0)
to the static variable SchillerNaumann::debug. The reason why the value is not directly used to assign the
value to the static variable is that the called method adds the debug switch to a dictionary, see Listing 482.
The last line of the macro expansion invokes another macro. Listing 483 shows the macro definition of
registerDebugSwitchWithName.
1 int Foam :: debug :: debugSwitch ( const char * name , const int defaultValue )
2 {
3 return debugSwitches () . l o o k u p O r A d d D e f a u l t
4 (
5 name , defaultValue , false , false
6 );
7 }
This offering is not approved or endorsed by ESI® Group, ESI-OpenCFD® or the OpenFOAM®
VIII 384
Foundation, the producer of the OpenFOAM® software and owner of the OpenFOAM® trademark.
The turbulence models are very prominent examples for the usefulness of the run-time selection mechanism.
At compile-time – the time we or the OpenFOAM developers compile a solver – nobody knows, what exact
turbulence model we want to use for our simulation. Thus, we need to decide at run-time – at the time the
solver reads all the case information – which turbulence model to use. In order to save us from writing a solver
for each turbulence model, solvers can be written in a generic way. I.e. at the time we compile the solver
nobody, not even the compiler, cares about the actual turbulence model. The base class turbulenceModel tells
the compiler and the solver how a turbulence model works, that is all we need to know at compile time.
However, at run-time we need to decide which turbulence model to use. Fortunately, OpenFOAM takes care
of that and we do not need to bother. In some cases, however, we would like to know which turbulence model
is currently used. We could achieve this by either reading the case data225 or by making use of the run-time
magic.
Listing 484 shows three lines of code. The intention behind this line is to print the return values of the
methods typeName_() and type(). These two methods were provided by the two macros dissected in Sections
57.12.1 and 57.12.2.
Listing 485 shows the results of the three lines of code of Listing 484. The code in Listing 484 presumes that
turbulence modelling is used in its generic form, as it is the case in e.g. pimpleFoam. In this example the
variable turbulence is of the type autoPtr<incompressible::turbulenceModel> turbulence.
From the output we see, that the variable turbulence is indeed of type turbulenceModel. However, as the
class turbulenceModel is an abstract base class, no solver will ever actually use turbulenceModel itself226 .
In this case, the solver used the kOmega turbulence model. Thus, the method type() returns the name of the
actual turbulence model. Here we also see the sense behind the distinction between the class name and the type
name as discussed some paragraphs above. In the example of an concrete class those are the same. For a base
class, however, this distinction makes perfect sence.
This offering is not approved or endorsed by ESI® Group, ESI-OpenCFD® or the OpenFOAM®
VIII 385
Foundation, the producer of the OpenFOAM® software and owner of the OpenFOAM® trademark.
57.13.1 Printing to Terminal
When running an application in parallel, we might want for each one of the parallel processes being able to
print to the Terminal, or we might want that only the master process can print to the Terminal. OpenFOAM
allows you to do both.
Listing 489: Computing and printing the total amoung of field X to the Terminal.
229 ... if the author is to be believed.
This offering is not approved or endorsed by ESI® Group, ESI-OpenCFD® or the OpenFOAM®
VIII 386
Foundation, the producer of the OpenFOAM® software and owner of the OpenFOAM® trademark.
If we were to sum up mesh.V(), which is a scalar field made-up of the cell’s volumes, we get the total volume
of the domain, when we use gSum(mesh.V()). If we used sum(mesh.V()), then we would get roughly the total
domain’s volume divided by the number of processes. This is roughly an N -th of the domain’s volume, as
decomposition does not always yield sub-domains with a size exactly one N -th of the globale domain, e.g. when
having an even number of cells and dividing into three parts.
57.14.1 Pitfalls
Operator precedence: use caution with vector products
In mathematics certain operations are evaluated with priority over others230 . The same holds true for most
programming languages. The general rules of operator precedence231 in C++ closely follow the rules known
from mathematics.
However, as OpenFOAM extends the rudimentary mathematical capabilities of standard C++ with concepts
such as vectors and tensors, the question of operator precedence becomes interesting. Since, there are no
vector products in C++ and completely new operators can not be defined, some existing operators have to be
overloaded to implement the vector products. Furthermore, the operator precedence of existing operators can
not be altered.
As it turns out, the bitwise AND (&) and bitwise XOR (^) have been overloaded to implement the inner
and outer vector product. An unfortunate side-effect of using these operators is, that the inner and outer vector
product have a lower precedence than the basic operators such as addition, subtraction and multiplication. This
is because the bitwise AND and bitwise XOR operators have a quite low precedence.
To the unsuspecting user, it may come as a surprise when the following formula results in a compilation error:
a·b − c
a · (b − c)
Trying to compile the formula from above, translated into OpenFOAM source code:
leads to a compiler error. Among the potentially plentyful lines of compiler warning and error messages, the
line below is the relevant one. It informs us of our intent to subtract a scalar from a vector, which is undefined.
error : no match for ’ operator - ’ ( operand types are ’ const vector { aka const Foam :: Vector <
double >} ’ and ’ const scalar { aka const double } ’)
This offering is not approved or endorsed by ESI® Group, ESI-OpenCFD® or the OpenFOAM®
VIII 387
Foundation, the producer of the OpenFOAM® software and owner of the OpenFOAM® trademark.
Thus, users are advised to use plenty of parentheses to avoid such problems. The issue with operator
precedence is well explained by Hrv Jasak in a forum post232 :
That’s because operator& and operator^ are really binary C++ operators in C++ and the language
does not allow you to define your own operators or change operator precedence.
We have chosen to re-use the operators for nice sytnax - makes the code look nice. Therefore, all I
can recommend is lots of brackets in vector/tensor products.
The same also applies to the double inner product, which takes two tensors of at least 2nd order. This operator
is implemented by overloading the logical AND (&&) operator, which has an even lower precedence than the
bitwise binary operators.
232 https://www.cfd-online.com/Forums/openfoam/61023-operator-precedence.html
This offering is not approved or endorsed by ESI® Group, ESI-OpenCFD® or the OpenFOAM®
VIII 388
Foundation, the producer of the OpenFOAM® software and owner of the OpenFOAM® trademark.
58 General remarks on OpenFOAM programming
This section covers some general advice for users who want to implement their own models and solvers or modify
existing ones.
cd $ W M _ P R O J E C T _ U S E R _ D I R
mkdir -p applications / solvers
mkdir src
Listing 492: Create the proper directories for a user’s solvers and models
Note the use of the variable $WM_PROJECT_USER_DIR, which resolves to your OpenFOAM installation’s user
directory, which also contains the run-directory ($FOAM_RUN).
Listing 493: Setting the name of pimpleFoam’s executable in the file Make/files of pimpleFoam’s source code233
233 The executeable does not necessarily have to have the same name as the source file. However, different names can lead to
confusion and make code maintenance harder. Therefore, it is strongly recommended to use consistent names, i.e. to name the
source file SOLVER.C and the executable SOLVER.
This offering is not approved or endorsed by ESI® Group, ESI-OpenCFD® or the OpenFOAM®
VIII 389
Foundation, the producer of the OpenFOAM® software and owner of the OpenFOAM® trademark.
Analogously, defining the name of the shared library234 is done by the setting LIB in the file Make/files of
the library’s source code.
Listing 494: Setting the name of the shared object of the Lagrangian particle library in the file Make/files of
Lagrangian library source code
The settings for EXE and LIB are full file paths. Thus, next to the assigment (the = symbol) we find a
directory, the path name separator (the / symbol) and the actual name of the executable or shared library.
Check Make/files
After adjusting the compilation settings, check and re-check the file Make/files. Listing 495 shows the vital
entries of the file highlighted. In the listing, the source file has the same name as the executable. Furthermore,
the executable will be located in the user’s application directory.
myApplication.C
The file Make/files controls what is compiled and where the resulting executable will be stored. Thus,
getting Make/files right will save yourself from breaking something else, i.e. the model or application you
base your new model or application on. On the other hand, the file Make/options controls what is needed to
successfully compile the model or application. Getting Make/options wrong initially will do no harm.
Check Make/options
The file Make/options tells the compiler where to find additional source files, and it tells the linker236 where to
find additional libraries. The file Make/options only needs to be edited, if you use existing models, or source
files from other directories. This, however, is often the case.
The content of the file Make/options is divided in two parts. First, there are the paths for compiler to
look for source files to include. The second part is a list of libraries for the linker to link the current model or
application with.
EXE_INC = \
- I$ ( LIB_SRC ) / meshTools / lnInclude \
- I$ ( LIB_SRC ) / finiteVolume / lnInclude
234 The main purpose of dividing code into applications and libraries is to allow for multiple unconnected applications using
certain implemented behaviour (the libraries). Thus, libraries are shared by an arbitrary number of applications. Hence, libraries
are compiled into files which are referred as shared objects or shared libraries. The names of these files are appended by the filename
extension so, i.e. libraryName.so.
235 by residing in different directories
236 Compilation of C or C++ code is usually done in two steps. First all files are compiled and then the object files generated by
This offering is not approved or endorsed by ESI® Group, ESI-OpenCFD® or the OpenFOAM®
VIII 390
Foundation, the producer of the OpenFOAM® software and owner of the OpenFOAM® trademark.
LIB_LIBS = \
- lmeshTools
Initial compilation
Once the existing sources have been copied and, most importantly, the compilation settings have been changed,
we can run an initial compilation. Although, at this point, nothing in the source code has changed, running an
initial compilation is recommended to check whether we have got the compilation settings right.
For applications simply execute wmake, for shared libraries the compiler gets an additional parameter:
wmake libso. After the compilation the compiled binary should show up in FOAM_USER_APPBIN or FOAM_USER_LIBBIN
respectively.
EXE_INC = \
- I$ ( LIB_SRC ) / meshTools / lnInclude \
- I$ ( LIB_SRC ) / finiteVolume / lnInclude \
-I$(MY_LIB_SRC_PATH)/myLibary/lnInclude
LIB_LIBS = \
- lmeshTools \
-L$(FOAM_USER_LIBBIN) \
-lmyLibary
58.5 Pitfalls
Modifying existing models or creating new ones bears the potential for many bugs and errors. This section
tries to discuss some of them, which either occur regularly or may be difficult to track down. Such a list can
never be complete and it is clearly biased towards the errors made and encountered by the author. These
errors are not necessarily restricted to OpenFOAM, moreover, modifying OpenFOAM involves programming
and programming involves bugs and errors. Enjoy reading.
This offering is not approved or endorsed by ESI® Group, ESI-OpenCFD® or the OpenFOAM®
VIII 391
Foundation, the producer of the OpenFOAM® software and owner of the OpenFOAM® trademark.
58.5.1 Segfault due to modified libary and failing to update the solver
Libraries are reusable parts of code, which are independent of the solver(s) using them. However, this in-
dependence may create problems if we modify the library and fail to recompile the solver(s) that are using
said library, even if said solver(s) have not been touched. The problem that might occur is a segmentation
fault (segfault in short) at construction of the modified objects. Unfortunately, a segfault does not produce very
telling error messages, see Listing 498. Note that we assume that compilation of the library finished successfully.
Further reading
https://stackoverflow.com/questions/2346806/what-is-a-segmentation-fault
https://en.wikipedia.org/wiki/Segmentation_fault
58.6 Tips
Check and double-check that you compile to the user-directories
Always make sure, that you compile your applications to FOAM_USER_APPBIN and your libraries to FOAM_USER_LIBBIN.
The reason for this, and the way how to ensure this, are discussed in 58.2.2.
When modifying a library, also recompile the solver(s) using the library
This mean a seemingly extraneous step239 , however, it might prevent weird behaviour. One reason for recom-
piling the solver using a recently modified library was discussed above in Section 58.5.1.
Furthermore, especially when templates are involved, e.g. you modify a templated class, it is vital to compile
the library which provided the templated model and the solver that uses the templated model. Templates need
special attention, care and love, do not neglect them.
237 Ifthe library compilation had failed, the linker would throw an error, if you tried to compile a solver using that library.
238 i.e.the case runs, when you use only standard OpenFOAM features.
239 In some cases it is sufficient only to compile the library, e.g. when fixing a type in an Info message.
This offering is not approved or endorsed by ESI® Group, ESI-OpenCFD® or the OpenFOAM®
VIII 392
Foundation, the producer of the OpenFOAM® software and owner of the OpenFOAM® trademark.
Use Allwclean or wclean liberally
Clean-up your temporary build-files for good measure by running wclean. Especially when templated classes
are involved, clearing build-files might be essential.
Also, if you update the underlying OpenFOAM version, recompiling your custom libraries and solvers will
also require cleaning of the build-files. If the underlying OpenFOAM installation, then the dependency list, i.e.
the *.dep file present in the Make directory of your code, may contain the file-names of files which might have
ceased to exist.
This offering is not approved or endorsed by ESI® Group, ESI-OpenCFD® or the OpenFOAM®
VIII 393
Foundation, the producer of the OpenFOAM® software and owner of the OpenFOAM® trademark.
59 wmake - the build system of OpenFOAM
OpenFOAM’s build system wmake has been developed along the lines of make240 .
1 F O A M _ V E R S I O N _ M A J O R := $ ( W M _ P R O J E C T _ V E R S I O N )
2 PFLAGS += - DFOAM_VERSION = $ ( F O A M _ V E R S I O N _ M A J O R )
3
4
5 ifeq ( $ ( F O A M _ VE R S I O N _ M A J O R ) ,9)
6 else ifeq ( $ ( F O A M _ V E R S I O N _ M A J O R ) ,8)
7 else
8 $ ( error OpenFOAM -7 and older is not supported )
9 endif
10
11
12 ifeq ( $ ( F O A M _ V E R S I O N _ M A J O R ) ,9)
13 $ ( info This branch )
14 COND_INC = \
15 - I$ ( LIB_SRC ) / t r an sp or t Mo de ls / lnInclude \
240 See https://en.wikipedia.org/wiki/Make_(software)
241 Note the restriction to all versions we would like to support. Supporting all versions of OpenFOAM is out of the question for
all but the most basic or simple models/solvers/tools.
242 See https://www.gnu.org/software/make/manual/html_node/Make-Control-Functions.html
This offering is not approved or endorsed by ESI® Group, ESI-OpenCFD® or the OpenFOAM®
VIII 394
Foundation, the producer of the OpenFOAM® software and owner of the OpenFOAM® trademark.
16 - I$ ( LIB_SRC ) / dynamicFvMesh / lnInclude
17 else
18 COND_INC = \
19 - I$ ( LIB_SRC ) / sampling / lnInclude
20 endif
21
22 EXE_INC = \
23 $ ( PFLAGS ) \
24 $ ( COND_INC ) \
25 - I$ ( LIB_SRC ) / finiteVolume / lnInclude \
26 - I$ ( LIB_SRC ) / meshTools / lnInclude
27
28
29 ifeq ( $ ( F O A M _ V E R S I O N _ M A J O R ) ,9)
30 COND_LIB = \
31 - lfvModels \
32 - l fvConstr aints
33 else
34 COND_LIB = \
35 - lfvOptions
36 endif
37
38 EXE_LIBS = \
39 $ ( COND_LIB ) \
40 - lfiniteVolume \
41 - lmeshTools
Listing 499: An options file with conditional include paths and library names.
Note, that the if statement in Listing 500 uses the variable that was passed as a compiler argument in Line
2 of Listing 499.
243 Between OpenFOAM-8 and OpenFOAM-9 multi-phase Eulerian turbulence modelling was re-organized.
This offering is not approved or endorsed by ESI® Group, ESI-OpenCFD® or the OpenFOAM®
VIII 395
Foundation, the producer of the OpenFOAM® software and owner of the OpenFOAM® trademark.
Part IX
Theory
This section covers more detailled topics and tries to look under the hood of OpenFOAM from a non-programming
view.
This offering is not approved or endorsed by ESI® Group, ESI-OpenCFD® or the OpenFOAM®
IX 396
Foundation, the producer of the OpenFOAM® software and owner of the OpenFOAM® trademark.
60 Discretization
60.1 Temporal discretization
60.2 Spatial discretization
The purpose of spatial discretization schemes is to compute the face values of fields whose values are stored at
the cell centre. The face values are then used e.g. for computing the spatial derivatives.
For quadrilateral and hexahedral meshes, where unique upstream and downstream faces and cells
can be identified, ANSYS FLUENT also provides the QUICK scheme for computing a higher-order
value of the convected variable at a face.
D ∂
= + (u · ∇) (201)
Dt ∂t
For example applied to an arbitrary scalar K
DK ∂K
= + u · ∇K (202)
Dt ∂t
Continuity equation
As a first example we look up the differential form of the continuity equation.
∂ρ
conservation form: + ∇ · (ρu) = 0 (203)
∂t
Dρ
nonconservation form: + ρ∇ · u = 0 (204)
Dt
Both forms are equivalent to each other, since we can express one equation easily by the other one with the
help of some simple mathematical operations.
This offering is not approved or endorsed by ESI® Group, ESI-OpenCFD® or the OpenFOAM®
IX 397
Foundation, the producer of the OpenFOAM® software and owner of the OpenFOAM® trademark.
∂ρ
+ ∇ · (ρu) = 0 (205)
∂t
∂ρ
+ ∇ρ · u + ρ∇ · u = 0 (206)
∂t
∂ρ
+ u · ∇ρ +ρ∇ · u = 0 (207)
|∂t {z }
Dρ
Dt
Transport equation
For the next example we use the right hand side of the transport equation of enthalpy in a multiphase problem.
This example is motivated by the energy equation of twoPhaseEulerFoam in OpenFOAM-2.3.x. We could also
have used the momentum equation, however, we want to avoid confusion by the repeated occurance of the
velocity.
We look up the energy equation for multiphase flows from a textbook or other resources [9, 6]. For the sake of
brevity, we state only the left hand side of the equation. The equation we looked up (Eqn. (208)) happens to be
formulated in the conservation form. We now rearrange the equation in order to gain the nonconservation form.
∂αk ρk hk
+ ∇ · (αk ρk uk hk ) = RHS (208)
∂t
by partial derivation of the LHS, we gain
∂αk ρk ∂hk
hk + αk ρk + hk ∇ · (αk ρk uk ) + αk ρk uk · ∇hk = RHS (209)
∂t
∂t
∂αk ρk ∂hk
hk + ∇ · (αk ρk uk ) +αk ρk + uk · ∇hk = RHS (210)
∂t ∂t
| {z } | {z }
I II
We now pay attention to the term marked by I, we recognize the phase-continuity equation which equals
zero. The term marked with II is the substantial derivative of hk . Thus we gain with Eqn. (211), the noncon-
servation form of the energy equation.
∂hk
αk ρk + uk · ∇hk = RHS (211)
∂t
Dhk
αk ρk = RHS (212)
Dt
All the operations we applied to get from Eqn. (208) to (211) applied only to the left hand side. Thus, the
distinction in conservation and nonconservation form applies only to the left hand side of the equation.
∂αk ρk hk ∂hk ∂αk ρk
+ ∇ · (αk ρk uk hk ) = αk ρk + uk · ∇hk + hk + ∇ · (αk ρk uk ) (213)
∂t ∂t ∂t
∂αk ρk hk ∂αk ρk ∂hk
+ ∇ · (αk ρk uk hk ) − hk + ∇ · (αk ρk uk ) = αk ρk + uk · ∇hk (214)
∂t ∂t ∂t
This offering is not approved or endorsed by ESI® Group, ESI-OpenCFD® or the OpenFOAM®
IX 398
Foundation, the producer of the OpenFOAM® software and owner of the OpenFOAM® trademark.
We now want to solve the energy equation. For this we choose the nonconservative form (211).
∂hk
αk ρk + uk · ∇hk = RHS (211)
∂t
Mathematically, Eqns. (211) and (215) are equivalent. However, when we now discretize both equations in
order to solve them numerically, the left hand sides of Eqns. (211) and (215) might actually be different, as the
discretised phase continuity equation might not equal zero.
We now take a break from math and take a look into the source code of twoPhaseEulerFoam-2.3.x. In Listing
502 we see the first terms of the energy equation of one phase. For a discussion on the full energy equations see
Section 45.5.
In Lines 3 and 4 of Listing 502 we see the left hand side of Eqn. (215).
Listing 501: The first terms of the energy equation in the file EEqns.H of twoPhaseEulerFoam.
Listing 502: The definition of the continuity error in the file twoPhaseEulerFoam.C.
We can create more resemblance if we repeat Eqn. (215) and name some of the terms. In Listing 502
the definition of the continuity error differs slightly from Eqn. (215). This is due to the fact, that the solver
considers phase sources, see Line 4 of Listing 502.
∂αk ρk hk ∂αk ρk
+ ∇ · (αk ρk uk hk ) −hk + ∇ · (αk ρk uk ) = RHS (215)
| ∂t
{z } | {z }
fvm::div(alphaRhoPhi1, he1) |
∂t
{z }
fvm::ddt(alpha1, rho1, he1) contErr1
This offering is not approved or endorsed by ESI® Group, ESI-OpenCFD® or the OpenFOAM®
IX 399
Foundation, the producer of the OpenFOAM® software and owner of the OpenFOAM® trademark.
61 Momentum diffusion in an incompressible fluid
61.1 Governing equations
In Section 42.1 we discussed the governing equations of a solver for incompressible fluids.
∂u
+ ∇(uu) + ∇ · dev(Ref f ) = −∇p + Q
(81)
∂t | {z }
=div(dev(Ref f ))
ef f
= −ν ef f ∇u + (∇u)T
R (75)
∂u
+ ∇(uu) + ∇ · dev(−ν ef f ∇u + (∇u)T ) = −∇p + Q
(82)
∂t
The momentum diffusion term is handled by the turbulence model.
∇ · dev(Ref f )
⇔ turbulence->divDevReff(U)
| {z }
=div(dev(Ref f ))
61.2 Implementation
All turbulence model of OpenFOAM are based on a generic turbulence model class. Figure 154 in Section 57.10
shows a class diagram. There, it is shown, that all RAS turbulence model classes as well as all LES turbulence
model classes are derived from the same base class. A lot of solvers of OpenFOAM allow the user to choose
between laminar simulation as well as RAS or LES turbulence modelling. Therefore, by the time of writting the
source code, nobody could have known, which turbulence exactly will handle the momentum diffusion term.
To overcome such problems, modern programming languages support a technique called polymorphism. In
the source code the instruction turbulence->divDevReff(U) is called to compute the diffusive term. This
instruction means, that the method divDevReff() of the object turbulence is called.
1 s i n g l e P h a s e T r a n s p o r t M o d e l la m i n a r T r a n s p o r t (U , phi ) ;
2
3 autoPtr < inc ompressib le :: turbulenceModel > turbulence
4 (
5 inco mpressib le :: tu rb u le nc eM o de l :: New (U , phi , l a m i n a rT r a n s p o r t )
6 );
This offering is not approved or endorsed by ESI® Group, ESI-OpenCFD® or the OpenFOAM®
IX 400
Foundation, the producer of the OpenFOAM® software and owner of the OpenFOAM® trademark.
By the time of compilation, it is guaranteed that the object turbulence is of the data type turbulenceModel.
However, turbulence will never actually be of the data type turbulenceModel. It will be of a data type derived
from turbulenceModel. The decision which exact method divDevReff() has to be called, will be made at run-
time based on the actual type of turbulence.
Listing 505 shows the declaration of the virtual method divDevReff(). See Section 57.10 for a discussion
on virtual methods. Listing 506 shows how this method is actually implemented by the standard k- turbulence
models of OpenFOAM.
tmp < fvVectorMatrix > kEpsilon :: divDevReff ( vol VectorFi eld & U ) const
{
return
(
- fvm :: laplacian ( nuEff () , U )
- fvc :: div ( nuEff () * dev ( T ( fvc :: grad ( U ) ) ) )
);
}
∇ · ν(∇U)T
= −∇ · (ν(∇U)) −
| {z } | {z }
laplacian(nu,U) div(nu*dev(T(grad(U))))
The momentum diffusion term is most probably split into two parts for numerical reasons.
This offering is not approved or endorsed by ESI® Group, ESI-OpenCFD® or the OpenFOAM®
IX 401
Foundation, the producer of the OpenFOAM® software and owner of the OpenFOAM® trademark.
62 The incompressible k- turbulence model
62.1 The k- turbulence model in literature
The governing equations for the k- model for a single phase are taken from Wilcox [69].
Eddy viscosity
k2
µT = ρCµ (216)
Turbulent kinetic energy
∂k ∂k ∂Ui ∂ µT ∂k
ρ + ρUj = τij − ρ + (µ + ) (217)
∂t ∂xj ∂xj ∂xj σk ∂xj
Dissipation Rate
2
∂ ∂ ∂Ui ∂ µT ∂
ρ + ρUj = C1 τij − C2 ρ + (µ + ) (218)
∂t ∂xj k ∂xj k ∂xj σ ∂xj
Closure coefficients
The transport equations for k and are reorganized to follow the basic structure
Dissipation Rate
2
∂ ∂ ∂ µT ∂ ∂Ui
ρ + ρUj − (µ + ) = C1 τij −C2 ρ (221)
∂t ∂xj ∂xj σ ∂x k ∂xj k
| {z } j | {z }
D G
Diffusivity constants
µT
Dk = µ + (222)
σk
µT
D = µ + (223)
σ
The constant expressions in the diffusive terms are combined into the diffusivity constants Dk and D . The
first term on the right hand side of the turbulent kinetic energy equation is the production of turbulent kinetic
energy G.
This offering is not approved or endorsed by ESI® Group, ESI-OpenCFD® or the OpenFOAM®
IX 402
Foundation, the producer of the OpenFOAM® software and owner of the OpenFOAM® trademark.
First, the transport equations for k and are divided by the density ρ. Therefore, all terms containing
viscosity contain the kinematic viscosity ν instead of the dynamic viscosity µ.
Secondly, the standard k- model of OpenFOAM has eliminated the model constant σk . Since the value of
this constant is one, this constant has been elimininated. This does not change the behaviour of the model.
However, if the user tries to change this model constant, nothing actually happens. See Section 32.4.2 for a
discussion and an example.
Finally, the convection term is converted into two term by the product rule of differentiation. See Eqn. (225).
µT = ρ νT
k2
νT = Cµ (224)
Turbulent kinetic energy, see Listing 508
∂k ∂k
Uj = U· = U · ∇k
∂xj ∂x
∂k
U· = ∇ · (Uk) − (∇ · U)k (225)
∂x
∂k
+ ∇ · (Uk) − (∇ · U)k − ∇ · (Dk ∇k) = G − (226)
∂t
Dissipation Rate
∂ 1 2
+ ∇ · (U) − (∇ · U) − ∇ · (D ∇) = C1 G − C2 (227)
∂t k k
Diffusivity constants - Note that σk has been eliminated from the equations
Dk = DkEff = ν + νT (228)
νT
D = DepsilonEff = ν + (229)
σ
Closure coefficients - default values
The default values of the model constants can be found in the constructor of the respective turbulence model
class.
= k (231)
k
|{z}
fvm::Sp(epsilon/k, k)
This offering is not approved or endorsed by ESI® Group, ESI-OpenCFD® or the OpenFOAM®
IX 403
Foundation, the producer of the OpenFOAM® software and owner of the OpenFOAM® trademark.
tmp < fvScalarMatrix > kEqn
(
fvm :: ddt ( k_ )
+ fvm :: div ( phi_ , k_ )
- fvm :: Sp ( fvc :: div ( phi_ ) , k_ )
- fvm :: laplacian ( DkEff () , k_ )
==
G
- fvm :: Sp ( epsilon_ / k_ , k_ )
);
Constructor
Listing 509 shows the first lines of the constructor of the kEpsilon class. The constructor receives five argu-
ments. After the colon (in line 9), the initialisation list follows. This list contains also the default values of the
model constants. See Section 56.5 for details about constructors in C++. In line 18 the default value of the
model constant Cµ is defined.
1 kEpsilon :: kEpsilon
2 (
3 const volV ectorFie ld & U ,
4 const s u r f a c e S c a l a r F i e l d & phi ,
5 tran sportMod el & transport ,
6 const word & turbulenceModelName ,
7 const word & modelName
8 )
9 :
10 RASModel ( modelName , U , phi , transport , t u r b u l e n c e M o d e l N a m e ) ,
11
12 Cmu_
13 (
14 dimensioned < scalar >:: l o o k u p O r A d d T o D i c t
15 (
16 " Cmu " ,
17 coeffDict_ ,
18 0.09
19 )
20 ),
21 /* code continues */
This offering is not approved or endorsed by ESI® Group, ESI-OpenCFD® or the OpenFOAM®
IX 404
Foundation, the producer of the OpenFOAM® software and owner of the OpenFOAM® trademark.
2. The model constants σk and σ are replaced by their reciprocal values.
3. Other than in the standard k- model, the model constant σk is not dropped. By defining a value for the
constant α1,k = 1/σk , a value for σk is assigned.
Turbulence modelling in bubbleFoam and twoPhaseEulerFoam is based on the liquid quantities. Turbulence of
the gas phase is considered by the use of the model constant Ct . This constant connects the turbulent viscosity
of the liquid and the gas phase. By setting this constant to zero, turbulence is ignored in the gas phase.
Eddy viscosity
k2
ν2,T = Cµ (232)
ν2,ef f = ν2 + ν2,T (233)
ν1,ef f = ν1 + Ct2 ν2,T (234)
∂ 1 2
+ ∇ · (U2 ) − (∇ · U2 ) − ∇ · (α1, ν2,ef f ∇) = C1 G − C2 (236)
∂t k k
Diffusivity constants - Note the different definition
1
α1,k =
σk
1
α1, =
σ
ν2,ef f
Dk = α1,k ν2,ef f = (237)
σk
ν2,ef f
D = α1, ν2,ef f = (238)
σ
Closure coefficients - default values
This offering is not approved or endorsed by ESI® Group, ESI-OpenCFD® or the OpenFOAM®
IX 405
Foundation, the producer of the OpenFOAM® software and owner of the OpenFOAM® trademark.
17 - fvm :: Sp ( C2 * epsilon /k , epsilon )
18 );
19
20 // Turbulent kinetic energy equation
21 fvSc alarMatr ix kEqn
22 (
23 fvm :: ddt ( k )
24 + fvm :: div ( phi2 , k )
25 - fvm :: Sp ( fvc :: div ( phi2 ) , k )
26 - fvm :: laplacian
27 (
28 alpha1k * nuEff2 , k ,
29 " laplacian ( DkEff , k ) "
30 )
31 ==
32 G
33 - fvm :: Sp ( epsilon /k , k )
34 );
35
36 // - Re - calculate turbulence viscosity
37 nut2 = Cmu * sqr ( k ) / epsilon ;
Listing 510: The turbulent transport equations of the bubbleFoam and twoPhaseEulerFoam solver
P = µT ∇U : ∇U + (∇U)T
(243)
Wilcox [69]
2
G = µT ∇U : ∇U + (∇U)T − ρkI : ∇U (244)
3
Some definitions use the dynamic viscosity and some others use the kinematic viscosity. For incompressible
fluids, this is no major difference between the definitions.
This offering is not approved or endorsed by ESI® Group, ESI-OpenCFD® or the OpenFOAM®
IX 406
Foundation, the producer of the OpenFOAM® software and owner of the OpenFOAM® trademark.
62.4.3 Notation
The definitions in Section 62.4.1 are written in vector notation. However, there seems to be a minor flaw in Eq.
(240). There
2
G = µT ∇U : ∇Ub + (∇Ub )T − ρkI : ∇U (244)
3
Using the following identities, the contraction can be replaced by an inner product
I : ∇U = tr(∇U) = ∇ · U (246)
For incompressible fluids the divergence of the velocity must be zero due to the continuity equation
∇·U = 0 (247)
T
2
G = µT ∇U : ∇Ub + (∇Ub ) − ρkI : ∇U (248)
|3 {z }
=0
Therefore, Eqns. (243) and (244) are identical if the fluid is incompressible. We now can examine the
differences of the definitions of the production term, using Eq. (243) as reference equation.
This offering is not approved or endorsed by ESI® Group, ESI-OpenCFD® or the OpenFOAM®
IX 407
Foundation, the producer of the OpenFOAM® software and owner of the OpenFOAM® trademark.
This leads to the answer
1
∇Ub : dev ∇Ub + (∇Ub )T
∇U2 : dev (sym(∇U2 )) = (257)
2
The definition of the production term in the source code differs in two ways from the definition in the source
code
1. The use of different viscosities, see Eqns. (240) and (241).
2. A factor of 2, compare Eqns. (250) and (257)
The reason for this differences is not clear. H. Rusche refers to an article which is not available to the author.
The second term of the rhs vanishes according to the continuity equation for an incompressible fluid
T
T 2
∇U : ∇U + (∇U) = ∇U : dev(∇U + (∇U) ) + (∇ · U) (265)
3 | {z }
∇ · U=0
Eq. (266) now resembles Eq. (260). Therefore, we proofed that the definition of bubbleFoam is equivalent to
the definition of Ferzinger
This offering is not approved or endorsed by ESI® Group, ESI-OpenCFD® or the OpenFOAM®
IX 408
Foundation, the producer of the OpenFOAM® software and owner of the OpenFOAM® trademark.
62.4.7 Definition of standard k- of OpenFOAM
We now compare the definition of the production term of the standard k- model implemented in OpenFOAM
with the definition found in [37].
P = νT ∇U : ∇U + (∇U)T
(243)
Starting from Eq. (243), we will use Eq. (266) and Eq. (256)
to gain
The lhs of Eq. (269) corresponds to Eq. (242). The rhs of Eq. (269) was derived from Eq. (243). Now, we use
some identities
1
dev(T) = T − tr(T) (251)
3
tr(sym(T)) = tr(T) (270)
I : ∇U = tr(∇U) = ∇ · U = 0 (246)
We now have
The following equation remains, which is easily proofed by some tensor calculus
This offering is not approved or endorsed by ESI® Group, ESI-OpenCFD® or the OpenFOAM®
IX 409
Foundation, the producer of the OpenFOAM® software and owner of the OpenFOAM® trademark.
Therefore, we can write
The following properties of skew tensors let the second contraction vanish
aii = 0 (279)
aij = −aji (280)
skew(T) : sym(T) = aij sij = 0 (281)
Finally, we obtain
Therefore, we proofed that the definition of the standard k- model is equivalent to the definition of Ferzinger.
This offering is not approved or endorsed by ESI® Group, ESI-OpenCFD® or the OpenFOAM®
IX 410
Foundation, the producer of the OpenFOAM® software and owner of the OpenFOAM® trademark.
63 Some theory behind the scenes of LES
63.1 LES model hierarchy
The large eddy simulation is based on the spatial filtering of the governing equations. Similar to the Reynolds-
averaged modelling strategy (filtering with respect to time), the large eddy modelling strategy requires some
closure models. In principle, the velocity is decomposed into a grid-scale and a sub-grid scale portion. The
grid-scale portion is resolved by the governing equations. The sub-grid scale portion – or the influence of the
sub-grid scale portion on the resolved velocity – needs to be modelled.
Similar to the RANS approach, the closure terms appear in the stress terms of the momentum equations.
There are several modelling strategies to close the equations. The class hierarchy of the LES models of Open-
FOAM reflects the different approaches. Figure 156 shows the first layer of the class hierarchy of the LES
models in OpenFOAM. First layer means that a class derived from the abstract class LESModel may be an
abstract class itself and therefore be the base for other classes244245 .
LESModel
Figure 156: First layer of the class hierarchy of the LES models of OpenFOAM
The classification according to Figure 156 is not the only possible way to divide all existing LES models into
categories.
63.2.2 Classification
The eddy viscosity models can be divided further based on the way the sub-grid viscosity is computed and the
complexity of the model.
244 In a class diagram a class with an italic written name is an abstract class. A class with an upright written name is an actual
class.
245 This shows the great advantage of object oriented programming. The class hierarchy of the code reflects the relation between
the objects in reality, e.g. every eddy viscosity model is an LES model, but not every LES model is an eddy viscosity model.
This offering is not approved or endorsed by ESI® Group, ESI-OpenCFD® or the OpenFOAM®
IX 411
Foundation, the producer of the OpenFOAM® software and owner of the OpenFOAM® trademark.
LESModel
laminar GenEddyVisc
spectEddyVisc
homogeneousDynOneEqEddy
homogeneousDynSmagorinsky
Smagorinsky2 mixedSmagorinsky
m2 m
[νSGS ] = = ·m (284)
s s
νSGS = CSGS lSGS qSGS (285)
A choice that is common to a number of eddy viscosity models in OpenFOAM is to choose the filter width
as the length scale and the square root of the sub-grid kinetic energy as teh velocity scale. Algebraic models
usually calculate the sub-grid kinetic energy from known quantities, e.g. based on the velocity gradient. One
equation models typically solve a transport equation for the sub-grid scale kinetic energy.
This offering is not approved or endorsed by ESI® Group, ESI-OpenCFD® or the OpenFOAM®
IX 412
Foundation, the producer of the OpenFOAM® software and owner of the OpenFOAM® trademark.
lSGS = ∆ (286)
[lSGS ] = m (287)
p
qSGS = kSGS (288)
r
m2 m
[qSGS ] = 2
= (289)
s s
with
S = sym(∇u) = sym(grad(u))
√
|T| = T : T
Some rearrangement of Eq. (290) is necessary to match the form of Definition (285) and (288). Eqns. (291)
to (293) show the necessary steps to match the generic definition of νSGS .
√
νSGS = CS2 |{z}
∆ |∆ {z
S : S} (291)
lSGS qSGS
p √
qSGS = kSGS = ∆ S : S (292)
2
⇒ kSGS = ∆ S : S (293)
Implementation
The implementation in the source code differs a little from the equations above.
1 tmp < volScalarField > k ( const tmp < volTensorField >& gradU ) const
2 {
3 return (2.0* ck_ / ce_ ) * sqr ( delta () ) * magSqr ( dev ( symm ( gradU ) ) ) ;
4 }
Listing 511 shows the implementation of how the sub-grid viscosity is computed by the Smagorinsky model
in OpenFOAM. Listing 512 shows how the model calculates the sub-grid kinetic energy.
√
nuSgs = ck∆ k (294)
ck
k = 2 ∆2 |dev S|2 (295)
ce
This offering is not approved or endorsed by ESI® Group, ESI-OpenCFD® or the OpenFOAM®
IX 413
Foundation, the producer of the OpenFOAM® software and owner of the OpenFOAM® trademark.
with
it follows
r
ck
nuSgs = ck∆ 2 ∆2 |dev S|2 (297)
ce
r
ck 2
nuSgs = ck 2 ∆ |dev S| (298)
ce
the comparison with Eq. 290 shows
p
νSGS = ck∆ kSGS (300)
This offering is not approved or endorsed by ESI® Group, ESI-OpenCFD® or the OpenFOAM®
IX 414
Foundation, the producer of the OpenFOAM® software and owner of the OpenFOAM® trademark.
the unresolved protion of the velocity. Thus, kSGS is called sub-grid kinetic energy.
∂kSGS
+ ∇ · (kSGS u) − ∇ · (Dk ∇kSGS ) = G − SGS (301)
∂t
with
Dk = ν + νSGS
G = νSGS |sym(∇u)|2
√
kSGS
SGS = ce kSGS
∆
Eq. 301 is similar to the transport equation for k of the k- model. Also the definition of the sub-grid viscos-
ity is similar to the definition of the turbulent viscosity of the k- model. This is not very obvious. Therefore,
we shall explore this matter further.
p
νSGS = ck∆ kSGS (300)
√
ce kSGS kSGS p
νSGS = ck √ ∆ kSGS (302)
ce kSGS kSGS
√ √
kSGS kSGS kSGS
νSGS = ck ce √ (303)
ce kSGS ∆kSGS
2
kSGS
νSGS = ck ce (304)
SGS
Eq. 304 is similar to Eq. 224 – the definition of the turbulent viscosity of the k- model
k2
νT = Cµ (224)
The product of ck and ce when using their default values gives ck · ce = 0.0985 which is approximately the
default value of Cµ of the k- model, which is Cµ = 0.09.
This offering is not approved or endorsed by ESI® Group, ESI-OpenCFD® or the OpenFOAM®
IX 415
Foundation, the producer of the OpenFOAM® software and owner of the OpenFOAM® trademark.
64 The use of phi
64.1 The question
The governing equations of the solvers of OpenFOAM are written in a special notation that makes it easy
to compare the source codes with equations from a fluid dynamics textbook. In Section 42.1 the governing
equations of the solver pimpleFoam are examined. There, the terms of Eq. 82 are compared with the source
code, see Listing 281. Here, we repeat the comparison of how the convective term is written in the sources and
how this term is expressed mathematically.
∇(uu) ⇔ fvm::div(phi, U)
| {z }
div(uu)
We now examine how phi is defined and how we can find phi in the math.
64.2 Implementation
64.2.1 The origin of fields
One way to learn more about phi is to look for its definition in the source code of OpenFOAM.
Listing 514 shows the first lines of the main function of the solver pimpleFoam. The main function of any
C or C++ program is entered, when this program is executed. So, the instructions of Listing 514 are the first
instructions that are executed, when the solver is called.
In line 6 of Listing 514 the file createFields.H is included. This file contains instructions that create the
data structures of all fields that are necessary for the solver (e.g. the pressure or the velocity field).
Listing 514: The first few line of the main function of pimpleFoam in pimpleFoam.C
The file createFields.H contains the content of Listing 515. There, the velocity field U is created. In line
15 the file createPhi.H is included. There, the field phi is created.
This offering is not approved or endorsed by ESI® Group, ESI-OpenCFD® or the OpenFOAM®
IX 416
Foundation, the producer of the OpenFOAM® software and owner of the OpenFOAM® trademark.
64.2.2 How phi is defined
Listing 516 shows the content of the file createPhi.H. From this Listing we see the data type of phi, it is
surfaceScalarField. This tells us, that phi is a scalar, that is defined on the faces of the control volumes
(cells) of the mesh.
Line 13 tells us how phi is defined. There, we find out, that phi is the inner product of the velocity – we
forget for the moment about the function linearInterpolate – and the face surface area vector. In Listing
517 we see the declaration of the function Sf(). In Listing 518 we see, that the variable mesh of Listing 516 is
of the type fvMesh.
1 Info < < " Reading / calculating face flux field phi \ n " << endl ;
2
3 s u r f a c e S c a l a r F i e l d phi
4 (
5 IOobject
6 (
7 " phi " ,
8 runTime . timeName () ,
9 mesh ,
10 IOobject :: READ_IF_PRESENT ,
11 IOobject :: AUTO_WRITE
12 ),
13 l i n e a r I n t e r p o l a t e ( U ) & mesh . Sf ()
14 );
Listing 517: The declaration of the method Sf() of the class fvMesh in the file fvMesh.H
1 Foam :: Info
2 << " Create mesh for time = "
3 << runTime . timeName () << Foam :: nl << Foam :: endl ;
4
5 Foam :: fvMesh mesh
6 (
7 Foam :: IOobject
8 (
9 Foam :: fvMesh :: defaultRegion ,
10 runTime . timeName () ,
11 runTime ,
12 Foam :: IOobject :: MUST_READ
13 )
14 );
∂u
+ ∇(uu) + ∇ · dev(−ν ef f ∇u + (∇u)T ) = −∇p + Q
(82)
∂t
This equation is written in diferential form and is valid everywhere in the fluid. In order to use the finite
volume method, we need the governing equations in the integral form. Integrating Eq. (82) over a control
volume yields:
Z Z
∂u
+ ∇(uu) + ∇ · dev(−ν ef f ∇u + (∇u)T ) dV =
−∇p + Q dV (305)
V ∂t V
This offering is not approved or endorsed by ESI® Group, ESI-OpenCFD® or the OpenFOAM®
IX 417
Foundation, the producer of the OpenFOAM® software and owner of the OpenFOAM® trademark.
Now we will have a closer look on the second term of Eq. (305). That is the convective term we already saw
at the beginning of this section.
Using Gauss’ theorem, we replace the integration over the volume of our control volume with the integration
over the surface of the control volume.
Z I
∇(uu) dV = (uu) · dS (306)
V ∂V
Because our control volume is a polyhedron (in most cases a hexahedron or a tetrahedron), the surface
integral reduces to a sum of intergrals over the faces Sf of the polyhedron.
I XZ
(uu) · dS = (uu) · dSf (307)
∂V f Sf
kSf k = Sf (308)
With Sf being the surface normal vector of the face f . The norm of this vector is equal to the area of the
face f . We denote with the subscript f the mean face-value of a quantity.
XZ X
(uu) · dSf = (uu)f · Sf (309)
f Sf f
Z
1
(uu)f = (uu) dSf (310)
Sf Sf
Eq. (312) contains the fundamental assumption or approximation of the finite volume method. It is assumed,
that the mean face-value of the product of the velocities is (approximately) equal to the product of the mean
face-values of the velocity, see Eq. (311). In general, the operations averaging and multiplication are not
commutative.
We are now nearly finished. The rhs of Eq. (312) contains all ingredients we need for phi. A surface area
vector, a velocity and an inner vector product. See Listing 516. However, this ingredients are not in the order
we need. Therefore, there is need for some more math to do.
A general rule of tensor calculus states:
a ⊗ b · c = a(b · c) (313)
In this document, we omit the symbol ⊗ for the sake of brevity.
a ⊗ b · c = (ab) · c (314)
Eq. (314) looks like the rhs of Eq. (312).
uf (uf · Sf ) = uf φf (316)
64.4 Summary
Now, after having dug deep into the sources and after having done some math, we can summarize all thoughts
so far. We want to understand this equivalency.
∇(uu) ⇔ fvm::div(phi, U)
| {z }
div(uu)
This offering is not approved or endorsed by ESI® Group, ESI-OpenCFD® or the OpenFOAM®
IX 418
Foundation, the producer of the OpenFOAM® software and owner of the OpenFOAM® trademark.
The math tells use the following identities.
Z I
∇(uu) dV = (uu) · dS (317)
V ∂V
I X
(uu) · dS = (uu)f · Sf (318)
∂V f
X X
(uu)f · Sf ≈ (uf uf ) · Sf (319)
f f
X X
(uf uf ) · Sf = uf (uf · Sf ) (320)
f f
X X
uf (uf · Sf ) = uf φf (321)
f f
We have shown, that the integral formulation of the convective term can be reformulated to incorporate φ
and u instead of uu.
This offering is not approved or endorsed by ESI® Group, ESI-OpenCFD® or the OpenFOAM®
IX 419
Foundation, the producer of the OpenFOAM® software and owner of the OpenFOAM® trademark.
65 Derivation of the IATE diameter model
In this section we cover the derivation of OpenFOAMs IATE diameter model from [35].
∂f ∂ dV X
+ ∇ · (f u) + f = Sj + Sph (322)
∂t ∂V dt j
The equation for the bubble number density distribution is much too detailled for most flow studies [41].
Thus, we derive a transport equation for the area concentration ai . The area concentration is a moment of the
bubble number density distribution. Besides the area concentration we can define further quantities based on
the moments of the number density distribution.
Eqn. (323) lists the general definition of the i-th moment mi of the probability density function f (x).
Z b
mi = f (x)xi dx (323)
a
Z Vmax
Total number of bubbles per unit volume n(x, t) = f (V, x, t)dV (324)
Vmin
Z Vmax
Volume fraction of bubbles α(x, t) = f (V, x, t)V dV (325)
Vmin
Z Vmax
Area concentration of bubbles ai (x, t) = f (V, x, t)Ai (V )dV (326)
Vmin
∂f ∂ dV X
Ai + Ai ∇ · (f u) + Ai f = Ai Sj + Sph (327)
∂t ∂V dt j
Z Vmax Z Vmax
∂f ∂ dV X
Ai + Ai ∇ · (f u) + Ai f dV = Ai Sj + Sph dV (328)
Vmin ∂t ∂V dt Vmin j
Now we will take a closer look on the single terms of Eqn. (328). For the first term, we simply apply Leibnitz
rule. Here it is important to note, that Ai is constant in space and time. With Eqn. (326), we gain the local
This offering is not approved or endorsed by ESI® Group, ESI-OpenCFD® or the OpenFOAM®
IX 420
Foundation, the producer of the OpenFOAM® software and owner of the OpenFOAM® trademark.
derivative of the interfacial area concentration ai .
Z Vmax Z Vmax
∂f ∂
Ai dV = Ai f dV (329)
Vmin ∂t ∂t Vmin
Z Vmax
∂f ∂
Ai dV = ai (330)
Vmin ∂t ∂t
The convective term of Eqn. (328) can be treated in a similar fashion. If the velocity is independent of the
bubble size, we can put the u in front of the integral over all bubble sizes. Thus, we gain the convective term
for the interfacial area concentration.
Z Vmax Z Vmax
Ai ∇ · (f u) dV = ∇ · (Ai f u) dV (331)
Vmin Vmin
!
Z Vmax Z Vmax
Ai ∇ · (f u) dV = ∇ · u Ai f dV (332)
Vmin Vmin
Z Vmax
Ai ∇ · (f u) dV = ∇ · (u ai ) (333)
Vmin
If the velocity is not independent of the bubble size we can follow a similar strategy to derive a convective
term which is formulated in terms of the interfacial area concentration.
Z Vmax Z Vmax
ai
Ai ∇ · (f u) dV = ∇· Ai f u dV (334)
Vmin Vmin ai
R Vmax !
Z Vmax Ai f udV
Vmin
Ai ∇ · (f u) dV = ∇ · ai (335)
Vmin ai
Z Vmax
Ai ∇ · (f u) dV = ∇ · (ai ui ) (336)
Vmin
With the average local bubble velocity weighted by the bubble number ui [20]
R Vmax
Ai f udV
ui = RVmin
Vmax
(337)
Vmin
Ai f dV
The third term of Eqn. (328) needs more special treatment. In Section 65.5.1 we show the proof for (338).
This term relates to the gas expansion.
Z Vmax
∂ dV 2 α̇
Ai f dV = − ai (338)
Vmin ∂V dt 3α
The RHS of Eqn. 328 contains the terms due to bubble-bubble interaction and due to phase change.
Z Vmax Z Vmax
∂f ∂ dV X
Ai + Ai ∇ · (f u) + Ai f dV = Ai Sj + Sph dV (328)
Vmin ∂t ∂V dt Vmin j
There are two approaches to model the source terms due to bubble interaction [43]. One can solve the
integral equation for these source terms (339) or solve algebraic equations using mean parameters (340).
The latter approach assumes monosized bubble, i.e. a bubble breaks up into two equalsized daughter bubbles
[43]. In this approach each bubble interaction results in a change of interfacial area ∆Ai = 13 Ai .
Z Vmax X
Ai Sj dV = Φj (339)
Vmin j
Φj = Sj ∆Ai (340)
This offering is not approved or endorsed by ESI® Group, ESI-OpenCFD® or the OpenFOAM®
IX 421
Foundation, the producer of the OpenFOAM® software and owner of the OpenFOAM® trademark.
with the interfacial area Ai
ai
Ai = (341)
n
1
and bubble number density n, Ψ = 36π for spherical bubbles
a3
n = Ψ i2 (342)
α
2
11 α
Φj = Sj (343)
3 Ψ ai
The phase change term can be modelled directly, but within the framework of this manual we will not
consider phase change. Thus we gained a transport equation for the interfacial area concentration ai .
2
∂ai 2 α̇ X1 1 α
+ ∇ · (u ai ) = ai + Sj (344)
∂t 3α j
3Ψ ai
ai = ακ (345)
6
dsm = (346)
κ
Thus, the Sauter mean diameter dsm equals
6α
dsm = (347)
ai
Which corresponds with the definition given in literature [33, 34].
6α
dsm = (348)
ai
Listing 519 and 520 show the relevant source code of the IATE diameter model. This source code is the basis
for Eqns. (345) and (346).
Listing 519: Definition of the method a() of the IATE diameter model classin the file IATE.H.
1 Foam :: tmp < Foam :: volScalarField > Foam :: d iameterM odels :: IATE :: dsm () const
2 {
3 return max (6/ max ( kappai_ , 6/ dMax_ ) , dMin_ ) ;
4 }
Listing 520: Definition of the method dsm() of the IATE diameter model class in the file IATE.C.
The definition of kappai_ as the interfacial curvature seems a bit counter-intuitive, as the curvature of a
sphere is the inverse of its radius.
This offering is not approved or endorsed by ESI® Group, ESI-OpenCFD® or the OpenFOAM®
IX 422
Foundation, the producer of the OpenFOAM® software and owner of the OpenFOAM® trademark.
65.3.2 Derivation of the governing equations
We will now derive the governing equations for the interfacial curvature κ from the equations for the interfacial
area concentration ai which we derived from the transport equations for the bubble size distribution.
Here we will make no further assumptions, as we are simply rearranging the equations. We start from the
transport equation for the interfacial area concentration ai and OpenFOAMs definition of ai .
2
∂ai 2 α̇ X1 1 α
+ ∇ · (u ai ) = ai + Sj (344)
∂t 3α j
3Ψ ai
ai = ακ (345)
∂ακ 2 α̇ X 1 1 α 2
+ ∇ · (u ακ) = ακ + Sj (349)
∂t 3α j
3 Ψ ακ
∂κ ∂α 2 X 1 1 1 2
α +κ + κ∇ · (u α) + αu · ∇κ = α̇κ + Sj (350)
∂t ∂t 3 j
3Ψ κ
∂α
∂κ
2 X 1 1 1 2
κ + ∇ · (u α) +α + u · ∇κ = α̇κ + Sj (351)
∂t ∂t 3 j
3Ψ κ
| {z }
α̇
∂κ
1 X 1 1 1 2
α + u · ∇κ = − α̇κ + Sj (352)
∂t 3 j
3Ψ κ
2
∂κ 1 κ X1 1 1 1
+ u · ∇κ = − α̇ + Sj (353)
∂t 3 α j
3Ψα κ
1 α
With κ = ai
2 X
∂κ 1 α̇ 1 α Sj
+ ∇ (κu) − κ∇
| {z· u} = − 3 α κ + 3Ψ (354)
∂t ai j
α
| {z } II | {z }
I III
The form of Eqn. (354) is chosen to match the equations given in [35]. The second term of the RHS has
exactly the same form as the equivalent terms in [35].
This offering is not approved or endorsed by ESI® Group, ESI-OpenCFD® or the OpenFOAM®
IX 423
Foundation, the producer of the OpenFOAM® software and owner of the OpenFOAM® trademark.
The right hand side of the equation in Listing 521 combines all term of the RHS of Eqn. (354) into the term
fvm::SuSp(R, kappai_). The method fvm::SuSp() implements a source term for a matrix equation. The
arguments translate to R * kappai_.
The first term on the RHS of Eqn. (354) is due to the change of bubble volume (dilatation effect). The code
in Listing 522 translates to Eqn. (355).
Listing 522: The first term of the RHS of Eqn. (354) of the transport equation in the file IATE.C.
∂α
1 ∂t + ∇ · (αu)
R= (355)
3 α
The method call fvm::SuSp(R, kappai_) multiplies R with kappai_. Thus we recognize the first term of
the RHS of Eq. (354).
1 α̇
Eqn. (354) III = − κ (356)
3α
OpenFOAM III = −Rκ (357)
1 α̇
R= (358)
3α
1 α̇
III = − κ (359)
3α
The other source terms related to the models for bubble-bubble interaction are added to R. Listing 523 shows
the loop over all sources, note the minus sign.
Listing 523: The second term of the RMS of Eqn. (354) of the transport equation in the file IATE.C.
For the interaction models the minus of Listing 523 cancels the minus of Listing 521.
This offering is not approved or endorsed by ESI® Group, ESI-OpenCFD® or the OpenFOAM®
IX 424
Foundation, the producer of the OpenFOAM® software and owner of the OpenFOAM® trademark.
65.4.1 Turbulent impact - TI
In [34, 35] the source term due to turbulent impact is stated as:
a3
n = Ψ i2 (360)
√α
ut = 2k (361)
r
nut W ecr W ecr
RT I = CT I exp − 1− where W ecr > W e (362)
Db We We
The Weber number W e can be seen as the ratio of inertia forces and surface tension forces and is defined
as:
ρu2 d
We = (363)
σ
with
ρ density
u characteristic velocity
d characteristic length scale
σ surface tension
The Weber number is provided by the class IATEsource as the base class for all interaction models. See
Section 65.4.4 for implementation details.
The critical Weber number W ecr and the model constant CT I must be provided by the user in the appropriate
dictionary.
√
ut = 2k (364)
" #" 1/3
!#
1/3
n2 ut Db2 αmax α
RRC = CRC 1/3 1/3 1/3
1 − exp −C 1/3
(365)
αmax (αmax − α ) αmax − α1/3
The model constants CRC , C and αmax need to be provided by the user.
1/3
RW E = CW E CD n2 Db2 ur (366)
The model constant CW E needs to be provided by the user.
1 Foam :: tmp < Foam :: volScalarField > Foam :: d iameterM odels :: IATEsource :: We ()
2 const
3 {
4 return otherPhase () . rho () * sqr ( Ur () ) * phase () . d () / fluid () . sigma () ;
5 }
This offering is not approved or endorsed by ESI® Group, ESI-OpenCFD® or the OpenFOAM®
IX 425
Foundation, the producer of the OpenFOAM® software and owner of the OpenFOAM® trademark.
Relative velocity
The relative velocity between the bubbles and the surrounding fluid is given by [32, 40]. Compare Eqn. (367)
and Listing 525.
1/4
√
σg∆ρ 1.75
ur = 2 (1 − α) (367)
ρ2L
1 Foam :: tmp < Foam :: volScalarField > Foam :: d iameterM odels :: IATEsource :: Ur () const
2 {
3 const u n i f o r m D i m e n s i o n e d V e c t o r F i e l d & g =
4 phase () . U () . db () . lookupObject < un ifo rmD im ens ion edV ect orF ie ld >( " g " ) ;
5
6 return
7 sqrt (2.0)
8 * pow025
9 (
10 fluid () . sigma () * mag ( g )
11 *( otherPhase () . rho () - phase () . rho () )
12 / sqr ( otherPhase () . rho () )
13 )
14 * pow ( max (1 - phase () , scalar (0) ) , 1.75) ;
15 }
Listing 525: The definition of the relative velocity between bubbles and surrounding liquid in IATEsource.C
The IATE implicitely applies only to bubbly systems, i.e. gas-liquid systems. If the IATE model is applied to
the denser phase, then Line 11 of Listing 525 leads to a floating-point exception (FPE). If phase refers to the
liquid phase, then Line 11 evaluates to a negative number. Raising a negative number to a non-integer power
is not possible within the domain of the real numbers. Thus, OpenFOAM will issue an error message due to an
floating-point exception.
This offering is not approved or endorsed by ESI® Group, ESI-OpenCFD® or the OpenFOAM®
IX 426
Foundation, the producer of the OpenFOAM® software and owner of the OpenFOAM® trademark.
30 R [ celli ] =
31 (1.0/3.0)
32 * Cti / d [ celli ]
33 * Ut [ celli ]
34 * sqrt (1 - WeCr / We [ celli ])
35 * exp ( - WeCr / We [ celli ]) ;
36 }
37 }
38
39 return tR ;
40 }
r
1 CT I W ecr W ecr
RT I = ut 1− exp − where W e > W ecr (368)
3 dsm We We
Comparing Eqns. (362) and (368) reveals some differences in formulation. This is due to the fact, that Eq.
(362) is a source term for the transport equation for the interfacial area concentration ai and Eq. (368) is a
source term for the transport equation for the interfacial curvature κ.
In the derivation of the curvature equation from the area concentration equation we divided by the volume
fraction. Otherwise, only rearrangement and variable substitution was performed.
For this term we now have a look on the RHS of the equations for ai and κ and compare the implementation
of OpenFOAM with the equations stated in literature.
We begin with repeating the equations for ai and κ. The interaction source term Sj can be found in this
form in [35].
∂ai 2 α̇ X 1 1 α 2
+ ∇ · (u ai ) = ai + Sj (344)
∂t 3α j
3 Ψ ai
2 X
∂κ 1 α̇ 1 α Sj
+ ∇ (κu) − κ∇ · u = − κ+ (354)
∂t 3α 3Ψ ai j
α
| {z }
IV
The interaction model source terms in the curvature equation of OpenFOAM takes the following form:
∂κ 1 α̇ X
+ ∇ (κu) − κ∇ · u = − κ+ Rj κ (369)
∂t 3α j
| {z }
IV
We now compare the terms marked with IV of Eqns. (354) and (369). As these terms must be equal, we
can form the following equation.
2 X
1 α Sj X
= Rj κ (370)
3Ψ ai j
α j
We now demand, that the summands need to be equal, and we focus on the term for turbulent break-up (TI)
2 r r
1 α 1 nut W ecr W ecr 1 CT I W ecr W ecr
CT I exp − 1− = ut 1 − exp − κ (371)
3Ψ ai α Db We We 3 dsm We We
| {z } | {z }
Sj Rj
Next, we cancel all common symbols and expressions, note the different symbols for the bubble diameter
(Db = dsm )
2
1 α 1
n=κ (372)
Ψ ai α
This offering is not approved or endorsed by ESI® Group, ESI-OpenCFD® or the OpenFOAM®
IX 427
Foundation, the producer of the OpenFOAM® software and owner of the OpenFOAM® trademark.
We now insert the definition of n, see Eq. (360)
2
1 a3i
1 α
Ψ =κ (373)
Ψ ai α α2
ai
=κ (374)
α
We now end up with an equation that is fulfilled, when we look at the definition of κ, see Eqn. (345)
ai = ακ (345)
Thus, we have demonstrated on the example of the source term for turbulent break-up of bubbles, that the
implementation of OpenFOAM follows exactly the model published in [35].
65.5 Appendix
65.5.1 The proof for Eqn. (338)
We use the following symbols.
x=V (375)
f (x) = f (V, x, t) (376)
g(x) = Ai (V ) (377)
a = Vmin (378)
b = Vmax (379)
We now take a closer look on the relation between the average interfacial area of a bubble Ai and the volume
of a bubble V .
Ai = d2 π (384)
d3 π
V = (385)
6 r
3 6V
⇒d= (386)
π
2/3
6V
Ai = π (387)
π
This offering is not approved or endorsed by ESI® Group, ESI-OpenCFD® or the OpenFOAM®
IX 428
Foundation, the producer of the OpenFOAM® software and owner of the OpenFOAM® trademark.
Returning to our simplified notation for this proof
2/3
6x
g(x) = π (388)
π
Z b Z b
∂ dx 2 g(x) dx
g(x) f (x) dx = − f (x) dx (393)
a ∂x dt a 3 x dt
Z b
2 b ẋ
Z
∂ dx
g(x) f (x) dx = − f (x)g(x)dx (394)
a ∂x dt 3 a x
Next, we take a closer look on the term ẋx . Since x is the volume of the bubbles V , we can relate V to
the void fraction or gas phase volume fraction α. For any control volume VCV we can state, that the volume
of the bubbles V is equal to the volume fraction times the control volume. Here we neglect mass transfer by
evaporation, see [34] for a derivation considering evaporation.
V = αVCV (395)
V̇ = α̇VCV (396)
V̇ α̇VCV α̇
= = (397)
V αVCV α
ẋ α̇
= (398)
x α
We further assume that the rate of change of volume is independent of the volume itself [34, 40].
V̇
6= f (V ) (399)
V
By using relation (394) and (398) on Eqn. (394), we gain
b
2 α̇ b
Z Z
∂ dx
g(x) f (x) dx = − f (x)g(x)dx (400)
a ∂x dt 3α a
This offering is not approved or endorsed by ESI® Group, ESI-OpenCFD® or the OpenFOAM®
IX 429
Foundation, the producer of the OpenFOAM® software and owner of the OpenFOAM® trademark.
66 Derivation of the governing equations for the MRF approach
66.1 Preliminary observations
In order to use the MRF approach the mesh has to be divided into different regions. As the MRF approach in
OpenFOAM covers only rotating reference frames246 only rotation can be imposed on a region. A region for
which a non-zero rotation is specified has to be axi-symmetric with respect to the rotational axis. Furthermore,
older versions of OpenFOAM247 only support steady rotation, i.e. the angular velocity ω is constant.
66.1.1 Pitfalls
Axi-symmetric region for MRF rotation
As stated above, the MRF region for applying reference frame rotations has to be axi-symmetric. However,
OpenFOAM performs no checks to test whether this is the case. Thus, on a region axi-symmetic with respect
to the z-axis, may very well be used to prescribe a reference frace rotation around the x-axis. The results will
be blatantly wrong, and the solver might crash. However, if you are unlucky enough, the solver will not crash
and compute woefully wrong results, wasting time and computational resources.
Always check whether the axis of the MRFProperties coincides with the sym-
metry axis of your MRF zone. Furthermore, make sure that origin of the
MRFProperties lies on the symmetry axis of the MRF zone.
∇·u = 0 (403)
is valid in all inertial frames of reference. An inertial frame of reference is either fixed in space and time or
moving with a constant translational velocity.
Due to the constraints listed in the previous section we consider only rotating reference frames in the MRF
method. To translate a vector from its representation in the inertial frame of reference to the rotating frame of
reference a rotation matrix Q is used. A rotation matrix has the property that the inverse is also the transposed.
Ru = Qu (404)
T
u=Q Ru (405)
−1 T
Q =Q (406)
The index R before the symbol u denotes that the vector R u is given in the rotating frame of reference. If
there is no index before the symbol the vector is given in the inertial coordinate system. The index R is put
before the symbol to prevent the vector R u to be mistaken as a relative velocity.
Beginning with the mass conservation equation in the inertial coordinate system we derive the mass conser-
vation in the rotating coordinate system.
∇·u = 0 (407)
∇· QT Q u = 0
(408)
| {z }
=I
∇· QT R u = 0
(409)
246 E.g. in Fluent it is possible to prescribe frame motion with unsteady translational and rotational speeds [9]. This leads
essentially to more additional terms in the governing equations. OpenFOAM, however, limits the frame motion to steady rotation.
247 Prior to OpenFOAM-3.0, see Section 66.4.2.
This offering is not approved or endorsed by ESI® Group, ESI-OpenCFD® or the OpenFOAM®
IX 430
Foundation, the producer of the OpenFOAM® software and owner of the OpenFOAM® trademark.
We use the relation ∇·(A·a) = (∇·A)·a + A : (∇a) and the note that the rotation matrix is constant in
space.
∇· QT R u = ∇·QT ·R u + QT : (∇R u)
(410)
| {z }
=0
∇· Q R u = QT : (∇R u)
T
(411)
QT : (∇R u) = 0 (412)
Next we multiply the equation from the left with the rotation matrix.
QQT : (∇R u) = 0 (413)
I : (∇R u) = 0 (414)
We remember that the contraction of the unit tensor and a velocity gradient is equal to the divergence of the
velocity.
I : (∇R u) = ∇·R u (415)
∇·R u = 0 (416)
Thus, we showed that the mass convervation equation with the velocity expressed in the rotating coordinate
system has the same formulation as the mass conservation equation in inertial coordinates.
u = ω × r + uR (417)
Eq. (417) can also be written in this form using the spin tensor Ω
u = Ω r + uR (418)
The spin tensor is a skew-symmetric tensor that contains the components of ω, the angular velocity vector.
0 −ωz ωy
Ω = ωz 0 −ωx (419)
−ωy ωx 0
We now derive the momentum equation for the velocity for the rotating zone starting from the momentum
conservation equation for incompressible Newtonian fluids.
∂u ∇p
+ (∇u) ·u = − + ∇· (ν∇u) (420)
∂t ρ
The terms on the LHS are the total time derivate of u. Thus, we can write
du ∇p
=− + ∇· (ν∇u) (421)
dt ρ
With Eq. (417) we yield
d ∇p
(Ω r + uR ) = − + ∇· (ν∇u) (422)
dt ρ
We consider only steady rotation; thus, the temporal derivative of the spin vanishes
duR dΩ dr ∇p
+ r+Ω =− + ∇· (ν∇u) (423)
dt dt
|{z} dt ρ
=0
duR ∇p
+ Ωu = − + ∇· (ν∇u) (424)
dt ρ
This offering is not approved or endorsed by ESI® Group, ESI-OpenCFD® or the OpenFOAM®
IX 431
Foundation, the producer of the OpenFOAM® software and owner of the OpenFOAM® trademark.
We now evaluate the total time derivative of uR
∂uR ∂uR dx ∇p
+ +Ωu = − + ∇· (ν∇u) (425)
∂t ∂x dt
| {z } |{z} ρ
=∇uR =u
∂uR ∇p
+ (∇uR ) ·u + Ωu = − + ∇· (ν∇u) (426)
∂t ρ
∂ ∇p
(u − Ω r) + (∇uR ) ·u + Ωu = − + ∇· (ν∇u) (427)
∂t ρ
∂
As the velocity component due to the steady rotation of the reference frame is constant, the term ∂t (Ω r) will
vanish
∂u ∇p
+ (∇uR ) ·u + Ωu = − + ∇· (ν∇u) (428)
∂t ρ
The second term on the LHS can be rewritten using the following identity
∂u ∇p
+ ∇· (uR u) = − + ∇· (ν∇u) − Ωu (431)
∂t ρ
Eq. (431) corresponds to the momentum equation in absolute velocity formulation that can be found in the
Fluent Theory Manual [9]. Another resource for the MRF approach in OpenFOAM is [48].
66.4.1 OpenFOAM-2.*
In OpenFOAM-2.2.x the MRF method is part of the fvOptions mechanism248 . This is a general mechanism
that allows for run-time selectable physics. The fvOptions framework is a generalization for the source terms in
the momentum equation. Via this framework the MRF approach can be selected along with momentum (e.g.
wind turbine rotors), porosity (i.e. for modelling porous zones) and energy sources (e.g. for regions with heat
transfer).
To provide this flexibility the fvOptions framework is implemented using an abstract class to define the
behaviour of the general source. Derived class implement the actual physics, e.g. the MRF method. Thus the
class MRFSource is derived from option.
The constructor of the class MRFSource calls the method initialise(). This method is defined in the
class MRFSource and calls the method correctBoundaryVelocity of the class MRFZone. In the method
correctBoundaryVelocity the velocity values of boundaries within an MRF-zone are set to the solid body
rotational velocity. Otherwise the no-slip boundary condition would enforce a zero absolute velocity which
would be clearly wrong.
248 See http://www.openfoam.org/version2.2.0/fvOptions.php
This offering is not approved or endorsed by ESI® Group, ESI-OpenCFD® or the OpenFOAM®
IX 432
Foundation, the producer of the OpenFOAM® software and owner of the OpenFOAM® trademark.
In Listing 527 we see the prescription of the solid body velocity for all faces that lie within the MRF-zone.
On these faces the solid body velocity is prescribed.
66.4.2 OpenFOAM-3.*
With OpenFOAM-3.0.0250 the MRF method was taken out from the fvOptions framework. The developers of
OpenFOAM give the following reason for this mode:
fvOptions does not have the appropriate structure to support MRF as it is based on option
selection by user-specified fields whereas MRF MUST be applied to all velocity fields in the particular
solver. A consequence of the particular design choices in fvOptions made it difficult to support MRF
for multiphase and it is easier to support frame-related and field related options separately.
Currently the MRF functionality provided supports only rotations but the structure will be
generalized to support other frame motions including linear acceleration, SRF rotation and 6DoF
which will be run-time selectable.
As noted in the cited message above, the MRF framework was also generalized. Thus, rotating reference frames
are not limited to steady rotations anymore. Listing 528 shows how this change allows to spin-up reference
frame rotation. This might improve numerical behaviour in the initial stages of the simulation.
249 In fact the zone can be any volume defined by any surface of revolution of the rotational axis of the reference frame. However,
This offering is not approved or endorsed by ESI® Group, ESI-OpenCFD® or the OpenFOAM®
IX 433
Foundation, the producer of the OpenFOAM® software and owner of the OpenFOAM® trademark.
MRF1
{
cellZone rotor ;
active yes ;
n o n R o t a t i ng P a t c h e s () ;
origin (0 0 0) ;
axis (0 0 1) ;
omega table
2(
(0 0.01)
(0.5 104.72)
);
}
This offering is not approved or endorsed by ESI® Group, ESI-OpenCFD® or the OpenFOAM®
IX 434
Foundation, the producer of the OpenFOAM® software and owner of the OpenFOAM® trademark.
Part X
Appendix
67 Useful Linux commands
67.1 Getting help
67.1.1 Display –help
Virtually all Linux commands display a summary of the programs purpose and usage. To display this message
the command has to be invoked with one of those parameters: -h, -help, --help. If the wrong parameter is
used the help message is displayed anyway or an error message naming the correct parameter to display the
usage information, see Listing 529.
Apparently all of the tools and solvers of OpenFOAM251 display such help messages. New Linux and
OpenFOAM users are strongly encouraged to study the help messages to deepen their understanding and
insight.
man cp
The man pages cover general commands of Linux, system call, library function of the C standard library
and much more. On some systems the man pages are only partially or not at all installed by default.
This offering is not approved or endorsed by ESI® Group, ESI-OpenCFD® or the OpenFOAM®
X 435
Foundation, the producer of the OpenFOAM® software and owner of the OpenFOAM® trademark.
find $ FO AM _T U TO RI AL S - name LESProperties
find looks for respectively finds all files with the name passed with the option -name in the specified folder
and its folders. xargs executes the passed command line. The output of find is passed to grep as input by a
pipe. grep then scans all files for the word probes.
cd $F OA M _T UT ORI AL S
git grep probes
Dispersed phase volume fraction = 0.194351 Min ( alpha ) = 7.52826 e -42 Max ( alpha ) = 1
Dispersed phase volume fraction = 0.060562 Min ( alpha ) = 2.30261 e -52 Max ( alpha ) = 1.00003
This offering is not approved or endorsed by ESI® Group, ESI-OpenCFD® or the OpenFOAM®
X 436
Foundation, the producer of the OpenFOAM® software and owner of the OpenFOAM® trademark.
Listing 536 shows how the user can scan the log file for the appropiate pattern. grep expects as first argument
the pattern to look for. The second argument is optional, it specifies the file from which to read. If no file was
specified, grep would read from standard input. The option -c makes grep display only the number of number
of matches. Otherwise, grep would display all lines in which a match was found. In a situation in which the
number of hits could reach hundreds or thousands, displaying all lines with a match could be unwise.
The first command in Listing 536 would detect a match for both lines of Listings 535. So this pattern
’Max(alpha) = 1’ is not useful to find out whether α exceeded unity or not.
The second command in Listing 536 will only detect lines in which α is larger than unity. So, of the two
lines of Listings 535, only the second one would result in a match.
# !/ bin / bash
# fine 01
echo ’ fine01 ’
cd ’ ./ f u l l C o l um n _ f i n e V 0 1 ’
echo ’ decomposing ’
decomposePar > foamDecompose . log
echo ’ reconstructing ’
reco nstructP ar > fo am Re c on st ru c t . log
# fine 02
echo ’ fine02 ’
cd ’ ../ f u l l C o l u m n _ f i n e V 0 2 ’
echo ’ decomposing ’
decomposePar > foamDecompose . log
This offering is not approved or endorsed by ESI® Group, ESI-OpenCFD® or the OpenFOAM®
X 437
Foundation, the producer of the OpenFOAM® software and owner of the OpenFOAM® trademark.
of runCalculations has to be known. In Section 12.3.2 explains this bit in detail. Listing 537 shows how to look
for the PID. The command in Listing 537 outputs two lines. The first line comes from the running script and
the second line stems from the running parallel calculation. This is because all running processes matching the
pattern run were searched for. Therefore, also the running instance of mpirun was found.
67.6 diff
diff is a command line tool that analyses two files and prints a summary of the differences of those files.
Further information on diff can be found in the man-pages or the help-message.
67.6.1 Meld
Meld is a graphical front-end to diff. This allows for a side-by-side comparison of both files under investi-
gation. Parts of the file that differ are highlighted by colors. For more information about Meld see http:
//meldmerge.org/.
This offering is not approved or endorsed by ESI® Group, ESI-OpenCFD® or the OpenFOAM®
X 438
Foundation, the producer of the OpenFOAM® software and owner of the OpenFOAM® trademark.
Figure 158: A screenshot of Meld
Listing 540: Change the extension of all files having the extension air to argon.
67.8 Miscellaneous
This section contains references to useful scripts or commands explained elsewhere in this document.
This offering is not approved or endorsed by ESI® Group, ESI-OpenCFD® or the OpenFOAM®
X 439
Foundation, the producer of the OpenFOAM® software and owner of the OpenFOAM® trademark.
Delete the processor* directories
If one or several simulations have been conducted on a computing cluster, it makes sense so reconstruct the
domain on the cluster. Otherwise the workstation of the user would be blocked for the time needed to complete
reconstruction. After reconstructing the domain the processor* directories still contain all the time step data.
If the processor* folders are deleted on the cluster, the user can afterwards copy the whole case directory to the
workstation without transmitting the solution data twice.
See Section 12.5.2 for how to deal with processor* directories.
Redirect output
Redirecting the output of a program is explained in Section 12.1.1.
This offering is not approved or endorsed by ESI® Group, ESI-OpenCFD® or the OpenFOAM®
X 440
Foundation, the producer of the OpenFOAM® software and owner of the OpenFOAM® trademark.
68 Archive data
Parametric studies generate a great deal of data. After the post-processing is done all files could be compressed
to save disk space. On Linux systems the tar archiving utility may be the agent of choice. The name tar comes
from tape archive, which is pretty descriptive in terms of the origins of this archiving program. A tar archive
is a single file which contains all archived files and folders. This step alone is only a reorganisation of the data,
fit for the usage of sequential data storage devices like magnetic tapes.
In a second step the tar archive needs to be compressed. For this task there are many possible choices. Linux
systems usually provide programs like gzip, bzip2 or xz. The distinction between archiving and compressing is
probably for historical as well as practical reasons. There is also one paradigm of the UNIX philosophy (Make
each program do one thing well) which supports the segregation in archiving and compression. The compression
programs usually differ in the utilised compression algorithms. There is one rule of thumb stating: The more
data is to be compressed, the longer compression takes.
Table 9 lists the achieved compression of a parametric studies with 21 cases totalling in 50 GB of data. The
data was written in ascii format. Compressing the data resulted in a 70+ % reduction of used disk space. If
space consuming cases are to archived, slow algorithms that result in good compression rates should be prefered.
Listing 541: Compressing the mesh with various tools; note the setting for maximum compression
Listing 542 shows the sizes of the original mesh and its compressed forms. The used compression algo-
rithms differ considerably. Compression was performed with the setting for best compression, the time it took
for each tool to compress the mesh was not recorded. However, the stronger the compression the more time it
takes to compress. Since for archiving purposes disk space is the limiting factor, we chose maximum compression.
This offering is not approved or endorsed by ESI® Group, ESI-OpenCFD® or the OpenFOAM®
X 441
Foundation, the producer of the OpenFOAM® software and owner of the OpenFOAM® trademark.
user@host :∼$ du - sh polyMesh *
23 M polyMesh
5 ,3 M polyMesh . tar . bz
6 ,2 M polyMesh . tar . gz
2 ,6 M polyMesh . tar . xz
Listing 542: Comparing the disk usage of a mesh and its various compressions
From the comparison in Listing 542 we see that the LZMA compression algorithm achieves the best com-
pression, followed by BZIP2 and GZIP. All three compression algorithms are widely available in the UNIX world
in the form of open source implementations.
Table 11: Comparing the resulting file size of the mesh archive file for various conditions/treatments. All file
or folder sizes were determined with the Linux command du -sh FILE. The mesh was compressed using the
LZMA algorithm at maximum compression: tar -cv constant/polyMesh | lzma -9 > polyMesh.tar.xz.
We can draw two conclusions from this comparison. The most obvious is, that writing data in binary format
is always favourable over writing in ascii format, especially for uncompressed data. Writing in ascii should only
be used for trouble-shooting. In production, binary is definitely the format of choice. Writing in binary not
only saves disk space in storage, it also provides the maximum read/write precision, since all relevant bits of
each numerical value are stored. In contrast, writing in ascii format only writes a finite number of significant
bits.
The second conclusion we can draw from the comparison above, is not to store the renumbered mesh. Even
if renumbering would/does254 not increase archive file size, renumbering is an operation we can easily perform
prior to our simulation. The time it takes to renumber the mesh is negligible compared to the overall simulation
time. Thus, we advise to archive meshes in an un-renumbered state. This, in addition to potential savings
on storage, gives future users the choice whether to run the simulation on a renumbered mesh or not. On an
already renumbered mesh it is impossible to determine the benefits of renumbering the mesh with respect to
simulation time or convergence. An operation which can always be performed at demand does not need to be
archived.
253 We denote the state of the mesh after mesh-creation by the term as-is in order to distinguish it from the renumbered state.
Mesh creation consists of a call to blockMesh, extruding a patch and finally removing parts of the mesh with subsetMesh. After
these steps, any sets of points, faces or cells are deleted. Also zones of any kind have not been defined. Thus, as-is denotes the
final, minimal mesh.
254 One case of renumbering causing larger archive file sizes does not necessarily mean that this will always cause this effect.
This offering is not approved or endorsed by ESI® Group, ESI-OpenCFD® or the OpenFOAM®
X 442
Foundation, the producer of the OpenFOAM® software and owner of the OpenFOAM® trademark.
References
[1] Intel 64 and IA-32 Architectures Optimization Reference Manual.
[2] Viscosity of gases. In David R. Lide, editor, CRC Handbook of Chemistry and Physics. CRC Press, 2005.
[12] A. Behzadi, R. I. Issa, and H. Rusche. Modelling of dispersed bubble and droplet flow at high phase
fractions. Chemical Engineering Science, 59:759–770, 2004.
[13] J. Boussinesq. Théorie de l’Écoulement tourbillant. Mem. Présentés par Drivers Savants Acad. Sci. Inst.
Fr., 23:46–50, 1877.
[14] Daniel Brennan. The Numerical Simulation of Two-Phase Flows in Settling Tanks. PhD thesis, Imperial
College of Science, Technology & Medicine, 2001.
[15] A. Burcat and B. Ruscic. Third millennium ideal gas and condensed phase thermochemical database for
combustion and updates from active thermochemical tables. Technical report, Argonne National Labora-
tory, 2005.
[16] N. Böcker, M. Grahl, A. Tota, P. Häussinger, P. Leitgeb, and B. Schmücker. Ullmann’s Encyclopedia of
Industrial Chemistry, chapter Nitrogen. Wiley-VCH Verlag GmbH & Co. KGaA, 2013.
[17] Yunus A. Çengel. Heat Transfer - a practical approach. McGraw-Hill, second edition, 2003.
[18] S. Chapman and T. G. Cowling. Mathematical theory of non-uniform gases. Cambridge University Press,
1952.
[19] C. P. Dahl. Numerical modelling of flow and settling in secondary settling tanks. PhD thesis, Aalborg
University, Denmark, 1993.
[20] J.-M. Delhaye. Some issues related to the modeling of interfacial areas in gas-liquid flows I. the conceptual
issues. Comptes Rendus de l’Académie des Sciences - Series {IIB} - Mechanics, 329(5):397–410, 2001.
[21] M. T. Dhotre and J. B. Joshi. CFD simulation of heat transfer in turbulent pipe flow. Industrial &
Engineering Chemistry Research, 43:2816–2829, 2004.
[22] Eric S. Raymond. The Art of UNIX Programming. Addison-Wesley, 2003.
[23] A. Eucken. Über die temperaturabhängigkeit der wärmeleitfähigkeit einiger gase. Physikalische Zeitschrift,
12(24):1101–1107, 1911.
[24] A. Eucken. Über das wärmeleitvermögen, die spezifische wärme und die innere reibung der gase. Physikalis-
che Zeitschrift, 14(8):324–331, 1913.
This offering is not approved or endorsed by ESI® Group, ESI-OpenCFD® or the OpenFOAM®
X 443
Foundation, the producer of the OpenFOAM® software and owner of the OpenFOAM® trademark.
[25] Agner Fog. Optimizing software in c++. Technical report, Technical University of Denmark, 2014.
[26] J. Fröhlich. Large Eddy Simulationen turbulenter Strömungen. Teubner, 2006.
[27] E. Peirano & A.-E. Almstedt H. Enwald. Eulerian two-phase flow theory applied to fluidization. Int. J.
Multiphase Flow, 22:21–66, 1996.
[28] David P. Hill. The computer simulation of dispersed two-phase flows. PhD thesis, Imperial College of
Science, Technology and Medicine, 1998.
[29] C. L. Hogan and R. B. Sawyer. The thermal conductivity of mmetal at high temperature. Journal of
Applied Physics, 23(2):177–180, 1952.
[30] B. Holenda, I. Pásztor, Á. Kárpáti, and Á Rédey. Comparison of one-dimensional secondary settling tank
models. Technical report, European Water Association (EWA), 2006.
[31] J. R. Howell, R. Siegel, and Mengüç. Thermal Radiation Heat Transfer. CRC Press, fifth edition, 2010.
[32] M. Ishii. One-dimensional drift-flux-model and constitutive equations for relative motion between pphase
in various two-phase flow regimes. Technical report, Argonne National Laboratory, 1977.
[33] M. Ishii and T. Hibiki. Thermo-Fluid Dynamics of Two-Phase Flow. Springer, 2nd edition, 2011.
[34] M. Ishii, S. Kim, and J. Uhle. Interfacial area transport equation: model development and benchmark
experiments. International Journal of Heat and Mass Transfer, 45:3111–3123, 2002.
[35] M. Ishii, S. Kim, and J. Kelly. Development of interfacial area transport equation. Nuclear Engineering
and Technology, 37(6):525–536, 2005.
[36] R. I. Issa. A simple model for ct . Private Communications, 1992. see Hill [28].
[37] M. Peric J. H. Ferzinger. Computational Methods for Fluid Dynamics. Springer, 2002.
[38] Hrvoje Jasak. Error Analysis and Estimation for the Finite Volume Method with Applications to Fluid
Flows. PhD thesis, Imperial College of Science, Technology & Medicine, 1996.
[39] Brian W. Kernighan and Dennis M. Ritchie. The C Programming Language. Prentice Hall, Inc., 2nd
edition, 1988.
[40] S. Kim, X. Sun, M. Ishii, S. G. Beus, and F. Lincoln. Interfacial area transport and evaluation of source
and sink terms for confined air-water bubbly flow. Nuclear Engineering and Design, 219:61–75, 2002.
[41] G. Kocamustafaogullari and M. Ishii. Foundation of the interfacial area transport equation and its closure
relations. Int. J. Heat Mass Transfer, 38(3):481–493, 1995.
[42] Fabian Peng Kärrholm. Numerical Modelling of Diesel Spray Injection, Turbulence Interaction and Com-
bustion. PhD thesis, Chalmers University of Technology, Göteborg, Sweden, 2008.
[43] Y. Liu, T. Hibiki, and M. Ishii. Modeling of interfacial area transport in two-phase flows. In Advances in
Multiphase Flow and Heat Transfer, volume 4, chapter 1, pages 3–27. Bentham Science Publishers, 2012.
[44] Alejandro López. Lpt for erosion modeling in openfoam – differences between solidparticle and kine-
maticparcel, and how to add erosion modeling. Technical report, Chalmers University of Technol-
ogy, 2014. URL http://www.tfd.chalmers.se/~hani/kurser/OS_CFD_2013/AlejandroLopez/LPT_for_
erosionModelling_report.pdf.
[45] G. B. Macpherson, N. Nordin, and H. G. Weller. Particle tracking in unstructured, arbitrarry polyhedral
meshes for use in cfd and molecular dynamics. Communications in Numerical Methods in Engineering, 25:
263–273, 2009.
[46] Holger Marschall. Towards the Numerical Simulation of Multi-Scale Two-Phase Flows. PhD thesis, Tech-
nische Universität München, 2011.
[47] M. Milelli. A numerical analysis of confined turbulent bubble plumes. PhD thesis, Swiss Federal Institute
of Technology Zurich, 2002.
This offering is not approved or endorsed by ESI® Group, ESI-OpenCFD® or the OpenFOAM®
X 444
Foundation, the producer of the OpenFOAM® software and owner of the OpenFOAM® trademark.
[48] Hakan Nilsson. Turbomachinery training at ofw8. Technical report, Chalmers University of Technology,
Gothenburg, Sweden, 2013.
[49] Niklas Nordin. Complex Chemistry Modeling of Diesel Spray Combustion. PhD thesis, Chalmers University
of Technology, 2009.
[50] International Union of Pure and Applied Chemistry. Iupac compendium of chemical terminology – the
gold book, 2014. URL http://goldbook.iupac.org/.
[51] OpenFOAM - Programmer’s Guide. OpenFOAM Foundation, 2.1.0 edition, 2011.
[52] OpenFOAM - User Guide. OpenFOAM Foundation, 2.1.0 edition, 2011.
[53] D. Pfleger and S. Becker. Modelling and simulation of the dynamic flow behaviour in a bubble column.
Chemical Engineering Science, 56:1737–1747, 2001.
[54] B. E. Poling, J. M. Prausnitz, and J. P. O’Connell. The Properties of Gases and Liquids. McGraw-Hill,
fifth edition edition, 2000.
[55] S. P. Pope. Turbulent Flows. Cambridge University Press, 2000.
[56] Henrik Rusche. Computational Fluid Dynamics of dispersed two-phase flows at high phase fractions. PhD
thesis, Imperial College of Science, Technology & Medicine, 2002.
[57] Y. Sato and K. Sekoguchi. Liquid velocity distribution in two-phase flow. International Journal of Multi-
phase Flow, 2:79–95, 1975.
[58] J. Smagorinsky. General circulation experiments with the primitive equations; i. the basic experiment.
Monthly Weather Review, 91:99, 1963.
[59] Bjarne Stroustrup. The C++ Programming language. Addison-Wesley, 4th edition, 2013.
[60] William Sutherland. Lii. the viscosity of gases and molecular force. The London, Edinburgh, and Dublin
Philosophical Magazine and Journal of Science, 36(223):507–531, 1893.
[61] Imre Takács. Experiments in Activated Sludge Modelling. PhD thesis, Ghent University, Belgium, 2008.
[62] D. G. Thomas. Transport characteristics of suspension: VIII. a note on the viscosity of Newtonian suspen-
sions of uniform spherical particles. Journal of Colloid Science, 1965.
[63] A. Tomiyama, I. Kataoka, T. Fukuda, and T. Sakaguchi. Drag coefficients of bubbles. 2nd report. drag
coefficient for a swarm of bubbles and its applicability to transient flow. Nippon Kikai Gakkai Ronbunshu,
61(588):2810–2817, 1995.
[64] VDI-Gesellschaft Verfahrenstechnik und Chemieingenieurwesen (GVC). Thermophsical properties. In VDI
Heat Atlas. Springer, 2010.
[65] Berend van Wachem. Derivation, implementation and validation of computer simulation models for gas-
solid fluidized beds. PhD thesis, Delft University of Technology, 2000.
[66] H. K. Versteeg and W. Malalasekera. An introduction to computational fluid dynamics – the finite volume
method. Longman Scientific & Technical, 1995.
[67] A. Vesilind. Design of prototype thickeners from batch settling tests. Water Sewage Works, 115(5):302–307,
1968.
[68] H. G. Weller, G. Tabor, H. Jasak, and C. Fureby. A tensorial approach to computational continuum
mechanics using object-oriented techniques. Computers in Physics, 12:620–631, 1998.
[69] David C. Wilcox. Turbulence Modelling for CFD. DCW Industries, Inc., 1994.
[70] M. L. Williams, R. F. Landel, and J. D. Ferry. The temperature dependence of relaxation mechanisms in
amorphous polymers and other glass-forming liquids. Journal of the American Chemical society, 77(14):
3701–3707, 1955.
[71] D. Zhang, N. G. Deen, and J. A. M. Kuipers. Numerical simulation of the dynamic flow behaviour in a
bubble column: A study of closures for turbulence and interface forces. Chemical Engineering Science, 61:
7593–7608, 2006.
This offering is not approved or endorsed by ESI® Group, ESI-OpenCFD® or the OpenFOAM®
X 445
Foundation, the producer of the OpenFOAM® software and owner of the OpenFOAM® trademark.
Nomenclature
This offering is not approved or endorsed by ESI® Group, ESI-OpenCFD® or the OpenFOAM®
X 446
Foundation, the producer of the OpenFOAM® software and owner of the OpenFOAM® trademark.